Document most code.

This commit is contained in:
Merlijn Wajer 2013-05-18 18:32:44 +02:00
parent 72dde4af77
commit 7c7abc7e59
4 changed files with 80 additions and 19 deletions

View File

@ -29,6 +29,9 @@ _ll = _nbits(KEY_MAX)
test_bit = lambda j, v: (v[j / _bpl] >> (j % _bpl)) & 1 test_bit = lambda j, v: (v[j / _bpl] >> (j % _bpl)) & 1
def get_keys(f, ev): def get_keys(f, ev):
"""
Get keys of type *f* from a specific input device *f*.
"""
buf = array.array('L', [0L] * _ll) buf = array.array('L', [0L] * _ll)
try: try:
fcntl.ioctl(f, EVIOCGBIT(ev, KEY_MAX), buf) fcntl.ioctl(f, EVIOCGBIT(ev, KEY_MAX), buf)
@ -58,19 +61,28 @@ def copy_event(estr):
return input_event(ev.time, ev.type, ev.code, ev.value) return input_event(ev.time, ev.type, ev.code, ev.value)
class InputDevice(object): class InputDevice(object):
"""
Class for reading input devices in /dev/input/
"""
def __init__(self, path): def __init__(self, path):
self._f = os.open(path, os.O_RDONLY) self._f = os.open(path, os.O_RDONLY)
def get_version(self): def get_version(self):
"""
Returns the version of the input device.
"""
return get_input_version(self._f) return get_input_version(self._f)
def get_name(self): def get_name(self):
"""
Returns the name of the input device.
"""
return get_input_name(self._f) return get_input_name(self._f)
# TODO: Maybe do not export keys?
def get_exposed_events(self): def get_exposed_events(self):
""" """
Returns all the keys exposed by this input device.
""" """
d = dict() d = dict()
for k, v in events.iteritems(): for k, v in events.iteritems():
@ -86,10 +98,16 @@ class InputDevice(object):
return d return d
def next_event(self): def next_event(self):
"""
Read the next event from the input device
"""
estr = os.read(self._f, ctypes.sizeof(input_event)) estr = os.read(self._f, ctypes.sizeof(input_event))
return copy_event(estr) return copy_event(estr)
def get_fd(self): def get_fd(self):
"""
Returns the underlying fd.
"""
return self._f return self._f
@ -97,9 +115,6 @@ class InputDevice(object):
if hasattr(self, '_f'): if hasattr(self, '_f'):
os.close(self._f) os.close(self._f)
class InputDeviceStream(object):
pass
def open_uinput(): def open_uinput():
try: try:
@ -144,6 +159,11 @@ def free_uinput_device(f):
class UInputDevice(object): class UInputDevice(object):
"""
Class to create input devices using /dev/(input/)?uinput
"""
def __init__(self): def __init__(self):
self._f = open_uinput() self._f = open_uinput()
if not self._f: if not self._f:
@ -151,17 +171,27 @@ class UInputDevice(object):
raise OSError raise OSError
def setup(self, name): 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._f, name)
def expose_event_type(self, evt): def expose_event_type(self, evt):
"""
Exposes a specific event type.
"""
fcntl.ioctl(self._f, UI_SET_EVBIT, evt) fcntl.ioctl(self._f, UI_SET_EVBIT, evt)
def expose_event(self, evt, evk): def expose_event(self, evt, evk):
"""
Exposes an event; make sure the event type is exposed as well.
"""
evbit = evbits[evt] evbit = evbits[evt]
fcntl.ioctl(self._f, evbit, evk) fcntl.ioctl(self._f, evbit, evk)
def fire_event(self, ev): def fire_event(self, ev):
""" """
Fire a new input event.
""" """
os.write(self._f, buffer(ev)[:]) os.write(self._f, buffer(ev)[:])

View File

@ -20,31 +20,34 @@ parser = optparse.OptionParser(description='Create input devices.',
) )
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')
parser.add_option('-v', '--verbose', action='store_true',
help='Enable verbose mode')
args, cfg = parser.parse_args() args, cfg = parser.parse_args()
# Unpickle from stdin ; currently this is the default and only way # Unpickle from stdin ; currently this is the default and only way
in_f = pickle.Unpickler(sys.stdin) in_f = pickle.Unpickler(sys.stdin)
# Read input device count
nifd = in_f.load() nifd = in_f.load()
print 'Got', nifd, 'inputs' # Read configuration
conf = in_f.load() conf = in_f.load()
# 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
config_merge(conf) config_merge(conf)
pretty_conf_print(conf) if args.verbose:
pretty_conf_print(conf)
m = KeyMapper(conf) m = KeyMapper(conf)
# TODO: Get amount of uinput devices to export # Get number of output devices (determined from conf)
nofd = get_exported_device_count(conf) nofd = get_exported_device_count(conf)
# Create and expose uinput devices
ofs = [] ofs = []
for f in xrange(nofd): for f in xrange(nofd):
d = UInputDevice() d = UInputDevice()
@ -52,6 +55,7 @@ for f in xrange(nofd):
d.setup('Example input device') d.setup('Example input device')
ofs.append(d) ofs.append(d)
# Map events
while True: while True:
if not args.compat: if not args.compat:
fd, ev = in_f.load() fd, ev = in_f.load()

View File

