From d1f38e30739733353c53a353a8bccfffd01adf6e Mon Sep 17 00:00:00 2001 From: Dan McDougall Date: Wed, 23 Apr 2014 13:47:10 -0400 Subject: [PATCH 1/2] ds4drv/config.py: Added support for trailing comments in ds4drv.conf --- ds4drv/config.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ds4drv/config.py b/ds4drv/config.py index 021b1b8..d01a791 100644 --- a/ds4drv/config.py +++ b/ds4drv/config.py @@ -229,6 +229,10 @@ def load_options(): for name, section in config.sections("mapping"): mapping = config.section(section) + for key, attr in mapping.items(): + if '#' in attr: # Remove tailing comments on the line + attr = attr.split('#', 1)[0].rstrip() + mapping[key] = attr parse_uinput_mapping(name, mapping) for controller in options.controllers: From 22ce4cef003b4c2ac0addc794991b933f383f086 Mon Sep 17 00:00:00 2001 From: Dan McDougall Date: Wed, 23 Apr 2014 13:49:09 -0400 Subject: [PATCH 2/2] ds4drv/uinput.py: Added support for emulating a mouse scroll wheel. ds4drv.conf: Added new mouse scroll wheel emulation settings. --- ds4drv.conf | 11 ++++++++++ ds4drv/uinput.py | 57 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/ds4drv.conf b/ds4drv.conf index e92f195..de4dc43 100644 --- a/ds4drv.conf +++ b/ds4drv.conf @@ -106,10 +106,21 @@ REL_Y = right_analog_y BTN_LEFT = button_r2 BTN_RIGHT = button_l2 +# Emulate mouse wheel on r1 and l1 +REL_WHEELUP = button_l1 +REL_WHEELDOWN = button_r1 + # Mouse settings #mouse_sensitivity = 0.6 #mouse_deadzone = 5 +# Emulate mouse wheel on r2 and l2 +REL_WHEELUP = button_l1 +REL_WHEELDOWN = button_r1 +# Scroll wheel emulation settings (values are in seconds) +#mouse_scroll_repeat_delay = 0.25 # How long to wait before continual scrolling +#mouse_scroll_delay = 0.05 # Lower this to scroll faster; raise to scroll slower + ## # Bindings diff --git a/ds4drv/uinput.py b/ds4drv/uinput.py index 581d314..8bbf5f5 100644 --- a/ds4drv/uinput.py +++ b/ds4drv/uinput.py @@ -1,4 +1,5 @@ import os.path +import time from collections import namedtuple @@ -12,6 +13,8 @@ DEFAULT_AXIS_OPTIONS = (0, 255, 0, 5) DEFAULT_MOUSE_SENSITIVTY = 0.6 DEFAULT_MOUSE_DEADZONE = 5 +DEFAULT_SCROLL_REPEAT_DELAY = .250 # Seconds to wait before continual scrolling +DEFAULT_SCROLL_DELAY = .035 # Seconds to wait between scroll events UInputMapping = namedtuple("UInputMapping", "name bustype vendor product version " @@ -20,6 +23,10 @@ _mappings = {} +# Add our simulated mousewheel codes +ecodes.REL_WHEELUP = 13 # Unique value for this lib +ecodes.REL_WHEELDOWN = 14 # Ditto + def parse_button(attr): if attr[0] in BUTTON_MODIFIERS: @@ -227,6 +234,7 @@ def __init__(self, layout): self.create_device(layout) self._write_cache = {} + self._scroll_details = {} def create_device(self, layout): """Creates a uinput device using the specified layout.""" @@ -259,9 +267,22 @@ def create_device(self, layout): layout.mouse_options.get("MOUSE_DEADZONE", DEFAULT_MOUSE_DEADZONE) ) + self.scroll_repeat_delay = float( + layout.mouse_options.get("MOUSE_SCROLL_REPEAT_DELAY", + DEFAULT_SCROLL_REPEAT_DELAY) + ) + self.scroll_delay = float( + layout.mouse_options.get("MOUSE_SCROLL_DELAY", + DEFAULT_SCROLL_DELAY) + ) for name in layout.mouse: - events[ecodes.EV_REL].append(name) + if name in (ecodes.REL_WHEELUP, ecodes.REL_WHEELDOWN): + if ecodes.REL_WHEEL not in events[ecodes.EV_REL]: + # This ensures that scroll wheel events can work + events[ecodes.EV_REL].append(ecodes.REL_WHEEL) + else: + events[ecodes.EV_REL].append(name) self.mouse_rel[name] = 0.0 self.device = UInput(name=layout.name, events=events, @@ -353,6 +374,40 @@ def emit_mouse(self, report): sensitivity = self.mouse_analog_sensitivity self.mouse_rel[name] += accel * sensitivity + # Emulate mouse wheel (needs special handling) + if name in (ecodes.REL_WHEELUP, ecodes.REL_WHEELDOWN): + ecode = ecodes.REL_WHEEL # The real event we need to emit + write = False + if getattr(report, attr): + self._scroll_details['direction'] = name + now = time.time() + last_write = self._scroll_details.get('last_write') + if not last_write: + # No delay for the first button press for fast feedback + write = True + self._scroll_details['count'] = 0 + if name == ecodes.REL_WHEELUP: + value = 1 + elif name == ecodes.REL_WHEELDOWN: + value = -1 + if last_write: + # Delay at least one cycle before continual scrolling + if self._scroll_details['count'] > 1: + if now - last_write > self.scroll_delay: + write = True + elif now - last_write > self.scroll_repeat_delay: + write = True + if write: + self.device.write(ecodes.EV_REL, ecode, value) + self._scroll_details['last_write'] = now + self._scroll_details['count'] += 1 + continue # No need to proceed further + else: + # Reset so you can quickly tap the button to scroll + if self._scroll_details.get('direction') == name: + self._scroll_details['last_write'] = 0 + self._scroll_details['count'] = 0 + rel = int(self.mouse_rel[name]) self.mouse_rel[name] = self.mouse_rel[name] - rel self.device.write(ecodes.EV_REL, name, rel)