Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ynsta/steamcontroller.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStany MARCEL <stanypub@gmail.com>2016-12-02 14:04:30 +0300
committerStany MARCEL <stanypub@gmail.com>2016-12-02 14:04:30 +0300
commit0c439095333dfed5aa36e594ef6840008128b36f (patch)
tree82ce7dba68d8a987b595327be73ee49059c5fbe9 /src
parent82e84c5cd1773f3236f09cd1a22c7ab363b72008 (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__.py32
-rw-r--r--src/daemon.py4
-rw-r--r--src/events.py18
-rw-r--r--src/uinput.c2
-rw-r--r--src/uinput.py65
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)