diff --git a/cinput.py b/cinput.py index 668d950..7294398 100644 --- a/cinput.py +++ b/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. diff --git a/configs/example_conf.py b/configs/example_conf.py deleted file mode 100644 index a378def..0000000 --- a/configs/example_conf.py +++ /dev/null @@ -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 diff --git a/configs/sidewinder-rel.py b/configs/sidewinder-rel.py new file mode 100644 index 0000000..d81f148 --- /dev/null +++ b/configs/sidewinder-rel.py @@ -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) diff --git a/configs/sidewinder.py b/configs/sidewinder.py new file mode 100644 index 0000000..307cc4e --- /dev/null +++ b/configs/sidewinder.py @@ -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) diff --git a/configs/touchscreen.py b/configs/touchscreen.py index cb7d3cd..338ac83 100644 --- a/configs/touchscreen.py +++ b/configs/touchscreen.py @@ -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 } diff --git a/input-create b/input-create index 3bae5b7..9e9fb4c 100755 --- a/input-create +++ b/input-create @@ -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 diff --git a/input-read b/input-read index 643106d..b200f3e 100755 --- a/input-read +++ b/input-read @@ -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: diff --git a/linux_input.py b/linux_input.py index 85fc091..1a6b001 100644 --- a/linux_input.py +++ b/linux_input.py @@ -89,7 +89,7 @@ class input_event(ctypes.Structure): ("value", ctypes.c_int32) ] -class input_id (ctypes.Structure): +class input_id(ctypes.Structure): _fields_ = [ ("bustype", ctypes.c_uint16), ("vendor", ctypes.c_uint16), @@ -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 */ # diff --git a/linux_uinput.py b/linux_uinput.py index c5474fe..9f2bcc0 100644 --- a/linux_uinput.py +++ b/linux_uinput.py @@ -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) ] diff --git a/mapper.py b/mapper.py index 9cc17e3..f4123c0 100644 --- a/mapper.py +++ b/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'])