caenyon/keyboard_input

View on GitHub
keyboard_input/linux/_draft/xinput2_listener.py

Summary

Maintainability
A
35 mins
Test Coverage
# coding=utf-8

from Xlib.display import Display
from Xlib.ext import xinput, xtest

KEYBOARD_MASTER = 3
EXIT_KEY = 127  # Pause-Key


class DeviceListener(object):
    def __init__(self):
        self.display = Display()

        self.win_root = self.display.screen().root

        extension_info = self.display.query_extension('XInputExtension')
        self.xinput_major = extension_info.major_opcode

        self.device = None

        v = xinput.query_version(self.display)
        print("Version: {}, {}".format(v.major_version, v.minor_version))

        self.select_device()

    def select_device(self, device=None):
        self.device = device
        mask = xinput.KeyPressMask + xinput.KeyReleaseMask
        if device is None:
            xinput.select_events(self.win_root, ((xinput.AllDevices, mask),))
        else:
            xinput.select_events(self.win_root, ((device, mask), (xinput.AllDevices, 0)))
            self.display.xinput_detach_slave(device)

    def event_loop(self):
        while True:
            event = self.display.next_event()
            if event.type == self.display.extension_event.GenericEvent \
                    and event.extension == self.xinput_major:
                if not self.handle_event(event):
                    break

    def get_device_id(self):
        event = self.display.next_event()
        if event.type == self.display.extension_event.GenericEvent \
                and event.extension == self.xinput_major:
            return event.data.deviceid

    def handle_event(self, event):
        self.send_event(event.data.detail, event.evtype == 2)
        # print("Event: {}, {}, {}".format(event.evtype, event.data.detail, event.data.deviceid))
        return not event.data.detail == EXIT_KEY

    def send_event(self, key_code, key_down):
        xtest.fake_input(self.display,
                         event_type=2 if key_down else 3,
                         detail=key_code)

    def close(self):
        self.display.xinput_attach_slave(self.device, KEYBOARD_MASTER)
        self.display.close()


if __name__ == '__main__':
    dl = DeviceListener()
    print("Press any key to select a device...")
    d_id = dl.get_device_id()
    print("Selected device: {}".format(d_id))
    dl.select_device(d_id)
    dl.event_loop()
    dl.close()