[node-patches] Change in ovirt-node[master]: utils: Add module for input handling

fabiand at fedoraproject.org fabiand at fedoraproject.org
Mon Jun 17 11:16:55 UTC 2013


Fabian Deutsch has uploaded a new change for review.

Change subject: utils: Add module for input handling
......................................................................

utils: Add module for input handling

This module can be used to send events on specififc inputs. This can
then be used to e.g. watch the capslock state.

Bug-Url: https://bugzilla.redhat.com/show_bug.cgi?id=927084
Change-Id: I90a950ef8f44b9a9d67f554b3e2788c66cd5f364
Signed-off-by: Fabian Deutsch <fabiand at fedoraproject.org>
---
A src/ovirt/node/utils/input.py
1 file changed, 502 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/92/15792/1

diff --git a/src/ovirt/node/utils/input.py b/src/ovirt/node/utils/input.py
new file mode 100644
index 0000000..b9d8014
--- /dev/null
+++ b/src/ovirt/node/utils/input.py
@@ -0,0 +1,502 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# logging_page.py - Copyright (C) 2013 Red Hat, Inc.
+# Written by Fabian Deutsch <fabiand at redhat.com>
+#
+# 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; version 2 of the License.
+#
+# 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., 51 Franklin Street, Fifth Floor, Boston,
+# MA  02110-1301, USA.  A copy of the GNU General Public License is
+# also available at http://www.gnu.org/copyleft/gpl.html.
+
+# pylint: disable-msg=E1101,E1102
+from ovirt.node import base
+import logging
+import os
+import select  # @UnresolvedImport
+import struct
+import sys
+import threading
+"""
+Simple wrapper to Linux input
+At some poitn switch to:
+https://github.com/gvalkov/python-evdev/
+
+See also:
+
+- http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/\
+Documentation/input/event-codes.txt?id=HEAD
+
+- http://stackoverflow.com/questions/13129804/python-how-to-get-current-\
+keylock-status
+
+- http://svn.navi.cx/misc/trunk/python/evdev/evdev.py
+"""
+
+
+class Enum(object):
+    def __init__(self, amap):
+        self.__add_attributes(amap)
+
+    def __add_attributes(self, amap):
+        self._amap = amap
+        for k, v in amap.items():
+            self.__dict__[v] = k
+
+    def __getitem__(self, key):
+        return self.by_key(key)
+
+    def get(self, key, fallback=None):
+        return self.by_key(key, fallback)
+
+    def by_key(self, key, fallback=None):
+        return self._amap[key] if key in self._amap else fallback
+
+    def by_value(self, value, fallback=None):
+        return self.__dict__[value] if value in self.__dict__ else fallback
+
+
+typeMap = Enum({
+    0x00: "EV_RST",
+    0x01: "EV_KEY",
+    0x02: "EV_REL",
+    0x03: "EV_ABS",
+    0x04: "EV_MSC",
+    0x11: "EV_LED",
+    0x12: "EV_SND",
+    0x14: "EV_REP",
+    0x15: "EV_FF",
+})
+
+
+codeMaps = Enum({
+    "EV_KEY": Enum({
+    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",
+    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",
+    0x111: "BTN_RIGHT",
+    0x112: "BTN_MIDDLE",
+    0x113: "BTN_SIDE",
+    0x114: "BTN_EXTRA",
+    0x115: "BTN_FORWARD",
+    0x116: "BTN_BACK",
+    0x120: "BTN_TRIGGER",
+    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",
+    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",
+    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",
+    }),
+
+    "EV_REL": Enum({
+    0x00: "REL_X",
+    0x01: "REL_Y",
+    0x02: "REL_Z",
+    0x06: "REL_HWHEEL",
+    0x07: "REL_DIAL",
+    0x08: "REL_WHEEL",
+    0x09: "REL_MISC",
+    }),
+
+    "EV_ABS": Enum({
+    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_MISC",
+    }),
+
+    "EV_MSC": Enum({
+    0x00: "MSC_SERIAL",
+    0x01: "MSC_PULSELED",
+    }),
+
+    "EV_LED": Enum({
+    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",
+    }),
+
+    "EV_REP": Enum({
+    0x00: "REP_DELAY",
+    0x01: "REP_PERIOD",
+    }),
+
+    "EV_SND": Enum({
+    0x00: "SND_CLICK",
+    0x01: "SND_BELL",
+    }),
+})
+
+
+class InputEvent(object):
+    def __init__(self, _type, code, value):
+        self.type = _type
+        self.code = code
+        self.value = value
+
+    def __str__(self):
+        return "<InputEvent type={type} code={code} value={value}>".format(
+            type=typeMap[self.type],
+            code=codeMaps[typeMap[self.type]].get(self.code, self.code),
+            value=self.value)
+
+    def __eq__(self, other):
+        vals = [(self.type, other.type),
+                (self.code, other.code),
+                (self.value, other.value)]
+        return all(sv == ov for sv, ov in vals if sv and ov)
+
+
+class InputParser(object):
+    fmt = "llHHI"
+    fmtsize = struct.calcsize(fmt)
+
+    def __init__(self, files):
+        assert type(files) is list
+        self.fds = [os.open(dev, os.O_RDONLY) for dev in files]
+
+    def __readevent(self, rs):
+        packages = []
+        try:
+            packages = (os.read(fd, self.fmtsize) for fd in rs)
+            for package in packages:
+                parsed = struct.unpack(self.fmt, package[:self.fmtsize])
+                timeval, suseconds, typ, code, value = parsed
+                if typ:
+                    yield timeval, suseconds, typ, value, code
+        except OSError as e:
+            logging.exception("Couldn't parse event: %s" % e)
+
+    def parse(self):
+        while 1:
+            rs, _, _ = select.select(self.fds, [], [])
+            for _, _, t, v, e in self.__readevent(rs):
+                yield InputEvent(t, e, v)
+
+
+class InputParserThread(threading.Thread):
+    """A thread to watch for input events
+    """
+    inputdevices = []
+    event_filter = None
+    on_event = None
+    logger = logging.getLogger(__package__)
+
+    def __init__(self, inputdevices, event_filter=None):
+        super(InputParserThread, self).__init__()
+        self.daemon = True
+        self.logger.info("Creating input watcher thread")
+        self.inputdevices = inputdevices
+        self.event_filter = event_filter
+        self.on_event = base.Base.Signal(self)
+
+    def run(self):
+        self.logger.info("Starting input watcher")
+        try:
+            assert self.inputdevices and self.on_event
+
+            parser = InputParser(self.inputdevices)
+            for event in parser.parse():
+                is_correct_event = (self.event_filter and event ==
+                                    self.event_filter)
+                if not self.event_filter or is_correct_event:
+                    self.on_event.emit(event)
+        except:
+            self.logger.exception("Exception in input watcher")
+
+
+if __name__ == "__main__":
+    def cb(evnt):
+        print evnt
+        if evnt == InputEvent(typeMap.EV_LED, None, None):
+            print "Found the event you were looking for:", evnt
+
+    p = InputParserThread(sys.argv[1:])
+    p.on_event_callback = cb
+    p.start()
+    p.join()


-- 
To view, visit http://gerrit.ovirt.org/15792
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I90a950ef8f44b9a9d67f554b3e2788c66cd5f364
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-node
Gerrit-Branch: master
Gerrit-Owner: Fabian Deutsch <fabiand at fedoraproject.org>



More information about the node-patches mailing list