mirror of
https://github.com/moparisthebest/uinput-mapper
synced 2025-02-16 06:50:13 -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])
|
buf = array.array('i', [0])
|
||||||
r = fcntl.ioctl(f, EVIOCGVERSION, buf)
|
r = fcntl.ioctl(f, EVIOCGVERSION, buf)
|
||||||
v = struct.unpack('@i', buf)[0]
|
v = buf.tolist()[0]
|
||||||
del buf
|
|
||||||
return "%d.%d.%d" % ( v >> 16, (v >> 8) & 0xff, v & 0xff)
|
return "%d.%d.%d" % ( v >> 16, (v >> 8) & 0xff, v & 0xff)
|
||||||
|
|
||||||
def get_input_name(f, l=256):
|
def get_input_name(f, l=256):
|
||||||
@ -19,9 +18,14 @@ def get_input_name(f, l=256):
|
|||||||
"""
|
"""
|
||||||
buf = array.array('c', ' ' * l)
|
buf = array.array('c', ' ' * l)
|
||||||
r = fcntl.ioctl(f, EVIOCGNAME(l), buf)
|
r = fcntl.ioctl(f, EVIOCGNAME(l), buf)
|
||||||
v = struct.unpack('%ds' % l, buf)[0]
|
return ''.join(buf.tolist()[:r])
|
||||||
del buf
|
|
||||||
return v[: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
|
_bpl = struct.calcsize('@L') * 8
|
||||||
_nbits = lambda x: ((x-1) / _bpl) + 1
|
_nbits = lambda x: ((x-1) / _bpl) + 1
|
||||||
@ -97,6 +101,9 @@ class InputDevice(object):
|
|||||||
|
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
def get_absprop(self, absk):
|
||||||
|
return read_abs_values(self.get_fd(), absk)
|
||||||
|
|
||||||
def next_event(self):
|
def next_event(self):
|
||||||
"""
|
"""
|
||||||
Read the next event from the input device
|
Read the next event from the input device
|
||||||
@ -127,7 +134,7 @@ def open_uinput():
|
|||||||
return None
|
return None
|
||||||
return f
|
return f
|
||||||
|
|
||||||
def write_uinput_device_info(f, name):
|
def write_uinput_device_info(uidev, f, name):
|
||||||
"""
|
"""
|
||||||
Create uinput device
|
Create uinput device
|
||||||
"""
|
"""
|
||||||
@ -136,7 +143,6 @@ def write_uinput_device_info(f, name):
|
|||||||
#handle_specs(f, specs)
|
#handle_specs(f, specs)
|
||||||
|
|
||||||
# Allocate other info
|
# Allocate other info
|
||||||
uidev = uinput_user_dev()
|
|
||||||
|
|
||||||
# TODO: Get from specs
|
# TODO: Get from specs
|
||||||
uidev.name = name
|
uidev.name = name
|
||||||
@ -169,12 +175,13 @@ class UInputDevice(object):
|
|||||||
if not self._f:
|
if not self._f:
|
||||||
print 'Failed to open uinput'
|
print 'Failed to open uinput'
|
||||||
raise OSError
|
raise OSError
|
||||||
|
self.uidev = uinput_user_dev()
|
||||||
|
|
||||||
def setup(self, name):
|
def setup(self, name):
|
||||||
"""
|
"""
|
||||||
Writes initial data and transforms the fd into the input device
|
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):
|
def expose_event_type(self, evt):
|
||||||
"""
|
"""
|
||||||
@ -189,6 +196,12 @@ class UInputDevice(object):
|
|||||||
evbit = evbits[evt]
|
evbit = evbits[evt]
|
||||||
fcntl.ioctl(self._f, evbit, evk)
|
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):
|
def fire_event(self, ev):
|
||||||
"""
|
"""
|
||||||
Fire a new input event.
|
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)
|
return int(y)
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
EV_ABS : {
|
(0, EV_ABS) : {
|
||||||
ABS_X : {
|
ABS_X : {
|
||||||
'type' : EV_ABS,
|
'type' : (0, EV_ABS),
|
||||||
'code' : ABS_X,
|
'code' : ABS_X,
|
||||||
'value' : transform_x
|
'value' : transform_x
|
||||||
},
|
},
|
||||||
ABS_Y : {
|
ABS_Y : {
|
||||||
'type' : EV_ABS,
|
'type' : (0, EV_ABS),
|
||||||
'code' : ABS_Y,
|
'code' : ABS_Y,
|
||||||
'value' : transform_y
|
'value' : transform_y
|
||||||
}
|
}
|
||||||
@ -54,8 +54,8 @@ def config_merge(c):
|
|||||||
c[k] = v
|
c[k] = v
|
||||||
|
|
||||||
# Uncomment this to make touch click too
|
# Uncomment this to make touch click too
|
||||||
c[EV_KEY][BTN_TOUCH] = {
|
c[(0, EV_KEY)][BTN_TOUCH] = {
|
||||||
'type' : EV_KEY,
|
'type' : (0, EV_KEY),
|
||||||
'code' : BTN_TOUCH,
|
'code' : BTN_TOUCH,
|
||||||
'value' : lambda x: 0
|
'value' : lambda x: 0
|
||||||
}
|
}
|
||||||
|
@ -34,6 +34,9 @@ nifd = in_f.load()
|
|||||||
# Read configuration
|
# Read configuration
|
||||||
conf = in_f.load()
|
conf = in_f.load()
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
pretty_conf_print(conf)
|
||||||
|
|
||||||
# Allow configurations to change our current configuration
|
# Allow configurations to change our current configuration
|
||||||
for path in cfg:
|
for path in cfg:
|
||||||
config_merge = imp.load_source('', path).config_merge
|
config_merge = imp.load_source('', path).config_merge
|
||||||
|
@ -3,7 +3,7 @@ import linux_uinput, ctypes, fcntl, os, sys
|
|||||||
import select
|
import select
|
||||||
|
|
||||||
from cinput import *
|
from cinput import *
|
||||||
from mapper import KeyMapper, parse_conf
|
from mapper import KeyMapper, parse_conf, pretty_conf_print
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import cPickle as pickle
|
import cPickle as pickle
|
||||||
@ -18,6 +18,8 @@ parser = optparse.OptionParser(description='Read input devices.',
|
|||||||
version='0.01')
|
version='0.01')
|
||||||
parser.add_option('-D', '--dump', action='store_false',
|
parser.add_option('-D', '--dump', action='store_false',
|
||||||
default=True, help='Dump will marshall all the events to stdout')
|
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',
|
parser.add_option('-C', '--compat', action='store_true',
|
||||||
help='Enable compatibility mode; for Python < 2.7')
|
help='Enable compatibility mode; for Python < 2.7')
|
||||||
@ -38,6 +40,9 @@ for idx, f in enumerate(fs):
|
|||||||
|
|
||||||
config.update(c)
|
config.update(c)
|
||||||
|
|
||||||
|
if args.verbose:
|
||||||
|
pretty_conf_print(config)
|
||||||
|
|
||||||
poll_obj, poll_mask = (select.poll, select.POLLIN) if args.compat else \
|
poll_obj, poll_mask = (select.poll, select.POLLIN) if args.compat else \
|
||||||
(select.epoll, select.EPOLLIN)
|
(select.epoll, select.EPOLLIN)
|
||||||
|
|
||||||
@ -46,7 +51,6 @@ pp = poll_obj()
|
|||||||
for f in fs:
|
for f in fs:
|
||||||
pp.register(f.get_fd(), poll_mask)
|
pp.register(f.get_fd(), poll_mask)
|
||||||
|
|
||||||
|
|
||||||
# Human readable info
|
# Human readable info
|
||||||
if args.dump:
|
if args.dump:
|
||||||
for f in fs:
|
for f in fs:
|
||||||
|
@ -89,7 +89,7 @@ class input_event(ctypes.Structure):
|
|||||||
("value", ctypes.c_int32)
|
("value", ctypes.c_int32)
|
||||||
]
|
]
|
||||||
|
|
||||||
class input_id (ctypes.Structure):
|
class input_id(ctypes.Structure):
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
("bustype", ctypes.c_uint16),
|
("bustype", ctypes.c_uint16),
|
||||||
("vendor", ctypes.c_uint16),
|
("vendor", ctypes.c_uint16),
|
||||||
@ -97,6 +97,17 @@ class input_id (ctypes.Structure):
|
|||||||
("version", ctypes.c_uint16),
|
("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
|
from ioctlhelp import IOR, IOW, IOC, IO, _IOC_READ
|
||||||
|
|
||||||
# Get driver version
|
# Get driver version
|
||||||
@ -146,6 +157,7 @@ EVIOCGPROP = lambda _len: IOC(_IOC_READ, ord('E'), 0x09,
|
|||||||
# Get event bits
|
# Get event bits
|
||||||
EVIOCGBIT = lambda ev, _len: IOC(_IOC_READ, ord('E'), 0x20 + ev, _len)
|
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 */
|
#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 */
|
#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),
|
("absmax", ctypes.c_int32 * linux_input.ABS_CNT),
|
||||||
("absmin", ctypes.c_int32 * linux_input.ABS_CNT),
|
("absmin", ctypes.c_int32 * linux_input.ABS_CNT),
|
||||||
("absfuzz", 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
|
#'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
|
return conf
|
||||||
|
|
||||||
|
|
||||||
@ -47,6 +57,11 @@ def pretty_conf_print(c):
|
|||||||
cinput.rev_events[n_ev_t],
|
cinput.rev_events[n_ev_t],
|
||||||
cinput.rev_event_keys[n_ev_t][vv['code']])
|
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):
|
def get_exported_device_count(c):
|
||||||
"""
|
"""
|
||||||
Iterate dictionary to find out how many devices are exported.
|
Iterate dictionary to find out how many devices are exported.
|
||||||
@ -97,3 +112,8 @@ class KeyMapper(object):
|
|||||||
continue
|
continue
|
||||||
d.expose_event_type(t)
|
d.expose_event_type(t)
|
||||||
d.expose_event(t, dat['code'])
|
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