From 138d96c8a6a3e3b19e081c450b834d1c3a4121e3 Mon Sep 17 00:00:00 2001 From: Weng Xuetian Date: Tue, 5 Apr 2022 19:30:25 -0700 Subject: [PATCH] Send key release event to input method. (#5281) Co-authored-by: Ethan Lee --- src/core/linux/SDL_fcitx.c | 8 ++--- src/core/linux/SDL_fcitx.h | 2 +- src/core/linux/SDL_ibus.c | 8 +++-- src/core/linux/SDL_ibus.h | 2 +- src/core/linux/SDL_ime.c | 6 ++-- src/core/linux/SDL_ime.h | 2 +- src/video/wayland/SDL_waylandevents.c | 11 ++++-- src/video/x11/SDL_x11events.c | 48 ++++++++++++--------------- 8 files changed, 46 insertions(+), 41 deletions(-) diff --git a/src/core/linux/SDL_fcitx.c b/src/core/linux/SDL_fcitx.c index 3f0794736..bab5e88f3 100644 --- a/src/core/linux/SDL_fcitx.c +++ b/src/core/linux/SDL_fcitx.c @@ -339,11 +339,11 @@ SDL_Fcitx_Reset(void) } SDL_bool -SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) +SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state) { - Uint32 state = Fcitx_ModState(); + Uint32 mod_state = Fcitx_ModState(); Uint32 handled = SDL_FALSE; - Uint32 is_release = SDL_FALSE; + Uint32 is_release = (state == SDL_RELEASED); Uint32 event_time = 0; if (!fcitx_client.ic_path) { @@ -351,7 +351,7 @@ SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) } if (SDL_DBus_CallMethod(FCITX_DBUS_SERVICE, fcitx_client.ic_path, FCITX_IC_DBUS_INTERFACE, "ProcessKeyEvent", - DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &state, DBUS_TYPE_BOOLEAN, &is_release, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID, + DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &keycode, DBUS_TYPE_UINT32, &mod_state, DBUS_TYPE_BOOLEAN, &is_release, DBUS_TYPE_UINT32, &event_time, DBUS_TYPE_INVALID, DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID)) { if (handled) { SDL_Fcitx_UpdateTextRect(NULL); diff --git a/src/core/linux/SDL_fcitx.h b/src/core/linux/SDL_fcitx.h index f7884ea43..c3cea523d 100644 --- a/src/core/linux/SDL_fcitx.h +++ b/src/core/linux/SDL_fcitx.h @@ -31,7 +31,7 @@ extern SDL_bool SDL_Fcitx_Init(void); extern void SDL_Fcitx_Quit(void); extern void SDL_Fcitx_SetFocus(SDL_bool focused); extern void SDL_Fcitx_Reset(void); -extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode); +extern SDL_bool SDL_Fcitx_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state); extern void SDL_Fcitx_UpdateTextRect(SDL_Rect *rect); extern void SDL_Fcitx_PumpEvents(void); diff --git a/src/core/linux/SDL_ibus.c b/src/core/linux/SDL_ibus.c index 20236e713..60af0ba29 100644 --- a/src/core/linux/SDL_ibus.c +++ b/src/core/linux/SDL_ibus.c @@ -503,14 +503,18 @@ SDL_IBus_Reset(void) } SDL_bool -SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) +SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state) { Uint32 result = 0; SDL_DBusContext *dbus = SDL_DBus_GetContext(); - + + if (IBus_CheckConnection(dbus)) { Uint32 mods = IBus_ModState(); Uint32 ibus_keycode = keycode - 8; + if (state == SDL_RELEASED) { + mods |= (1 << 30); // IBUS_RELEASE_MASK + } if (!SDL_DBus_CallMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent", DBUS_TYPE_UINT32, &keysym, DBUS_TYPE_UINT32, &ibus_keycode, DBUS_TYPE_UINT32, &mods, DBUS_TYPE_INVALID, DBUS_TYPE_BOOLEAN, &result, DBUS_TYPE_INVALID)) { diff --git a/src/core/linux/SDL_ibus.h b/src/core/linux/SDL_ibus.h index 73a9f1b8b..71d1f2d30 100644 --- a/src/core/linux/SDL_ibus.h +++ b/src/core/linux/SDL_ibus.h @@ -41,7 +41,7 @@ extern void SDL_IBus_Reset(void); /* Sends a keypress event to IBus, returns SDL_TRUE if IBus used this event to update its candidate list or change input methods. PumpEvents should be called some time after this, to recieve the TextInput / TextEditing event back. */ -extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode); +extern SDL_bool SDL_IBus_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state); /* Update the position of IBus' candidate list. If rect is NULL then this will just reposition it relative to the focused window's new position. */ diff --git a/src/core/linux/SDL_ime.c b/src/core/linux/SDL_ime.c index 84c461f8b..9c0cb80f0 100644 --- a/src/core/linux/SDL_ime.c +++ b/src/core/linux/SDL_ime.c @@ -27,7 +27,7 @@ typedef SDL_bool (*_SDL_IME_Init)(void); typedef void (*_SDL_IME_Quit)(void); typedef void (*_SDL_IME_SetFocus)(SDL_bool); typedef void (*_SDL_IME_Reset)(void); -typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32); +typedef SDL_bool (*_SDL_IME_ProcessKeyEvent)(Uint32, Uint32, Uint8 state); typedef void (*_SDL_IME_UpdateTextRect)(SDL_Rect *); typedef void (*_SDL_IME_PumpEvents)(void); @@ -127,10 +127,10 @@ SDL_IME_Reset(void) } SDL_bool -SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode) +SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state) { if (SDL_IME_ProcessKeyEvent_Real) - return SDL_IME_ProcessKeyEvent_Real(keysym, keycode); + return SDL_IME_ProcessKeyEvent_Real(keysym, keycode, state); return SDL_FALSE; } diff --git a/src/core/linux/SDL_ime.h b/src/core/linux/SDL_ime.h index a28a4b430..cc5b105f0 100644 --- a/src/core/linux/SDL_ime.h +++ b/src/core/linux/SDL_ime.h @@ -31,7 +31,7 @@ extern SDL_bool SDL_IME_Init(void); extern void SDL_IME_Quit(void); extern void SDL_IME_SetFocus(SDL_bool focused); extern void SDL_IME_Reset(void); -extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode); +extern SDL_bool SDL_IME_ProcessKeyEvent(Uint32 keysym, Uint32 keycode, Uint8 state); extern void SDL_IME_UpdateTextRect(SDL_Rect *rect); extern void SDL_IME_PumpEvents(void); diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c index f4d6ade27..b81c9db4a 100644 --- a/src/video/wayland/SDL_waylandevents.c +++ b/src/video/wayland/SDL_waylandevents.c @@ -921,7 +921,7 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard, } static SDL_bool -keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, SDL_bool *handled_by_ime) +keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint32_t key, Uint8 state, SDL_bool *handled_by_ime) { SDL_WindowData *window = input->keyboard_focus; const xkb_keysym_t *syms; @@ -938,12 +938,16 @@ keyboard_input_get_text(char text[8], const struct SDL_WaylandInput *input, uint sym = syms[0]; #ifdef SDL_USE_IME - if (SDL_IME_ProcessKeyEvent(sym, key + 8)) { + if (SDL_IME_ProcessKeyEvent(sym, key + 8, state)) { *handled_by_ime = SDL_TRUE; return SDL_TRUE; } #endif + if (state == SDL_RELEASED) { + return SDL_FALSE; + } + if (input->xkb.compose_state && WAYLAND_xkb_compose_state_feed(input->xkb.compose_state, sym) == XKB_COMPOSE_FEED_ACCEPTED) { switch(WAYLAND_xkb_compose_state_get_status(input->xkb.compose_state)) { case XKB_COMPOSE_COMPOSING: @@ -977,7 +981,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, SDL_bool handled_by_ime = SDL_FALSE; if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { - has_text = keyboard_input_get_text(text, input, key, &handled_by_ime); + has_text = keyboard_input_get_text(text, input, key, SDL_PRESSED, &handled_by_ime); } else { if (keyboard_repeat_is_set(&input->keyboard_repeat)) { // Send any due key repeat events before stopping the repeat and generating the key up event @@ -987,6 +991,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard, keyboard_repeat_handle(&input->keyboard_repeat, time - input->keyboard_repeat.wl_press_time); keyboard_repeat_clear(&input->keyboard_repeat); } + keyboard_input_get_text(text, input, key, SDL_RELEASED, &handled_by_ime); } if (!handled_by_ime && key < SDL_arraysize(xfree86_scancode_table2)) { diff --git a/src/video/x11/SDL_x11events.c b/src/video/x11/SDL_x11events.c index 186f37b05..31e739c70 100644 --- a/src/video/x11/SDL_x11events.c +++ b/src/video/x11/SDL_x11events.c @@ -996,8 +996,9 @@ X11_DispatchEvent(_THIS, XEvent *xevent) } break; - /* Key press? */ - case KeyPress:{ + /* Key press/release? */ + case KeyPress: + case KeyRelease: { KeyCode keycode = xevent->xkey.keycode; KeySym keysym = NoSymbol; char text[SDL_TEXTINPUTEVENT_TEXT_SIZE]; @@ -1005,7 +1006,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent) SDL_bool handled_by_ime = SDL_FALSE; #ifdef DEBUG_XEVENTS - printf("window %p: KeyPress (X11 keycode = 0x%X)\n", data, xevent->xkey.keycode); + printf("window %p: %s (X11 keycode = 0x%X)\n" data, (xevent->type == KeyPress ? "KeyPress" : "KeyRelease"), xevent->xkey.keycode); #endif #if 1 if (videodata->key_layout[keycode] == SDL_SCANCODE_UNKNOWN && keycode) { @@ -1021,7 +1022,7 @@ X11_DispatchEvent(_THIS, XEvent *xevent) /* */ SDL_zeroa(text); #ifdef X_HAVE_UTF8_STRING - if (data->ic) { + if (data->ic && xevent->type == KeyPress) { X11_Xutf8LookupString(data->ic, &xevent->xkey, text, sizeof(text), &keysym, &status); } else { @@ -1033,35 +1034,30 @@ X11_DispatchEvent(_THIS, XEvent *xevent) #ifdef SDL_USE_IME if(SDL_GetEventState(SDL_TEXTINPUT) == SDL_ENABLE){ - handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode); + handled_by_ime = SDL_IME_ProcessKeyEvent(keysym, keycode, (xevent->type == KeyPress ? SDL_PRESSED : SDL_RELEASED)); } #endif if (!handled_by_ime) { - /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */ - if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) { - SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]); - } - if(*text) { - SDL_SendKeyboardText(text); + if (xevent->type == KeyPress) { + /* Don't send the key if it looks like a duplicate of a filtered key sent by an IME */ + if (xevent->xkey.keycode != videodata->filter_code || xevent->xkey.time != videodata->filter_time) { + SDL_SendKeyboardKey(SDL_PRESSED, videodata->key_layout[keycode]); + } + if(*text) { + SDL_SendKeyboardText(text); + } + } else { + if (X11_KeyRepeat(display, xevent)) { + /* We're about to get a repeated key down, ignore the key up */ + break; + } + SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]); } } - X11_UpdateUserTime(data, xevent->xkey.time); - } - break; - - /* Key release? */ - case KeyRelease:{ - KeyCode keycode = xevent->xkey.keycode; - -#ifdef DEBUG_XEVENTS - printf("window %p: KeyRelease (X11 keycode = 0x%X)\n", data, xevent->xkey.keycode); -#endif - if (X11_KeyRepeat(display, xevent)) { - /* We're about to get a repeated key down, ignore the key up */ - break; + if (xevent->type == KeyPress) { + X11_UpdateUserTime(data, xevent->xkey.time); } - SDL_SendKeyboardKey(SDL_RELEASED, videodata->key_layout[keycode]); } break;