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