diff --git a/glfw/ibus_glfw.c b/glfw/ibus_glfw.c index 3def48300..561626a34 100644 --- a/glfw/ibus_glfw.c +++ b/glfw/ibus_glfw.c @@ -49,6 +49,70 @@ enum Capabilities { IBUS_CAP_SURROUNDING_TEXT = 1 << 5 }; +typedef enum +{ + IBUS_SHIFT_MASK = 1 << 0, + IBUS_LOCK_MASK = 1 << 1, + IBUS_CONTROL_MASK = 1 << 2, + IBUS_MOD1_MASK = 1 << 3, + IBUS_MOD2_MASK = 1 << 4, + IBUS_MOD3_MASK = 1 << 5, + IBUS_MOD4_MASK = 1 << 6, + IBUS_MOD5_MASK = 1 << 7, + IBUS_BUTTON1_MASK = 1 << 8, + IBUS_BUTTON2_MASK = 1 << 9, + IBUS_BUTTON3_MASK = 1 << 10, + IBUS_BUTTON4_MASK = 1 << 11, + IBUS_BUTTON5_MASK = 1 << 12, + + /* The next few modifiers are used by XKB, so we skip to the end. + * Bits 15 - 23 are currently unused. Bit 29 is used internally. + */ + + /* ibus mask */ + IBUS_HANDLED_MASK = 1 << 24, + IBUS_FORWARD_MASK = 1 << 25, + IBUS_IGNORED_MASK = IBUS_FORWARD_MASK, + + IBUS_SUPER_MASK = 1 << 26, + IBUS_HYPER_MASK = 1 << 27, + IBUS_META_MASK = 1 << 28, + + IBUS_RELEASE_MASK = 1 << 30, + + IBUS_MODIFIER_MASK = 0x5f001fff +} IBusModifierType; + + +static uint32_t +ibus_key_state(unsigned int glfw_modifiers, int action) { + uint32_t ans = action == GLFW_RELEASE ? IBUS_RELEASE_MASK : 0; +#define M(g, i) if(glfw_modifiers & GLFW_MOD_##g) ans |= i + M(SHIFT, IBUS_SHIFT_MASK); + M(CAPS_LOCK, IBUS_LOCK_MASK); + M(CONTROL, IBUS_CONTROL_MASK); + M(ALT, IBUS_MOD1_MASK); + M(NUM_LOCK, IBUS_MOD2_MASK); + M(SUPER, IBUS_MOD4_MASK); + /* To do: figure out how to get super/hyper/meta */ +#undef M + return ans; +} + +static unsigned int +glfw_modifiers(uint32_t ibus_key_state) { + unsigned int ans = 0; +#define M(g, i) if(ibus_key_state & i) ans |= GLFW_MOD_##g + M(SHIFT, IBUS_SHIFT_MASK); + M(CAPS_LOCK, IBUS_LOCK_MASK); + M(CONTROL, IBUS_CONTROL_MASK); + M(ALT, IBUS_MOD1_MASK); + M(NUM_LOCK, IBUS_MOD2_MASK); + M(SUPER, IBUS_MOD4_MASK); + /* To do: figure out how to get super/hyper/meta */ +#undef M + return ans; +} static bool test_env_var(const char *name, const char *val) { @@ -106,6 +170,29 @@ get_ibus_text_from_message(DBusMessage *msg) { return text; } +static void +handle_ibus_forward_key_event(DBusMessage *msg) { + uint32_t keysym, keycode, state; + DBusMessageIter iter; + dbus_message_iter_init(msg, &iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) return; + dbus_message_iter_get_basic(&iter, &keysym); + dbus_message_iter_next(&iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) return; + dbus_message_iter_get_basic(&iter, &keycode); + dbus_message_iter_next(&iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT32) return; + dbus_message_iter_get_basic(&iter, &state); + + int mods = glfw_modifiers(state); + + debug("IBUS: ForwardKeyEvent: keysym=%x, keycode=%x, state=%x, glfw_mods=%x\n", keysym, keycode, state, mods); + glfw_xkb_forwarded_key_from_ime(keysym, mods); +} + static void send_text(const char *text, GLFWIMEState ime_state) { _GLFWwindow *w = _glfwFocusedWindow(); @@ -126,7 +213,7 @@ message_handler(DBusConnection *conn UNUSED, DBusMessage *msg, void *user_data) _GLFWIBUSData *ibus = (_GLFWIBUSData*)user_data; (void)ibus; const char *text; - switch(glfw_dbus_match_signal(msg, IBUS_INPUT_INTERFACE, "CommitText", "UpdatePreeditText", "HidePreeditText", "ShowPreeditText", NULL)) { + switch(glfw_dbus_match_signal(msg, IBUS_INPUT_INTERFACE, "CommitText", "UpdatePreeditText", "HidePreeditText", "ShowPreeditText", "ForwardKeyEvent", NULL)) { case 0: text = get_ibus_text_from_message(msg); debug("IBUS: CommitText: '%s'\n", text ? text : "(nil)"); @@ -134,8 +221,8 @@ message_handler(DBusConnection *conn UNUSED, DBusMessage *msg, void *user_data) break; case 1: text = get_ibus_text_from_message(msg); - send_text(text, GLFW_IME_PREEDIT_CHANGED); debug("IBUS: UpdatePreeditText: '%s'\n", text ? text : "(nil)"); + send_text(text, GLFW_IME_PREEDIT_CHANGED); break; case 2: debug("IBUS: HidePreeditText\n"); @@ -143,6 +230,9 @@ message_handler(DBusConnection *conn UNUSED, DBusMessage *msg, void *user_data) case 3: debug("IBUS: ShowPreeditText\n"); break; + case 4: + handle_ibus_forward_key_event(msg); + break; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -376,56 +466,6 @@ glfw_ibus_set_cursor_geometry(_GLFWIBUSData *ibus, int x, int y, int w, int h) { } } -typedef enum -{ - IBUS_SHIFT_MASK = 1 << 0, - IBUS_LOCK_MASK = 1 << 1, - IBUS_CONTROL_MASK = 1 << 2, - IBUS_MOD1_MASK = 1 << 3, - IBUS_MOD2_MASK = 1 << 4, - IBUS_MOD3_MASK = 1 << 5, - IBUS_MOD4_MASK = 1 << 6, - IBUS_MOD5_MASK = 1 << 7, - IBUS_BUTTON1_MASK = 1 << 8, - IBUS_BUTTON2_MASK = 1 << 9, - IBUS_BUTTON3_MASK = 1 << 10, - IBUS_BUTTON4_MASK = 1 << 11, - IBUS_BUTTON5_MASK = 1 << 12, - - /* The next few modifiers are used by XKB, so we skip to the end. - * Bits 15 - 23 are currently unused. Bit 29 is used internally. - */ - - /* ibus mask */ - IBUS_HANDLED_MASK = 1 << 24, - IBUS_FORWARD_MASK = 1 << 25, - IBUS_IGNORED_MASK = IBUS_FORWARD_MASK, - - IBUS_SUPER_MASK = 1 << 26, - IBUS_HYPER_MASK = 1 << 27, - IBUS_META_MASK = 1 << 28, - - IBUS_RELEASE_MASK = 1 << 30, - - IBUS_MODIFIER_MASK = 0x5f001fff -} IBusModifierType; - - -static uint32_t -ibus_key_state(unsigned int glfw_modifiers, int action) { - uint32_t ans = action == GLFW_RELEASE ? IBUS_RELEASE_MASK : 0; -#define M(g, i) if(glfw_modifiers & GLFW_MOD_##g) ans |= i - M(SHIFT, IBUS_SHIFT_MASK); - M(CAPS_LOCK, IBUS_LOCK_MASK); - M(CONTROL, IBUS_CONTROL_MASK); - M(ALT, IBUS_MOD1_MASK); - M(NUM_LOCK, IBUS_MOD2_MASK); - M(SUPER, IBUS_MOD4_MASK); - /* To do: figure out how to get super/hyper/meta */ -#undef M - return ans; -} - void key_event_processed(DBusMessage *msg, const char* errmsg, void *data) { uint32_t handled = 0; diff --git a/glfw/xkb_glfw.c b/glfw/xkb_glfw.c index d238b7583..61871255e 100644 --- a/glfw/xkb_glfw.c +++ b/glfw/xkb_glfw.c @@ -842,6 +842,19 @@ glfw_xkb_key_from_ime(_GLFWIBUSKeyEvent *ev, bool handled_by_ime, bool failed) { last_handled_press_keycode = ev->glfw_ev.native_key; } +void +glfw_xkb_forwarded_key_from_ime(xkb_keysym_t keysym, unsigned int glfw_mods) { + _GLFWwindow *w = _glfwFocusedWindow(); + if (w && w->callbacks.keyboard) { + GLFWkeyevent fake_ev = {.action = GLFW_PRESS}; + fake_ev.native_key = keysym; + fake_ev.key = glfw_key_for_sym(keysym); + fake_ev.mods = glfw_mods; + fake_ev.ime_state = GLFW_IME_NONE; + w->callbacks.keyboard((GLFWwindow*) w, &fake_ev); + } +} + static bool is_switch_layout_key(xkb_keysym_t xkb_sym) { return xkb_sym == XKB_KEY_ISO_First_Group || xkb_sym == XKB_KEY_ISO_Last_Group || xkb_sym == XKB_KEY_ISO_Next_Group || xkb_sym == XKB_KEY_ISO_Prev_Group || xkb_sym == XKB_KEY_Mode_switch; diff --git a/glfw/xkb_glfw.h b/glfw/xkb_glfw.h index f3857ce50..e45153028 100644 --- a/glfw/xkb_glfw.h +++ b/glfw/xkb_glfw.h @@ -98,3 +98,4 @@ void glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keyco int glfw_xkb_keysym_from_name(const char *name, bool case_sensitive); void glfw_xkb_update_ime_state(_GLFWwindow *w, _GLFWXKBData *xkb, const GLFWIMEUpdateEvent *ev); void glfw_xkb_key_from_ime(_GLFWIBUSKeyEvent *ev, bool handled_by_ime, bool failed); +void glfw_xkb_forwarded_key_from_ime(xkb_keysym_t keysym, unsigned int glfw_mods);