Working ABS properties. \o/

This commit is contained in:
Merlijn Wajer 2013-05-19 13:07:59 +02:00
parent 4be3fc0b65
commit aba2913a4b
10 changed files with 124 additions and 65 deletions

View File

@ -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.

View File

@ -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
View 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
View 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)

View File

@ -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
}

View File

@ -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

View File

@ -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:

View File

@ -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 */
#

View File

@ -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)
]

View File

@ -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'])