From 21d3b69908f239522497562590d870c60752db4f Mon Sep 17 00:00:00 2001 From: PakoSt Date: Sun, 15 Aug 2021 20:51:46 +0100 Subject: [PATCH 01/17] Add new driver file for DualSense --- scc/drivers/ds5drv.py | 428 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 428 insertions(+) create mode 100644 scc/drivers/ds5drv.py diff --git a/scc/drivers/ds5drv.py b/scc/drivers/ds5drv.py new file mode 100644 index 000000000..372554c7b --- /dev/null +++ b/scc/drivers/ds5drv.py @@ -0,0 +1,428 @@ +#!/usr/bin/env python2 +""" +SC Controller - Dualshock 4 Driver + +Extends HID driver with DS4-specific options. +""" + +from scc.drivers.hiddrv import BUTTON_COUNT, ButtonData, AxisType, AxisData +from scc.drivers.hiddrv import HIDController, HIDDecoder, hiddrv_test +from scc.drivers.hiddrv import AxisMode, AxisDataUnion, AxisModeData +from scc.drivers.hiddrv import HatswitchModeData, _lib +from scc.drivers.evdevdrv import HAVE_EVDEV, EvdevController, get_axes +from scc.drivers.evdevdrv import get_evdev_devices_from_syspath +from scc.drivers.evdevdrv import make_new_device +from scc.drivers.usb import register_hotplug_device +from scc.constants import SCButtons, ControllerFlags +from scc.constants import STICK_PAD_MIN, STICK_PAD_MAX +from scc.tools import init_logging, set_logging_level +import sys, logging, ctypes +log = logging.getLogger("DS4") + +VENDOR_ID = 0x054c +PRODUCT_ID = 0x09cc + + +class DS4Controller(HIDController): + # Most of axes are the same + BUTTON_MAP = ( + SCButtons.X, + SCButtons.A, + SCButtons.B, + SCButtons.Y, + SCButtons.LB, + SCButtons.RB, + 1 << 64, + 1 << 64, + SCButtons.BACK, + SCButtons.START, + SCButtons.STICKPRESS, + SCButtons.RPAD, + SCButtons.C, + SCButtons.CPADPRESS, + ) + + flags = ( ControllerFlags.EUREL_GYROS + | ControllerFlags.HAS_RSTICK + | ControllerFlags.HAS_CPAD + | ControllerFlags.HAS_DPAD + | ControllerFlags.SEPARATE_STICK + | ControllerFlags.NO_GRIPS + ) + + + def _load_hid_descriptor(self, config, max_size, vid, pid, test_mode): + # Overrided and hardcoded + self._decoder = HIDDecoder() + self._decoder.axes[AxisType.AXIS_LPAD_X] = AxisData( + mode = AxisMode.HATSWITCH, byte_offset = 5, size = 8, + data = AxisDataUnion(hatswitch = HatswitchModeData( + button = SCButtons.LPAD | SCButtons.LPADTOUCH, + min = STICK_PAD_MIN, max = STICK_PAD_MAX + ))) + self._decoder.axes[AxisType.AXIS_STICK_X] = AxisData( + mode = AxisMode.AXIS, byte_offset = 1, size = 8, + data = AxisDataUnion(axis = AxisModeData( + scale = 1.0, offset = -127.5, clamp_max = 257, deadzone = 10 + ))) + self._decoder.axes[AxisType.AXIS_STICK_Y] = AxisData( + mode = AxisMode.AXIS, byte_offset = 2, size = 8, + data = AxisDataUnion(axis = AxisModeData( + scale = -1.0, offset = 127.5, clamp_max = 257, deadzone = 10 + ))) + self._decoder.axes[AxisType.AXIS_RPAD_X] = AxisData( + mode = AxisMode.AXIS, byte_offset = 3, size = 8, + data = AxisDataUnion(axis = AxisModeData( + button = SCButtons.RPADTOUCH, + scale = 1.0, offset = -127.5, clamp_max = 257, deadzone = 10 + ))) + self._decoder.axes[AxisType.AXIS_RPAD_Y] = AxisData( + mode = AxisMode.AXIS, byte_offset = 4, size = 8, + data = AxisDataUnion(axis = AxisModeData( + button = SCButtons.RPADTOUCH, + scale = -1.0, offset = 127.5, clamp_max = 257, deadzone = 10 + ))) + self._decoder.axes[AxisType.AXIS_LTRIG] = AxisData( + mode = AxisMode.AXIS, byte_offset = 8, size = 8, + data = AxisDataUnion(axis = AxisModeData( + scale = 1.0, clamp_max = 1, deadzone = 10 + ))) + self._decoder.axes[AxisType.AXIS_RTRIG] = AxisData( + mode = AxisMode.AXIS, byte_offset = 9, size = 8, + data = AxisDataUnion(axis = AxisModeData( + scale = 1.0, clamp_max = 1, deadzone = 10 + ))) + self._decoder.axes[AxisType.AXIS_GPITCH] = AxisData( + mode = AxisMode.DS4ACCEL, byte_offset = 13) + self._decoder.axes[AxisType.AXIS_GROLL] = AxisData( + mode = AxisMode.DS4ACCEL, byte_offset = 17) + self._decoder.axes[AxisType.AXIS_GYAW] = AxisData( + mode = AxisMode.DS4ACCEL, byte_offset = 15) + self._decoder.axes[AxisType.AXIS_Q1] = AxisData( + mode = AxisMode.DS4GYRO, byte_offset = 23) + self._decoder.axes[AxisType.AXIS_Q2] = AxisData( + mode = AxisMode.DS4GYRO, byte_offset = 19) + self._decoder.axes[AxisType.AXIS_Q3] = AxisData( + mode = AxisMode.DS4GYRO, byte_offset = 21) + + self._decoder.axes[AxisType.AXIS_CPAD_X] = AxisData( + mode = AxisMode.DS4TOUCHPAD, byte_offset = 36) + self._decoder.axes[AxisType.AXIS_CPAD_Y] = AxisData( + mode = AxisMode.DS4TOUCHPAD, byte_offset = 37, bit_offset=4) + self._decoder.buttons = ButtonData( + enabled = True, byte_offset=5, bit_offset=4, size=14, + button_count = 14 + ) + + if test_mode: + for x in xrange(BUTTON_COUNT): + self._decoder.buttons.button_map[x] = x + else: + for x in xrange(BUTTON_COUNT): + self._decoder.buttons.button_map[x] = 64 + for x, sc in enumerate(DS4Controller.BUTTON_MAP): + self._decoder.buttons.button_map[x] = self.button_to_bit(sc) + + self._packet_size = 64 + + + def input(self, endpoint, data): + # Special override for CPAD touch button + if _lib.decode(ctypes.byref(self._decoder), data): + if self.mapper: + if ord(data[35]) >> 7: + # cpad is not touched + self._decoder.state.buttons &= ~SCButtons.CPADTOUCH + else: + self._decoder.state.buttons |= SCButtons.CPADTOUCH + self.mapper.input(self, + self._decoder.old_state, self._decoder.state) + + + def get_gyro_enabled(self): + # Cannot be actually turned off, so it's always active + # TODO: Maybe emulate turning off? + return True + + + def get_type(self): + return "ds4" + + + def get_gui_config_file(self): + return "ds4-config.json" + + + def __repr__(self): + return "" % (self.get_id(), ) + + + def _generate_id(self): + """ + ID is generated as 'ds4' or 'ds4:X' where 'X' starts as 1 and increases + as controllers with same ids are connected. + """ + magic_number = 1 + id = "ds4" + while id in self.daemon.get_active_ids(): + id = "ds4:%s" % (magic_number, ) + magic_number += 1 + return id + + +class DS4EvdevController(EvdevController): + TOUCH_FACTOR_X = STICK_PAD_MAX / 940.0 + TOUCH_FACTOR_Y = STICK_PAD_MAX / 470.0 + BUTTON_MAP = { + 304: "A", + 305: "B", + 307: "Y", + 308: "X", + 310: "LB", + 311: "RB", + 314: "BACK", + 315: "START", + 316: "C", + 317: "STICKPRESS", + 318: "RPAD" + # 319: "CPAD", + } + AXIS_MAP = { + 0: { "axis": "stick_x", "deadzone": 4, "max": 255, "min": 0 }, + 1: { "axis": "stick_y", "deadzone": 4, "max": 0, "min": 255 }, + 3: { "axis": "rpad_x", "deadzone": 4, "max": 255, "min": 0 }, + 4: { "axis": "rpad_y", "deadzone": 8, "max": 0, "min": 255 }, + 2: { "axis": "ltrig", "max": 255, "min": 0 }, + 5: { "axis": "rtrig", "max": 255, "min": 0 }, + 16: { "axis": "lpad_x", "deadzone": 0, "max": 1, "min": -1 }, + 17: { "axis": "lpad_y", "deadzone": 0, "max": -1, "min": 1 } + } + BUTTON_MAP_OLD = { + 304: "X", + 305: "A", + 306: "B", + 307: "Y", + 308: "LB", + 309: "RB", + 312: "BACK", + 313: "START", + 314: "STICKPRESS", + 315: "RPAD", + 316: "C", + # 317: "CPAD", + } + AXIS_MAP_OLD = { + 0: { "axis": "stick_x", "deadzone": 4, "max": 255, "min": 0 }, + 1: { "axis": "stick_y", "deadzone": 4, "max": 0, "min": 255 }, + 2: { "axis": "rpad_x", "deadzone": 4, "max": 255, "min": 0 }, + 5: { "axis": "rpad_y", "deadzone": 8, "max": 0, "min": 255 }, + 3: { "axis": "ltrig", "max": 32767, "min": -32767 }, + 4: { "axis": "rtrig", "max": 32767, "min": -32767 }, + 16: { "axis": "lpad_x", "deadzone": 0, "max": 1, "min": -1 }, + 17: { "axis": "lpad_y", "deadzone": 0, "max": -1, "min": 1 } + } + GYRO_MAP = { + EvdevController.ECODES.ABS_RX : ('gpitch', 0.01), + EvdevController.ECODES.ABS_RY : ('gyaw', 0.01), + EvdevController.ECODES.ABS_RZ : ('groll', 0.01), + EvdevController.ECODES.ABS_X : (None, 1), # 'q2' + EvdevController.ECODES.ABS_Y : (None, 1), # 'q3' + EvdevController.ECODES.ABS_Z : (None, -1), # 'q1' + } + flags = ( ControllerFlags.EUREL_GYROS + | ControllerFlags.HAS_RSTICK + | ControllerFlags.HAS_CPAD + | ControllerFlags.HAS_DPAD + | ControllerFlags.SEPARATE_STICK + | ControllerFlags.NO_GRIPS + ) + + def __init__(self, daemon, controllerdevice, gyro, touchpad): + config = { + 'axes' : DS4EvdevController.AXIS_MAP, + 'buttons' : DS4EvdevController.BUTTON_MAP, + 'dpads' : {} + } + if controllerdevice.info.version & 0x8000 == 0: + # Older kernel uses different mappings + # see kernel source, drivers/hid/hid-sony.c#L2748 + config['axes'] = DS4EvdevController.AXIS_MAP_OLD + config['buttons'] = DS4EvdevController.BUTTON_MAP_OLD + self._gyro = gyro + self._touchpad = touchpad + for device in (self._gyro, self._touchpad): + if device: + device.grab() + EvdevController.__init__(self, daemon, controllerdevice, None, config) + if self.poller: + self.poller.register(touchpad.fd, self.poller.POLLIN, self._touchpad_input) + self.poller.register(gyro.fd, self.poller.POLLIN, self._gyro_input) + + + def _gyro_input(self, *a): + new_state = self._state + try: + for event in self._gyro.read(): + if event.type == self.ECODES.EV_ABS: + axis, factor = DS4EvdevController.GYRO_MAP[event.code] + if axis: + new_state = new_state._replace( + **{ axis : int(event.value * factor) }) + except IOError: + # Errors here are not even reported, evdev class handles important ones + return + + if new_state is not self._state: + old_state, self._state = self._state, new_state + if self.mapper: + self.mapper.input(self, old_state, new_state) + + + def _touchpad_input(self, *a): + new_state = self._state + try: + for event in self._touchpad.read(): + if event.type == self.ECODES.EV_ABS: + if event.code == self.ECODES.ABS_MT_POSITION_X: + value = event.value * DS4EvdevController.TOUCH_FACTOR_X + value = STICK_PAD_MIN + int(value) + new_state = new_state._replace(cpad_x = value) + elif event.code == self.ECODES.ABS_MT_POSITION_Y: + value = event.value * DS4EvdevController.TOUCH_FACTOR_Y + value = STICK_PAD_MAX - int(value) + new_state = new_state._replace(cpad_y = value) + elif event.type == 0: + pass + elif event.code == self.ECODES.BTN_LEFT: + if event.value == 1: + b = new_state.buttons | SCButtons.CPADPRESS + new_state = new_state._replace(buttons = b) + else: + b = new_state.buttons & ~SCButtons.CPADPRESS + new_state = new_state._replace(buttons = b) + elif event.code == self.ECODES.BTN_TOUCH: + if event.value == 1: + b = new_state.buttons | SCButtons.CPADTOUCH + new_state = new_state._replace(buttons = b) + else: + b = new_state.buttons & ~SCButtons.CPADTOUCH + new_state = new_state._replace(buttons = b, + cpad_x = 0, cpad_y = 0) + except IOError: + # Errors here are not even reported, evdev class handles important ones + return + + if new_state is not self._state: + old_state, self._state = self._state, new_state + if self.mapper: + self.mapper.input(self, old_state, new_state) + + + def close(self): + EvdevController.close(self) + for device in (self._gyro, self._touchpad): + try: + self.poller.unregister(device.fd) + device.ungrab() + except: pass + + + def get_gyro_enabled(self): + # Cannot be actually turned off, so it's always active + # TODO: Maybe emulate turning off? + return True + + + def get_type(self): + return "ds4evdev" + + + def get_gui_config_file(self): + return "ds4-config.json" + + + def __repr__(self): + return "" % (self.get_id(), ) + + + def _generate_id(self): + """ + ID is generated as 'ds4' or 'ds4:X' where 'X' starts as 1 and increases + as controllers with same ids are connected. + """ + magic_number = 1 + id = "ds4" + while id in self.daemon.get_active_ids(): + id = "ds4:%s" % (magic_number, ) + magic_number += 1 + return id + + +def init(daemon, config): + """ Registers hotplug callback for ds4 device """ + + def hid_callback(device, handle): + return DS4Controller(device, daemon, handle, None, None) + + def make_evdev_device(syspath, *whatever): + devices = get_evdev_devices_from_syspath(syspath) + # With kernel 4.10 or later, PS4 controller pretends to be 3 different devices. + # 1st, determining which one is actual controller is needed + controllerdevice = None + for device in devices: + count = len(get_axes(device)) + if count == 8: + # 8 axes - Controller + controllerdevice = device + if not controllerdevice: + log.warning("Failed to determine controller device") + return None + # 2nd, find motion sensor and touchpad with physical address matching controllerdevice + gyro, touchpad = None, None + phys = device.phys.split("/")[0] + for device in devices: + if device.phys.startswith(phys): + axes = get_axes(device) + count = len(axes) + if count == 6: + # 6 axes + if EvdevController.ECODES.ABS_MT_POSITION_X in axes: + # kernel 4.17+ - touchpad + touchpad = device + else: + # gyro sensor + gyro = device + pass + elif count == 4: + # 4 axes - Touchpad + touchpad = device + # 3rd, do a magic + if controllerdevice and gyro and touchpad: + return make_new_device(DS4EvdevController, controllerdevice, gyro, touchpad) + + + def fail_cb(syspath, vid, pid): + if HAVE_EVDEV: + log.warning("Failed to acquire USB device, falling back to evdev driver. This is far from optimal.") + make_evdev_device(syspath) + else: + log.error("Failed to acquire USB device and evdev is not available. Everything is lost and DS4 support disabled.") + # TODO: Maybe add_error here, but error reporting needs little rework so it's not threated as fatal + # daemon.add_error("ds4", "No access to DS4 device") + + if config["drivers"].get("hiddrv") or (HAVE_EVDEV and config["drivers"].get("evdevdrv")): + register_hotplug_device(hid_callback, VENDOR_ID, PRODUCT_ID, on_failure=fail_cb) + if HAVE_EVDEV and config["drivers"].get("evdevdrv"): + daemon.get_device_monitor().add_callback("bluetooth", + VENDOR_ID, PRODUCT_ID, make_evdev_device, None) + return True + else: + log.warning("Neither HID nor Evdev driver is enabled, DS4 support cannot be enabled.") + return False + + +if __name__ == "__main__": + """ Called when executed as script """ + init_logging() + set_logging_level(True, True) + sys.exit(hiddrv_test(DS4Controller, [ "054c:09cc" ])) From cd7e15a866f141ff6bafc67f2b47eb73b924aa50 Mon Sep 17 00:00:00 2001 From: PakoSt Date: Sun, 15 Aug 2021 20:55:14 +0100 Subject: [PATCH 02/17] Alter the product id to match Dualsense --- scc/drivers/ds5drv.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scc/drivers/ds5drv.py b/scc/drivers/ds5drv.py index 372554c7b..c9b8a82ab 100644 --- a/scc/drivers/ds5drv.py +++ b/scc/drivers/ds5drv.py @@ -20,7 +20,7 @@ log = logging.getLogger("DS4") VENDOR_ID = 0x054c -PRODUCT_ID = 0x09cc +PRODUCT_ID = 0x0ce6 class DS4Controller(HIDController): @@ -425,4 +425,4 @@ def fail_cb(syspath, vid, pid): """ Called when executed as script """ init_logging() set_logging_level(True, True) - sys.exit(hiddrv_test(DS4Controller, [ "054c:09cc" ])) + sys.exit(hiddrv_test(DS4Controller, [ "054c:0ce6" ])) From f3dac21d59ad6a94fba42ca30fd6fd06ac25b71c Mon Sep 17 00:00:00 2001 From: PakoSt Date: Sun, 15 Aug 2021 21:03:07 +0100 Subject: [PATCH 03/17] Hard coded changes to the HID byte_offsets Working: - Dpad - Sticks - Buttons --- scc/drivers/ds5drv.py | 57 ++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/scc/drivers/ds5drv.py b/scc/drivers/ds5drv.py index c9b8a82ab..6623bd8e0 100644 --- a/scc/drivers/ds5drv.py +++ b/scc/drivers/ds5drv.py @@ -17,7 +17,7 @@ from scc.constants import STICK_PAD_MIN, STICK_PAD_MAX from scc.tools import init_logging, set_logging_level import sys, logging, ctypes -log = logging.getLogger("DS4") +log = logging.getLogger("DS5") VENDOR_ID = 0x054c PRODUCT_ID = 0x0ce6 @@ -54,12 +54,16 @@ class DS4Controller(HIDController): def _load_hid_descriptor(self, config, max_size, vid, pid, test_mode): # Overrided and hardcoded self._decoder = HIDDecoder() + + # Dpad works on DualSense! self._decoder.axes[AxisType.AXIS_LPAD_X] = AxisData( - mode = AxisMode.HATSWITCH, byte_offset = 5, size = 8, + mode = AxisMode.HATSWITCH, byte_offset = 8, size = 8, data = AxisDataUnion(hatswitch = HatswitchModeData( button = SCButtons.LPAD | SCButtons.LPADTOUCH, min = STICK_PAD_MIN, max = STICK_PAD_MAX ))) + + # Sticks are the same as DS4 self._decoder.axes[AxisType.AXIS_STICK_X] = AxisData( mode = AxisMode.AXIS, byte_offset = 1, size = 8, data = AxisDataUnion(axis = AxisModeData( @@ -82,35 +86,44 @@ def _load_hid_descriptor(self, config, max_size, vid, pid, test_mode): button = SCButtons.RPADTOUCH, scale = -1.0, offset = 127.5, clamp_max = 257, deadzone = 10 ))) + + # Triggers self._decoder.axes[AxisType.AXIS_LTRIG] = AxisData( - mode = AxisMode.AXIS, byte_offset = 8, size = 8, + mode = AxisMode.AXIS, byte_offset = 5, size = 8, # Not sure about the size data = AxisDataUnion(axis = AxisModeData( scale = 1.0, clamp_max = 1, deadzone = 10 ))) self._decoder.axes[AxisType.AXIS_RTRIG] = AxisData( - mode = AxisMode.AXIS, byte_offset = 9, size = 8, + mode = AxisMode.AXIS, byte_offset = 6, size = 8, # Not sure about the size data = AxisDataUnion(axis = AxisModeData( scale = 1.0, clamp_max = 1, deadzone = 10 ))) - self._decoder.axes[AxisType.AXIS_GPITCH] = AxisData( - mode = AxisMode.DS4ACCEL, byte_offset = 13) - self._decoder.axes[AxisType.AXIS_GROLL] = AxisData( - mode = AxisMode.DS4ACCEL, byte_offset = 17) - self._decoder.axes[AxisType.AXIS_GYAW] = AxisData( - mode = AxisMode.DS4ACCEL, byte_offset = 15) - self._decoder.axes[AxisType.AXIS_Q1] = AxisData( - mode = AxisMode.DS4GYRO, byte_offset = 23) - self._decoder.axes[AxisType.AXIS_Q2] = AxisData( - mode = AxisMode.DS4GYRO, byte_offset = 19) - self._decoder.axes[AxisType.AXIS_Q3] = AxisData( - mode = AxisMode.DS4GYRO, byte_offset = 21) + + # TODO: Gyro + # self._decoder.axes[AxisType.AXIS_GPITCH] = AxisData( + # mode = AxisMode.DS4ACCEL, byte_offset = 13) + # self._decoder.axes[AxisType.AXIS_GROLL] = AxisData( + # mode = AxisMode.DS4ACCEL, byte_offset = 17) + # self._decoder.axes[AxisType.AXIS_GYAW] = AxisData( + # mode = AxisMode.DS4ACCEL, byte_offset = 15) + # self._decoder.axes[AxisType.AXIS_Q1] = AxisData( + # mode = AxisMode.DS4GYRO, byte_offset = 23) + # self._decoder.axes[AxisType.AXIS_Q2] = AxisData( + # mode = AxisMode.DS4GYRO, byte_offset = 19) + # self._decoder.axes[AxisType.AXIS_Q3] = AxisData( + # mode = AxisMode.DS4GYRO, byte_offset = 21) + # TODO: Touchpad self._decoder.axes[AxisType.AXIS_CPAD_X] = AxisData( - mode = AxisMode.DS4TOUCHPAD, byte_offset = 36) - self._decoder.axes[AxisType.AXIS_CPAD_Y] = AxisData( - mode = AxisMode.DS4TOUCHPAD, byte_offset = 37, bit_offset=4) + mode = AxisMode.DS4TOUCHPAD, byte_offset = 36) + # self._decoder.axes[AxisType.AXIS_CPAD_Y] = AxisData( + # mode = AxisMode.DS4TOUCHPAD, byte_offset = 37, bit_offset=4) + + # Button maps seem to work for standard arrangement (matching Xbox360) + # Not enough information about the button event triggered when LT && RT are pressed? + # Could be connected to adaptive triggers? self._decoder.buttons = ButtonData( - enabled = True, byte_offset=5, bit_offset=4, size=14, + enabled = True, byte_offset=8, bit_offset=4, size=14, # Not sure about bit offset button_count = 14 ) @@ -180,6 +193,9 @@ class DS4EvdevController(EvdevController): 308: "X", 310: "LB", 311: "RB", + # TODO: Figure out what it is the purpose of the button event when using the trigger + # 312: "LT2", + # 313: "RT2", 314: "BACK", 315: "START", 316: "C", @@ -197,6 +213,7 @@ class DS4EvdevController(EvdevController): 16: { "axis": "lpad_x", "deadzone": 0, "max": 1, "min": -1 }, 17: { "axis": "lpad_y", "deadzone": 0, "max": -1, "min": 1 } } + # TODO: Should the old button for DS4 map be removed? DualSense support came with kernel 5.12 BUTTON_MAP_OLD = { 304: "X", 305: "A", From 5a8a3a15eccfe375db665238a4f57510b7e9d55b Mon Sep 17 00:00:00 2001 From: PakoSt Date: Sun, 15 Aug 2021 21:08:52 +0100 Subject: [PATCH 04/17] Enable ds5drv in default config --- scc/config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scc/config.py b/scc/config.py index 15609241d..8b755e9e8 100644 --- a/scc/config.py +++ b/scc/config.py @@ -36,6 +36,7 @@ class Config(object): "hiddrv": True, "evdevdrv": True, "ds4drv": True, # At least one of hiddrv or evdevdrv has to be enabled as well + "ds5drv": True, }, "fix_xinput" : True, # If True, attempt is done to deatach emulated controller # from 'Virtual core pointer' core device. From ea058913cf72f0b19a8ccbce7eaa2717c3940bac Mon Sep 17 00:00:00 2001 From: PakoSt Date: Mon, 16 Aug 2021 21:49:02 +0100 Subject: [PATCH 05/17] Gyro enabled --- scc/drivers/ds5drv.py | 82 +++++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/scc/drivers/ds5drv.py b/scc/drivers/ds5drv.py index 6623bd8e0..c269a17d4 100644 --- a/scc/drivers/ds5drv.py +++ b/scc/drivers/ds5drv.py @@ -99,25 +99,25 @@ def _load_hid_descriptor(self, config, max_size, vid, pid, test_mode): scale = 1.0, clamp_max = 1, deadzone = 10 ))) - # TODO: Gyro - # self._decoder.axes[AxisType.AXIS_GPITCH] = AxisData( - # mode = AxisMode.DS4ACCEL, byte_offset = 13) - # self._decoder.axes[AxisType.AXIS_GROLL] = AxisData( - # mode = AxisMode.DS4ACCEL, byte_offset = 17) - # self._decoder.axes[AxisType.AXIS_GYAW] = AxisData( - # mode = AxisMode.DS4ACCEL, byte_offset = 15) - # self._decoder.axes[AxisType.AXIS_Q1] = AxisData( - # mode = AxisMode.DS4GYRO, byte_offset = 23) - # self._decoder.axes[AxisType.AXIS_Q2] = AxisData( - # mode = AxisMode.DS4GYRO, byte_offset = 19) - # self._decoder.axes[AxisType.AXIS_Q3] = AxisData( - # mode = AxisMode.DS4GYRO, byte_offset = 21) + # Gyro + self._decoder.axes[AxisType.AXIS_GPITCH] = AxisData( + mode = AxisMode.DS4ACCEL, byte_offset = 16) # Pitch found + self._decoder.axes[AxisType.AXIS_GROLL] = AxisData( + mode = AxisMode.DS4ACCEL, byte_offset = 20) # Roll + self._decoder.axes[AxisType.AXIS_GYAW] = AxisData( + mode = AxisMode.DS4ACCEL, byte_offset = 18) # Yaw found + self._decoder.axes[AxisType.AXIS_Q1] = AxisData( + mode = AxisMode.DS4GYRO, byte_offset = 26) + self._decoder.axes[AxisType.AXIS_Q2] = AxisData( + mode = AxisMode.DS4GYRO, byte_offset = 22) + self._decoder.axes[AxisType.AXIS_Q3] = AxisData( + mode = AxisMode.DS4GYRO, byte_offset = 24) # TODO: Touchpad - self._decoder.axes[AxisType.AXIS_CPAD_X] = AxisData( - mode = AxisMode.DS4TOUCHPAD, byte_offset = 36) - # self._decoder.axes[AxisType.AXIS_CPAD_Y] = AxisData( - # mode = AxisMode.DS4TOUCHPAD, byte_offset = 37, bit_offset=4) + # self._decoder.axes[AxisType.AXIS_CPAD_X] = AxisData( + # mode = AxisMode.DS4TOUCHPAD, byte_offset = 33, bit_offset=2) + #self._decoder.axes[AxisType.AXIS_CPAD_Y] = AxisData( + # mode = AxisMode.DS4TOUCHPAD, byte_offset = 34, bit_offset=4) # Button maps seem to work for standard arrangement (matching Xbox360) # Not enough information about the button event triggered when LT && RT are pressed? @@ -214,30 +214,30 @@ class DS4EvdevController(EvdevController): 17: { "axis": "lpad_y", "deadzone": 0, "max": -1, "min": 1 } } # TODO: Should the old button for DS4 map be removed? DualSense support came with kernel 5.12 - BUTTON_MAP_OLD = { - 304: "X", - 305: "A", - 306: "B", - 307: "Y", - 308: "LB", - 309: "RB", - 312: "BACK", - 313: "START", - 314: "STICKPRESS", - 315: "RPAD", - 316: "C", - # 317: "CPAD", - } - AXIS_MAP_OLD = { - 0: { "axis": "stick_x", "deadzone": 4, "max": 255, "min": 0 }, - 1: { "axis": "stick_y", "deadzone": 4, "max": 0, "min": 255 }, - 2: { "axis": "rpad_x", "deadzone": 4, "max": 255, "min": 0 }, - 5: { "axis": "rpad_y", "deadzone": 8, "max": 0, "min": 255 }, - 3: { "axis": "ltrig", "max": 32767, "min": -32767 }, - 4: { "axis": "rtrig", "max": 32767, "min": -32767 }, - 16: { "axis": "lpad_x", "deadzone": 0, "max": 1, "min": -1 }, - 17: { "axis": "lpad_y", "deadzone": 0, "max": -1, "min": 1 } - } + # BUTTON_MAP_OLD = { + # 304: "X", + # 305: "A", + # 306: "B", + # 307: "Y", + # 308: "LB", + # 309: "RB", + # 312: "BACK", + # 313: "START", + # 314: "STICKPRESS", + # 315: "RPAD", + # 316: "C", + # # 317: "CPAD", + # } + # AXIS_MAP_OLD = { + # 0: { "axis": "stick_x", "deadzone": 4, "max": 255, "min": 0 }, + # 1: { "axis": "stick_y", "deadzone": 4, "max": 0, "min": 255 }, + # 2: { "axis": "rpad_x", "deadzone": 4, "max": 255, "min": 0 }, + # 5: { "axis": "rpad_y", "deadzone": 8, "max": 0, "min": 255 }, + # 3: { "axis": "ltrig", "max": 32767, "min": -32767 }, + # 4: { "axis": "rtrig", "max": 32767, "min": -32767 }, + # 16: { "axis": "lpad_x", "deadzone": 0, "max": 1, "min": -1 }, + # 17: { "axis": "lpad_y", "deadzone": 0, "max": -1, "min": 1 } + # } GYRO_MAP = { EvdevController.ECODES.ABS_RX : ('gpitch', 0.01), EvdevController.ECODES.ABS_RY : ('gyaw', 0.01), From 853688204df48a6a467a007a9b1ee3a27f61ee39 Mon Sep 17 00:00:00 2001 From: PakoSt Date: Thu, 19 Aug 2021 16:34:12 +0100 Subject: [PATCH 06/17] DualSense gyro byte offset found --- scc/drivers/ds5drv.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scc/drivers/ds5drv.py b/scc/drivers/ds5drv.py index c269a17d4..a6052da8f 100644 --- a/scc/drivers/ds5drv.py +++ b/scc/drivers/ds5drv.py @@ -113,11 +113,11 @@ def _load_hid_descriptor(self, config, max_size, vid, pid, test_mode): self._decoder.axes[AxisType.AXIS_Q3] = AxisData( mode = AxisMode.DS4GYRO, byte_offset = 24) - # TODO: Touchpad - # self._decoder.axes[AxisType.AXIS_CPAD_X] = AxisData( - # mode = AxisMode.DS4TOUCHPAD, byte_offset = 33, bit_offset=2) - #self._decoder.axes[AxisType.AXIS_CPAD_Y] = AxisData( - # mode = AxisMode.DS4TOUCHPAD, byte_offset = 34, bit_offset=4) + # Touchpad + self._decoder.axes[AxisType.AXIS_CPAD_X] = AxisData( + mode = AxisMode.DS4TOUCHPAD, byte_offset = 34) # DualSense X + self._decoder.axes[AxisType.AXIS_CPAD_Y] = AxisData( + mode = AxisMode.DS4TOUCHPAD, byte_offset = 35, bit_offset =4) # DualSense Y # Button maps seem to work for standard arrangement (matching Xbox360) # Not enough information about the button event triggered when LT && RT are pressed? From 7207b999aa8b14d55cfb2e42d17d3238d3622aec Mon Sep 17 00:00:00 2001 From: PakoSt Date: Thu, 19 Aug 2021 17:25:34 +0100 Subject: [PATCH 07/17] Refactoring from DS4 to DS5 Note: Only AxisMode remains as DS4 --- scc/drivers/ds5drv.py | 67 ++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/scc/drivers/ds5drv.py b/scc/drivers/ds5drv.py index a6052da8f..a59c12553 100644 --- a/scc/drivers/ds5drv.py +++ b/scc/drivers/ds5drv.py @@ -1,8 +1,8 @@ #!/usr/bin/env python2 """ -SC Controller - Dualshock 4 Driver +SC Controller - DualSense driver -Extends HID driver with DS4-specific options. +Extends HID driver with DS5-specific options. """ from scc.drivers.hiddrv import BUTTON_COUNT, ButtonData, AxisType, AxisData @@ -23,7 +23,7 @@ PRODUCT_ID = 0x0ce6 -class DS4Controller(HIDController): +class DS5Controller(HIDController): # Most of axes are the same BUTTON_MAP = ( SCButtons.X, @@ -100,6 +100,7 @@ def _load_hid_descriptor(self, config, max_size, vid, pid, test_mode): ))) # Gyro + # Leaving the AxisMode naming to match DS4 self._decoder.axes[AxisType.AXIS_GPITCH] = AxisData( mode = AxisMode.DS4ACCEL, byte_offset = 16) # Pitch found self._decoder.axes[AxisType.AXIS_GROLL] = AxisData( @@ -133,7 +134,7 @@ def _load_hid_descriptor(self, config, max_size, vid, pid, test_mode): else: for x in xrange(BUTTON_COUNT): self._decoder.buttons.button_map[x] = 64 - for x, sc in enumerate(DS4Controller.BUTTON_MAP): + for x, sc in enumerate(DS5Controller.BUTTON_MAP): self._decoder.buttons.button_map[x] = self.button_to_bit(sc) self._packet_size = 64 @@ -159,7 +160,7 @@ def get_gyro_enabled(self): def get_type(self): - return "ds4" + return "ds5" def get_gui_config_file(self): @@ -167,23 +168,23 @@ def get_gui_config_file(self): def __repr__(self): - return "" % (self.get_id(), ) + return "" % (self.get_id(), ) def _generate_id(self): """ - ID is generated as 'ds4' or 'ds4:X' where 'X' starts as 1 and increases + ID is generated as 'ds5' or 'ds5:X' where 'X' starts as 1 and increases as controllers with same ids are connected. """ magic_number = 1 - id = "ds4" + id = "ds5" while id in self.daemon.get_active_ids(): - id = "ds4:%s" % (magic_number, ) + id = "ds5:%s" % (magic_number, ) magic_number += 1 return id -class DS4EvdevController(EvdevController): +class DS5EvdevController(EvdevController): TOUCH_FACTOR_X = STICK_PAD_MAX / 940.0 TOUCH_FACTOR_Y = STICK_PAD_MAX / 470.0 BUTTON_MAP = { @@ -256,15 +257,15 @@ class DS4EvdevController(EvdevController): def __init__(self, daemon, controllerdevice, gyro, touchpad): config = { - 'axes' : DS4EvdevController.AXIS_MAP, - 'buttons' : DS4EvdevController.BUTTON_MAP, + 'axes' : DS5EvdevController.AXIS_MAP, + 'buttons' : DS5EvdevController.BUTTON_MAP, 'dpads' : {} } - if controllerdevice.info.version & 0x8000 == 0: - # Older kernel uses different mappings - # see kernel source, drivers/hid/hid-sony.c#L2748 - config['axes'] = DS4EvdevController.AXIS_MAP_OLD - config['buttons'] = DS4EvdevController.BUTTON_MAP_OLD + # if controllerdevice.info.version & 0x8000 == 0: + # # Older kernel uses different mappings + # # see kernel source, drivers/hid/hid-sony.c#L2748 + # config['axes'] = DS4EvdevController.AXIS_MAP_OLD + # config['buttons'] = DS4EvdevController.BUTTON_MAP_OLD self._gyro = gyro self._touchpad = touchpad for device in (self._gyro, self._touchpad): @@ -281,7 +282,7 @@ def _gyro_input(self, *a): try: for event in self._gyro.read(): if event.type == self.ECODES.EV_ABS: - axis, factor = DS4EvdevController.GYRO_MAP[event.code] + axis, factor = DS5EvdevController.GYRO_MAP[event.code] if axis: new_state = new_state._replace( **{ axis : int(event.value * factor) }) @@ -301,11 +302,11 @@ def _touchpad_input(self, *a): for event in self._touchpad.read(): if event.type == self.ECODES.EV_ABS: if event.code == self.ECODES.ABS_MT_POSITION_X: - value = event.value * DS4EvdevController.TOUCH_FACTOR_X + value = event.value * DS5EvdevController.TOUCH_FACTOR_X value = STICK_PAD_MIN + int(value) new_state = new_state._replace(cpad_x = value) elif event.code == self.ECODES.ABS_MT_POSITION_Y: - value = event.value * DS4EvdevController.TOUCH_FACTOR_Y + value = event.value * DS5EvdevController.TOUCH_FACTOR_Y value = STICK_PAD_MAX - int(value) new_state = new_state._replace(cpad_y = value) elif event.type == 0: @@ -351,35 +352,35 @@ def get_gyro_enabled(self): def get_type(self): - return "ds4evdev" - + return "ds5evdev" + # TODO: Create ds5-config.json for GUI def get_gui_config_file(self): return "ds4-config.json" def __repr__(self): - return "" % (self.get_id(), ) + return "" % (self.get_id(), ) def _generate_id(self): """ - ID is generated as 'ds4' or 'ds4:X' where 'X' starts as 1 and increases + ID is generated as 'ds5' or 'ds5:X' where 'X' starts as 1 and increases as controllers with same ids are connected. """ magic_number = 1 - id = "ds4" + id = "ds5" while id in self.daemon.get_active_ids(): - id = "ds4:%s" % (magic_number, ) + id = "ds5:%s" % (magic_number, ) magic_number += 1 return id def init(daemon, config): - """ Registers hotplug callback for ds4 device """ + """ Registers hotplug callback for ds5 device """ def hid_callback(device, handle): - return DS4Controller(device, daemon, handle, None, None) + return DS5Controller(device, daemon, handle, None, None) def make_evdev_device(syspath, *whatever): devices = get_evdev_devices_from_syspath(syspath) @@ -415,7 +416,7 @@ def make_evdev_device(syspath, *whatever): touchpad = device # 3rd, do a magic if controllerdevice and gyro and touchpad: - return make_new_device(DS4EvdevController, controllerdevice, gyro, touchpad) + return make_new_device(DS5EvdevController, controllerdevice, gyro, touchpad) def fail_cb(syspath, vid, pid): @@ -423,9 +424,9 @@ def fail_cb(syspath, vid, pid): log.warning("Failed to acquire USB device, falling back to evdev driver. This is far from optimal.") make_evdev_device(syspath) else: - log.error("Failed to acquire USB device and evdev is not available. Everything is lost and DS4 support disabled.") + log.error("Failed to acquire USB device and evdev is not available. Everything is lost and DS5 support disabled.") # TODO: Maybe add_error here, but error reporting needs little rework so it's not threated as fatal - # daemon.add_error("ds4", "No access to DS4 device") + # daemon.add_error("ds5", "No access to DS5 device") if config["drivers"].get("hiddrv") or (HAVE_EVDEV and config["drivers"].get("evdevdrv")): register_hotplug_device(hid_callback, VENDOR_ID, PRODUCT_ID, on_failure=fail_cb) @@ -434,7 +435,7 @@ def fail_cb(syspath, vid, pid): VENDOR_ID, PRODUCT_ID, make_evdev_device, None) return True else: - log.warning("Neither HID nor Evdev driver is enabled, DS4 support cannot be enabled.") + log.warning("Neither HID nor Evdev driver is enabled, DS5 support cannot be enabled.") return False @@ -442,4 +443,4 @@ def fail_cb(syspath, vid, pid): """ Called when executed as script """ init_logging() set_logging_level(True, True) - sys.exit(hiddrv_test(DS4Controller, [ "054c:0ce6" ])) + sys.exit(hiddrv_test(DS5Controller, [ "054c:0ce6" ])) From d83f956634a9e4d6720a596304bbd49e36733d09 Mon Sep 17 00:00:00 2001 From: PakoSt Date: Sat, 21 Aug 2021 10:35:56 +0100 Subject: [PATCH 08/17] Fix DualSense jumpy behavior in USB mode. ToDo: - Find source of speed difference b-n USB and BT mode touchpad cursor --- scc/drivers/ds5drv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scc/drivers/ds5drv.py b/scc/drivers/ds5drv.py index a59c12553..4a46495a5 100644 --- a/scc/drivers/ds5drv.py +++ b/scc/drivers/ds5drv.py @@ -144,7 +144,7 @@ def input(self, endpoint, data): # Special override for CPAD touch button if _lib.decode(ctypes.byref(self._decoder), data): if self.mapper: - if ord(data[35]) >> 7: + if ord(data[33]) >> 7: # cpad is not touched self._decoder.state.buttons &= ~SCButtons.CPADTOUCH else: From a8239bb0c6f1ceadeaaff9fa5c7a7e79289f52b7 Mon Sep 17 00:00:00 2001 From: PakoSt Date: Sat, 21 Aug 2021 14:21:36 +0100 Subject: [PATCH 09/17] DS5 Background image --- ds5.svg | 351 +++++++++++++++++ images/controller-images/ds5.svg | 620 +++++++++++++++++++++++++++++++ 2 files changed, 971 insertions(+) create mode 100644 ds5.svg create mode 100644 images/controller-images/ds5.svg diff --git a/ds5.svg b/ds5.svg new file mode 100644 index 000000000..3b67d01e4 --- /dev/null +++ b/ds5.svg @@ -0,0 +1,351 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/controller-images/ds5.svg b/images/controller-images/ds5.svg new file mode 100644 index 000000000..1f7a4125e --- /dev/null +++ b/images/controller-images/ds5.svg @@ -0,0 +1,620 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 7546aa7944ad1621dfbd8aea8546ba430704aed3 Mon Sep 17 00:00:00 2001 From: PakoSt Date: Sat, 21 Aug 2021 14:36:32 +0100 Subject: [PATCH 10/17] Add DS5 specific menu buttons --- images/button-images/ds5SELECT.svg | 78 ++++++++++++++++++++++++++++++ images/button-images/ds5START.svg | 78 ++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 images/button-images/ds5SELECT.svg create mode 100644 images/button-images/ds5START.svg diff --git a/images/button-images/ds5SELECT.svg b/images/button-images/ds5SELECT.svg new file mode 100644 index 000000000..91f7bdc43 --- /dev/null +++ b/images/button-images/ds5SELECT.svg @@ -0,0 +1,78 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + diff --git a/images/button-images/ds5START.svg b/images/button-images/ds5START.svg new file mode 100644 index 000000000..c5414ef0f --- /dev/null +++ b/images/button-images/ds5START.svg @@ -0,0 +1,78 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + From 9dd860f99c7642d2b267ba1291a83921c9b69728 Mon Sep 17 00:00:00 2001 From: PakoSt Date: Sat, 21 Aug 2021 14:37:27 +0100 Subject: [PATCH 11/17] Use DS5 specific config --- images/ds5-config.json | 27 +++++++++++++++++++++++++++ scc/drivers/ds5drv.py | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 images/ds5-config.json diff --git a/images/ds5-config.json b/images/ds5-config.json new file mode 100644 index 000000000..757bd55e9 --- /dev/null +++ b/images/ds5-config.json @@ -0,0 +1,27 @@ +{ + "gui": { + "background": "ds5", + "buttons": [ + "CROSS", "CIRCLE", "SQUARE", "TRIANGLE", "ds5SELECT", + "C", "ds5START", "LB", "RB", "LT", "RT", + "STICK", "LPAD", "RPAD", "LG", "RG" + ] + }, + + "_ " : "Buttons defined here are not actually loaded by driver, but gui", + "__" : "uses list to determine what buttons and axes are available", + + "gyros": true, + "buttons": { + "288": "Y", + "289": "B", + "290": "A", + "291": "X", + "294": "RB", + "295": "LB", + "298": "C", + "293": "CPAD", + "296": "BACK", + "297": "START" + } +} \ No newline at end of file diff --git a/scc/drivers/ds5drv.py b/scc/drivers/ds5drv.py index 4a46495a5..c00b56fc8 100644 --- a/scc/drivers/ds5drv.py +++ b/scc/drivers/ds5drv.py @@ -164,7 +164,7 @@ def get_type(self): def get_gui_config_file(self): - return "ds4-config.json" + return "ds5-config.json" def __repr__(self): From 13e6186dbaf1ac95c4aa845e7258b64cd7abf5c4 Mon Sep 17 00:00:00 2001 From: PakoSt Date: Sat, 21 Aug 2021 14:38:54 +0100 Subject: [PATCH 12/17] Remove wrong svg upload --- ds5.svg | 351 -------------------------------------------------------- 1 file changed, 351 deletions(-) delete mode 100644 ds5.svg diff --git a/ds5.svg b/ds5.svg deleted file mode 100644 index 3b67d01e4..000000000 --- a/ds5.svg +++ /dev/null @@ -1,351 +0,0 @@ - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From d3d275dcd6333eff63771eebf0f3ece3df591bb1 Mon Sep 17 00:00:00 2001 From: PakoSt Date: Sat, 21 Aug 2021 14:48:23 +0100 Subject: [PATCH 13/17] Use ds5 GUI config in evdev --- scc/drivers/ds5drv.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scc/drivers/ds5drv.py b/scc/drivers/ds5drv.py index c00b56fc8..7495c96cf 100644 --- a/scc/drivers/ds5drv.py +++ b/scc/drivers/ds5drv.py @@ -356,7 +356,7 @@ def get_type(self): # TODO: Create ds5-config.json for GUI def get_gui_config_file(self): - return "ds4-config.json" + return "ds5-config.json" def __repr__(self): From bd70b718ee7b0817a9ffea2fed75e92b4437ecf7 Mon Sep 17 00:00:00 2001 From: PakoSt Date: Sat, 21 Aug 2021 16:05:36 +0100 Subject: [PATCH 14/17] Add DualSense driver toggle in Glade --- glade/global_settings.glade | 1555 +++++++++++++++++++---------------- 1 file changed, 843 insertions(+), 712 deletions(-) diff --git a/glade/global_settings.glade b/glade/global_settings.glade index ced3925c0..886b5213f 100644 --- a/glade/global_settings.glade +++ b/glade/global_settings.glade @@ -1,27 +1,27 @@ - + 100 - 1 - 10 + 1 + 10 0.01 10.01 1 - 0.10000000000000001 - 1 - 0.01 + 0.10 + 1 + 0.01 0.01 10.01 1 - 0.10000000000000001 - 1 - 0.01 + 0.10 + 1 + 0.01 @@ -160,35 +160,35 @@ - 650 - False + 650 + False action-editor False - center-on-parent - True - dialog + center-on-parent + True + dialog True - False + False vertical True - False + False True True - False - warning + False + warning - False + False 6 - end + end @@ -199,8 +199,8 @@ Restart Emulation True - True - True + True + True @@ -218,12 +218,12 @@ - False + False 16 True - False + False gtk-dialog-warning 6 @@ -236,7 +236,7 @@ True - False + False Emulation has to be restarted to apply all settings. If you have any games running, restarting emulation will "unplug" virtual gamepad, what may cause them to ignore future inputs @@ -274,19 +274,20 @@ or even crash. True - True + True + True - False - 10 - 10 - 10 - 10 + False + 10 + 10 + 10 + 10 True - False + False On-Screen Keyboard Bindings 0 @@ -294,65 +295,65 @@ or even crash. - 0 - 6 + 0 + 6 6 True - False - 20 - 10 - 5 + False + 20 + 10 + 5 Stick 0 - 0 - 7 + 0 + 7 True - False - 20 - 10 - 5 + False + 20 + 10 + 5 Triggers 0 - 0 - 8 + 0 + 8 Advanced... True - True - True - 50 - 50 - 15 + True + True + 50 + 50 + 15 True - 0 - 9 + 0 + 9 6 True - False - 20 - 5 + False + 20 + 5 True lstStickAction @@ -364,17 +365,17 @@ or even crash. - 1 - 7 + 1 + 7 5 True - False - 20 - 5 + False + 20 + 5 True lstTriggersAction @@ -386,16 +387,16 @@ or even crash. - 1 - 8 + 1 + 8 5 True - False - 20 + False + 20 Pad Sensitivity 0 @@ -403,126 +404,126 @@ or even crash. - 0 - 10 + 0 + 10 6 True - False - 20 - 10 - 5 + False + 20 + 10 + 5 Horizontal 0 - 0 - 11 + 0 + 11 2 True - False - 20 - 10 - 5 + False + 20 + 10 + 5 Vertical 0 - 0 - 12 + 0 + 12 2 True - True - 5 + True + 5 True adjSensitivityX - 1 - right + 1 + right - 2 - 11 + 2 + 11 3 True - True - 5 + True + 5 True adjSensitivityY - 1 - right + 1 + right - 2 - 12 + 2 + 12 3 True - True - True - 10 - 20 - 5 + True + True + 10 + 20 + 5 True - False + False gtk-clear - 5 - 11 + 5 + 11 True - True - True - 10 - 20 - 5 + True + True + 10 + 20 + 5 True - False + False gtk-clear - 5 - 12 + 5 + 12 True - False - 5 + False + 5 Default Menu Items 0 @@ -530,8 +531,8 @@ or even crash. - 0 - 0 + 0 + 0 6 @@ -539,26 +540,26 @@ or even crash. cbMI_0 True - True - False - 20 - 10 - 5 + True + False + 20 + 10 + 5 True - True + True True - False + False List of recent profiles 0 - 0 - 1 + 0 + 1 3 @@ -566,26 +567,26 @@ or even crash. cbMI_6 True - True - False - 5 - 20 - 5 + True + False + 5 + 20 + 5 True - True + True True - False + False Run Program... 0 - 3 - 1 + 3 + 1 3 @@ -593,25 +594,25 @@ or even crash. cbMI_1 True - True - False - 20 - 5 - 5 - True + True + False + 20 + 5 + 5 + True True - False + False Autoswitch options 0 - 0 - 2 + 0 + 2 3 @@ -619,25 +620,25 @@ or even crash. cbMI_5 True - True - False - 5 - 20 - 5 - True + True + False + 5 + 20 + 5 + True True - False + False Kill Current Window 0 - 3 - 2 + 3 + 2 3 @@ -645,25 +646,25 @@ or even crash. cbMI_2 True - True - False - 20 - 5 - 5 - True + True + False + 20 + 5 + 5 + True True - False + False Window switcher 0 - 0 - 3 + 0 + 3 3 @@ -671,25 +672,25 @@ or even crash. cbMI_7 True - True - False - 5 - 20 - 5 - True + True + False + 5 + 20 + 5 + True True - False + False Show Current Bindings 0 - 3 - 3 + 3 + 3 3 @@ -697,25 +698,25 @@ or even crash. cbMI_8 True - True - False - 20 - 5 - 5 - True + True + False + 20 + 5 + 5 + True True - False + False Games List 0 - 0 - 4 + 0 + 4 3 @@ -723,25 +724,25 @@ or even crash. cbMI_4 True - True - False - 5 - 20 - 5 - True + True + False + 5 + 20 + 5 + True True - False + False Turn Controller OFF 0 - 3 - 5 + 3 + 5 3 @@ -749,25 +750,25 @@ or even crash. cbMI_3 True - True - False - 20 - 5 - 5 - True + True + False + 20 + 5 + 5 + True True - False + False Display Keyboard 0 - 0 - 5 + 0 + 5 3 @@ -775,25 +776,25 @@ or even crash. cbMI_9 True - True - False - 5 - 20 - 5 - True + True + False + 5 + 20 + 5 + True True - False + False Edit Current Bindings 0 - 3 - 4 + 3 + 4 3 @@ -802,214 +803,215 @@ or even crash. True - False + False Menus & Keyboard - True - False + True + False + True - False - 10 - 10 - 10 - 10 + False + 10 + 10 + 10 + 10 True - True - True - 20 - 10 - 5 + True + True + 20 + 10 + 5 True - 1 - 3 + 1 + 3 True - True - True - 20 - 10 - 5 + True + True + 20 + 10 + 5 True - 1 - 6 + 1 + 6 True - True - True - 20 - 10 - 5 + True + True + 20 + 10 + 5 True - 1 - 4 + 1 + 4 True - True - True - 20 - 10 - 5 + True + True + 20 + 10 + 5 True - 1 - 5 + 1 + 5 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Separator Text 0 - 2 - 3 + 2 + 3 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Selected Text 0 - 2 - 4 + 2 + 4 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Selected Background 0 - 2 - 5 + 2 + 5 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Selected Border 0 - 2 - 6 + 2 + 6 True - True - True - 20 - 20 - 5 + True + True + 20 + 20 + 5 True - 3 - 3 + 3 + 3 True - True - True - 20 - 20 - 5 + True + True + 20 + 20 + 5 True - 3 - 4 + 3 + 4 True - True - True - 20 - 20 - 5 + True + True + 20 + 20 + 5 True - 3 - 5 + 3 + 5 True - True - True - 20 - 20 - 5 + True + True + 20 + 20 + 5 True - 3 - 6 + 3 + 6 True - False + False OSD Menu Colors 0 @@ -1017,76 +1019,76 @@ or even crash. - 0 - 2 + 0 + 2 4 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Text 0 - 0 - 3 + 0 + 3 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Item Border 0 - 0 - 6 + 0 + 6 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Background 0 - 0 - 4 + 0 + 4 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Border 0 - 0 - 5 + 0 + 5 True - False - 10 + False + 10 On-Screen Keyboard Colors 0 @@ -1094,187 +1096,187 @@ or even crash. - 0 - 7 + 0 + 7 4 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Normal Button 0 - 0 - 8 + 0 + 8 True - True - True - 20 - 10 - 5 + True + True + 20 + 10 + 5 True - 1 - 8 + 1 + 8 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Pressed Button 0 - 0 - 9 + 0 + 9 20 True - True - True - 20 - 10 - 5 + True + True + 20 + 10 + 5 True - 1 - 9 + 1 + 9 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Special Button 0 - 0 - 10 + 0 + 10 20 True - True - True - 20 - 10 - 5 + True + True + 20 + 10 + 5 True - 1 - 10 + 1 + 10 20 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Text 0 - 2 - 8 + 2 + 8 20 True - True - True - 20 - 20 - 5 + True + True + 20 + 20 + 5 True - 3 - 8 + 3 + 8 True - False - 20 - 5 - 5 + False + 20 + 5 + 5 Higlight 0 - 2 - 9 + 2 + 9 20 True - True - True - 20 - 20 - 5 + True + True + 20 + 20 + 5 True - 3 - 9 + 3 + 9 True - False + False - 2 - 10 + 2 + 10 2 True - False + False OSD Style 0 @@ -1282,19 +1284,19 @@ or even crash. - 0 - 0 + 0 + 0 2 True - False - 50 - 10 - 5 - 10 + False + 50 + 10 + 5 + 10 True lstOSDStyle 0 @@ -1307,15 +1309,15 @@ or even crash. - 0 - 1 + 0 + 1 2 True - False + False Color Preset 0 @@ -1323,18 +1325,18 @@ or even crash. - 2 - 0 + 2 + 0 2 True - False - 50 - 5 - 10 + False + 50 + 5 + 10 True lstOSDColorPreset 0 @@ -1347,8 +1349,8 @@ or even crash. - 2 - 1 + 2 + 1 2 @@ -1360,35 +1362,36 @@ or even crash. True - False + False OSD Colors 1 - True - False + True + False + True - False - 10 - 10 - 10 - 10 + False + 10 + 10 + 10 + 10 True False - True - False + True + False True - True + True True - False + False Enable Steam Controller support 0 @@ -1398,8 +1401,8 @@ or even crash. - 0 - 0 + 0 + 0 3 @@ -1407,15 +1410,15 @@ or even crash. ds4drv True - True - False - 5 - True + True + False + 5 + True True - False + False Enable Dualshock4 (PS4 controller) support 0 @@ -1425,16 +1428,16 @@ or even crash. - 0 - 1 + 0 + 3 3 True - False - 20 + False + 20 Other registered controllers 0 0 @@ -1443,55 +1446,55 @@ or even crash. - 0 - 8 + 0 + 10 3 True - False - 30 + False + 30 If enabled, any connected Dualshock4 controller will be automatically used by SC-Controller 0 0 - 0 - 2 + 0 + 4 3 True - False - 20 + False + 20 Controller listed here are automatically used by SC-Controller whenever they are connected. 0 - 0 - 9 + 0 + 11 3 - 100 + 100 True - True - 20 - 20 + True + 20 + 20 True - in + in True - True + True lstControllers - False + False @@ -1516,8 +1519,8 @@ or even crash. - 0 - 10 + 0 + 12 3 @@ -1525,15 +1528,15 @@ or even crash. hiddrv True - True - False - 5 - True + True + False + 5 + True True - False + False Enable HID device support 0 @@ -1543,8 +1546,8 @@ or even crash. - 0 - 3 + 0 + 5 3 @@ -1552,15 +1555,15 @@ or even crash. evdevdrv True - True - False - 5 - True + True + False + 5 + True True - False + False Enable evdev support 0 @@ -1570,35 +1573,35 @@ or even crash. - 0 - 4 + 0 + 6 3 True - False - 20 - 20 - 3 + False + 20 + 20 + 3 True True - True - True + True + True False False True - False + False True - False + False gtk-add 3 @@ -1611,7 +1614,7 @@ or even crash. True - False + False Register New Controller @@ -1632,7 +1635,7 @@ or even crash. True - False + False True @@ -1644,15 +1647,15 @@ or even crash. True - True - True + True + True False False True - False + False gtk-remove 3 @@ -1666,38 +1669,39 @@ or even crash. - 0 - 11 + 0 + 13 3 - False - True + False + True Note: python-evdev package is needed for non-steam controller support - 0 - 5 + 0 + 7 + 3 remotepad True - True - False - 5 - True + True + False + 5 + True True - False + False Enable Remote RetroPad protocol support 0 @@ -1707,34 +1711,69 @@ or even crash. - 0 - 6 + 0 + 8 3 True - False - 30 + False + 30 If enabled, any device or application compatibile with Retroarch's Remote RetroPad protocol on network can connect and remote-control this computer as additional gamepad. <a href="https://github.com/kozec/sc-controller/wiki/Using-phone-with-Retroarch-as-additional-controller">See wiki for instructions and more info.</a> - True + True 0 0 - 0 - 7 + 0 + 9 3 - + + ds5drv + True + True + False + 5 + True + + + + True + False + Enable DualSense(PS5 controller) support + + + + + + + + 0 + 1 + 3 + - + + True + False + 30 + If enabled, any connected DualSense controller will be automatically used by SC-Controller + 0 + 0 + + + 0 + 2 + 3 + @@ -1744,53 +1783,54 @@ on network can connect and remote-control this computer as additional gamepad. True - False + False Controllers 2 - False + False + True - False - 10 - 10 - 10 - 10 + False + 10 + 10 + 10 + 10 True True True - True - False - 10 - 5 - True + True + False + 10 + 5 + True True - False + False Show _OSD notification when profile is switched automatically - True - cbShowOSD + True + cbShowOSD - 0 - 1 + 0 + 1 True - False - 10 + False + 10 Switching Rules 0 @@ -1798,29 +1838,29 @@ on network can connect and remote-control this computer as additional gamepad. - 0 - 2 + 0 + 2 sw - 200 + 200 True - True - 10 - 5 - 5 + True + 10 + 5 + 5 True - in + in True - True + True True lstItems True - True + True @@ -1854,14 +1894,14 @@ on network can connect and remote-control this computer as additional gamepad. - 0 - 3 + 0 + 3 True - False + False Automatic Profile Switching Options 0 @@ -1869,32 +1909,32 @@ on network can connect and remote-control this computer as additional gamepad. - 0 - 0 + 0 + 0 True - False - 10 + False + 10 True True - True - True + True + True False False True - False + False True - False + False gtk-edit 3 @@ -1907,8 +1947,8 @@ on network can connect and remote-control this computer as additional gamepad. True - False - 5 + False + 5 Edit Condition @@ -1929,7 +1969,7 @@ on network can connect and remote-control this computer as additional gamepad. True - False + False True @@ -1941,16 +1981,16 @@ on network can connect and remote-control this computer as additional gamepad. True - True - True - 10 + True + True + 10 False False True - False + False gtk-remove 3 @@ -1965,16 +2005,16 @@ on network can connect and remote-control this computer as additional gamepad. True - True - True - 10 + True + True + 10 False False True - False + False gtk-add 3 @@ -1988,10 +2028,40 @@ on network can connect and remote-control this computer as additional gamepad. - 0 - 4 + 0 + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 @@ -2000,38 +2070,39 @@ on network can connect and remote-control this computer as additional gamepad. True - False + False Autoswitcher 3 - True - False + True + False + True - False - 10 - 10 - 10 - 10 + False + 10 + 10 + 10 + 10 True - True - False - 5 - True + True + False + 5 + True True - False + False Enable Input Test Mode - True - cbShowOSD + True + cbShowOSD @@ -2039,45 +2110,45 @@ on network can connect and remote-control this computer as additional gamepad. - 0 - 0 + 0 + 0 True - False - 25 - 25 - 5 + False + 25 + 25 + 5 Allows applications to <b>watch and possibly log</b> gamepad inputs. When enabled, main application window will display pressed buttons, grips, triggers, finger positions on both pads and stick angle. - True + True True 0 - 0 - 1 + 0 + 1 True - True - False - 15 - True + True + False + 15 + True True - False + False Use Serial Numbers to Identify Controllers - True - cbShowOSD + True + cbShowOSD @@ -2085,25 +2156,25 @@ grips, triggers, finger positions on both pads and stick angle. - 0 - 3 + 0 + 3 True - True - False - 15 - True + True + False + 15 + True True - False + False Automatically Disable Emulation When Closing GUI - True - cbShowOSD + True + cbShowOSD @@ -2111,49 +2182,49 @@ grips, triggers, finger positions on both pads and stick angle. - 0 - 8 + 0 + 8 True - True - False - 30 - 5 - True + True + False + 30 + 5 + True True - False + False Minimize to status icon instead closing - True - cbShowOSD + True + cbShowOSD - 0 - 6 + 0 + 6 True - True - False - 15 - True + True + False + 15 + True True - False + False Enable Status (Systray) Icon - True - cbShowOSD + True + cbShowOSD @@ -2161,42 +2232,42 @@ grips, triggers, finger positions on both pads and stick angle. - 0 - 5 + 0 + 5 True - False - 25 - 25 - 5 + False + 25 + 25 + 5 Try disabling this option your controller stops working randomly. - True + True True 0 - 0 - 4 + 0 + 4 True - True - False - 15 - True + True + False + 15 + True True - False + False Enable Rumble Support - True - cbShowOSD + True + cbShowOSD @@ -2204,25 +2275,25 @@ grips, triggers, finger positions on both pads and stick angle. - 0 - 2 + 0 + 2 True - True - False - 15 - True + True + False + 15 + True True - False + False Display message about new version after SC-Controller upgrade - True - cbShowOSD + True + cbShowOSD @@ -2230,32 +2301,92 @@ grips, triggers, finger positions on both pads and stick angle. - 0 - 9 + 0 + 9 True - True - False - 30 - 5 - True + True + False + 30 + 5 + True True - False + False Minimize to tray on start - cbShowOSD + cbShowOSD - 0 - 7 + 0 + 7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4 @@ -2264,13 +2395,13 @@ grips, triggers, finger positions on both pads and stick angle. True - False + False Advanced 4 - True - False + True + False @@ -2285,39 +2416,39 @@ grips, triggers, finger positions on both pads and stick angle. True - False + False Settings - True + True - 500 - False + 500 + False condition editor False True - center-on-parent - dialog - True - True - Dialog + center-on-parent + dialog + True + True + Dialog True - False - 20 - 25 - 5 - 15 + False + 20 + 25 + 5 + 15 vertical True - False - 5 + False + 5 Condition 0 @@ -2333,16 +2464,16 @@ grips, triggers, finger positions on both pads and stick angle. True - True - False - 5 - 5 + True + False + 5 + 5 0 - True + True True - False + False Match Window Title 0 @@ -2360,13 +2491,13 @@ grips, triggers, finger positions on both pads and stick angle. True - False - 20 + False + 20 vertical True - True + True @@ -2379,10 +2510,10 @@ grips, triggers, finger positions on both pads and stick angle. Match exact title True - True - False + True + False 0 - True + True @@ -2395,10 +2526,10 @@ grips, triggers, finger positions on both pads and stick angle. Use regular expression True - True - False + True + False 0 - True + True @@ -2417,16 +2548,16 @@ grips, triggers, finger positions on both pads and stick angle. True - True - False - 15 - 5 + True + False + 15 + 5 0 - True + True True - False + False Match Window Class @@ -2443,8 +2574,8 @@ grips, triggers, finger positions on both pads and stick angle. True - True - 20 + True + 20 False @@ -2455,8 +2586,8 @@ grips, triggers, finger positions on both pads and stick angle. True - False - 15 + False + 15 Action 0 @@ -2472,15 +2603,15 @@ grips, triggers, finger positions on both pads and stick angle. True - True - False - 5 + True + False + 5 True - True + True True - False + False Activate Profile @@ -2497,10 +2628,10 @@ grips, triggers, finger positions on both pads and stick angle. True - False - 25 - 5 - 5 + False + 25 + 5 + 5 lstProfile @@ -2528,16 +2659,16 @@ grips, triggers, finger positions on both pads and stick angle. True - True - False - 5 + True + False + 5 True - True + True rbProfile True - False + False Turn Off Controller @@ -2554,16 +2685,16 @@ grips, triggers, finger positions on both pads and stick angle. True - True - False - 5 + True + False + 5 True - True + True rbProfile True - False + False Restart Daemon @@ -2582,16 +2713,16 @@ grips, triggers, finger positions on both pads and stick angle. True - False + False Edit Condition - True + True gtk-save True - True - True - True + True + True + True