uinput-mapper/cinput.py

202 lines
4.6 KiB
Python
Raw Normal View History

2013-04-17 18:34:45 -04:00
from linux_input import *
2013-04-19 19:10:16 -04:00
from linux_uinput import *
2013-04-17 18:48:24 -04:00
import array, struct, fcntl, os, sys
2013-04-18 18:10:15 -04:00
def get_input_version(f):
2013-04-19 19:10:16 -04:00
"""
Returns the input version of a specified fd of a device
"""
2013-04-18 18:10:15 -04:00
buf = array.array('i', [0])
r = fcntl.ioctl(f, EVIOCGVERSION, buf)
v = struct.unpack('@i', buf)[0]
del buf
2013-04-18 18:10:15 -04:00
return "%d.%d.%d" % ( v >> 16, (v >> 8) & 0xff, v & 0xff)
def get_input_name(f, l=256):
2013-04-19 19:10:16 -04:00
"""
Returns the name of a specified fd of a device
"""
2013-04-18 18:10:15 -04:00
buf = array.array('c', ' ' * l)
r = fcntl.ioctl(f, EVIOCGNAME(l), buf)
v = struct.unpack('%ds' % l, buf)[0]
del buf
return v[:r]
2013-04-18 18:10:15 -04:00
_bpl = struct.calcsize('@L') * 8
_nbits = lambda x: ((x-1) / _bpl) + 1
_ll = _nbits(KEY_MAX)
test_bit = lambda j, v: (v[j / _bpl] >> (j % _bpl)) & 1
def get_keys(f, ev):
2013-05-18 12:32:44 -04:00
"""
Get keys of type *f* from a specific input device *f*.
"""
2013-04-18 18:10:15 -04:00
buf = array.array('L', [0L] * _ll)
try:
fcntl.ioctl(f, EVIOCGBIT(ev, KEY_MAX), buf)
except IOError:
#print >>sys.stderr, 'Whoops!', rev_events[ev]
return None
2013-04-18 18:10:15 -04:00
v = struct.unpack('@%dL' % _ll, buf)
del buf
r = []
2013-04-18 18:10:15 -04:00
for j in range(0, KEY_MAX):
if test_bit(j, v):
r.append(j)
return r
def copy_event(estr):
"""
Copy event from a string returned by read().
We return a copy because the string will probably be freed.
"""
e = ctypes.cast(estr, ctypes.POINTER(input_event))
ev = e.contents
return input_event(ev.time, ev.type, ev.code, ev.value)
class InputDevice(object):
2013-05-18 12:32:44 -04:00
"""
Class for reading input devices in /dev/input/
"""
def __init__(self, path):
self._f = os.open(path, os.O_RDONLY)
2013-04-18 18:10:15 -04:00
def get_version(self):
2013-05-18 12:32:44 -04:00
"""
Returns the version of the input device.
"""
return get_input_version(self._f)
def get_name(self):
2013-05-18 12:32:44 -04:00
"""
Returns the name of the input device.
"""
return get_input_name(self._f)
def get_exposed_events(self):
"""
2013-05-18 12:32:44 -04:00
Returns all the keys exposed by this input device.
"""
d = dict()
for k, v in events.iteritems():
l = get_keys(self._f, v)
if l:
d[k] = []
for ev in l:
try:
d[k].append(rev_event_keys[v][ev])
except KeyError:
pass
return d
def next_event(self):
2013-05-18 12:32:44 -04:00
"""
Read the next event from the input device
"""
estr = os.read(self._f, ctypes.sizeof(input_event))
return copy_event(estr)
def get_fd(self):
2013-05-18 12:32:44 -04:00
"""
Returns the underlying fd.
"""
2013-05-18 11:39:00 -04:00
return self._f
def __del__(self):
if hasattr(self, '_f'):
os.close(self._f)
2013-04-17 18:48:24 -04:00
2013-04-19 19:10:16 -04:00
def open_uinput():
try:
f = os.open('/dev/uinput', os.O_WRONLY | os.O_NONBLOCK)
2013-05-18 16:25:17 -04:00
except OSError:
2013-04-19 19:10:16 -04:00
try:
f = os.open('/dev/input/uinput', os.O_WRONLY | os.O_NONBLOCK)
2013-05-18 16:25:17 -04:00
except OSError:
2013-04-19 19:10:16 -04:00
print 'FAIL MUCH?'
return None
return f
def write_uinput_device_info(f, name):
2013-04-19 19:10:16 -04:00
"""
Create uinput device
"""
# Add keys, etc
#handle_specs(f, specs)
# Allocate other info
uidev = uinput_user_dev()
# TODO: Get from specs
uidev.name = name
uidev._id.bustype = 0x03 # BUS_USB (TODO)
uidev._id.vendor = 0x42
uidev._id.product = 0xbebe
uidev._id.version = 1
buf = buffer(uidev)[:]
# Write dev info
os.write(f, buf)
fcntl.ioctl(f, UI_DEV_CREATE)
return f
def free_uinput_device(f):
return fcntl.ioctl(f, UI_DEV_DESTROY)
class UInputDevice(object):
2013-05-18 12:32:44 -04:00
"""
Class to create input devices using /dev/(input/)?uinput
"""
def __init__(self):
self._f = open_uinput()
if not self._f:
print 'Failed to open uinput'
raise OSError
def setup(self, name):
2013-05-18 12:32:44 -04:00
"""
Writes initial data and transforms the fd into the input device
"""
write_uinput_device_info(self._f, name)
def expose_event_type(self, evt):
2013-05-18 12:32:44 -04:00
"""
Exposes a specific event type.
"""
fcntl.ioctl(self._f, UI_SET_EVBIT, evt)
2013-04-19 19:10:16 -04:00
def expose_event(self, evt, evk):
2013-05-18 12:32:44 -04:00
"""
Exposes an event; make sure the event type is exposed as well.
"""
evbit = evbits[evt]
fcntl.ioctl(self._f, evbit, evk)
def fire_event(self, ev):
"""
2013-05-18 12:32:44 -04:00
Fire a new input event.
"""
os.write(self._f, buffer(ev)[:])
2013-04-19 19:10:16 -04:00
def __del__(self):
if hasattr(self, '_f'):
free_uinput_device(self._f)
2013-04-19 19:10:16 -04:00