diff --git a/src/x11_platform.h b/src/x11_platform.h index 62ba36b9..5f3b8c54 100644 --- a/src/x11_platform.h +++ b/src/x11_platform.h @@ -96,6 +96,12 @@ typedef struct _GLFWwindowX11 // The last position the cursor was warped to by GLFW int warpPosX, warpPosY; + // The information from the last KeyPress event + struct { + unsigned int keycode; + Time time; + } last; + } _GLFWwindowX11; diff --git a/src/x11_window.c b/src/x11_window.c index 95391d93..8364a7b6 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -844,8 +844,13 @@ static void leaveFullscreenMode(_GLFWwindow* window) static void processEvent(XEvent *event) { _GLFWwindow* window = NULL; + int keycode = 0; Bool filtered = False; + // HACK: Save scancode as some IMs clear the field in XFilterEvent + if (event->type == KeyPress || event->type == KeyRelease) + keycode = event->xkey.keycode; + if (_glfw.x11.im) filtered = XFilterEvent(event, None); @@ -863,28 +868,31 @@ static void processEvent(XEvent *event) { case KeyPress: { - const int key = translateKey(event->xkey.keycode); + const int key = translateKey(keycode); const int mods = translateState(event->xkey.state); const int plain = !(mods & (GLFW_MOD_CONTROL | GLFW_MOD_ALT)); if (window->x11.ic) { - int i; - Status status; - wchar_t buffer[16]; - - if (filtered) + // HACK: Ignore duplicate key press events generated by ibus + // Corresponding release events are filtered out by the + // GLFW key repeat logic + if (window->x11.last.keycode != keycode || + window->x11.last.time != event->xkey.time) { - // HACK: Ignore key press events intended solely for XIM - if (event->xkey.keycode) - { - _glfwInputKey(window, - key, event->xkey.keycode, - GLFW_PRESS, mods); - } + if (keycode) + _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); } - else + + window->x11.last.keycode = keycode; + window->x11.last.time = event->xkey.time; + + if (!filtered) { + int i; + Status status; + wchar_t buffer[16]; + const int count = XwcLookupString(window->x11.ic, &event->xkey, buffer, sizeof(buffer), @@ -899,9 +907,7 @@ static void processEvent(XEvent *event) KeySym keysym; XLookupString(&event->xkey, NULL, 0, &keysym, NULL); - _glfwInputKey(window, - key, event->xkey.keycode, - GLFW_PRESS, mods); + _glfwInputKey(window, key, keycode, GLFW_PRESS, mods); const long character = _glfwKeySym2Unicode(keysym); if (character != -1) @@ -913,7 +919,7 @@ static void processEvent(XEvent *event) case KeyRelease: { - const int key = translateKey(event->xkey.keycode); + const int key = translateKey(keycode); const int mods = translateState(event->xkey.state); if (!_glfw.x11.xkb.detectable) @@ -929,7 +935,7 @@ static void processEvent(XEvent *event) if (next.type == KeyPress && next.xkey.window == event->xkey.window && - next.xkey.keycode == event->xkey.keycode) + next.xkey.keycode == keycode) { // HACK: Repeat events sometimes leak through due to // some sort of time drift, so add an epsilon @@ -947,7 +953,7 @@ static void processEvent(XEvent *event) } } - _glfwInputKey(window, key, event->xkey.keycode, GLFW_RELEASE, mods); + _glfwInputKey(window, key, keycode, GLFW_RELEASE, mods); return; }