Improved gamepad support

- Gamepads are now recognized by their "vendor" and "product" codes only.
- It was previously including other information like name, version etc
- Added a new item on the Settings page for "default gamepad type"
- If a gamepad is not "recognized", it is treated as the default type
This commit is contained in:
David Carley
2022-09-11 17:28:53 +00:00
parent 1cda3cbbef
commit 2851239ce4
7 changed files with 814 additions and 659 deletions

View File

@@ -29,6 +29,8 @@ class Config(object):
self.log.exception( self.log.exception(
'Internal error: Failed to load config template') 'Internal error: Failed to load config template')
self.reload()
def load(self): def load(self):
path = self.ctrl.get_path('config.json') path = self.ctrl.get_path('config.json')

View File

@@ -32,7 +32,7 @@ class Ctrl(object):
self.mach = bbctrl.Mach(self, self.avr) self.mach = bbctrl.Mach(self, self.avr)
self.preplanner = bbctrl.Preplanner(self) self.preplanner = bbctrl.Preplanner(self)
if not args.demo: if not args.demo:
self.jog = bbctrl.Jog(self) self.gamepadSupport = bbctrl.GamepadSupport(self)
self.pwr = bbctrl.Pwr(self) self.pwr = bbctrl.Pwr(self)
self.mach.connect() self.mach.connect()

View File

