Browse Source

extended controls: print warning if 'missed key release event' bug occurs

Fabian Peter Hammerle 6 years ago
parent
commit
29062894da
1 changed files with 28 additions and 2 deletions
  1. 28 2
      tooncher/controls.py

+ 28 - 2
tooncher/controls.py

@@ -114,6 +114,7 @@ class ExtendedControls:
         self._default_action = ForwardKeyEventAction()
         self._engine_window = None
         self._other_engine_windows = None
+        self._active_key_registry = {}
         self._enabled = False
 
     @property
@@ -155,16 +156,16 @@ class ExtendedControls:
         while self.engine_running:
             while self.xdisplay.pending_events():
                 self._handle_xevent(self._xdisplay.next_event())
+            self._check_active_key_registry()
             x_wait_for_event(self.xdisplay, timeout_seconds=1)
 
     def _handle_xevent(self, xevent):
-        # TODO investigate why some release events get lost
-        # https://stackoverflow.com/q/18160792/5894777
         if isinstance(xevent, Xlib.protocol.event.KeyPress) \
                 or isinstance(xevent, Xlib.protocol.event.KeyRelease):
             self._handle_xkeyevent(xevent)
 
     def _handle_xkeyevent(self, xkeyevent):
+        self._update_active_key_registry(xkeyevent)
         keysym_in = self._xdisplay.keycode_to_keysym(
             xkeyevent.detail,
             index=0,
@@ -232,3 +233,28 @@ class ExtendedControls:
         if not self._other_engine_windows:
             self._other_engine_windows = self.find_other_engine_windows()
         return self._other_engine_windows
+
+    def _update_active_key_registry(self, xkeyevent):
+        # see self._check_active_key_registry
+        keycode = xkeyevent.detail
+        if isinstance(xkeyevent, Xlib.protocol.event.KeyPress):
+            self._active_key_registry[keycode] = xkeyevent
+        elif keycode in self._active_key_registry:
+            del self._active_key_registry[keycode]
+
+    def _check_active_key_registry(self):
+        """
+        WORKAROUND
+        For an unknown reason some key release events don't get queued
+        when multiple keys are being released simultaneously.
+        So we keep a hashmap of supposedly currently pressed keys
+        and periodically compare it with xdispaly.query_keymap().
+
+        ref: https://stackoverflow.com/q/18160792/5894777
+        """
+        # https://tronche.com/gui/x/xlib/input/XQueryKeymap.html
+        keymap = self.xdisplay.query_keymap()
+        missed_releases = []
+        for keycode, press_event in self._active_key_registry.items():
+            if not (1 << (keycode & ((1 << 3) - 1))) & keymap[keycode >> 3]:
+                print("WARN missed release event of key {}".format(keycode))