input: Restructure to use GObject and io_watches

This isn't ideal, since opening all of the devices in /dev/input is slow, and
this runs on the UI thread, but it works for now. Ultimately, InputReader should
probably be restructured as a threading.Thread and use GLib.idle_add to send the
signals out.
This commit is contained in:
June Tate-Gans 2021-05-03 18:09:08 -05:00
parent 65c2580e45
commit ce8a106ea3

View File

@ -1,56 +1,78 @@
import threading
import gi import gi
import glob import evdev
import asyncio import threading
from evdev import InputDevice
from evdev import KeyEvent
from evdev import ecodes
gi.require_version('Gtk', '3.0') gi.require_version('Gtk', '3.0')
from gi.repository import GObject from gi.repository import GObject, GLib
import evdev
from evdev import InputDevice
from evdev import ecodes
from select import select
class InputReader(threading.Thread, GObject.GObject): class InputReader(GObject.Object):
INPUT_PATH = '/dev/input' INPUT_PATH = '/dev/input'
def __init__(self): def __init__(self):
threading.Thread.__init__(self, daemon=True) GObject.Object.__init__(self)
GObject.GObject.__init__(self)
self.reset()
def reset(self): self._capturing = False
self._isRunning = False self._watches = []
self._keyStates = {} self._keyStates = {}
@GObject.Signal(name='evdev-key-released') def capture(self):
def keyReleased(self, keyCode, time): if self._capturing:
print('key released: %d') return False
@GObject.Signal(name='evdev-key-pressed') self._capturing = True
def keyPressed(self, keyCode, time):
print('key pressed: %d')
def run(self): self._keyStates = {}
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
devices = [InputDevice(path) for path in evdev.list_devices()] devices = [InputDevice(path) for path in evdev.list_devices()]
keyboards = [dev for dev in devices if ecodes.EV_KEY in dev.capabilities()] self._keyboards = [dev for dev in devices
print('Have keyboards: %s' % (keyboards)) if ecodes.EV_KEY in dev.capabilities()]
self._keyboards = {dev.fd: dev for dev in self._keyboards}
self._watches = []
for fd, kbd in self._keyboards.items():
watch = GLib.io_add_watch(fd,
GLib.PRIORITY_HIGH,
GLib.IO_IN,
self.handleEvent)
self._watches.append(watch)
while self._isRunning: return False
r, w, x = select(keyboards, [], [])
print('keyboards listening!') def stop(self):
for fd in r: if not self._capturing:
for event in keyboards[fd].read(): return False
for i in self._watches:
GLib.source_remove(i)
for fd, kbd in self._keyboards.items():
del kbd
del fd
self._keyboards = None
self._watches = []
self._keyStates = {}
self._capturing = False
return False
def handleEvent(self, fd, condition, *args):
for event in self._keyboards[fd].read():
if event.type != ecodes.EV_KEY: if event.type != ecodes.EV_KEY:
continue continue
keyCode = event.keycode event = KeyEvent(event)
keyDown = event.keystate == event.key_down if 'BTN_MOUSE' in event.keycode:
lastKeyState = self._keystates.get(keyCode, False) continue
keyCode = event.scancode
keyDown = event.keystate in (
event.key_down, event.key_hold)
lastKeyState = self._keyStates.get(keyCode, False)
if keyDown and not lastKeyState: if keyDown and not lastKeyState:
self.emit('evdev-key-pressed', self.emit('evdev-key-pressed',
@ -59,5 +81,14 @@ class InputReader(threading.Thread, GObject.GObject):
self.emit('evdev-key-released', self.emit('evdev-key-released',
keyCode, event.event.timestamp()) keyCode, event.event.timestamp())
def shutdown(self): self._keyStates[keyCode] = keyDown
self._isRunning = False
return True
@GObject.Signal(name='evdev-key-released', arg_types=[int, float])
def keyReleased(self, keyCode, time):
pass
@GObject.Signal(name='evdev-key-pressed', arg_types=[int, float])
def keyPressed(self, keyCode, time):
pass