mirror of
https://github.com/moparisthebest/uinput-mapper
synced 2024-11-24 08:52:14 -05:00
Working ABS properties. \o/
This commit is contained in:
parent
4be3fc0b65
commit
aba2913a4b
29
cinput.py
29
cinput.py
@ -9,8 +9,7 @@ def get_input_version(f):
|
||||
"""
|
||||
buf = array.array('i', [0])
|
||||
r = fcntl.ioctl(f, EVIOCGVERSION, buf)
|
||||
v = struct.unpack('@i', buf)[0]
|
||||
del buf
|
||||
v = buf.tolist()[0]
|
||||
return "%d.%d.%d" % ( v >> 16, (v >> 8) & 0xff, v & 0xff)
|
||||
|
||||
def get_input_name(f, l=256):
|
||||
@ -19,9 +18,14 @@ def get_input_name(f, l=256):
|
||||
"""
|
||||
buf = array.array('c', ' ' * l)
|
||||
r = fcntl.ioctl(f, EVIOCGNAME(l), buf)
|
||||
v = struct.unpack('%ds' % l, buf)[0]
|
||||
del buf
|
||||
return v[:r]
|
||||
return ''.join(buf.tolist()[:r])
|
||||
|
||||
def read_abs_values(f, abs_ev):
|
||||
buf = array.array('i', [0] * 6)
|
||||
|
||||
r = fcntl.ioctl(f, EVIOCGABS(abs_ev), buf)
|
||||
val = input_absinfo(*buf.tolist())
|
||||
return val
|
||||
|
||||
_bpl = struct.calcsize('@L') * 8
|
||||
_nbits = lambda x: ((x-1) / _bpl) + 1
|
||||
@ -97,6 +101,9 @@ class InputDevice(object):
|
||||
|
||||
return d
|
||||
|
||||
def get_absprop(self, absk):
|
||||
return read_abs_values(self.get_fd(), absk)
|
||||
|
||||
def next_event(self):
|
||||
"""
|
||||
Read the next event from the input device
|
||||
@ -127,7 +134,7 @@ def open_uinput():
|
||||
return None
|
||||
return f
|
||||
|
||||
def write_uinput_device_info(f, name):
|
||||
def write_uinput_device_info(uidev, f, name):
|
||||
"""
|
||||
Create uinput device
|
||||
"""
|
||||
@ -136,7 +143,6 @@ def write_uinput_device_info(f, name):
|
||||
#handle_specs(f, specs)
|
||||
|
||||
# Allocate other info
|
||||
uidev = uinput_user_dev()
|
||||
|
||||
# TODO: Get from specs
|
||||
uidev.name = name
|
||||
@ -169,12 +175,13 @@ class UInputDevice(object):
|
||||
if not self._f:
|
||||
print 'Failed to open uinput'
|
||||
raise OSError
|
||||
self.uidev = uinput_user_dev()
|
||||
|
||||
def setup(self, name):
|
||||
"""
|
||||
Writes initial data and transforms the fd into the input device
|
||||
"""
|
||||
write_uinput_device_info(self._f, name)
|
||||
write_uinput_device_info(self.uidev, self._f, name)
|
||||
|
||||
def expose_event_type(self, evt):
|
||||
"""
|
||||
@ -189,6 +196,12 @@ class UInputDevice(object):
|
||||
evbit = evbits[evt]
|
||||
fcntl.ioctl(self._f, evbit, evk)
|
||||
|
||||
def set_absprop(self, absk, _max=0, _min=0, fuzz=0, flat=0):
|
||||
self.uidev.absmax[absk] = _max
|
||||
self.uidev.absmin[absk] = _min
|
||||
self.uidev.absfuzz[absk] = fuzz
|
||||
self.uidev.absflat[absk] = flat
|
||||
|
||||
def fire_event(self, ev):
|
||||
"""
|
||||
Fire a new input event.
|
||||
|
@ -1,48 +0,0 @@
|
||||
from cinput import *
|
||||
|
||||
overrule = lambda x: -x*2
|
||||
passthrough = lambda x: x
|
||||
|
||||
config = {
|
||||
EV_REL : {
|
||||
#REL_X : {
|
||||
# 'type' : EV_REL,
|
||||
# 'code' : REL_X,
|
||||
# 'value': overrule
|
||||
#},
|
||||
#REL_Y : {
|
||||
# 'type': EV_REL,
|
||||
# 'code': REL_Y,
|
||||
# 'value' : overrule
|
||||
#},
|
||||
REL_X : {
|
||||
'type' : EV_REL,
|
||||
'code' : REL_X,
|
||||
'value' : lambda x: 0
|
||||
},
|
||||
REL_Y : {
|
||||
'type' : EV_REL,
|
||||
'code' : REL_Y,
|
||||
'value' : lambda x: 0
|
||||
},
|
||||
REL_WHEEL : {
|
||||
'type' : EV_REL,
|
||||
'code' : REL_WHEEL,
|
||||
'value' : lambda x: -x*2
|
||||
}
|
||||
},
|
||||
EV_KEY : {
|
||||
BTN_LEFT : {
|
||||
'type' : EV_KEY,
|
||||
'code' : BTN_LEFT,
|
||||
'value' : passthrough
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def config_merge(c):
|
||||
for k, v in config.iteritems():
|
||||
if k in c:
|
||||
c[k].update(v)
|
||||
else:
|
||||
c[k] = v
|
34
configs/sidewinder-rel.py
Normal file
34
configs/sidewinder-rel.py
Normal file
@ -0,0 +1,34 @@
|
||||
from cinput import *
|
||||
|
||||
"""
|
||||
Configuration for a simple Microsoft SideWinter Game Pad Pro USB version 1.0
|
||||
... as REL input pointer device
|
||||
"""
|
||||
|
||||
|
||||
config = {
|
||||
(0, EV_KEY): {
|
||||
BTN_A: {
|
||||
'type' : (0, EV_KEY),
|
||||
'code' : BTN_MOUSE,
|
||||
'value' : lambda x: 0 if x == 0 else 1
|
||||
}
|
||||
},
|
||||
(0, EV_ABS) : {
|
||||
ABS_X: {
|
||||
'type' : (0, EV_REL),
|
||||
'code' : REL_X,
|
||||
'value' : lambda x: x / 7,
|
||||
},
|
||||
ABS_Y: {
|
||||
'type' : (0, EV_REL),
|
||||
'code' : REL_Y,
|
||||
'value' : lambda x: x / 7,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def config_merge(c):
|
||||
del c[(0, EV_KEY)]
|
||||
del c[(0, EV_ABS)]
|
||||
c.update(config)
|
21
configs/sidewinder.py
Normal file
21
configs/sidewinder.py
Normal file
@ -0,0 +1,21 @@
|
||||
from cinput import *
|
||||
|
||||
|
||||
"""
|
||||
Configuration for a simple Microsoft SideWinter Game Pad Pro USB version 1.0
|
||||
... as ABS input pointer device
|
||||
"""
|
||||
|
||||
config = {
|
||||
(0, EV_KEY): {
|
||||
BTN_A: {
|
||||
'type' : (0, EV_KEY),
|
||||
'code' : BTN_MOUSE,
|
||||
'value' : lambda x: 0 if x == 0 else 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def config_merge(c):
|
||||
del c[(0, EV_KEY)]
|
||||
c.update(config)
|
@ -31,14 +31,14 @@ def transform_y(y):
|
||||
return int(y)
|
||||
|
||||
config = {
|
||||
EV_ABS : {
|
||||
(0, EV_ABS) : {
|
||||
ABS_X : {
|
||||
'type' : EV_ABS,
|
||||
'type' : (0, EV_ABS),
|
||||
'code' : ABS_X,
|
||||
'value' : transform_x
|
||||
},
|
||||
ABS_Y : {
|
||||
'type' : EV_ABS,
|
||||
'type' : (0, EV_ABS),
|
||||
'code' : ABS_Y,
|
||||
'value' : transform_y
|
||||
}
|
||||
@ -54,8 +54,8 @@ def config_merge(c):
|
||||
c[k] = v
|
||||
|
||||
# Uncomment this to make touch click too
|
||||
c[EV_KEY][BTN_TOUCH] = {
|
||||
'type' : EV_KEY,
|
||||
c[(0, EV_KEY)][BTN_TOUCH] = {
|
||||
'type' : (0, EV_KEY),
|
||||
'code' : BTN_TOUCH,
|
||||
'value' : lambda x: 0
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ nifd = in_f.load()
|
||||
# Read configuration
|
||||
conf = in_f.load()
|
||||
|
||||
if args.verbose:
|
||||
pretty_conf_print(conf)
|
||||
|
||||
# Allow configurations to change our current configuration
|
||||
for path in cfg:
|
||||
config_merge = imp.load_source('', path).config_merge
|
||||
|
@ -3,7 +3,7 @@ import linux_uinput, ctypes, fcntl, os, sys
|
||||
import select
|
||||
|
||||
from cinput import *
|
||||
from mapper import KeyMapper, parse_conf
|
||||
from mapper import KeyMapper, parse_conf, pretty_conf_print
|
||||
|
||||
try:
|
||||
import cPickle as pickle
|
||||
@ -18,6 +18,8 @@ parser = optparse.OptionParser(description='Read input devices.',
|
||||
version='0.01')
|
||||
parser.add_option('-D', '--dump', action='store_false',
|
||||
default=True, help='Dump will marshall all the events to stdout')
|
||||
parser.add_option('-v', '--verbose', action='store_true',
|
||||
default=False, help='Enable verbose mode (do not combine with -D)')
|
||||
|
||||
parser.add_option('-C', '--compat', action='store_true',
|
||||
help='Enable compatibility mode; for Python < 2.7')
|
||||
@ -38,6 +40,9 @@ for idx, f in enumerate(fs):
|
||||
|
||||
config.update(c)
|
||||
|
||||
if args.verbose:
|
||||
pretty_conf_print(config)
|
||||
|
||||
poll_obj, poll_mask = (select.poll, select.POLLIN) if args.compat else \
|
||||
(select.epoll, select.EPOLLIN)
|
||||
|
||||
@ -46,7 +51,6 @@ pp = poll_obj()
|
||||
for f in fs:
|
||||
pp.register(f.get_fd(), poll_mask)
|
||||
|
||||
|
||||
# Human readable info
|
||||
if args.dump:
|
||||
for f in fs:
|
||||
|
@ -97,6 +97,17 @@ class input_id (ctypes.Structure):
|
||||
("version", ctypes.c_uint16),
|
||||
]
|
||||
|
||||
class input_absinfo(ctypes.Structure):
|
||||
_fields_ = [
|
||||
("value", ctypes.c_int32),
|
||||
("minimum", ctypes.c_int32),
|
||||
("maximum", ctypes.c_int32),
|
||||
("fuzz", ctypes.c_int32),
|
||||
("flat", ctypes.c_int32),
|
||||
("resolution", ctypes.c_int32)
|
||||
]
|
||||
|
||||
|
||||
from ioctlhelp import IOR, IOW, IOC, IO, _IOC_READ
|
||||
|
||||
# Get driver version
|
||||
@ -146,6 +157,7 @@ EVIOCGPROP = lambda _len: IOC(_IOC_READ, ord('E'), 0x09,
|
||||
# Get event bits
|
||||
EVIOCGBIT = lambda ev, _len: IOC(_IOC_READ, ord('E'), 0x20 + ev, _len)
|
||||
|
||||
EVIOCGABS = lambda _abs: IOR(ord('E'), 0x40 + _abs, ctypes.sizeof(input_absinfo))
|
||||
#EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) /* get abs value/limits */
|
||||
#EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) /* set abs value/limits */
|
||||
#
|
||||
|
@ -59,5 +59,5 @@ class uinput_user_dev(ctypes.Structure):
|
||||
("absmax", ctypes.c_int32 * linux_input.ABS_CNT),
|
||||
("absmin", ctypes.c_int32 * linux_input.ABS_CNT),
|
||||
("absfuzz", ctypes.c_int32 * linux_input.ABS_CNT),
|
||||
("absflac", ctypes.c_int32 * linux_input.ABS_CNT)
|
||||
("absflat", ctypes.c_int32 * linux_input.ABS_CNT)
|
||||
]
|
||||
|
20
mapper.py
20
mapper.py
@ -30,6 +30,16 @@ def parse_conf(f, devname):
|
||||
#'value' : lambda x: x
|
||||
}
|
||||
|
||||
if t == cinput.EV_ABS:
|
||||
p = f.get_absprop(tt)
|
||||
conf[(devname, t)][tt]['prop'] = {
|
||||
'max' : p.maximum,
|
||||
'min' : p.minimum,
|
||||
'fuzz' : p.fuzz,
|
||||
'flat' : p.flat
|
||||
}
|
||||
|
||||
|
||||
return conf
|
||||
|
||||
|
||||
@ -47,6 +57,11 @@ def pretty_conf_print(c):
|
||||
cinput.rev_events[n_ev_t],
|
||||
cinput.rev_event_keys[n_ev_t][vv['code']])
|
||||
|
||||
if n_ev_t == cinput.EV_ABS:
|
||||
print 'Properties: Max: %d Min: %d Fuzz: %d Flat: %d' % (
|
||||
vv['prop']['max'], vv['prop']['min'],
|
||||
vv['prop']['fuzz'], vv['prop']['flat'])
|
||||
|
||||
def get_exported_device_count(c):
|
||||
"""
|
||||
Iterate dictionary to find out how many devices are exported.
|
||||
@ -97,3 +112,8 @@ class KeyMapper(object):
|
||||
continue
|
||||
d.expose_event_type(t)
|
||||
d.expose_event(t, dat['code'])
|
||||
|
||||
if t == cinput.EV_ABS:
|
||||
p = dat['prop']
|
||||
d.set_absprop(dat['code'], _max=p['max'], _min=p['min'],
|
||||
fuzz=p['fuzz'], flat=p['flat'])
|
||||
|
Loading…
Reference in New Issue
Block a user