On Fri, 2008-12-12 at 23:53 -0800, Greg KH wrote: > On Fri, Dec 12, 2008 at 10:42:28PM -0800, Matt Helsley wrote: > > The Genius PenSketch 12x9 tablet has a puck (labeled a > > "Tablet Mouse") in addition to a pen. Without registering a quirk > > the tablet appears to be a single input device that reports the > > wrong axis information in /proc/bus/input/devices, and sends > > incorrect events (e.g. ABS_Z instead of ABS_Y). This information > > confuses the X evdev driver and makes the device impossible to > > use. > > > > The quirk fixes events and splits the device into multiple input > > event devices so that at least the puck is useful. > > > > Signed-off-by: Matt Helsley <matt.helsley@xxxxxxxxx> > > --- > > NOTE: xinput lists the puck but not the pen. I've been using a > > python script to verify the contents of the events independently > > of X and, as far as I can tell, the remaining problems are in X > > itself. > > I have a tablet here that I'm having troubles getting to work. Any > chance I could get a copy of your python script so I can try to debug > what is going wrong, and if it's a X problem or a kernel issue like you > found for your device? > > thanks, > > greg k-h Sure. Sometime around 2.6.24 I updated this script (originally by Micah Dowty) to include more evdev #defines, work on 64-bit systems, and decode some bitvectors into their C symbols. Cheers, -Matt Helsley #!/usr/bin/env python """ evdev.py This is a Python interface to the Linux input system's event device. Events can be read from an open event file and decoded into spiffy python objects. The Event objects can optionally be fed into a Device object that represents the complete state of the device being monitored. Copyright (C) 2003-2004 Micah Dowty <micah@xxxxxxx> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA From: http://svn.navi.cx/misc/trunk/python/evdev/ """ import struct, sys, os, time, errno from fcntl import ioctl import binascii import array __all__ = ["Event", "Device"] def hexbytes(s): return str(len(s)) + ': ' + binascii.hexlify(s) def demo(): """Open the event device named on the command line, use incoming events to update a device, and show the state of this device. """ dev = Device(sys.argv[1]) print dev while 1: dev.poll() #time.sleep(0.1) class bitmap: def __init__(self, bits = None): if bits is None: self.bits = array.array('c') else: self.bits = array.array('c', bits) def set_bits(self, from_str): self.bits.fromstring(from_str) def test_bit(self, bit_num): return ord(self.bits[(bit_num >> 3)]) & (1 << (bit_num & 7)) def num_bits(self): return len(self.bits)*8 def num_bytes(self): return len(self.bits) def is_empty(self): return (self.num_bytes == 0) def clear_bit(self, bit_num): byte = self.bits[(bit_num >> 3)] byte = byte & ~(1 << (bit_num & 7)) self.bits[(bit_num >> 3)] = byte def set_bit(self, bit_num): byte = self.bits[(bit_num >> 3)] byte = byte | (1 << (bit_num & 7)) self.bits[(bit_num >> 3)] = byte def hex(self): return binascii.hexlify(self.bits.tostring()) def expand(self, names, delim = ','): name_list = [] for i in range(0, self.num_bits()): if self.test_bit(i): if callable(names): name = names(i) else: try: name = names.fromNumber(i) except: name = names[i] if not isinstance(name, basestring): name = str(name) name_list.append(name) return delim.join(name_list) class BaseDevice: """Base class representing the state of an input device, with axes and buttons. Event instances can be fed into the Device to update its state. """ def __init__(self): self.axes = {} self.absAxisInfo = {} self.buttons = {} self.name = None def update(self, event): f = getattr(self, "update_%s" % event.type, None) if f: f(event) def __repr__(self): items = [ str(i) for i in self.__dict__.items() ] return str('\n'.join(items)) def update_EV_KEY(self, event): self.buttons[event.code] = event.value def update_EV_ABS(self, event): self.axes[event.code] = event.value def update_EV_REL(self, event): self.axes[event.code] = self.axes.get(event.code, 0) + event.value def __getitem__(self, name): """Retrieve the current value of an axis or button, or zero if no data has been received for it yet. """ if name in self.axes: return self.axes[name] else: return self.buttons.get(name, 0) # asm-generic/ioctl.h IOC_NRBITS = 8L IOC_TYPEBITS = 8L IOC_SIZEBITS = 14L IOC_DIRBITS = 2L IOC_NRMASK = ((1L << IOC_NRBITS)-1L) IOC_TYPEMASK = ((1L << IOC_TYPEBITS)-1L) IOC_SIZEMASK = ((1L << IOC_SIZEBITS)-1L) IOC_DIRMASK = ((1L << IOC_DIRBITS)-1L) IOC_NRSHIFT = 0L IOC_TYPESHIFT = IOC_NRSHIFT+IOC_NRBITS IOC_SIZESHIFT = IOC_TYPESHIFT+IOC_TYPEBITS IOC_DIRSHIFT = IOC_SIZESHIFT+IOC_SIZEBITS IOC_NONE = 0L IOC_WRITE = 1L IOC_READ = 2L def IOC(dir, type, nr, size): return (dir<<IOC_DIRSHIFT)|(size<<IOC_SIZESHIFT)|(type<<IOC_TYPESHIFT)|(nr<<IOC_NRSHIFT) def IO(type, nr): return IOC(IOC_NONE,type,nr,0) def IOR(type, nr, size): return IOC(IOC_READ,type,nr,size) def IOW(type, nr, size): return IOC(IOC_WRITE,type,nr,size) def IOWR(type, nr, size): return IOC(IOC_READ|IOC_WRITE,type,nr,size) def IOC_DIR(nr): return (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK) def IOC_TYPE(nr): return (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK) def IOC_NR(nr): return (((nr) >> IOC_NRSHIFT) & IOC_NRMASK) def IOC_SIZE(nr): return (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK) ## end of ioctl defs # python struct format defs and their sizes int_format = "i" int_size = struct.calcsize(int_format) int_array2_format = "2i" int_array2_size = struct.calcsize(int_array2_format) input_id_format = "4H" # u16 input_id_size = struct.calcsize(input_id_format) input_absinfo_format = "5i" # s32 input_absinfo_size = struct.calcsize(input_absinfo_format) ff_effect_format = "HhH HH HH HHHHH HHHH IH" # space denotes nested struct ff_effect_size = struct.calcsize(ff_effect_format) ## begin input.h IOCTL defs # evdev ioctl constants and EVIOC functions. ASCII 'E' == 0x45 EVIOCGVERSION = IOR(0x45, 0x01, int_size) # get driver version EVIOCGID = IOR(0x45, 0x02, input_id_size) # get device struct input_id EVIOCGREP = IOR(0x45, 0x03, int_array2_size) # get repeat settings EVIOCSREP = IOW(0x45, 0x03, int_array2_size) # set repeat settings EVIOCGKEYCODE = IOR(0x45, 0x04, int_array2_size) # get keycode EVIOCSKEYCODE = IOW(0x45, 0x04, int_array2_size) # set keycode # these are functions and not merely values because the ioctl number # incorporates more than a simple command (usually length of a buffer) # note that buffers can only be of a length representable by 14 bits # (see /usr/include/asm-generic/ioctl.h) def EVIOCGNAME(length): return IOC(IOC_READ, 0x45, 0x06, length) def EVIOCGPHYS(length): return IOC(IOC_READ, 0x45, 0x07, length) def EVIOCGUNIQ(length): return IOC(IOC_READ, 0x45, 0x08, length) def EVIOCGKEY(length): return IOC(IOC_READ, 0x45, 0x18, length) def EVIOCGLED(length): return IOC(IOC_READ, 0x45, 0x19, length) def EVIOCGSND(length): return IOC(IOC_READ, 0x45, 0x1a, length) def EVIOCGSW(length): return IOC(IOC_READ, 0x45, 0x1b, length) def EVIOCGBIT(ev, length): # get event bits return IOC(IOC_READ, 0x45, 0x20 + ev, length) def EVIOCGABS(abs): # get abs value/limits return IOR(0x45, 0x40 + abs, input_absinfo_size) def EVIOCSABS(abs): # set abs value/limits return IOW(0x45, 0x40 + abs, input_absinfo_size) EVIOCSFF = IOC(IOC_WRITE, 0x45, 0x80, ff_effect_size) EVIOCRMFF = IOW(0x45, 0x81, int_size) EVIOCGEFFECTS = IOR(0x45, 0x84, int_size) EVIOCGRAB = IOW(0x45, 0x90, int_size) def NBYTES(highest_bit): return ((highest_bit - 1)/8) + 1 class Device(BaseDevice): """An abstract input device attached to a Linux evdev device node""" def ioctl(self, op, buffer): return ioctl(self.fd, op, buffer) # ioctl convenience functions: get/set string, int, int[2], int[n] # Get a string up to length characters. Note that length is also # encoded in op. Trims unused space after the nul byte. def ioctl_get_string(self, op, length): buffer = "\0"*length buffer = self.ioctl(op, buffer) return buffer[:buffer.find("\0")] # Get an automatically sized string. Needs the operation given as # a function of string length -- not a constant string length! # Can be slow because we guess how long the name is and repeat # if our guess was not large enough. def ioctl_get_astring(self, opfn, initial_guessed_len=1): length = initial_guessed_len # print repr(opfn) while True: buffer = self.ioctl_get_string(opfn(length), length) if (len(buffer)+1) < length: break length = length*2 # print "done! length: %d string: %s" % (length, buffer) return buffer # Get length bytes. Note that length is also encoded in op. def ioctl_get_bytes(self, op, length): buffer = "\0"*length return self.ioctl(op, buffer) def ioctl_get_bitmap(self, op, length): buffer = '\0'*length buffer = self.ioctl(op, buffer) return bitmap(bits=buffer) # Get an int def ioctl_get_int(self, op): buffer = "\0"*int_size return struct.unpack(int_format, ioctl(self.fd, op, buffer)) # Get two ints def ioctl_get_int2(self, op): buffer = "\0"*int_array2_size return struct.unpack(int_array2_format, ioctl(self.fd, op, buffer)) # Get an array of num_ints ints def ioctl_get_int_array(self, op, num_ints): format = "i"*num_ints buffer = "\0"*struct.calcsize(format) return struct.unpack(format, ioctl(self.fd, op, buffer)) # Set a string -- length is encoded in op def ioctl_set_string(self, op, buffer): self.ioctl(op, buffer) # Set an int def ioctl_set_int(self, op, value): buffer = struct.pack(int_format, value) self.ioctl(op, buffer) # Set two ints def ioctl_set_int2(self, op, values): buffer = struct.pack(int_array2_format, *values) self.ioctl(op, buffer) # Set n ints, where n is the number of elements in the values sequence def ioctl_set_int_array(self, op, values): l = len(values) format = "i"*l buffer = struct.pack(format, *values) self.ioctl(op, buffer) def __get_bits(self, name, name_max): ev_bit = Event.typeMap.toNumber(name) if name == 'EV_SYN' or self.ev_bits.test_bit(ev_bit): bits = "\0"*NBYTES(Event.codeMaps[name].toNumber(name_max)) l = len(bits) try: bits = self.ioctl_get_bytes(EVIOCGBIT(ev_bit, l),l) bits = bitmap(bits=bits) except (IOError), err: bits = bitmap(bits=None) return bits else: return bitmap(bits=None) def __init__(self, filename): BaseDevice.__init__(self) self.path = filename self.fd = os.open(filename, os.O_RDWR)#|os.O_NONBLOCK) # Get some important, non-changing info about the device try: self.version = self.ioctl_get_int(EVIOCGVERSION)[0] except (IOError), err: self.version = -1 try: buffer = self.ioctl_get_bytes(EVIOCGID, input_id_size) values = struct.unpack(input_id_format, buffer) id = dict(zip(('bustype', 'vendor', 'product', 'version'), values)) self.id = id except (IOError), err: self.id = None try: self.name = self.ioctl_get_astring(EVIOCGNAME) except (IOError), err: self.name = '<ERROR: ioctl(EVIOCGNAME): ' + str(err) + ' >' try: self.phys = self.ioctl_get_astring(EVIOCGPHYS) except (IOError), err: self.phys = '<ERROR: ioctl(EVIOCGPHYS): ' + str(err) + ' >' try: self.uniq = self.ioctl_get_astring(EVIOCGUNIQ) except (IOError), err: self.uniq = '<ERROR: ioctl(EVIOCUNIQ): ' + str(err) + ' >' # Fill out bitmaps showing what types of events we get l = NBYTES(Event.typeMap.toNumber('EV_MAX')) bits = self.ioctl_get_bytes(EVIOCGBIT(0, l), l) self.ev_bits = bitmap(bits=bits) self.ev_bits = self.__get_bits('EV_SYN', 'EV_MAX') self.key_bits = self.__get_bits('EV_KEY', 'KEY_MAX') self.rel_bits = self.__get_bits('EV_REL', 'REL_MAX') self.abs_bits = self.__get_bits('EV_ABS', 'ABS_MAX') self.msc_bits = self.__get_bits('EV_MSC', 'MSC_MAX') self.led_bits = self.__get_bits('EV_LED', 'LED_MAX') self.snd_bits = self.__get_bits('EV_SND', 'SND_MAX') self.rep_bits = self.__get_bits('EV_REP', 'REP_MAX') self.get_axis() self.grabbed = False self.ev_num = 0 # self.grab() def __repr__(self): l = ['Event Device: ', self.path, '\n\tNAME: ', self.name, '\n\tPHYS: ', self.phys, '\n\tUNIQ: ', self.uniq, '\n\tBUSTYPE: ', busMap.fromNumber(self.id['bustype']), ' \tVENDOR: ', str(self.id['vendor']), ' \tPRODUCT: ', str(self.id['product']), ' \tVERSION: ', str(self.id['version']), '\n\tEVENT PROTOCOL VERSION: ', str(self.version), '\n\tEV_BITS: ', self.ev_bits.expand(Event.typeMap)] if self.ev_bits.test_bit(Event.typeMap.toNumber('EV_KEY')): l.append('\n\tEV_KEY: ' + self.key_bits.expand(Event.codeMaps['EV_KEY'])) if self.ev_bits.test_bit(Event.typeMap.toNumber('EV_REL')): l.append('\n\tEV_REL: ' + self.rel_bits.expand(Event.codeMaps['EV_REL'])) if self.ev_bits.test_bit(Event.typeMap.toNumber('EV_ABS')): l.append('\n\tEV_ABS: ' + self.abs_bits.expand(Event.codeMaps['EV_ABS'])) if self.ev_bits.test_bit(Event.typeMap.toNumber('EV_MSC')): l.append('\n\tEV_MSC: ' + self.msc_bits.expand(Event.codeMaps['EV_MSC'])) if self.ev_bits.test_bit(Event.typeMap.toNumber('EV_LED')): l.append('\n\tEV_LED: ' + self.led_bits.expand(Event.codeMaps['EV_LED'])) if self.ev_bits.test_bit(Event.typeMap.toNumber('EV_SND')): l.append('\n\tEV_SND: ' + self.snd_bits.expand(Event.codeMaps['EV_SND'])) if self.ev_bits.test_bit(Event.typeMap.toNumber('EV_REP')): l.append('\n\tEV_REP: ' + self.rep_bits.expand(Event.codeMaps['EV_REP'])) for name in self.absAxisInfo.keys(): l.append('\n\t' + name + ': ' + str(self.absAxisInfo[name])) return ''.join(l) # Convenience functions for getting various event device parameters def get_switches(self, length): pass def get_repeat(self): if not self.repeat is None: return dict(zip(('delay', 'period'), self.repeat)) self.repeat = self.ioctl_get_int2(EVIOCGREP) return dict(zip(('delay', 'period'), self.repeat)) def set_repeat(self, delay, period): self.ioctl_set_int2(EVIOCSREP, (delay, period)) self.repeat = (delay, period) # unlike some event ioctls, we don't cache keycodes def get_keycode(self, keys): buffer = struct.pack(int_array2_format, keys[0], keys[1]) return struct.unpack(int_array2_format, self.ioctl(EVIOCGKEYCODE, buffer)) def set_keycode(self, keys): return self.ioctl_set_int2(EVIOCSKEYCODE, keys) def get_abs(self, abs): pass def set_abs(self, abs): pass def grab(self): if not self.grabbed: self.ioctl(EVIOCGRAB, 1L) self.grabbed = True else: self.ioctl(EVIOCGRAB, 0L) self.grabbed = False def poll(self): """Receive and process all available input events""" while 1: try: buffer = os.read(self.fd, Event.format_size) except (OSError), err: return ev = Event(buffer=buffer) self.ev_num = self.ev_num + 1 print '%d: %s' % (self.ev_num, ev) self.update(ev) def get_axis(self): """Read device capabilities via ioctl()""" # Test for those event types where axis limits are relevant ev_bit = Event.typeMap.toNumber('EV_ABS') if not self.ev_bits.test_bit(ev_bit): return # Read each absolute axis limits absmap = Event.codeMaps['EV_ABS'] buffer = "\0"*input_absinfo_size self.absAxisInfo = {} for name, number in absmap.nameMap.iteritems(): if number >= absmap.toNumber('ABS_MAX'): continue if not self.abs_bits.test_bit(number): continue values = struct.unpack(input_absinfo_format, self.ioctl(EVIOCGABS(number), buffer)) values = dict(zip(( 'value', 'min', 'max', 'fuzz', 'flat' ),values)) self.absAxisInfo[name] = values def update_EV_ABS(self, event): """Scale the absolute axis into the range [-1, 1] using absAxisInfo""" try: info = self.absAxisInfo[event.code] except KeyError: return range = float(info['max'] - info['min']) self.axes[event.code] = (event.value - info['min']) / range * 2.0 - 1.0 class EnumDict: """A 1:1 mapping from numbers to strings or other objects, for enumerated types and other assigned numbers. The mapping can be queried in either direction. All values, by default, map to themselves. """ def __init__(self, numberMap): self.numberMap = numberMap self.nameMap = {} for key, value in numberMap.iteritems(): self.nameMap[value] = key def toNumber(self, name): return self.nameMap.get(name, name) def fromNumber(self, num): return self.numberMap.get(num, num) # # Useful vim command for updating these tables using copy-paste of these # #defines from include/linux/input.h: # :%s/^\#define \([^[:space:]]*\)[[:space:]]\+\(0x[0-9a-fA-F]*\).*$/\t\t\2: "\1",/gc # idMap = EnumDict({ 0: "ID_BUS", 1: "ID_VENDOR", 2: "ID_PRODUCT", 3: "ID_VERSION", }) busMap = EnumDict({ 0x01: "BUS_PCI", 0x02: "BUS_ISAPNP", 0x03: "BUS_USB", 0x04: "BUS_HIL", 0x05: "BUS_BLUETOOTH", 0x06: "BUS_VIRTUAL", 0x10: "BUS_ISA", 0x11: "BUS_I8042", 0x12: "BUS_XTKBD", 0x13: "BUS_RS232", 0x14: "BUS_GAMEPORT", 0x15: "BUS_PARPORT", 0x16: "BUS_AMIGA", 0x17: "BUS_ADB", 0x18: "BUS_I2C", 0x19: "BUS_HOST", 0x1a: "BUS_GSC", 0x1b: "BUS_ATARI", }) class Event: """Represents one linux input system event. It can be encoded and decoded in the 'struct input_event' format used by the kernel. Types and codes are automatically encoded and decoded with the # names used in input.h """ # format: on AMD64 its LLHHi and *not* LLHHl format = "LLHHi" format_size = struct.calcsize(format) # One check to ensure proper formatting below is to search for the next # occurence of the following pattern in vim: # "[[:space:]]*$ codeMaps = { "EV_SYN": EnumDict({ 0x00: "EV_SYN", 0x01: "EV_KEY", 0x02: "EV_REL", 0x03: "EV_ABS", 0x04: "EV_MSC", 0x05: "EV_SW", 0x11: "EV_LED", 0x12: "EV_SND", 0x14: "EV_REP", 0x15: "EV_FF", 0x16: "EV_PWR", 0x17: "EV_FF_STATUS", 0x1f: "EV_MAX", }), "EV_KEY": EnumDict({ 0: "KEY_RESERVED", 1: "KEY_ESC", 2: "KEY_1", 3: "KEY_2", 4: "KEY_3", 5: "KEY_4", 6: "KEY_5", 7: "KEY_6", 8: "KEY_7", 9: "KEY_8", 10: "KEY_9", 11: "KEY_0", 12: "KEY_MINUS", 13: "KEY_EQUAL", 14: "KEY_BACKSPACE", 15: "KEY_TAB", 16: "KEY_Q", 17: "KEY_W", 18: "KEY_E", 19: "KEY_R", 20: "KEY_T", 21: "KEY_Y", 22: "KEY_U", 23: "KEY_I", 24: "KEY_O", 25: "KEY_P", 26: "KEY_LEFTBRACE", 27: "KEY_RIGHTBRACE", 28: "KEY_ENTER", 29: "KEY_LEFTCTRL", 30: "KEY_A", 31: "KEY_S", 32: "KEY_D", 33: "KEY_F", 34: "KEY_G", 35: "KEY_H", 36: "KEY_J", 37: "KEY_K", 38: "KEY_L", 39: "KEY_SEMICOLON", 40: "KEY_APOSTROPHE", 41: "KEY_GRAVE", 42: "KEY_LEFTSHIFT", 43: "KEY_BACKSLASH", 44: "KEY_Z", 45: "KEY_X", 46: "KEY_C", 47: "KEY_V", 48: "KEY_B", 49: "KEY_N", 50: "KEY_M", 51: "KEY_COMMA", 52: "KEY_DOT", 53: "KEY_SLASH", 54: "KEY_RIGHTSHIFT", 55: "KEY_KPASTERISK", 56: "KEY_LEFTALT", 57: "KEY_SPACE", 58: "KEY_CAPSLOCK", 59: "KEY_F1", 60: "KEY_F2", 61: "KEY_F3", 62: "KEY_F4", 63: "KEY_F5", 64: "KEY_F6", 65: "KEY_F7", 66: "KEY_F8", 67: "KEY_F9", 68: "KEY_F10", 69: "KEY_NUMLOCK", 70: "KEY_SCROLLLOCK", 71: "KEY_KP7", 72: "KEY_KP8", 73: "KEY_KP9", 74: "KEY_KPMINUS", 75: "KEY_KP4", 76: "KEY_KP5", 77: "KEY_KP6", 78: "KEY_KPPLUS", 79: "KEY_KP1", 80: "KEY_KP2", 81: "KEY_KP3", 82: "KEY_KP0", 83: "KEY_KPDOT", 84: "KEY_103RD", 85: "KEY_F13", 86: "KEY_102ND", 87: "KEY_F11", 88: "KEY_F12", 89: "KEY_F14", 90: "KEY_F15", 91: "KEY_F16", 92: "KEY_F17", 93: "KEY_F18", 94: "KEY_F19", 95: "KEY_F20", 96: "KEY_KPENTER", 97: "KEY_RIGHTCTRL", 98: "KEY_KPSLASH", 99: "KEY_SYSRQ", 100: "KEY_RIGHTALT", 101: "KEY_LINEFEED", 102: "KEY_HOME", 103: "KEY_UP", 104: "KEY_PAGEUP", 105: "KEY_LEFT", 106: "KEY_RIGHT", 107: "KEY_END", 108: "KEY_DOWN", 109: "KEY_PAGEDOWN", 110: "KEY_INSERT", 111: "KEY_DELETE", 112: "KEY_MACRO", 113: "KEY_MUTE", 114: "KEY_VOLUMEDOWN", 115: "KEY_VOLUMEUP", 116: "KEY_POWER", 117: "KEY_KPEQUAL", 118: "KEY_KPPLUSMINUS", 119: "KEY_PAUSE", 120: "KEY_F21", 121: "KEY_F22", 122: "KEY_F23", 123: "KEY_F24", 124: "KEY_KPCOMMA", 125: "KEY_LEFTMETA", 126: "KEY_RIGHTMETA", 127: "KEY_COMPOSE", 128: "KEY_STOP", 129: "KEY_AGAIN", 130: "KEY_PROPS", 131: "KEY_UNDO", 132: "KEY_FRONT", 133: "KEY_COPY", 134: "KEY_OPEN", 135: "KEY_PASTE", 136: "KEY_FIND", 137: "KEY_CUT", 138: "KEY_HELP", 139: "KEY_MENU", 140: "KEY_CALC", 141: "KEY_SETUP", 142: "KEY_SLEEP", 143: "KEY_WAKEUP", 144: "KEY_FILE", 145: "KEY_SENDFILE", 146: "KEY_DELETEFILE", 147: "KEY_XFER", 148: "KEY_PROG1", 149: "KEY_PROG2", 150: "KEY_WWW", 151: "KEY_MSDOS", 152: "KEY_COFFEE", 153: "KEY_DIRECTION", 154: "KEY_CYCLEWINDOWS", 155: "KEY_MAIL", 156: "KEY_BOOKMARKS", 157: "KEY_COMPUTER", 158: "KEY_BACK", 159: "KEY_FORWARD", 160: "KEY_CLOSECD", 161: "KEY_EJECTCD", 162: "KEY_EJECTCLOSECD", 163: "KEY_NEXTSONG", 164: "KEY_PLAYPAUSE", 165: "KEY_PREVIOUSSONG", 166: "KEY_STOPCD", 167: "KEY_RECORD", 168: "KEY_REWIND", 169: "KEY_PHONE", 170: "KEY_ISO", 171: "KEY_CONFIG", 172: "KEY_HOMEPAGE", 173: "KEY_REFRESH", 174: "KEY_EXIT", 175: "KEY_MOVE", 176: "KEY_EDIT", 177: "KEY_SCROLLUP", 178: "KEY_SCROLLDOWN", 179: "KEY_KPLEFTPAREN", 180: "KEY_KPRIGHTPAREN", 181: "KEY_INTL1", 182: "KEY_INTL2", 183: "KEY_INTL3", 184: "KEY_INTL4", 185: "KEY_INTL5", 186: "KEY_INTL6", 187: "KEY_INTL7", 188: "KEY_INTL8", 189: "KEY_INTL9", 190: "KEY_LANG1", 191: "KEY_LANG2", 192: "KEY_LANG3", 193: "KEY_LANG4", 194: "KEY_LANG5", 195: "KEY_LANG6", 196: "KEY_LANG7", 197: "KEY_LANG8", 198: "KEY_LANG9", 200: "KEY_PLAYCD", 201: "KEY_PAUSECD", 202: "KEY_PROG3", 203: "KEY_PROG4", 205: "KEY_SUSPEND", 206: "KEY_CLOSE", 220: "KEY_UNKNOWN", 224: "KEY_BRIGHTNESSDOWN", 225: "KEY_BRIGHTNESSUP", 0x100: "BTN_0 (BTN_MISC)", # aka BTN_MISC 0x101: "BTN_1", 0x102: "BTN_2", 0x103: "BTN_3", 0x104: "BTN_4", 0x105: "BTN_5", 0x106: "BTN_6", 0x107: "BTN_7", 0x108: "BTN_8", 0x109: "BTN_9", 0x110: "BTN_LEFT (BTN_MOUSE)", # aka BTN_MOUSE 0x111: "BTN_RIGHT", 0x112: "BTN_MIDDLE", 0x113: "BTN_SIDE", 0x114: "BTN_EXTRA", 0x115: "BTN_FORWARD", 0x116: "BTN_BACK", 0x117: "BTN_TASK", 0x120: "BTN_TRIGGER (BTN_JOYSTICK)", # aka BTN_JOYSTICK 0x121: "BTN_THUMB", 0x122: "BTN_THUMB2", 0x123: "BTN_TOP", 0x124: "BTN_TOP2", 0x125: "BTN_PINKIE", 0x126: "BTN_BASE", 0x127: "BTN_BASE2", 0x128: "BTN_BASE3", 0x129: "BTN_BASE4", 0x12a: "BTN_BASE5", 0x12b: "BTN_BASE6", 0x12f: "BTN_DEAD", 0x130: "BTN_A (BTN_GAMEPAD)", # aka BTN_GAMEPAD 0x131: "BTN_B", 0x132: "BTN_C", 0x133: "BTN_X", 0x134: "BTN_Y", 0x135: "BTN_Z", 0x136: "BTN_TL", 0x137: "BTN_TR", 0x138: "BTN_TL2", 0x139: "BTN_TR2", 0x13a: "BTN_SELECT", 0x13b: "BTN_START", 0x13c: "BTN_MODE", 0x13d: "BTN_THUMBL", 0x13e: "BTN_THUMBR", 0x140: "BTN_TOOL_PEN (BTN_DIGI)", # aka BTN_DIGI 0x141: "BTN_TOOL_RUBBER", 0x142: "BTN_TOOL_BRUSH", 0x143: "BTN_TOOL_PENCIL", 0x144: "BTN_TOOL_AIRBRUSH", 0x145: "BTN_TOOL_FINGER", 0x146: "BTN_TOOL_MOUSE", 0x147: "BTN_TOOL_LENS", 0x14a: "BTN_TOUCH", 0x14b: "BTN_STYLUS", 0x14c: "BTN_STYLUS2", 0x14d: "BTN_TOOL_DOUBLETAP", 0x14e: "BTN_TOOL_TRIPLETAP", 0x150: "BTN_GEAR_DOWN (BTN_WHEEL)", # aka BTN_WHEEL 0x150: "BTN_GEAR_UP", 0x160: "KEY_OK", 0x161: "KEY_SELECT", 0x162: "KEY_GOTO", 0x163: "KEY_CLEAR", 0x164: "KEY_POWER2", 0x165: "KEY_OPTION", 0x166: "KEY_INFO", 0x167: "KEY_TIME", 0x168: "KEY_VENDOR", 0x169: "KEY_ARCHIVE", 0x16a: "KEY_PROGRAM", 0x16b: "KEY_CHANNEL", 0x16c: "KEY_FAVORITES", 0x16d: "KEY_EPG", 0x16e: "KEY_PVR", 0x16f: "KEY_MHP", 0x170: "KEY_LANGUAGE", 0x171: "KEY_TITLE", 0x172: "KEY_SUBTITLE", 0x173: "KEY_ANGLE", 0x174: "KEY_ZOOM", 0x175: "KEY_MODE", 0x176: "KEY_KEYBOARD", 0x177: "KEY_SCREEN", 0x178: "KEY_PC", 0x179: "KEY_TV", 0x17a: "KEY_TV2", 0x17b: "KEY_VCR", 0x17c: "KEY_VCR2", 0x17d: "KEY_SAT", 0x17e: "KEY_SAT2", 0x17f: "KEY_CD", 0x180: "KEY_TAPE", 0x181: "KEY_RADIO", 0x182: "KEY_TUNER", 0x183: "KEY_PLAYER", 0x184: "KEY_TEXT", 0x185: "KEY_DVD", 0x186: "KEY_AUX", 0x187: "KEY_MP3", 0x188: "KEY_AUDIO", 0x189: "KEY_VIDEO", 0x18a: "KEY_DIRECTORY", 0x18b: "KEY_LIST", 0x18c: "KEY_MEMO", 0x18d: "KEY_CALENDAR", 0x18e: "KEY_RED", 0x18f: "KEY_GREEN", 0x190: "KEY_YELLOW", 0x191: "KEY_BLUE", 0x192: "KEY_CHANNELUP", 0x193: "KEY_CHANNELDOWN", 0x194: "KEY_FIRST", 0x195: "KEY_LAST", 0x196: "KEY_AB", 0x197: "KEY_NEXT", 0x198: "KEY_RESTART", 0x199: "KEY_SLOW", 0x19a: "KEY_SHUFFLE", 0x19b: "KEY_BREAK", 0x19c: "KEY_PREVIOUS", 0x19d: "KEY_DIGITS", 0x19e: "KEY_TEEN", 0x19f: "KEY_TWEN", 0x1a0: "KEY_VIDEOPHONE", 0x1a1: "KEY_GAMES", 0x1a2: "KEY_ZOOMIN", 0x1a3: "KEY_ZOOMOUT", 0x1a4: "KEY_ZOOMRESET", 0x1a5: "KEY_WORDPROCESSOR", 0x1a6: "KEY_EDITOR", 0x1a7: "KEY_SPREADSHEET", 0x1a8: "KEY_GRAPHICSEDITOR", 0x1a9: "KEY_PRESENTATION", 0x1aa: "KEY_DATABASE", 0x1ab: "KEY_NEWS", 0x1ac: "KEY_VOICEMAIL", 0x1ad: "KEY_ADDRESSBOOK", 0x1ae: "KEY_MESSENGER", 0x1af: "KEY_DISPLAYTOGGLE", 0x1b0: "KEY_SPELLCHECK", 0x1b1: "KEY_LOGOFF", 0x1b2: "KEY_DOLLAR", 0x1b3: "KEY_EURO", 0x1b4: "KEY_FRAMEBACK", 0x1b5: "KEY_FRAMEFORWARD", 0x1b6: "KEY_CONTEXT_MENU", 0x1c0: "KEY_DEL_EOL", 0x1c1: "KEY_DEL_EOS", 0x1c2: "KEY_INS_LINE", 0x1c3: "KEY_DEL_LINE", 0x1d0: "KEY_FN", 0x1d1: "KEY_FN_ESC", 0x1d2: "KEY_FN_F1", 0x1d3: "KEY_FN_F2", 0x1d4: "KEY_FN_F3", 0x1d5: "KEY_FN_F4", 0x1d6: "KEY_FN_F5", 0x1d7: "KEY_FN_F6", 0x1d8: "KEY_FN_F7", 0x1d9: "KEY_FN_F8", 0x1da: "KEY_FN_F9", 0x1db: "KEY_FN_F10", 0x1dc: "KEY_FN_F11", 0x1dd: "KEY_FN_F12", 0x1de: "KEY_FN_1", 0x1df: "KEY_FN_2", 0x1e0: "KEY_FN_D", 0x1e1: "KEY_FN_E", 0x1e2: "KEY_FN_F", 0x1e3: "KEY_FN_S", 0x1e4: "KEY_FN_B", 0x1f1: "KEY_BRL_DOT1", 0x1f2: "KEY_BRL_DOT2", 0x1f3: "KEY_BRL_DOT3", 0x1f4: "KEY_BRL_DOT4", 0x1f5: "KEY_BRL_DOT5", 0x1f6: "KEY_BRL_DOT6", 0x1f7: "KEY_BRL_DOT7", 0x1f8: "KEY_BRL_DOT8", 0x1f9: "KEY_BRL_DOT9", 0x1fa: "KEY_BRL_DOT10", 0x1ff: "KEY_MAX", }), "EV_REL": EnumDict({ 0x00: "REL_X", 0x01: "REL_Y", 0x02: "REL_Z", 0x03: "REL_RX", 0x04: "REL_RY", 0x05: "REL_RZ", 0x06: "REL_HWHEEL", 0x07: "REL_DIAL", 0x08: "REL_WHEEL", 0x09: "REL_MISC", 0x0f: "REL_MAX", }), "EV_ABS": EnumDict({ 0x00: "ABS_X", 0x01: "ABS_Y", 0x02: "ABS_Z", 0x03: "ABS_RX", 0x04: "ABS_RY", 0x05: "ABS_RZ", 0x06: "ABS_THROTTLE", 0x07: "ABS_RUDDER", 0x08: "ABS_WHEEL", 0x09: "ABS_GAS", 0x0a: "ABS_BRAKE", 0x10: "ABS_HAT0X", 0x11: "ABS_HAT0Y", 0x12: "ABS_HAT1X", 0x13: "ABS_HAT1Y", 0x14: "ABS_HAT2X", 0x15: "ABS_HAT2Y", 0x16: "ABS_HAT3X", 0x17: "ABS_HAT3Y", 0x18: "ABS_PRESSURE", 0x19: "ABS_DISTANCE", 0x1a: "ABS_TILT_X", 0x1b: "ABS_TILT_Y", 0x1c: "ABS_TOOL_WIDTH", 0x20: "ABS_VOLUME", 0x28: "ABS_MISC", 0x3f: "ABS_MAX", }), "EV_SW": EnumDict({ 0x00: "SW_LID", 0x01: "SW_TABLET_MODE", 0x02: "SW_HEADPHONE_INSERT", 0x03: "SW_RADIO", 0x0f: "SW_MAX", }), "EV_MSC": EnumDict({ 0x00: "MSC_SERIAL", 0x01: "MSC_PULSELED", 0x02: "MSC_GESTURE", 0x03: "MSC_RAW", 0x04: "MSC_SCAN", 0x07: "MSC_MAX", }), "EV_LED": EnumDict({ 0x00: "LED_NUML", 0x01: "LED_CAPSL", 0x02: "LED_SCROLLL", 0x03: "LED_COMPOSE", 0x04: "LED_KANA", 0x05: "LED_SLEEP", 0x06: "LED_SUSPEND", 0x07: "LED_MUTE", 0x08: "LED_MISC", 0x09: "LED_MAIL", 0x0a: "LED_CHARGING", 0x0f: "LED_MAX", }), "EV_REP": EnumDict({ 0x00: "REP_DELAY", 0x01: "REP_PERIOD", 0x01: "REP_MAX", }), "EV_SND": EnumDict({ 0x00: "SND_CLICK", 0x01: "SND_BELL", 0x02: "SND_TONE", 0x07: "SND_MAX", }), } typeMap = codeMaps["EV_SYN"] # TODO FF (force feedback) constants # If there were no matches before this point " # then the check passed. (see comment preceding these EnumDict tables) def __init__(self, timestamp=0, type=0, code=0, value=0, buffer=None, readFrom=None): self.timestamp = timestamp self.type = type self.code = code self.value = value #print hexbytes(buffer) if (buffer is not None) and (len(buffer) >= 1): #self.format_size): self.unpack(buffer) if readFrom is not None: self.readFrom(readFrom) def __repr__(self): return "<Event timestamp=%r type=%r code=%r value=%r>" % ( self.timestamp, self.type, self.code, self.value) def pack(self): """Pack this event into an input_event struct in the local machine's byte order. """ secs = int(self.timestamp) usecs = int((self.timestamp - secs) * 1000000) packedType = self.typeMap.toNumber(self.type) if self.type in self.codeMaps: packedCode = self.codeMaps[self.type].toNumber(self.code) else: packedCode = self.code return struct.pack(self.format, secs, usecs, packedType, packedCode, self.value) def unpack(self, s): """Unpack ourselves from the given string,, an input_event struct in the local byte order. """ secs, usecs, packedType, packedCode, self.value = struct.unpack(self.format, s) self.timestamp = secs + (usecs / 1000000.0) self.type = self.typeMap.fromNumber(packedType) if self.type in self.codeMaps: self.code = self.codeMaps[self.type].fromNumber(packedCode) else: self.code = packedCode def readFrom(self, stream): """Read the next event from the given file-like object""" self.unpack(stream.read(self.format_size)) if __name__ == "__main__": demo() ### The End ### -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html