mirror of
https://github.com/kovidgoyal/kitty.git
synced 2024-09-11 14:45:31 +03:00
ibus: Add support for ForwardKeyEvent signal
The ForwardKeyEvent ibus signal is used to maintain ordering between CommitText events and non-IME key events. The ordering is important for Korean IMEs, where it automatically commits text whenever a character is fully composed. This is different from Chinese/Japanese IMEs, where user manually presses a key to commit each word. Without this patch, kitty can't handle non-IME key events when used with ibus-hangul, which utilizes ForwardKeyEvent signal. Without ForwardKeyEvent: ``` key | sequence of events from application's view r | UpdatePreeditText 'ㄱ' k | UpdatePreeditText '가' 1 | (receives the reply to ProcessKeyEvent call: "native_key: 0x31 release: 0 handled: 0") | -> UpdatePreeditText '' | -> CommitText '가' ``` Application receives "1가", which is incorrect. With ForwardKeyEvent: ``` key | sequence of events from application's view r | UpdatePreeditText 'ㄱ' k | UpdatePreeditText '가' 1 | (receives the reply to ProcessKeyEvent call: "native_key: 0x31 release: 0 handled: 1", and kitty discards the event) | -> UpdatePreeditText '' | -> CommitText '가' | -> ForwardKeyEvent keysym=0x31("1") ``` Application receives "가1", which is correct. Relevant ibus-hangul github issue to implement ForwardKeyEvent: https://github.com/libhangul/ibus-hangul/issues/42 Relevant changes in Qt to handle ForwardKeyEvent: https://codereview.qt-project.org/c/qt/qtbase/+/212179, https://codereview.qt-project.org/c/qt/qtbase/+/255587
This commit is contained in:
parent
b1375e5ed1
commit
4232904055
144
glfw/ibus_glfw.c
vendored
144
glfw/ibus_glfw.c
vendored
@ -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;
|
||||
|
13
glfw/xkb_glfw.c
vendored
13
glfw/xkb_glfw.c
vendored
@ -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;
|
||||
|
1
glfw/xkb_glfw.h
vendored
1
glfw/xkb_glfw.h
vendored
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user