From 53275c91374174dbffb10c214386872fe08bfc08 Mon Sep 17 00:00:00 2001 From: Benoit de Chezelles Date: Tue, 24 Sep 2019 04:27:49 +0200 Subject: [PATCH 1/2] Extract key event data to struct --- glfw/glfw.py | 6 +++ glfw/glfw3.h | 35 ++++++++++----- glfw/ibus_glfw.c | 29 ++++++++----- glfw/ibus_glfw.h | 15 +++---- glfw/input.c | 31 +++++++++----- glfw/internal.h | 3 +- glfw/window.c | 4 +- glfw/xkb_glfw.c | 100 +++++++++++++++++++++++++------------------ glfw/xkb_glfw.h | 2 +- kitty/data-types.h | 3 +- kitty/glfw-wrapper.h | 83 +++++++++++++++++++++-------------- kitty/glfw.c | 10 ++--- kitty/glfw_tests.c | 4 +- kitty/keys.c | 14 ++++-- 14 files changed, 215 insertions(+), 124 deletions(-) diff --git a/glfw/glfw.py b/glfw/glfw.py index 38876e8ae..1027ba1ed 100755 --- a/glfw/glfw.py +++ b/glfw/glfw.py @@ -185,6 +185,12 @@ def generate_wrappers(glfw_header): p = src.find('*/', p) preamble = src[p + 2:first] header = '''\ +// +// THIS FILE IS GENERATED BY glfw.py +// +// SAVE YOURSELF SOME TIME, DO NOT MANUALLY EDIT +// + #pragma once #include #include diff --git a/glfw/glfw3.h b/glfw/glfw3.h index 4c9036f9b..4614ba5f3 100644 --- a/glfw/glfw3.h +++ b/glfw/glfw3.h @@ -1177,6 +1177,29 @@ typedef struct GLFWwindow GLFWwindow; */ typedef struct GLFWcursor GLFWcursor; +typedef struct GLFWkeyevent +{ + // The [keyboard key](@ref keys) that was pressed or released. + int key; + + // The system-specific scancode of the key. + int scancode; + + // The event action. Either `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. + int action; + + // Bit field describing which [modifier keys](@ref mods) were held down. + int mods; + + // UTF-8 encoded text generated by this key event or empty string. + const char *text; + + // Used for Input Method events. Zero for normal key events. + // A value of 1 means the pre-edit text for the input event has been changed. + // A value of 2 means the text should be committed. + int ime_state; +} GLFWkeyevent; + /*! @brief The function signature for error callbacks. * * This is the function signature for error callback functions. @@ -1462,15 +1485,7 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int); * the "s" key will generate text "o" and GLFW_KEY_O. * * @param[in] window The window that received the event. - * @param[in] key The [keyboard key](@ref keys) that was pressed or released. - * @param[in] scancode The system-specific scancode of the key. - * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. - * @param[in] mods Bit field describing which [modifier keys](@ref mods) were - * held down. - * @param[in] text UTF-8 encoded text generated by this key event or empty string. - * @param[in] status Used for Input Method events. Zero for normal key events. - * A value of 1 means the pre-edit text for the input event has been changed. - * A value of 2 means the text should be committed. + * @param[in] ev TODO: blablabla * * @note On X11/Wayland if a modifier other than the modifiers GLFW reports * (ctrl/shift/alt/super) is used, GLFW will report the shifted key rather @@ -1484,7 +1499,7 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int); * * @ingroup input */ -typedef void (* GLFWkeyboardfun)(GLFWwindow*, int, int, int, int, const char*, int); +typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*); /*! @brief The function signature for file drop callbacks. * diff --git a/glfw/ibus_glfw.c b/glfw/ibus_glfw.c index d6caa0c09..dce4d3a8c 100644 --- a/glfw/ibus_glfw.c +++ b/glfw/ibus_glfw.c @@ -107,10 +107,14 @@ get_ibus_text_from_message(DBusMessage *msg) { } static inline void -send_text(const char *text, int state) { +send_text(const char *text, int ime_state) { _GLFWwindow *w = _glfwFocusedWindow(); if (w && w->callbacks.keyboard) { - w->callbacks.keyboard((GLFWwindow*) w, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0, text, state); + GLFWkeyevent fake_ev; + _glfwInitializeKeyEvent(&fake_ev, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0); + fake_ev.text = text; + fake_ev.ime_state = ime_state; + w->callbacks.keyboard((GLFWwindow*) w, &fake_ev); } } @@ -393,31 +397,36 @@ ibus_key_state(unsigned int glfw_modifiers, int action) { void key_event_processed(DBusMessage *msg, const char* errmsg, void *data) { uint32_t handled = 0; - KeyEvent *ev = (KeyEvent*)data; - bool is_release = ev->action == GLFW_RELEASE; + _GLFWIBUSKeyEvent *ev = (_GLFWIBUSKeyEvent*)data; + // Restore key's text from the text embedded in the structure. + ev->glfw_ev.text = ev->__embedded_text; + bool is_release = ev->glfw_ev.action == GLFW_RELEASE; bool failed = false; if (errmsg) { _glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to process key with error: %s", errmsg); failed = true; } else { glfw_dbus_get_args(msg, "Failed to get IBUS handled key from reply", DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID); - debug("IBUS processed scancode: 0x%x release: %d handled: %u\n", ev->keycode, is_release, handled); + debug("IBUS processed scancode: 0x%x release: %d handled: %u\n", ev->glfw_ev.scancode, is_release, handled); } glfw_xkb_key_from_ime(ev, handled ? true : false, failed); free(ev); } bool -ibus_process_key(const KeyEvent *ev_, _GLFWIBUSData *ibus) { +ibus_process_key(const _GLFWIBUSKeyEvent *ev_, _GLFWIBUSData *ibus) { if (!check_connection(ibus)) return false; - KeyEvent *ev = malloc(sizeof(KeyEvent)); + _GLFWIBUSKeyEvent *ev = malloc(sizeof(_GLFWIBUSKeyEvent)); if (!ev) return false; - memcpy(ev, ev_, sizeof(KeyEvent)); - uint32_t state = ibus_key_state(ev->glfw_modifiers, ev->action); + memcpy(ev, ev_, sizeof(_GLFWIBUSKeyEvent)); + // Put the key's text in a field IN the structure, for proper serialization. + memcpy(ev->__embedded_text, ev->glfw_ev.text, sizeof(ev->__embedded_text)); + ev->glfw_ev.text = NULL; + uint32_t state = ibus_key_state(ev->glfw_ev.mods, ev->glfw_ev.action); if (!glfw_dbus_call_method_with_reply( ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent", 3000, key_event_processed, ev, - DBUS_TYPE_UINT32, &ev->ibus_sym, DBUS_TYPE_UINT32, &ev->ibus_keycode, DBUS_TYPE_UINT32, + DBUS_TYPE_UINT32, &ev->ibus_keysym, DBUS_TYPE_UINT32, &ev->ibus_keycode, DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID)) { free(ev); return false; diff --git a/glfw/ibus_glfw.h b/glfw/ibus_glfw.h index a09de2e53..57d09866a 100644 --- a/glfw/ibus_glfw.h +++ b/glfw/ibus_glfw.h @@ -27,6 +27,7 @@ #pragma once +#include "internal.h" #include "dbus_glfw.h" #include @@ -38,18 +39,16 @@ typedef struct { } _GLFWIBUSData; typedef struct { - xkb_keycode_t keycode, ibus_keycode; - xkb_keysym_t keysym, ibus_sym; - unsigned int glfw_modifiers; - int action; + xkb_keycode_t ibus_keycode; + xkb_keysym_t ibus_keysym; GLFWid window_id; - int glfw_keycode; - char text[64]; -} KeyEvent; + GLFWkeyevent glfw_ev; + char __embedded_text[64]; +} _GLFWIBUSKeyEvent; void glfw_connect_to_ibus(_GLFWIBUSData *ibus); void glfw_ibus_terminate(_GLFWIBUSData *ibus); void glfw_ibus_set_focused(_GLFWIBUSData *ibus, bool focused); void glfw_ibus_dispatch(_GLFWIBUSData *ibus); -bool ibus_process_key(const KeyEvent *ev_, _GLFWIBUSData *ibus); +bool ibus_process_key(const _GLFWIBUSKeyEvent *ev_, _GLFWIBUSData *ibus); void glfw_ibus_set_cursor_geometry(_GLFWIBUSData *ibus, int x, int y, int w, int h); diff --git a/glfw/input.c b/glfw/input.c index 66bc8fe2d..4cd7ecaa3 100644 --- a/glfw/input.c +++ b/glfw/input.c @@ -256,33 +256,44 @@ static bool parseMapping(_GLFWmapping* mapping, const char* string) ////// GLFW event API ////// ////////////////////////////////////////////////////////////////////////// +void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int scancode, int action, int mods) +{ + ev->key = key; + ev->scancode = scancode; + ev->action = action; + ev->mods = mods; + ev->text = ""; + ev->ime_state = 0; +} + // Notifies shared code of a physical key event // -void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state) +void _glfwInputKeyboard(_GLFWwindow* window, GLFWkeyevent* ev) { - if (key >= 0 && key <= GLFW_KEY_LAST) + if (ev->key >= 0 && ev->key <= GLFW_KEY_LAST) { bool repeated = false; - if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE) + if (ev->action == GLFW_RELEASE && window->keys[ev->key] == GLFW_RELEASE) return; - if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS) + if (ev->action == GLFW_PRESS && window->keys[ev->key] == GLFW_PRESS) repeated = true; - if (action == GLFW_RELEASE && window->stickyKeys) - window->keys[key] = _GLFW_STICK; + if (ev->action == GLFW_RELEASE && window->stickyKeys) + window->keys[ev->key] = _GLFW_STICK; else - window->keys[key] = (char) action; + window->keys[ev->key] = (char) ev->action; if (repeated) - action = GLFW_REPEAT; + ev->action = GLFW_REPEAT; } + // FIXME: will need to update ev->virtual_mods here too? if (window->callbacks.keyboard) { - if (!window->lockKeyMods) mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); - window->callbacks.keyboard((GLFWwindow*) window, key, scancode, action, mods, text, state); + if (!window->lockKeyMods) ev->mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); + window->callbacks.keyboard((GLFWwindow*) window, ev); } } diff --git a/glfw/internal.h b/glfw/internal.h index cffc29e75..7ac9e3e44 100644 --- a/glfw/internal.h +++ b/glfw/internal.h @@ -756,7 +756,8 @@ void _glfwInputWindowDamage(_GLFWwindow* window); void _glfwInputWindowCloseRequest(_GLFWwindow* window); void _glfwInputWindowMonitor(_GLFWwindow* window, _GLFWmonitor* monitor); -void _glfwInputKeyboard(_GLFWwindow* window, int key, int scancode, int action, int mods, const char* text, int state); +void _glfwInitializeKeyEvent(GLFWkeyevent *ev, int key, int scancode, int action, int mods); +void _glfwInputKeyboard(_GLFWwindow *window, GLFWkeyevent *ev); void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset, int flags); void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods); void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos); diff --git a/glfw/window.c b/glfw/window.c index 2e8213f29..7d2ba71b9 100644 --- a/glfw/window.c +++ b/glfw/window.c @@ -57,7 +57,9 @@ void _glfwInputWindowFocus(_GLFWwindow* window, bool focused) if (window->keys[key] == GLFW_PRESS) { const int scancode = _glfwPlatformGetKeyScancode(key); - _glfwInputKeyboard(window, key, scancode, GLFW_RELEASE, 0, "", 0); + GLFWkeyevent ev; + _glfwInitializeKeyEvent(&ev, key, scancode, GLFW_RELEASE, 0); + _glfwInputKeyboard(window, &ev); } } diff --git a/glfw/xkb_glfw.c b/glfw/xkb_glfw.c index d61fc5708..dd75b9dce 100644 --- a/glfw/xkb_glfw.c +++ b/glfw/xkb_glfw.c @@ -445,16 +445,14 @@ glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t scancode) { } -static KeyEvent key_event = {0}; - static inline xkb_keysym_t -compose_symbol(struct xkb_compose_state *composeState, xkb_keysym_t sym, int *compose_completed) { +compose_symbol(struct xkb_compose_state *composeState, xkb_keysym_t sym, int *compose_completed, char *key_text, int n) { *compose_completed = 0; if (sym == XKB_KEY_NoSymbol || !composeState) return sym; if (xkb_compose_state_feed(composeState, sym) != XKB_COMPOSE_FEED_ACCEPTED) return sym; switch (xkb_compose_state_get_status(composeState)) { case XKB_COMPOSE_COMPOSED: - xkb_compose_state_get_utf8(composeState, key_event.text, sizeof(key_event.text)); + xkb_compose_state_get_utf8(composeState, key_text, n); *compose_completed = 1; return xkb_compose_state_get_one_sym(composeState); case XKB_COMPOSE_COMPOSING: @@ -534,11 +532,14 @@ glfw_xkb_update_ime_state(_GLFWwindow *w, _GLFWXKBData *xkb, int which, int a, i } void -glfw_xkb_key_from_ime(KeyEvent *ev, bool handled_by_ime, bool failed) { +glfw_xkb_key_from_ime(_GLFWIBUSKeyEvent *ev, bool handled_by_ime, bool failed) { _GLFWwindow *window = _glfwWindowForId(ev->window_id); if (failed && window && window->callbacks.keyboard) { // notify application to remove any existing pre-edit text - window->callbacks.keyboard((GLFWwindow*) window, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0, "", 1); + GLFWkeyevent fake_ev; + _glfwInitializeKeyEvent(&fake_ev, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0); + fake_ev.ime_state = 1; + window->callbacks.keyboard((GLFWwindow*) window, &fake_ev); } static xkb_keycode_t last_handled_press_keycode = 0; // We filter out release events that correspond to the last press event @@ -547,53 +548,58 @@ glfw_xkb_key_from_ime(KeyEvent *ev, bool handled_by_ime, bool failed) { // you'd need to implement a ring buffer to store pending key presses. xkb_keycode_t prev_handled_press = last_handled_press_keycode; last_handled_press_keycode = 0; - bool is_release = ev->action == GLFW_RELEASE; - debug("From IBUS: scancode: 0x%x name: %s is_release: %d\n", ev->keycode, glfw_xkb_keysym_name(ev->keysym), is_release); - if (window && !handled_by_ime && !(is_release && ev->keycode == prev_handled_press)) { + bool is_release = ev->glfw_ev.action == GLFW_RELEASE; + debug("From IBUS: scancode: 0x%x name: %s is_release: %d\n", ev->glfw_ev.scancode, glfw_xkb_keysym_name(ev->glfw_ev.key), is_release); + if (window && !handled_by_ime && !(is_release && ev->glfw_ev.scancode == (int) prev_handled_press)) { debug("↳ to application: glfw_keycode: 0x%x (%s) keysym: 0x%x (%s) action: %s %s text: %s\n", - ev->glfw_keycode, _glfwGetKeyName(ev->glfw_keycode), ev->keysym, glfw_xkb_keysym_name(ev->keysym), - (ev->action == GLFW_RELEASE ? "RELEASE" : (ev->action == GLFW_PRESS ? "PRESS" : "REPEAT")), - format_mods(ev->glfw_modifiers), ev->text + ev->glfw_ev.scancode, _glfwGetKeyName(ev->glfw_ev.scancode), ev->glfw_ev.key, glfw_xkb_keysym_name(ev->glfw_ev.key), + (ev->glfw_ev.action == GLFW_RELEASE ? "RELEASE" : (ev->glfw_ev.action == GLFW_PRESS ? "PRESS" : "REPEAT")), + format_mods(ev->glfw_ev.mods), ev->glfw_ev.text ); - _glfwInputKeyboard(window, ev->glfw_keycode, ev->keysym, ev->action, ev->glfw_modifiers, ev->text, 0); + + ev->glfw_ev.ime_state = 0; + _glfwInputKeyboard(window, &ev->glfw_ev); } else debug("↳ discarded\n"); - if (!is_release && handled_by_ime) last_handled_press_keycode = ev->keycode; + if (!is_release && handled_by_ime) last_handled_press_keycode = ev->glfw_ev.scancode; } +static char key_text[64] = {0}; + void glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action) { const xkb_keysym_t *syms, *clean_syms, *default_syms; - xkb_keysym_t glfw_sym; - xkb_keycode_t code_for_sym = scancode; - key_event.ibus_keycode = scancode; + xkb_keysym_t xkb_sym; + xkb_keycode_t code_for_sym = scancode, ibus_keycode = scancode; + GLFWkeyevent glfw_ev; + _glfwInitializeKeyEvent(&glfw_ev, GLFW_KEY_UNKNOWN, 0, GLFW_PRESS, 0); // init with default values #ifdef _GLFW_WAYLAND code_for_sym += 8; #else - key_event.ibus_keycode -= 8; + ibus_keycode -= 8; #endif debug("%s scancode: 0x%x ", action == GLFW_RELEASE ? "Release" : "Press", scancode); XKBStateGroup *sg = &xkb->states; int num_syms = xkb_state_key_get_syms(sg->state, code_for_sym, &syms); int num_clean_syms = xkb_state_key_get_syms(sg->clean_state, code_for_sym, &clean_syms); - key_event.text[0] = 0; + key_text[0] = 0; // According to the documentation of xkb_compose_state_feed it does not // support multi-sym events, so we ignore them if (num_syms != 1 || num_clean_syms != 1) { debug("num_syms: %d num_clean_syms: %d ignoring event\n", num_syms, num_clean_syms); return; } - glfw_sym = clean_syms[0]; + xkb_sym = clean_syms[0]; debug("clean_sym: %s ", glfw_xkb_keysym_name(clean_syms[0])); if (action == GLFW_PRESS || action == GLFW_REPEAT) { const char *text_type = "composed_text"; int compose_completed; - glfw_sym = compose_symbol(sg->composeState, syms[0], &compose_completed); - if (glfw_sym == XKB_KEY_NoSymbol && !compose_completed) { + xkb_sym = compose_symbol(sg->composeState, syms[0], &compose_completed, key_text, sizeof(key_text)); + if (xkb_sym == XKB_KEY_NoSymbol && !compose_completed) { debug("compose not complete, ignoring.\n"); return; } - debug("composed_sym: %s ", glfw_xkb_keysym_name(glfw_sym)); - if (glfw_sym == syms[0]) { // composed sym is the same as non-composed sym + debug("composed_sym: %s ", glfw_xkb_keysym_name(xkb_sym)); + if (xkb_sym == syms[0]) { // composed sym is the same as non-composed sym // Only use the clean_sym if no mods other than the mods we report // are active (for example if ISO_Shift_Level_* mods are active // they are not reported by GLFW so the key should be the shifted @@ -601,37 +607,49 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t xkb_mod_mask_t consumed_unknown_mods = xkb_state_key_get_consumed_mods(sg->state, code_for_sym) & sg->activeUnknownModifiers; if (sg->activeUnknownModifiers) debug("%s", format_xkb_mods(xkb, "active_unknown_mods", sg->activeUnknownModifiers)); if (consumed_unknown_mods) { debug("%s", format_xkb_mods(xkb, "consumed_unknown_mods", consumed_unknown_mods)); } - else glfw_sym = clean_syms[0]; + else xkb_sym = clean_syms[0]; // xkb returns text even if alt and/or super are pressed - if ( ((GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER) & sg->modifiers) == 0) xkb_state_key_get_utf8(sg->state, code_for_sym, key_event.text, sizeof(key_event.text)); + if ( ((GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER) & sg->modifiers) == 0) { + xkb_state_key_get_utf8(sg->state, code_for_sym, key_text, sizeof(key_text)); + } text_type = "text"; } - if ((1 <= key_event.text[0] && key_event.text[0] <= 31) || key_event.text[0] == 127) key_event.text[0] = 0; // don't send text for ascii control codes - if (key_event.text[0]) { debug("%s: %s ", text_type, key_event.text); } + if ((1 <= key_text[0] && key_text[0] <= 31) || key_text[0] == 127) { + key_text[0] = 0; // don't send text for ascii control codes + } + if (key_text[0]) { debug("%s: %s ", text_type, key_text); } } - int glfw_keycode = glfw_key_for_sym(glfw_sym); + int glfw_sym = glfw_key_for_sym(xkb_sym); bool is_fallback = false; - if (glfw_keycode == GLFW_KEY_UNKNOWN && !key_event.text[0]) { + if (glfw_sym == GLFW_KEY_UNKNOWN && !key_text[0]) { int num_default_syms = xkb_state_key_get_syms(sg->default_state, code_for_sym, &default_syms); if (num_default_syms > 0) { - glfw_sym = default_syms[0]; - glfw_keycode = glfw_key_for_sym(glfw_sym); + xkb_sym = default_syms[0]; + glfw_sym = glfw_key_for_sym(xkb_sym); is_fallback = true; } } debug( "%s%s: %d (%s) xkb_key: %d (%s)\n", format_mods(sg->modifiers), - is_fallback ? "glfw_fallback_key" : "glfw_key", glfw_keycode, _glfwGetKeyName(glfw_keycode), - glfw_sym, glfw_xkb_keysym_name(glfw_sym) + is_fallback ? "glfw_fallback_key" : "glfw_key", glfw_sym, _glfwGetKeyName(glfw_sym), + xkb_sym, glfw_xkb_keysym_name(xkb_sym) ); - key_event.action = action; key_event.glfw_modifiers = sg->modifiers; - key_event.keycode = scancode; key_event.keysym = glfw_sym; - key_event.window_id = window->id; key_event.glfw_keycode = glfw_keycode; - key_event.ibus_sym = syms[0]; - if (ibus_process_key(&key_event, &xkb->ibus)) { - debug("↳ to IBUS: keycode: 0x%x keysym: 0x%x (%s) %s\n", key_event.ibus_keycode, key_event.ibus_sym, glfw_xkb_keysym_name(key_event.ibus_sym), format_mods(key_event.glfw_modifiers)); + + glfw_ev.action = action; + glfw_ev.scancode = xkb_sym; + glfw_ev.key = glfw_sym; + glfw_ev.mods = sg->modifiers; + glfw_ev.text = key_text; + + _GLFWIBUSKeyEvent ibus_ev; + ibus_ev.glfw_ev = glfw_ev; + ibus_ev.ibus_keycode = ibus_keycode; + ibus_ev.window_id = window->id; + ibus_ev.ibus_keysym = syms[0]; + if (ibus_process_key(&ibus_ev, &xkb->ibus)) { + debug("↳ to IBUS: scancode: 0x%x keysym: 0x%x (%s) %s\n", ibus_ev.ibus_keycode, ibus_ev.ibus_keysym, glfw_xkb_keysym_name(ibus_ev.ibus_keysym), format_mods(ibus_ev.glfw_ev.mods)); } else { - _glfwInputKeyboard(window, glfw_keycode, glfw_sym, action, sg->modifiers, key_event.text, 0); + _glfwInputKeyboard(window, &glfw_ev); } } diff --git a/glfw/xkb_glfw.h b/glfw/xkb_glfw.h index 99e9ea8c9..c454a2d5b 100644 --- a/glfw/xkb_glfw.h +++ b/glfw/xkb_glfw.h @@ -93,4 +93,4 @@ xkb_keysym_t glfw_xkb_sym_for_key(int key); void glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action); int glfw_xkb_keysym_from_name(const char *name, bool case_sensitive); void glfw_xkb_update_ime_state(_GLFWwindow *w, _GLFWXKBData *xkb, int which, int a, int b, int c, int d); -void glfw_xkb_key_from_ime(KeyEvent *ev, bool handled_by_ime, bool failed); +void glfw_xkb_key_from_ime(_GLFWIBUSKeyEvent *ev, bool handled_by_ime, bool failed); diff --git a/kitty/data-types.h b/kitty/data-types.h index 3bd35f49b..f1a52180c 100644 --- a/kitty/data-types.h +++ b/kitty/data-types.h @@ -13,6 +13,7 @@ #include #include #include +#include "glfw-wrapper.h" // Required minimum OpenGL version #define OPENGL_REQUIRED_VERSION_MAJOR 3 #define OPENGL_REQUIRED_VERSION_MINOR 3 @@ -309,7 +310,7 @@ void focus_in_event(void); void scroll_event(double, double, int); void fake_scroll(int, bool); void set_special_key_combo(int glfw_key, int mods, bool is_native); -void on_key_input(int key, int scancode, int action, int mods, const char*, int); +void on_key_input(GLFWkeyevent *ev); void request_window_attention(id_type, bool); #ifndef __APPLE__ void play_canberra_sound(const char *which_sound, const char *event_id); diff --git a/kitty/glfw-wrapper.h b/kitty/glfw-wrapper.h index 0127da2d4..65b8d2cde 100644 --- a/kitty/glfw-wrapper.h +++ b/kitty/glfw-wrapper.h @@ -1,3 +1,9 @@ +// +// THIS FILE IS GENERATED BY glfw.py +// +// SAVE YOURSELF SOME TIME, DO NOT MANUALLY EDIT +// + #pragma once #include #include @@ -18,7 +24,7 @@ * backward-compatible. * @ingroup init */ -#define GLFW_VERSION_MINOR 3 +#define GLFW_VERSION_MINOR 4 /*! @brief The revision number of the GLFW library. * * This is incremented when a bug fix release is made that does not contain any @@ -725,62 +731,62 @@ #define GLFW_CLIENT_API 0x00022001 /*! @brief Context client API major version hint and attribute. * - * Context client API major version [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context client API major version [hint](@ref GLFW_CONTEXT_VERSION_MAJOR_hint) + * and [attribute](@ref GLFW_CONTEXT_VERSION_MAJOR_attrib). */ #define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 /*! @brief Context client API minor version hint and attribute. * - * Context client API minor version [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context client API minor version [hint](@ref GLFW_CONTEXT_VERSION_MINOR_hint) + * and [attribute](@ref GLFW_CONTEXT_VERSION_MINOR_attrib). */ #define GLFW_CONTEXT_VERSION_MINOR 0x00022003 /*! @brief Context client API revision number hint and attribute. * - * Context client API revision number [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context client API revision number + * [attribute](@ref GLFW_CONTEXT_REVISION_attrib). */ #define GLFW_CONTEXT_REVISION 0x00022004 /*! @brief Context robustness hint and attribute. * - * Context client API revision number [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context client API revision number [hint](@ref GLFW_CONTEXT_ROBUSTNESS_hint) + * and [attribute](@ref GLFW_CONTEXT_ROBUSTNESS_attrib). */ #define GLFW_CONTEXT_ROBUSTNESS 0x00022005 /*! @brief OpenGL forward-compatibility hint and attribute. * - * OpenGL forward-compatibility [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * OpenGL forward-compatibility [hint](@ref GLFW_OPENGL_FORWARD_COMPAT_hint) + * and [attribute](@ref GLFW_OPENGL_FORWARD_COMPAT_attrib). */ #define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 /*! @brief OpenGL debug context hint and attribute. * - * OpenGL debug context [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * OpenGL debug context [hint](@ref GLFW_OPENGL_DEBUG_CONTEXT_hint) and + * [attribute](@ref GLFW_OPENGL_DEBUG_CONTEXT_attrib). */ #define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 /*! @brief OpenGL profile hint and attribute. * - * OpenGL profile [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * OpenGL profile [hint](@ref GLFW_OPENGL_PROFILE_hint) and + * [attribute](@ref GLFW_OPENGL_PROFILE_attrib). */ #define GLFW_OPENGL_PROFILE 0x00022008 /*! @brief Context flush-on-release hint and attribute. * - * Context flush-on-release [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context flush-on-release [hint](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_hint) and + * [attribute](@ref GLFW_CONTEXT_RELEASE_BEHAVIOR_attrib). */ #define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 /*! @brief Context error suppression hint and attribute. * - * Context error suppression [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context error suppression [hint](@ref GLFW_CONTEXT_NO_ERROR_hint) and + * [attribute](@ref GLFW_CONTEXT_NO_ERROR_attrib). */ #define GLFW_CONTEXT_NO_ERROR 0x0002200A /*! @brief Context creation API hint and attribute. * - * Context creation API [hint](@ref GLFW_CLIENT_API_hint) and - * [attribute](@ref GLFW_CLIENT_API_attrib). + * Context creation API [hint](@ref GLFW_CONTEXT_CREATION_API_hint) and + * [attribute](@ref GLFW_CONTEXT_CREATION_API_attrib). */ #define GLFW_CONTEXT_CREATION_API 0x0002200B /*! @brief Window content area scaling window @@ -934,6 +940,29 @@ typedef struct GLFWwindow GLFWwindow; */ typedef struct GLFWcursor GLFWcursor; +typedef struct GLFWkeyevent +{ + // The [keyboard key](@ref keys) that was pressed or released. + int key; + + // The system-specific scancode of the key. + int scancode; + + // The event action. Either `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. + int action; + + // Bit field describing which [modifier keys](@ref mods) were held down. + int mods; + + // UTF-8 encoded text generated by this key event or empty string. + const char *text; + + // Used for Input Method events. Zero for normal key events. + // A value of 1 means the pre-edit text for the input event has been changed. + // A value of 2 means the text should be committed. + int ime_state; +} GLFWkeyevent; + /*! @brief The function signature for error callbacks. * * This is the function signature for error callback functions. @@ -1219,15 +1248,7 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int); * the "s" key will generate text "o" and GLFW_KEY_O. * * @param[in] window The window that received the event. - * @param[in] key The [keyboard key](@ref keys) that was pressed or released. - * @param[in] scancode The system-specific scancode of the key. - * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. - * @param[in] mods Bit field describing which [modifier keys](@ref mods) were - * held down. - * @param[in] text UTF-8 encoded text generated by this key event or empty string. - * @param[in] Used for Input Method events. Zero for normal key events. - * A value of 1 means the pre-edit text for the input event has been changed. - * A value of 2 means the text should be committed. + * @param[in] ev TODO: blablabla * * @note On X11/Wayland if a modifier other than the modifiers GLFW reports * (ctrl/shift/alt/super) is used, GLFW will report the shifted key rather @@ -1241,7 +1262,7 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double,int); * * @ingroup input */ -typedef void (* GLFWkeyboardfun)(GLFWwindow*, int, int, int, int, const char*, int); +typedef void (* GLFWkeyboardfun)(GLFWwindow*, GLFWkeyevent*); /*! @brief The function signature for file drop callbacks. * diff --git a/kitty/glfw.c b/kitty/glfw.c index 33a77a260..5e1574144 100644 --- a/kitty/glfw.c +++ b/kitty/glfw.c @@ -230,14 +230,14 @@ refresh_callback(GLFWwindow *w) { static int mods_at_last_key_or_button_event = 0; static void -key_callback(GLFWwindow *w, int key, int scancode, int action, int mods, const char* text, int state) { +key_callback(GLFWwindow *w, GLFWkeyevent *ev) { if (!set_callback_window(w)) return; - mods_at_last_key_or_button_event = mods; + mods_at_last_key_or_button_event = ev->mods; global_state.callback_os_window->cursor_blink_zero_time = monotonic(); - if (key >= 0 && key <= GLFW_KEY_LAST) { - global_state.callback_os_window->is_key_pressed[key] = action == GLFW_RELEASE ? false : true; + if (ev->key >= 0 && ev->key <= GLFW_KEY_LAST) { + global_state.callback_os_window->is_key_pressed[ev->key] = ev->action == GLFW_RELEASE ? false : true; } - if (is_window_ready_for_callbacks()) on_key_input(key, scancode, action, mods, text, state); + if (is_window_ready_for_callbacks()) on_key_input(ev); global_state.callback_os_window = NULL; request_tick_callback(); } diff --git a/kitty/glfw_tests.c b/kitty/glfw_tests.c index 399f594dd..2823f0461 100644 --- a/kitty/glfw_tests.c +++ b/kitty/glfw_tests.c @@ -31,9 +31,9 @@ static void* empty_thread_main(void* data UNUSED) return 0; } -static void key_callback(GLFWwindow *w UNUSED, int key, int scancode UNUSED, int action, int mods UNUSED, const char* text UNUSED, int state UNUSED) +static void key_callback(GLFWwindow *w UNUSED, GLFWkeyevent *ev) { - if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + if (ev->key == GLFW_KEY_ESCAPE && ev->action == GLFW_PRESS) { glfwSetWindowShouldClose(w, true); wakeup_main_loop(); } diff --git a/kitty/keys.c b/kitty/keys.c index 16b603010..33b1d3a42 100644 --- a/kitty/keys.c +++ b/kitty/keys.c @@ -121,16 +121,24 @@ update_ime_position(OSWindow *os_window, Window* w, Screen *screen) { #define debug(...) if (OPT(debug_keyboard)) printf(__VA_ARGS__); void -on_key_input(int key, int scancode, int action, int mods, const char* text, int state) { +on_key_input(GLFWkeyevent *ev) { Window *w = active_window(); + int action, scancode, key, mods; + const char *text; + action = ev->action; + scancode = ev->scancode; + key = ev->key; + mods = ev->mods; + text = ev->text; + debug("on_key_input: glfw key: %d native_code: 0x%x action: %s mods: 0x%x text: '%s' state: %d ", key, scancode, (action == GLFW_RELEASE ? "RELEASE" : (action == GLFW_PRESS ? "PRESS" : "REPEAT")), - mods, text, state); + mods, text, ev->ime_state); if (!w) { debug("no active window, ignoring\n"); return; } if (OPT(mouse_hide_wait) < 0 && !is_modifier_key(key)) hide_mouse(global_state.callback_os_window); Screen *screen = w->render_data.screen; - switch(state) { + switch(ev->ime_state) { case 1: // update pre-edit text update_ime_position(global_state.callback_os_window, w, screen); screen_draw_overlay_text(screen, text); From aadab38487802b1f06cf7369f815002ccd71a91a Mon Sep 17 00:00:00 2001 From: Benoit de Chezelles Date: Tue, 24 Sep 2019 21:58:18 +0200 Subject: [PATCH 2/2] Fix compilation for macos --- glfw/cocoa_window.m | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/glfw/cocoa_window.m b/glfw/cocoa_window.m index 292659db8..127354f5f 100644 --- a/glfw/cocoa_window.m +++ b/glfw/cocoa_window.m @@ -1055,6 +1055,8 @@ - (void)keyDown:(NSEvent *)event const bool previous_has_marked_text = [self hasMarkedText]; [self unmarkText]; _glfw.ns.text[0] = 0; + GLFWkeyevent glfw_keyevent; + _glfwInitializeKeyEvent(&glfw_keyevent, key, scancode, GLFW_PRESS, mods); if (!_glfw.ns.unicodeData) { // Using the cocoa API for key handling is disabled, as there is no // reliable way to handle dead keys using it. Only use it if the @@ -1095,14 +1097,16 @@ - (void)keyDown:(NSEvent *)event if (window->ns.deadKeyState && (char_count == 0 || scancode == 0x75)) { // 0x75 is the delete key which needs to be ignored during a compose sequence debug_key(@"Sending pre-edit text for dead key (text: %@ markedText: %@).\n", @(format_text(_glfw.ns.text)), markedText); - _glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods, - [[markedText string] UTF8String], 1); // update pre-edit text + glfw_keyevent.text = [[markedText string] UTF8String]; + glfw_keyevent.ime_state = 1; + _glfwInputKeyboard(window, &glfw_keyevent); // update pre-edit text return; } if (in_compose_sequence) { debug_key(@"Clearing pre-edit text at end of compose sequence\n"); - _glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods, - NULL, 1); // clear pre-edit text + glfw_keyevent.text = NULL; + glfw_keyevent.ime_state = 1; + _glfwInputKeyboard(window, &glfw_keyevent); // clear pre-edit text } } if (is_ascii_control_char(_glfw.ns.text[0])) _glfw.ns.text[0] = 0; // don't send text for ascii control codes @@ -1110,18 +1114,22 @@ - (void)keyDown:(NSEvent *)event @(format_text(_glfw.ns.text)), @(_glfwGetKeyName(key)), markedText); if (!window->ns.deadKeyState) { if ([self hasMarkedText]) { - _glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods, - [[markedText string] UTF8String], 1); // update pre-edit text + glfw_keyevent.text = [[markedText string] UTF8String]; + glfw_keyevent.ime_state = 1; + _glfwInputKeyboard(window, &glfw_keyevent); // update pre-edit text } else if (previous_has_marked_text) { - _glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods, - NULL, 1); // clear pre-edit text + glfw_keyevent.text = NULL; + glfw_keyevent.ime_state = 1; + _glfwInputKeyboard(window, &glfw_keyevent); // clear pre-edit text } if (([self hasMarkedText] || previous_has_marked_text) && !_glfw.ns.text[0]) { // do not pass keys like BACKSPACE while there's pre-edit text, let IME handle it return; } } - _glfwInputKeyboard(window, key, scancode, GLFW_PRESS, mods, _glfw.ns.text, 0); + glfw_keyevent.text = _glfw.ns.text; + glfw_keyevent.ime_state = 0; + _glfwInputKeyboard(window, &glfw_keyevent); } - (void)flagsChanged:(NSEvent *)event @@ -1143,14 +1151,19 @@ - (void)flagsChanged:(NSEvent *)event else action = GLFW_RELEASE; - _glfwInputKeyboard(window, key, [event keyCode], action, mods, "", 0); + GLFWkeyevent glfw_keyevent; + _glfwInitializeKeyEvent(&glfw_keyevent, key, [event keyCode], action, mods); + _glfwInputKeyboard(window, &glfw_keyevent); } - (void)keyUp:(NSEvent *)event { const int key = translateKey([event keyCode], true); const int mods = translateFlags([event modifierFlags]); - _glfwInputKeyboard(window, key, [event keyCode], GLFW_RELEASE, mods, "", 0); + + GLFWkeyevent glfw_keyevent; + _glfwInitializeKeyEvent(&glfw_keyevent, key, [event keyCode], GLFW_RELEASE, mods); + _glfwInputKeyboard(window, &glfw_keyevent); } - (void)scrollWheel:(NSEvent *)event