@ -24,23 +24,27 @@ parser.add_option('-C', '--compat', action='store_true',
args, input_file = parser.parse_args() args, input_file = parser.parse_args()
if len(input_file) == 0: if len(input_file) == 0:
parser.print_help() parser.print_help()
exit(0) exit(0)
# Open input devices
fs = map(InputDevice, input_file) fs = map(InputDevice, input_file)
# Create configuration
config = {} config = {}
for idx, f in enumerate(fs): for idx, f in enumerate(fs):
c = parse_conf(f, idx) c = parse_conf(f, idx)
config.update(c) config.update(c)
# Add all devices to epoll
pp = select.epoll() pp = select.epoll()
for f in fs: for f in fs:
pp.register(f.get_fd(), select.EPOLLIN) pp.register(f.get_fd(), select.EPOLLIN)
# Human readable info
if args.dump: if args.dump:
for f in fs: for f in fs:
print 'Version:', f.get_version() print 'Version:', f.get_version()
@ -51,6 +55,7 @@ if args.dump:
print k + ':', ', '.join(v) print k + ':', ', '.join(v)
else: else:
# Dump initial information over pickle to stdout
p = pickle.Pickler(sys.stdout) p = pickle.Pickler(sys.stdout)
p.dump(len(fs)) p.dump(len(fs))
@ -59,7 +64,6 @@ else:
sys.stdout.flush() sys.stdout.flush()
i = 0
while True: while True:
events = pp.poll() events = pp.poll()
@ -69,7 +73,7 @@ while True:
if not ev_mask & select.EPOLLIN: if not ev_mask & select.EPOLLIN:
continue continue
# Lets undo that epoll speedup ;-) # Lets undo that epoll speedup ;-) FIXME XXX
for idx, _ in enumerate(fs): for idx, _ in enumerate(fs):
if _.get_fd() == fd: if _.get_fd() == fd:
f = _ f = _
@ -80,7 +84,8 @@ while True:
if args.dump: if args.dump:
try: try:
print i, ev.time.tv_sec, ev.time.tv_usec print i, ev.time.tv_sec, ev.time.tv_usec
s = '%s %s %d' % (rev_events[ev.type], rev_event_keys[ev.type][ev.code], ev.value) s = '%s %s %d' % (rev_events[ev.type],
rev_event_keys[ev.type][ev.code], ev.value)
print 'Event type:', s print 'Event type:', s
except KeyError: except KeyError:
pass pass
@ -89,9 +94,7 @@ while True:
if not args.compat: if not args.compat:
p.dump((i, ev)) p.dump((i, ev))
else: else:
# Use this rather than the line above if you use an old python version (also p.dump((i, (ev.time.tv_sec, ev.time.tv_usec,
# edit create.py) ev.type, ev.code, ev.value)))
p.dump((i, (ev.time.tv_sec, ev.time.tv_usec, ev.type, ev.code,
ev.value)))
sys.stdout.flush() sys.stdout.flush()

View File

@ -1,8 +1,17 @@
# encoding: utf-8 # encoding: utf-8
import cinput import cinput
# XXX: Also parse name, etc """
Module to help out with config parsing and input mapping
"""
def parse_conf(f, devname): def parse_conf(f, devname):
"""
Reads in input devices and returns a config that contains all the events
exported by the device.
devname specificies the idx of this input device
"""
conf = {} conf = {}
e = f.get_exposed_events() e = f.get_exposed_events()
for k, v in e.iteritems(): for k, v in e.iteritems():
@ -25,6 +34,9 @@ def parse_conf(f, devname):
def pretty_conf_print(c): def pretty_conf_print(c):
"""
Function to print an entire configuration
"""
for k, v in c.iteritems(): for k, v in c.iteritems():
print 'Input:', k[0], 'Type:', cinput.rev_events[k[1]] print 'Input:', k[0], 'Type:', cinput.rev_events[k[1]]
for kk, vv in v.iteritems(): for kk, vv in v.iteritems():
@ -36,6 +48,10 @@ def pretty_conf_print(c):
cinput.rev_event_keys[n_ev_t][vv['code']]) cinput.rev_event_keys[n_ev_t][vv['code']])
def get_exported_device_count(c): def get_exported_device_count(c):
"""
Iterate dictionary to find out how many devices are exported.
(Rather simple at the moment)
"""
m = 0 m = 0
for _, v in c.iteritems(): for _, v in c.iteritems():
for _, o in v.iteritems(): for _, o in v.iteritems():
@ -49,6 +65,10 @@ class KeyMapper(object):
self._config = config self._config = config
def map_event(self, ev, fd): def map_event(self, ev, fd):
"""
Maps an event *ev* from fd *fd* to a possibly different event and output
fd *ofd*.
"""
_type = ev.type _type = ev.type
if _type in self._config: if _type in self._config:
@ -67,6 +87,10 @@ class KeyMapper(object):
return ofd, ev return ofd, ev
def expose(self, d, fd): def expose(self, d, fd):
"""
Expose exposes events to a uinput-device *d* with index *fd* from the
config passed to __init__.
"""
for (n, evt), v in self._config.iteritems(): for (n, evt), v in self._config.iteritems():
for code, dat in v.iteritems(): for code, dat in v.iteritems():
ofd, t = dat['type'] ofd, t = dat['type']