Просмотр исходного кода

X11: Fix detection of key events duplicated by XIM

Background: The IM will filter out key events, instead sending exact
duplicate events that are not filtered.  It does not send these for
every event, however, so the duplicate events cannot be relied on for
key input.  Instead we need to identify and discard them.  Since they
are identical, they have the same timestamp as the originals.

The previous duplicate event detection would consume unrelated key
events if the keys were pressed simultaneously, as it only tracked
a single timestamp.

This fixes that issue for any combination of keys, at the expense of
a 1 KB array per GLFW window.

This fix is a stopgap until explicit IME support is done.

Based on #1472 by @LucaRood.

Fixes #1112.
Fixes #1415.
Fixes #1616.
Fixes #1663.
Closes #1472.
Camilla Löwy 5 лет назад
Родитель
Сommit
9a3664b4a9
3 измененных файлов с 17 добавлено и 8 удалено
  1. 4 0
      README.md
  2. 3 2
      src/x11_platform.h
  3. 10 6
      src/x11_window.c

+ 4 - 0
README.md

@@ -190,6 +190,8 @@ information on what to include when reporting a bug.
    non-printable keys (#1598)
    non-printable keys (#1598)
  - [X11] Bugfix: Function keys were mapped to `GLFW_KEY_UNKNOWN` for some layout
  - [X11] Bugfix: Function keys were mapped to `GLFW_KEY_UNKNOWN` for some layout
    combinaitons (#1598)
    combinaitons (#1598)
+ - [X11] Bugfix: Keys pressed simultaneously with others were not always
+   reported (#1112,#1415,#1472,#1616)
  - [Wayland] Removed support for `wl_shell` (#1443)
  - [Wayland] Removed support for `wl_shell` (#1443)
  - [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432)
  - [Wayland] Bugfix: The `GLFW_HAND_CURSOR` shape used the wrong image (#1432)
  - [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled
  - [Wayland] Bugfix: `CLOCK_MONOTONIC` was not correctly enabled
@@ -364,8 +366,10 @@ skills.
  - Eddie Ringle
  - Eddie Ringle
  - Max Risuhin
  - Max Risuhin
  - Jorge Rodriguez
  - Jorge Rodriguez
+ - Luca Rood
  - Ed Ropple
  - Ed Ropple
  - Aleksey Rybalkin
  - Aleksey Rybalkin
+ - Mikko Rytkönen
  - Riku Salminen
  - Riku Salminen
  - Brandon Schaefer
  - Brandon Schaefer
  - Sebastian Schuberth
  - Sebastian Schuberth

+ 3 - 2
src/x11_platform.h

@@ -402,8 +402,9 @@ typedef struct _GLFWwindowX11
     // The last position the cursor was warped to by GLFW
     // The last position the cursor was warped to by GLFW
     int             warpCursorPosX, warpCursorPosY;
     int             warpCursorPosX, warpCursorPosY;
 
 
-    // The time of the last KeyPress event
-    Time            lastKeyTime;
+    // The time of the last KeyPress event per keycode, for discarding
+    // duplicate key events generated for some keys by ibus
+    Time            keyPressTimes[256];
 
 
 } _GLFWwindowX11;
 } _GLFWwindowX11;
 
 

+ 10 - 6
src/x11_window.c

@@ -1265,16 +1265,20 @@ static void processEvent(XEvent *event)
 
 
             if (window->x11.ic)
             if (window->x11.ic)
             {
             {
-                // HACK: Ignore duplicate key press events generated by ibus
-                //       These have the same timestamp as the original event
-                //       Corresponding release events are filtered out
-                //       implicitly by the GLFW key repeat logic
-                if (window->x11.lastKeyTime < event->xkey.time)
+                // HACK: Do not report the key press events duplicated by XIM
+                //       Duplicate key releases are filtered out implicitly by
+                //       the GLFW key repeat logic in _glfwInputKey
+                //       A timestamp per key is used to handle simultaneous keys
+                // NOTE: Always allow the first event for each key through
+                //       (the server never sends a timestamp of zero)
+                // NOTE: Timestamp difference is compared to handle wrap-around
+                Time diff = event->xkey.time - window->x11.keyPressTimes[keycode];
+                if (diff == event->xkey.time || (diff > 0 && diff < (1 << 31)))
                 {
                 {
                     if (keycode)
                     if (keycode)
                         _glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
                         _glfwInputKey(window, key, keycode, GLFW_PRESS, mods);
 
 
-                    window->x11.lastKeyTime = event->xkey.time;
+                    window->x11.keyPressTimes[keycode] = event->xkey.time;
                 }
                 }
 
 
                 if (!filtered)
                 if (!filtered)