Skip to content

Commit

Permalink
ds4drv/uinput.py: Added support for emulating a mouse scroll wheel.
Browse files Browse the repository at this point in the history
ds4drv.conf: Added new mouse scroll wheel emulation settings.
  • Loading branch information
liftoff committed Apr 23, 2014
1 parent d1f38e3 commit 22ce4ce
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 1 deletion.
11 changes: 11 additions & 0 deletions ds4drv.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
57 changes: 56 additions & 1 deletion ds4drv/uinput.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os.path
import time

from collections import namedtuple

Expand All @@ -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 "
Expand All @@ -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:
Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 22ce4ce

Please sign in to comment.