@@ -4,7 +4,6 @@ from evdev.ecodes import EV, EV_ABS, EV_KEY
import errno import errno
import evdev import evdev
import functools import functools
import hashlib
import json import json
import os import os
import pyudev import pyudev
@@ -14,16 +13,16 @@ import typing
userGamepadConfigs = {} userGamepadConfigs = {}
gamepadConfigs = { factoryGamepadConfigs = {
"default": { "default": {
"sign-x": 1, "sign-x": 1,
"sign-y": -1, "sign-y": -1,
"sign-z": -1, "sign-z": -1,
"deadband": 0.15, "deadband": 0.15,
"debug": False, "debug": False,
"type": "XBOX",
}, },
"9E2B3A63": { "XBOX": {
"description": "Logitech 710, X mode",
"EV_KEY:308": "speed-4", "EV_KEY:308": "speed-4",
"EV_KEY:305": "speed-3", "EV_KEY:305": "speed-3",
"EV_KEY:304": "speed-2", "EV_KEY:304": "speed-2",
@@ -38,8 +37,7 @@ gamepadConfigs = {
"EV_ABS:2": "lock-y", "EV_ABS:2": "lock-y",
"EV_ABS:5": "lock-x", "EV_ABS:5": "lock-x",
}, },
"B98EF4EC": { "PLAYSTATION": {
"description": "Logitech 710, D mode",
"EV_KEY:307": "speed-4", "EV_KEY:307": "speed-4",
"EV_KEY:306": "speed-3", "EV_KEY:306": "speed-3",
"EV_KEY:305": "speed-2", "EV_KEY:305": "speed-2",
@@ -54,24 +52,7 @@ gamepadConfigs = {
"EV_KEY:310": "lock-y", "EV_KEY:310": "lock-y",
"EV_KEY:311": "lock-x", "EV_KEY:311": "lock-x",
}, },
"268256FD": { "SMX-LEFT": {
"description": "EasySMX ESM-9013, top lights mode",
"EV_KEY:308": "speed-4",
"EV_KEY:305": "speed-3",
"EV_KEY:304": "speed-2",
"EV_KEY:307": "speed-1",
"EV_ABS:0": "axis-x",
"EV_ABS:16": "axis-x",
"EV_ABS:1": "axis-y",
"EV_ABS:17": "axis-y",
"EV_ABS:4": "axis-z",
"EV_KEY:310": "lock-y",
"EV_KEY:311": "lock-x",
"EV_ABS:2": "lock-y",
"EV_ABS:5": "lock-x",
},
"23CEC0CB": {
"description": "EasySMX ESM-9013, left lights mode",
"EV_KEY:304": "speed-4", "EV_KEY:304": "speed-4",
"EV_KEY:305": "speed-3", "EV_KEY:305": "speed-3",
"EV_KEY:306": "speed-2", "EV_KEY:306": "speed-2",
@@ -86,8 +67,7 @@ gamepadConfigs = {
"EV_KEY:310": "lock-y", "EV_KEY:310": "lock-y",
"EV_KEY:311": "lock-x", "EV_KEY:311": "lock-x",
}, },
"370DCB72": { "SMX-BOTTOM": {
"description": "EasySMX ESM-9013, bottom lights mode",
"EV_KEY:308": "speed-4", "EV_KEY:308": "speed-4",
"EV_KEY:305": "speed-3", "EV_KEY:305": "speed-3",
"EV_KEY:304": "speed-2", "EV_KEY:304": "speed-2",
@@ -102,117 +82,77 @@ gamepadConfigs = {
"EV_KEY:312": "lock-y", "EV_KEY:312": "lock-y",
"EV_KEY:313": "lock-x", "EV_KEY:313": "lock-x",
}, },
"0BD0841F": { "045E:02A1": {
"description": "Sony Playstation 4 Dual-Shock Controller",
"EV_KEY:307": "speed-4",
"EV_KEY:306": "speed-3",
"EV_KEY:305": "speed-2",
"EV_KEY:304": "speed-1",
"EV_ABS:0": "axis-x",
"EV_ABS:16": "axis-x",
"EV_ABS:1": "axis-y",
"EV_ABS:17": "axis-y",
"EV_ABS:5": "axis-z",
"EV_KEY:308": "lock-y",
"EV_KEY:309": "lock-x",
"EV_KEY:310": "lock-y",
"EV_KEY:311": "lock-x",
},
"D09463DD": {
"description": "Sony Playstation 5 Controller",
"EV_KEY:307": "speed-4",
"EV_KEY:306": "speed-3",
"EV_KEY:305": "speed-2",
"EV_KEY:304": "speed-1",
"EV_ABS:0": "axis-x",
"EV_ABS:16": "axis-x",
"EV_ABS:1": "axis-y",
"EV_ABS:17": "axis-y",
"EV_ABS:5": "axis-z",
"EV_KEY:308": "lock-y",
"EV_KEY:309": "lock-x",
"EV_KEY:310": "lock-y",
"EV_KEY:311": "lock-x",
},
"06656EBD": {
"description": "XBox One Controller",
"EV_KEY:308": "speed-4",
"EV_KEY:305": "speed-3",
"EV_KEY:304": "speed-2",
"EV_KEY:307": "speed-1",
"EV_ABS:0": "axis-x",
"EV_ABS:16": "axis-x",
"EV_ABS:1": "axis-y",
"EV_ABS:17": "axis-y",
"EV_ABS:4": "axis-z",
"EV_KEY:310": "lock-y",
"EV_KEY:311": "lock-x",
"EV_ABS:2": "lock-y",
"EV_ABS:5": "lock-x",
},
"BFF99E89": {
"description": "XBox 360 Controller", "description": "XBox 360 Controller",
"EV_KEY:308": "speed-4", "type": "XBOX"
"EV_KEY:305": "speed-3",
"EV_KEY:304": "speed-2",
"EV_KEY:307": "speed-1",
"EV_ABS:0": "axis-x",
"EV_ABS:16": "axis-x",
"EV_ABS:1": "axis-y",
"EV_ABS:17": "axis-y",
"EV_ABS:4": "axis-z",
"EV_KEY:310": "lock-y",
"EV_KEY:311": "lock-x",
"EV_ABS:2": "lock-y",
"EV_ABS:5": "lock-x",
}, },
"4E0C75F7": { "045E:028E": {
"description": "EasySMX ESM-9100 XBox Controller, top lights mode", "description": "Xbox360 Controller",
"EV_KEY:308": "speed-4", "type": "XBOX",
"EV_KEY:305": "speed-3",
"EV_KEY:304": "speed-2",
"EV_KEY:307": "speed-1",
"EV_ABS:0": "axis-x",
"EV_ABS:16": "axis-x",
"EV_ABS:1": "axis-y",
"EV_ABS:17": "axis-y",
"EV_ABS:4": "axis-z",
"EV_KEY:310": "lock-y",
"EV_KEY:311": "lock-x",
"EV_ABS:17": "axis-y",
"EV_ABS:4": "axis-z"
}, },
"E310BCC0": { "045E:028F": {
"description": "EasySMX ESM-9100, left lights mode", "description": "Xbox360 Wireless Controller",
"EV_KEY:304": "speed-4", "type": "XBOX",
"EV_KEY:305": "speed-3",
"EV_KEY:306": "speed-2",
"EV_KEY:307": "speed-1",
"EV_ABS:0": "axis-x",
"EV_ABS:16": "axis-x",
"EV_ABS:1": "axis-y",
"EV_ABS:17": "axis-y",
"EV_ABS:5": "axis-z",
"EV_KEY:308": "lock-y",
"EV_KEY:309": "lock-x",
"EV_KEY:310": "lock-y",
"EV_KEY:311": "lock-x",
}, },
"96D2AC48": { "045E:0B12": {
"description": "XBox One Controller",
"type": "XBOX"
},
"046D:C216": {
"description": "Logitech F310, D mode",
"type": "PLAYSTATION"
},
"046D:C216": {
"description": "Logitech F510, D mode",
"type": "PLAYSTATION"
},
"046D:C219": {
"description": "Logitech F710, D mode",
"type": "PLAYSTATION"
},
"046D:C21D": {
"description": "Logitech F310, X mode",
"type": "XBOX"
},
"046D:C21E": {
"description": "Logitech F510, X mode",
"type": "XBOX"
},
"046D:C21F": {
"description": "Logitech 710, X mode",
"type": "XBOX"
},
"054C:05C4": {
"description": "Sony Playstation 4 DualShock Controller",
"type": "PLAYSTATION"
},
"054C:09CC": {
"description": "Sony Playstation 4 DualShock Controller",
"type": "PLAYSTATION"
},
"054C:0BA0": {
"description": "Sony Playstation 4 DualShock Controller",
"type": "PLAYSTATION"
},
"054C:0CE6": {
"description": "Sony Playstation 5 DualSense Controller",
"type": "PLAYSTATION"
},
"11C0:5500": {
"description": "EasySMX ESM-9013, bottom lights mode",
"type": "SMX-BOTTOM"
},
"11C1:9101": {
"description": "EasySMX ESM-9013, left lights mode",
"type": "SMX-LEFT"
},
"20BC:5500": {
"description": "EasySMX ESM-9100, bottom lights mode", "description": "EasySMX ESM-9100, bottom lights mode",
"EV_KEY:308": "speed-4", "type": "SMX-BOTTOM"
"EV_KEY:305": "speed-3", },
"EV_KEY:304": "speed-2", "20BC:9100": {
"EV_KEY:307": "speed-1", "description": "EasySMX ESM-9100, left lights mode",
"EV_ABS:0": "axis-x", "type": "SMX-LEFT"
"EV_ABS:16": "axis-x",
"EV_ABS:1": "axis-y",
"EV_ABS:17": "axis-y",
"EV_ABS:5": "axis-z",
"EV_KEY:310": "lock-y",
"EV_KEY:311": "lock-x",
"EV_KEY:312": "lock-y",
"EV_KEY:313": "lock-x",
}, },
} }
@@ -254,6 +194,25 @@ def processCapabilities(capabilities):
return result return result
def loadConfig(id):
config = {
**factoryGamepadConfigs.get("default"),
**userGamepadConfigs.get("default", {}),
**factoryGamepadConfigs.get(id, {}),
**userGamepadConfigs.get(id, {})
}
while "type" in config:
type = config.pop("type")
config = {
**factoryGamepadConfigs.get(type, {}),
**userGamepadConfigs.get(type, {}),
**config,
}
return config
# A forward declaration, so Command can reference it # A forward declaration, so Command can reference it
class Gamepad(object): class Gamepad(object):
pass pass
@@ -298,15 +257,11 @@ class Gamepad(object):
for key in _udev.properties} for key in _udev.properties}
} }
json = sorted_json(self._details["evdev"]) self.id = "{:04X}:{:04X}".format(_evdev.info.vendor,
self.hash = hashlib.sha256(json.encode()).hexdigest()[-8:].upper() _evdev.info.product)
self.config = loadConfig(self.id)
self.config = { self.log("Configuration Settings: {}".format(self.config))
**gamepadConfigs.get("default"),
**userGamepadConfigs.get("default", {}),
**gamepadConfigs.get(self.hash, {}),
**userGamepadConfigs.get(self.hash, {})
}
def read(self): def read(self):
return self._evdev.read() return self._evdev.read()
@@ -374,7 +329,7 @@ class Gamepad(object):
return round(value, 3) return round(value, 3)
def log(self, msg): def log(self, msg):
self._log.info("{}: {}".format(self.hash, msg)) self._log.info("{}: {}".format(self.id, msg))
def logOnce(self, msg): def logOnce(self, msg):
if self.config.get("debug") or msg not in self._logOnceRecord: if self.config.get("debug") or msg not in self._logOnceRecord:
@@ -390,11 +345,11 @@ class Gamepad(object):
"devicePath": self.devicePath, "devicePath": self.devicePath,
"bustype": self._evdev.info.bustype, "bustype": self._evdev.info.bustype,
"details": self._details, "details": self._details,
"hash": self.hash "id": self.id
}) })
class Jog(object): class GamepadSupport(object):
gamepads = {} # type: dict[typing.Union[int, str], Gamepad] gamepads = {} # type: dict[typing.Union[int, str], Gamepad]
lock = {"x": False, "y": False} lock = {"x": False, "y": False}
axes = {"x": 0, "y": 0, "z": 0} axes = {"x": 0, "y": 0, "z": 0}
@@ -419,8 +374,9 @@ class Jog(object):
global userGamepadConfigs global userGamepadConfigs
userGamepadConfigs = json.load(f) userGamepadConfigs = json.load(f)
except: except:
self.log.info("Failed to read 'gamepads.json':")
self.log.info(traceback.format_exc()) self.log.info(traceback.format_exc())
self.log.info("Failed to read 'gamepads.json'") userGamepadConfigs = {}
def _startMonitoring(self): def _startMonitoring(self):
self.udev_context = pyudev.Context() self.udev_context = pyudev.Context()
@@ -465,6 +421,8 @@ class Jog(object):
self._listen("/dev/input/{}".format(match.group())) self._listen("/dev/input/{}".format(match.group()))
def _listen(self, devicePath: str): def _listen(self, devicePath: str):
self._refreshDefaultGamepadType()
gamepad = Gamepad( gamepad = Gamepad(
self.log, evdev.InputDevice(devicePath), self.log, evdev.InputDevice(devicePath),
pyudev.Devices.from_device_file(self.udev_context, devicePath)) pyudev.Devices.from_device_file(self.udev_context, devicePath))
@@ -558,6 +516,18 @@ class Jog(object):
def _processDisabled(self, command: Command): def _processDisabled(self, command: Command):
pass pass
def _refreshDefaultGamepadType(self):
defaultGamepadType = self.ctrl.config.get("gamepad-default-type")
if defaultGamepadType is not None:
default = factoryGamepadConfigs.get("default", {})
default["type"] = defaultGamepadType
factoryGamepadConfigs["default"] = default
default = userGamepadConfigs.get("default")
if default is not None:
default.pop("type", None)
def _updateJogging(self): def _updateJogging(self):
try: try:
if not self.changed: if not self.changed:

