1 # encoding: utf-8
2
3 import os
4 import stat
5 import glob
6
7 from evdev import ecodes
8 from evdev.events import event_factory
9
10
11 def list_devices(input_device_dir='/dev/input'):
12 '''List readable character devices.'''
13
14 fns = glob.glob('{0}/event*'.format(input_device_dir))
15 fns = list(filter(is_device, fns))
16
17 return fns
18
19
20 def is_device(fn):
21 '''Determine if a file exists, is readable and is a character device.'''
22
23 if not os.path.exists(fn):
24 return False
25
26 m = os.stat(fn)[stat.ST_MODE]
27 if not stat.S_ISCHR(m):
28 return False
29
30 if not os.access(fn, os.R_OK):
31 return False
32
33 return True
34
35
36 def categorize(event):
37 '''
38 Categorize an event according to its type.
39
40 The :data:`event_factory <evdev.events.event_factory>` dictionary maps
41 event types to their classes. If there is no corresponding key, the event
42 is returned as it was.
43 '''
44
45 if event.type in event_factory:
46 return event_factory[event.type](event)
47 else:
48 return event
49
50
51 def resolve_ecodes(typecodemap, unknown='?'):
52 '''
53 Resolve event codes and types to their verbose names.
54
55 :param typecodemap: mapping of event types to lists of event codes
56 :param unknown: symbol to which unknown types or codes will be resolved
57
58 Example::
59
60 resolve_ecodes({ 1 : [272, 273, 274] })
61 { ('EV_KEY', 1) : [('BTN_MOUSE', 272), ('BTN_RIGHT', 273), ('BTN_MIDDLE', 274)] }
62
63 If the typecodemap contains absolute axis info (wrapped in
64 instances of `AbsInfo <evdev.device.AbsInfo>`) the result would
65 look like::
66
67 resove_ecodes({ 3 : [(0, AbsInfo(...))] })
68 { ('EV_ABS', 3L): [(('ABS_X', 0L), AbsInfo(...))] }
69 '''
70
71 for etype, codes in typecodemap.items():
72 type_name = ecodes.EV[etype]
73
74 # ecodes.keys are a combination of KEY_ and BTN_ codes
75 if etype == ecodes.EV_KEY:
76 code_names = ecodes.keys
77 else:
78 code_names = getattr(ecodes, type_name.split('_')[-1])
79
80 res = []
81 for i in codes:
82 # elements with AbsInfo(), eg { 3 : [(0, AbsInfo(...)), (1, AbsInfo(...))] }
83 if isinstance(i, tuple):
84 l = ((code_names[i[0]], i[0]), i[1]) if i[0] in code_names \
85 else ((unknown, i[0]), i[1])
86
87 # just ecodes { 0 : [0, 1, 3], 1 : [30, 48] }
88 else:
89 l = (code_names[i], i) if i in code_names else (unknown, i)
90
91 res.append(l)
92
93 yield (type_name, etype), res
94
95
96 __all__ = list_devices, is_device, categorize, resolve_ecodes