diff options
author | Stany MARCEL <stanypub@gmail.com> | 2016-12-02 14:04:30 +0300 |
---|---|---|
committer | Stany MARCEL <stanypub@gmail.com> | 2016-12-02 14:04:30 +0300 |
commit | 0c439095333dfed5aa36e594ef6840008128b36f (patch) | |
tree | 82ce7dba68d8a987b595327be73ee49059c5fbe9 /src | |
parent | 82e84c5cd1773f3236f09cd1a22c7ab363b72008 (diff) |
Close issue #47 close uinput and turn off controller
A long press (>2s) to the steam button close and deleate the uinput device
The device is created on first event to prevent it to be created at daemon
restart
When the daeomon is stopped the controller should also be powered off
Signed-off-by: Stany MARCEL <stanypub@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/__init__.py | 32 | ||||
-rw-r--r-- | src/daemon.py | 4 | ||||
-rw-r--r-- | src/events.py | 18 | ||||
-rw-r--r-- | src/uinput.c | 2 | ||||
-rw-r--r-- | src/uinput.py | 65 |
5 files changed, 97 insertions, 24 deletions
diff --git a/src/__init__.py b/src/__init__.py index eebb073..1bf111e 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -24,7 +24,8 @@ import struct from enum import IntEnum from threading import Timer -import time +from time import time + VENDOR_ID = 0x28de PRODUCT_ID = [0x1102, 0x1142, 0x1142, 0x1142, 0x1142] @@ -65,6 +66,10 @@ STEAM_CONTROLER_FORMAT = [ _FORMATS, _NAMES = zip(*STEAM_CONTROLER_FORMAT) +EXITCMD = struct.pack('>' + 'I' * 2, + 0x9f046f66, + 0x66210000) + SteamControllerInput = namedtuple('SteamControllerInput', ' '.join([x for x in _NAMES if not x.startswith('ukn_')])) SCI_NULL = SteamControllerInput._make(struct.unpack('<' + ''.join(_FORMATS), b'\x00' * 64)) @@ -159,6 +164,7 @@ class SteamController(object): setting.getProtocol() == 0 and number == i+1): self._handle.claimInterface(number) + self._number = number claimed = True except usb1.USBErrorBusy: claimed = False @@ -188,7 +194,7 @@ class SteamController(object): self._timer = None self._tup = None - self._lastusb = time.time() + self._lastusb = time() # Disable Haptic auto feedback @@ -205,10 +211,16 @@ class SteamController(object): 0x2f010000)) self._ctx.handleEvents() - - def __del__(self): + def _close(self): if self._handle: + self._sendControl(EXITCMD) + self._handle.releaseInterface(self._number) + self._handle.resetDevice() self._handle.close() + self._handle = None + + def __del__(self): + self._close() def _sendControl(self, data, timeout=0): @@ -221,6 +233,9 @@ class SteamController(object): data=data + zeros, timeout=timeout) + def addExit(self): + self._cmsg.insert(0, EXITCMD) + def addFeedback(self, position, amplitude=128, period=0, count=1): """ Add haptic feedback to be send on next usb tick @@ -252,20 +267,18 @@ class SteamController(object): if self._tup is None: return - self._lastusb = time.time() + self._lastusb = time() if isinstance(self._cb_args, (list, tuple)): self._cb(self, self._tup, *self._cb_args) else: self._cb(self, self._tup) - - self._period = HPERIOD def _callbackTimer(self): - d = time.time() - self._lastusb + d = time() - self._lastusb self._timer.cancel() if d > DURATION: @@ -295,7 +308,8 @@ class SteamController(object): if len(self._cmsg) > 0: cmsg = self._cmsg.pop() self._sendControl(cmsg) - + if cmsg == EXITCMD: + break except usb1.USBErrorInterrupted: pass diff --git a/src/daemon.py b/src/daemon.py index 029f360..964c765 100644 --- a/src/daemon.py +++ b/src/daemon.py @@ -10,6 +10,8 @@ import atexit import signal import syslog import psutil +import traceback +import gc class Daemon(object): """A generic daemon class. @@ -96,6 +98,8 @@ class Daemon(object): self.run() except Exception as e: # pylint: disable=W0703 syslog.syslog(syslog.LOG_ERR, '{}: {!s}'.format(os.path.basename(sys.argv[0]), e)) + syslog.syslog(syslog.LOG_ERR, traceback.format_exc()) + gc.collect() else: syslog.syslog(syslog.LOG_INFO, '{}: steam client is runing'.format(os.path.basename(sys.argv[0]))) time.sleep(2) diff --git a/src/events.py b/src/events.py index bca43b3..ecfdb89 100644 --- a/src/events.py +++ b/src/events.py @@ -27,6 +27,7 @@ events """ +from time import time from math import sqrt from enum import IntEnum @@ -40,6 +41,8 @@ import steamcontroller.uinput as sui from collections import deque +EXIT_PRESS_DURATION = 2.0 + class Pos(IntEnum): """Specify witch pad or trig is used""" RIGHT = 0 @@ -118,7 +121,13 @@ class EventMapper(object): self._trig_axes_callbacks = [None, None] self._moved = [0, 0] + self._steam_pressed_time = 0.0 + def __del__(self): + if hasattr(self, '_uip') and self._uip: + for u in self._uip: + del u + self._uip = [] def process(self, sc, sci): """ @@ -188,17 +197,26 @@ class EventMapper(object): else: return False + # Manage long steam press to exit + if btn_add & SCButtons.STEAM == SCButtons.STEAM: + self._steam_pressed_time = time() + if (sci.buttons & SCButtons.STEAM == SCButtons.STEAM and + time() - self._steam_pressed_time > EXIT_PRESS_DURATION): + sc.addExit() + # Manage buttons for btn, (mode, ev) in self._btn_map.items(): if mode is None: continue + if btn & btn_add: if mode is Modes.CALLBACK: ev(self, btn, True) else: _keypressed(mode, ev) elif btn & btn_rem: + if mode is Modes.CALLBACK: ev(self, btn, False) else: diff --git a/src/uinput.c b/src/uinput.c index a2d5e33..e28110a 100644 --- a/src/uinput.c +++ b/src/uinput.c @@ -208,6 +208,6 @@ void uinput_syn(int fd) void uinput_destroy(int fd) { - ioctl(fd, UI_DEV_DESTROY); + ioctl(fd, UI_DEV_DESTROY, 0); close(fd); } diff --git a/src/uinput.py b/src/uinput.py index 537af2b..8ab8d25 100644 --- a/src/uinput.py +++ b/src/uinput.py @@ -22,8 +22,10 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. + import os import ctypes +import _ctypes import time from math import pi, copysign, sqrt from enum import IntEnum @@ -191,6 +193,13 @@ class UInput(object): self._a, self._amin, self._amax, self._afuzz, self._aflat = zip(*axes) self._r = rels + self.vendor = vendor + self.product = product + self.name = name + self.keyboard = keyboard + self._fd = None + + def createDevice(self): possible_paths = [] for extension in get_so_extensions(): possible_paths.append( @@ -214,6 +223,7 @@ class UInput(object): '\n'.join(possible_paths) ) ) + self._lib = ctypes.CDLL(lib) c_k = (ctypes.c_uint16 * len(self._k))(*self._k) @@ -223,11 +233,11 @@ class UInput(object): c_afuzz = (ctypes.c_int32 * len(self._afuzz))(*self._afuzz) c_aflat = (ctypes.c_int32 * len(self._aflat))(*self._aflat) c_r = (ctypes.c_uint16 * len(self._r))(*self._r) - c_vendor = ctypes.c_uint16(vendor) - c_product = ctypes.c_uint16(product) - c_keyboard = ctypes.c_int(keyboard) + c_vendor = ctypes.c_uint16(self.vendor) + c_product = ctypes.c_uint16(self.product) + c_keyboard = ctypes.c_int(self.keyboard) - c_name = ctypes.c_char_p(name) + c_name = ctypes.c_char_p(self.name) self._fd = self._lib.uinput_init(ctypes.c_int(len(self._k)), c_k, ctypes.c_int(len(self._a)), @@ -251,6 +261,10 @@ class UInput(object): @param int axis key or btn event (KEY_* or BTN_*) @param int val event value """ + + if self._fd == None: + self.createDevice() + self._lib.uinput_key(self._fd, ctypes.c_uint16(key), ctypes.c_int32(val)) @@ -263,6 +277,10 @@ class UInput(object): @param int axis abs event (ABS_*) @param int val event value """ + + if self._fd == None: + self.createDevice() + self._lib.uinput_abs(self._fd, ctypes.c_uint16(axis), ctypes.c_int32(val)) @@ -274,6 +292,10 @@ class UInput(object): @param int rel rel event (REL_*) @param int val event value """ + + if self._fd == None: + self.createDevice() + self._lib.uinput_rel(self._fd, ctypes.c_uint16(rel), ctypes.c_int32(val)) @@ -284,6 +306,10 @@ class UInput(object): @param int val scan event value (scancode) """ + + if self._fd == None: + self.createDevice() + self._lib.uinput_scan(self._fd, ctypes.c_int32(val)) @@ -291,6 +317,10 @@ class UInput(object): """ Generate a syn event """ + + if self._fd == None: + self.createDevice() + self._lib.uinput_syn(self._fd) @@ -302,6 +332,9 @@ class UInput(object): @param int period period is ms """ + if self._fd == None: + self.createDevice() + self._lib.uinput_set_delay_period(self._fd, ctypes.c_int32(delay), ctypes.c_int32(period)) @@ -317,8 +350,12 @@ class UInput(object): def __del__(self): - if self._lib: + + if self._lib and self._fd: self._lib.uinput_destroy(self._fd) + self._fd = None + _ctypes.dlclose(self._lib._handle) + self._lib = None class Gamepad(UInput): @@ -430,9 +467,9 @@ class Mouse(UInput): self._radscale = (degree * pi / 180) / ampli self._mass = mass self._friction = friction - self._r = r - self._I = (2 * self._mass * self._r**2) / 5.0 - self._a = self._r * self._friction / self._I + self._rad = r + self._I = (2 * self._mass * self._rad**2) / 5.0 + self._acc = self._rad * self._friction / self._I self._xvel_dq = deque(maxlen=mean_len) self._yvel_dq = deque(maxlen=mean_len) @@ -465,8 +502,8 @@ class Mouse(UInput): self._scr_mass = mass self._scr_friction = friction self._scr_r = r - self._scr_I = (2 * self._mass * self._r**2) / 5.0 - self._scr_a = self._r * self._friction / self._I + self._scr_I = (2 * self._mass * self._rad**2) / 5.0 + self._scr_a = self._rad * self._friction / self._I self._scr_xvel_dq = deque(maxlen=mean_len) self._scr_yvel_dq = deque(maxlen=mean_len) @@ -528,11 +565,11 @@ class Mouse(UInput): _hyp = sqrt((self._xvel**2) + (self._yvel**2)) if _hyp != 0.0: - _ax = self._a * (abs(self._xvel) / _hyp) - _ay = self._a * (abs(self._yvel) / _hyp) + _ax = self._acc * (abs(self._xvel) / _hyp) + _ay = self._acc * (abs(self._yvel) / _hyp) else: - _ax = self._a - _ay = self._a + _ax = self._acc + _ay = self._acc # Cap friction desceleration _dvx = min(abs(self._xvel), _ax * dt) |