View File

@@ -14,7 +14,7 @@ from bbctrl.FileHandler import FileHandler
from bbctrl.Config import Config from bbctrl.Config import Config
from bbctrl.Mach import Mach from bbctrl.Mach import Mach
from bbctrl.Web import Web from bbctrl.Web import Web
from bbctrl.Jog import Jog from bbctrl.GamepadSupport import GamepadSupport
from bbctrl.Ctrl import Ctrl from bbctrl.Ctrl import Ctrl
from bbctrl.Pwr import Pwr from bbctrl.Pwr import Pwr
from bbctrl.I2C import I2C from bbctrl.I2C import I2C

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,11 @@
type Template = { type Template = {
type?: string; type?: string;
values?: (string | number)[]; values?: (
| string
| number
| { title: string; value: string | number }
)[];
unit?: "string"; unit?: "string";
iunit?: "string"; iunit?: "string";
min?: number; min?: number;
@@ -97,8 +101,11 @@
{#if template.values} {#if template.values}
<select {name} bind:value on:change={onChange}> <select {name} bind:value on:change={onChange}>
{#each template.values as opt} {#each template.values as opt}
<option value={opt} disabled={opt === "-----"}> <option
{opt} value={opt?.value ?? opt}
disabled={opt === "-----"}
>
{opt?.title ?? opt}
</option> </option>
{/each} {/each}
</select> </select>

View File

@@ -44,6 +44,17 @@
</div> </div>
</fieldset> </fieldset>
<h2>Gamepads / Joypads</h2>
<fieldset>
<ConfigTemplatedInput key={`settings.gamepad-default-type`} />
</fieldset>
<p>
If you have a gamepad that is not officially supported, and doesn't seem
to be working right, try changing <tt>gamepad-default-type</tt> to one of
the other types.
</p>
<fieldset> <fieldset>
<h2>Probe Dimensions</h2> <h2>Probe Dimensions</h2>
{#each Object.keys(configTemplate.probe) as key} {#each Object.keys(configTemplate.probe) as key}