Linux: Fix release event for the final key in a compose sequence not being reported. Fixes #4285

This commit is contained in:
Kovid Goyal 2021-11-29 19:26:16 +05:30
parent cdb1138465
commit bd288bd18f
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
6 changed files with 38 additions and 25 deletions

View File

@ -1250,7 +1250,7 @@ is_ascii_control_char(char x) {
const bool process_text = !window->ns.textInputFilterCallback || window->ns.textInputFilterCallback(key, mods, keycode, flags) != 1;
_glfw.ns.text[0] = 0;
if (keycode == 0x33 /* backspace */ || keycode == 0x35 /* escape */) [self unmarkText];
GLFWkeyevent glfw_keyevent = {.key = key, .native_key = keycode, .action = GLFW_PRESS, .mods = mods};
GLFWkeyevent glfw_keyevent = {.key = key, .native_key = keycode, .native_key_id = keycode, .action = GLFW_PRESS, .mods = 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
@ -1357,7 +1357,7 @@ is_ascii_control_char(char x) {
action = GLFW_PRESS;
}
GLFWkeyevent glfw_keyevent = {.key = key, .native_key = [event keyCode], .action = action, .mods = mods};
GLFWkeyevent glfw_keyevent = {.key = key, .native_key = [event keyCode], .native_key_id = [event keyCode], .action = action, .mods = mods};
_glfwInputKeyboard(window, &glfw_keyevent);
}
@ -1367,7 +1367,7 @@ is_ascii_control_char(char x) {
const uint32_t key = translateKey(keycode, true);
const int mods = translateFlags([event modifierFlags]);
GLFWkeyevent glfw_keyevent = {.key = key, .native_key = keycode, .action = GLFW_RELEASE, .mods = mods};
GLFWkeyevent glfw_keyevent = {.key = key, .native_key = keycode, .native_key_id = keycode, .action = GLFW_RELEASE, .mods = mods};
add_alternate_keys(&glfw_keyevent, event);
debug_key("\x1b[32mRelease:\x1b[m native_key: 0x%x (%s) glfw_key: 0x%x %s\n",
keycode, safe_name_for_keycode(keycode), key, format_mods(mods));

4
glfw/glfw3.h vendored
View File

@ -1245,6 +1245,10 @@ typedef struct GLFWkeyevent
// A value of GLFW_IME_PREEDIT_CHANGED means the pre-edit text for the input event has been changed.
// A value of GLFW_IME_COMMIT_TEXT means the text should be committed.
GLFWIMEState ime_state;
// For internal use only. On Linux it is the actual keycode reported by the windowing system, in contrast
// to native_key which can be the result of a compose operation. On macOS it is the same as native_key.
uint32_t native_key_id;
} GLFWkeyevent;
/*! @brief The function pointer type for error callbacks.

40
glfw/input.c vendored
View File

@ -274,11 +274,11 @@ static bool parseMapping(_GLFWmapping* mapping, const char* string)
//////////////////////////////////////////////////////////////////////////
static void
set_key_action(_GLFWwindow *window, uint32_t key, int val, int idx) {
set_key_action(_GLFWwindow *window, const GLFWkeyevent *ev, int action, int idx) {
const unsigned sz = arraysz(window->activated_keys);
if (idx < 0) {
for (unsigned i = 0; i < sz; i++) {
if (window->activated_keys[i].key == 0) {
if (window->activated_keys[i].native_key_id == 0) {
idx = i;
break;
}
@ -286,18 +286,18 @@ set_key_action(_GLFWwindow *window, uint32_t key, int val, int idx) {
if (idx < 0) {
idx = sz - 1;
memmove(window->activated_keys, window->activated_keys + 1, sizeof(window->activated_keys[0]) * (sz - 1));
window->activated_keys[sz - 1].key = key;
window->activated_keys[sz - 1].native_key_id = 0;
}
}
if (val == GLFW_RELEASE) {
if (action == GLFW_RELEASE) {
memset(window->activated_keys + idx, 0, sizeof(window->activated_keys[0]));
if (idx < (int)sz - 1) {
memmove(window->activated_keys + idx, window->activated_keys + idx + 1, sizeof(window->activated_keys[0]) * (sz - 1 - idx));
memset(window->activated_keys + sz - 1, 0, sizeof(window->activated_keys[0]));
}
} else {
window->activated_keys[idx].key = key;
window->activated_keys[idx].action = val;
window->activated_keys[idx] = *ev;
window->activated_keys[idx].text = NULL;
}
}
@ -305,30 +305,39 @@ set_key_action(_GLFWwindow *window, uint32_t key, int val, int idx) {
//
void _glfwInputKeyboard(_GLFWwindow* window, GLFWkeyevent* ev)
{
if (ev->key > 0)
if (ev->native_key_id > 0)
{
bool repeated = false;
int idx = -1;
int current_action = GLFW_RELEASE;
const unsigned sz = arraysz(window->activated_keys);
for (unsigned i = 0; i < sz; i++) {
if (window->activated_keys[i].key == ev->key) {
if (window->activated_keys[i].native_key_id == ev->native_key_id) {
idx = i;
current_action = window->activated_keys[i].action;
break;
}
}
if (ev->action == GLFW_RELEASE && current_action == GLFW_RELEASE)
return;
if (ev->action == GLFW_RELEASE) {
if (current_action == GLFW_RELEASE) return;
if (idx > -1) {
const GLFWkeyevent *press_event = window->activated_keys + idx;
if (press_event->action == GLFW_PRESS || press_event->action == GLFW_REPEAT) {
// Compose sequences under X11 give a different key value for press and release events
// but we want the same key value so override it.
ev->native_key = press_event->native_key;
ev->key = press_event->key;
ev->shifted_key = press_event->shifted_key;
ev->alternate_key = press_event->alternate_key;
}
}
}
if (ev->action == GLFW_PRESS && current_action == GLFW_PRESS)
repeated = true;
if (ev->action == GLFW_RELEASE && window->stickyKeys)
set_key_action(window, ev->key, _GLFW_STICK, idx);
else
set_key_action(window, ev->key, ev->action, idx);
set_key_action(window, ev, (ev->action == GLFW_RELEASE && window->stickyKeys) ? _GLFW_STICK : ev->action, idx);
if (repeated)
ev->action = GLFW_REPEAT;
@ -823,7 +832,8 @@ GLFWAPI GLFWKeyAction glfwGetKey(GLFWwindow* handle, uint32_t key)
if (current_action == _GLFW_STICK)
{
// Sticky mode: release key now
set_key_action(window, key, GLFW_RELEASE, idx);
GLFWkeyevent ev = {0};
set_key_action(window, &ev, GLFW_RELEASE, idx);
current_action = GLFW_PRESS;
}

7
glfw/internal.h vendored
View File

@ -402,11 +402,6 @@ struct _GLFWcontext
_GLFWcontextOSMesa osmesa;
};
typedef struct GLFWKeyState {
uint32_t key;
char action;
} GLFWKeyState;
// Window and context structure
//
struct _GLFWwindow
@ -437,7 +432,7 @@ struct _GLFWwindow
bool lockKeyMods;
int cursorMode;
char mouseButtons[GLFW_MOUSE_BUTTON_LAST + 1];
GLFWKeyState activated_keys[16];
GLFWkeyevent activated_keys[16];
// Virtual cursor position when cursor is disabled
double virtualCursorPosX, virtualCursorPosY;
bool rawMouseMotion;

2
glfw/xkb_glfw.c vendored
View File

@ -866,7 +866,7 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
const xkb_keysym_t *syms, *clean_syms, *default_syms;
xkb_keysym_t xkb_sym, shifted_xkb_sym = XKB_KEY_NoSymbol, alternate_xkb_sym = XKB_KEY_NoSymbol;
xkb_keycode_t code_for_sym = xkb_keycode, ibus_keycode = xkb_keycode;
GLFWkeyevent glfw_ev = {.action = GLFW_PRESS};
GLFWkeyevent glfw_ev = {.action = GLFW_PRESS, .native_key_id = xkb_keycode};
#ifdef _GLFW_WAYLAND
code_for_sym += 8;
#else

4
kitty/glfw-wrapper.h generated
View File

@ -983,6 +983,10 @@ typedef struct GLFWkeyevent
// A value of GLFW_IME_PREEDIT_CHANGED means the pre-edit text for the input event has been changed.
// A value of GLFW_IME_COMMIT_TEXT means the text should be committed.
GLFWIMEState ime_state;
// For internal use only. On Linux it is the actual keycode reported by the windowing system, in contrast
// to native_key which can be the result of a compose operation. On macOS it is the same as native_key.
uint32_t native_key_id;
} GLFWkeyevent;
/*! @brief The function pointer type for error callbacks.