1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
# encoding: utf-8
import re
import os
import stat
import glob
import collections
from evdev import ecodes
from evdev.events import event_factory
def list_devices(input_device_dir='/dev/input'):
'''List readable character devices in ``input_device_dir``.'''
fns = glob.glob('{}/event*'.format(input_device_dir))
fns = list(filter(is_device, fns))
return fns
def is_device(fn):
'''Check if ``fn`` is a readable and writable character device.'''
if not os.path.exists(fn):
return False
m = os.stat(fn)[stat.ST_MODE]
if not stat.S_ISCHR(m):
return False
if not os.access(fn, os.R_OK | os.W_OK):
return False
return True
def categorize(event):
'''
Categorize an event according to its type.
The :data:`event_factory <evdev.events.event_factory>` dictionary
maps event types to sub-classes of :class:`InputEvent
<evdev.events.InputEvent>`. If the event cannot be categorized, it
is returned unmodified.'''
if event.type in event_factory:
return event_factory[event.type](event)
else:
return event
def resolve_ecodes_dict(typecodemap, unknown='?'):
'''
Resolve event codes and types to their verbose names.
:param typecodemap: mapping of event types to lists of event codes.
:param unknown: symbol to which unknown types or codes will be resolved.
Example
-------
>>> resolve_ecodes_dict({ 1: [272, 273, 274] })
{ ('EV_KEY', 1): [('BTN_MOUSE', 272),
('BTN_RIGHT', 273),
('BTN_MIDDLE', 274)] }
If ``typecodemap`` contains absolute axis info (instances of
:class:`AbsInfo <evdev.device.AbsInfo>` ) the result would look
like:
>>> resolve_ecodes_dict({ 3: [(0, AbsInfo(...))] })
{ ('EV_ABS', 3L): [(('ABS_X', 0L), AbsInfo(...))] }
'''
for etype, codes in typecodemap.items():
type_name = ecodes.EV[etype]
# ecodes.keys are a combination of KEY_ and BTN_ codes
if etype == ecodes.EV_KEY:
ecode_dict = ecodes.keys
else:
ecode_dict = getattr(ecodes, type_name.split('_')[-1])
resolved = resolve_ecodes(ecode_dict, codes, unknown)
yield (type_name, etype), resolved
def resolve_ecodes(ecode_dict, ecode_list, unknown='?'):
'''
Resolve event codes and types to their verbose names.
Example
-------
>>> resolve_ecodes(ecodes.BTN, [272, 273, 274])
[(['BTN_LEFT', 'BTN_MOUSE'], 272), ('BTN_RIGHT', 273), ('BTN_MIDDLE', 274)]
'''
res = []
for ecode in ecode_list:
# elements with AbsInfo(), eg { 3 : [(0, AbsInfo(...)), (1, AbsInfo(...))] }
if isinstance(ecode, tuple):
if ecode[0] in ecode_dict:
l = ((ecode_dict[ecode[0]], ecode[0]), ecode[1])
else:
l = ((unknown, ecode[0]), ecode[1])
# just ecodes, e.g: { 0 : [0, 1, 3], 1 : [30, 48] }
else:
if ecode in ecode_dict:
l = (ecode_dict[ecode], ecode)
else:
l = (unknown, ecode)
res.append(l)
return res
def find_ecodes_by_regex(regex):
'''
Find ecodes matching a regex and return a mapping of event type to event codes.
regex can be a pattern string or a compiled regular expression object.
Example
-------
>>> find_ecodes_by_regex(r'(ABS|KEY)_BR(AKE|EAK)')
{1: [411], 3: [10]}
>>> res = find_ecodes_by_regex(r'(ABS|KEY)_BR(AKE|EAK)')
>>> resolve_ecodes_dict(res)
{
('EV_KEY', 1): [('KEY_BREAK', 411)],
('EV_ABS', 3): [('ABS_BRAKE', 10)]
}
'''
regex = re.compile(regex) # re.compile is idempotent
result = collections.defaultdict(list)
for type_code, codes in ecodes.bytype.items():
for code, names in codes.items():
names = (names,) if isinstance(names, str) else names
for name in names:
if regex.match(name):
result[type_code].append(code)
break
return dict(result)
__all__ = ('list_devices', 'is_device', 'categorize', 'resolve_ecodes', 'resolve_ecodes_dict', 'find_ecodes_by_regex')
|