Handle keys returned by IBUS
This commit is contained in:
parent
56063b283e
commit
c6c6a18375
18
glfw/ibus_glfw.c
vendored
18
glfw/ibus_glfw.c
vendored
@ -391,26 +391,28 @@ 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;
|
||||
GLFWbool is_release = ev->action == GLFW_RELEASE;
|
||||
if (errmsg) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "IBUS: Failed to process key with error: %s", errmsg);
|
||||
return;
|
||||
} 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);
|
||||
}
|
||||
uint32_t handled;
|
||||
if (!glfw_dbus_get_args(msg, "Failed to get IBUS handled key from reply", DBUS_TYPE_BOOLEAN, &handled, DBUS_TYPE_INVALID)) return;
|
||||
KeyEvent *ev = (KeyEvent*)data;
|
||||
debug("IBUS processed scancode: 0x%x release: %d handled: %u\n", ev->keycode, ev->action == GLFW_RELEASE, handled);
|
||||
glfw_xkb_key_from_ime(ev, handled ? GLFW_TRUE : GLFW_FALSE);
|
||||
free(ev);
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
ibus_process_key(const KeyEvent *ev_) {
|
||||
if (!check_connection(ev_->ibus)) return GLFW_FALSE;
|
||||
ibus_process_key(const KeyEvent *ev_, _GLFWIBUSData *ibus) {
|
||||
if (!check_connection(ibus)) return GLFW_FALSE;
|
||||
KeyEvent *ev = malloc(sizeof(KeyEvent));
|
||||
if (!ev) return GLFW_FALSE;
|
||||
memcpy(ev, ev_, sizeof(KeyEvent));
|
||||
uint32_t state = ibus_key_state(ev->glfw_modifiers, ev->action);
|
||||
if (!glfw_dbus_call_method_with_reply(
|
||||
ev->ibus->conn, IBUS_SERVICE, ev->ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent",
|
||||
ibus->conn, IBUS_SERVICE, ibus->input_ctx_path, IBUS_INPUT_INTERFACE, "ProcessKeyEvent",
|
||||
key_event_processed, ev,
|
||||
DBUS_TYPE_UINT32, &ev->keysym, DBUS_TYPE_UINT32, &ev->keycode, DBUS_TYPE_UINT32,
|
||||
&state, DBUS_TYPE_INVALID)) {
|
||||
|
||||
4
glfw/ibus_glfw.h
vendored
4
glfw/ibus_glfw.h
vendored
@ -42,12 +42,12 @@ typedef struct {
|
||||
xkb_keysym_t keysym;
|
||||
unsigned int glfw_modifiers;
|
||||
int action;
|
||||
_GLFWIBUSData *ibus;
|
||||
GLFWid window_id;
|
||||
} KeyEvent;
|
||||
|
||||
void glfw_connect_to_ibus(_GLFWIBUSData *ibus);
|
||||
void glfw_ibus_terminate(_GLFWIBUSData *ibus);
|
||||
void glfw_ibus_set_focused(_GLFWIBUSData *ibus, GLFWbool focused);
|
||||
void glfw_ibus_dispatch(_GLFWIBUSData *ibus);
|
||||
GLFWbool ibus_process_key(const KeyEvent *ev_);
|
||||
GLFWbool ibus_process_key(const KeyEvent *ev_, _GLFWIBUSData *ibus);
|
||||
void glfw_ibus_set_cursor_geometry(_GLFWIBUSData *ibus, int x, int y, int w, int h);
|
||||
|
||||
3
glfw/internal.h
vendored
3
glfw/internal.h
vendored
@ -705,7 +705,6 @@ void _glfwPlatformUnlockMutex(_GLFWmutex* mutex);
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _glfwInputWindowFocus(_GLFWwindow* window, GLFWbool focused);
|
||||
_GLFWwindow* _glfwFocusedWindow();
|
||||
void _glfwInputWindowPos(_GLFWwindow* window, int xpos, int ypos);
|
||||
void _glfwInputWindowSize(_GLFWwindow* window, int width, int height);
|
||||
void _glfwInputFramebufferSize(_GLFWwindow* window, int width, int height);
|
||||
@ -771,5 +770,7 @@ const char* _glfwGetKeyName(int key);
|
||||
GLFWbool _glfwInitVulkan(int mode);
|
||||
void _glfwTerminateVulkan(void);
|
||||
const char* _glfwGetVulkanResultString(VkResult result);
|
||||
_GLFWwindow* _glfwFocusedWindow();
|
||||
_GLFWwindow* _glfwWindowForId(GLFWid id);
|
||||
|
||||
char* _glfw_strdup(const char* source);
|
||||
|
||||
9
glfw/window.c
vendored
9
glfw/window.c
vendored
@ -79,6 +79,15 @@ _GLFWwindow* _glfwFocusedWindow() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_GLFWwindow* _glfwWindowForId(GLFWid id) {
|
||||
_GLFWwindow *w = _glfw.windowListHead;
|
||||
while (w) {
|
||||
if (w->id == _glfw.focusedWindowId) return w;
|
||||
w = w->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Notifies shared code that a window has moved
|
||||
// The position is specified in client-area relative screen coordinates
|
||||
//
|
||||
|
||||
2
glfw/wl_init.c
vendored
2
glfw/wl_init.c
vendored
@ -308,7 +308,7 @@ static void pointerHandleButton(void* data,
|
||||
state == WL_POINTER_BUTTON_STATE_PRESSED
|
||||
? GLFW_PRESS
|
||||
: GLFW_RELEASE,
|
||||
_glfw.wl.xkb.modifiers);
|
||||
_glfw.wl.xkb.states.modifiers);
|
||||
}
|
||||
|
||||
static void pointerHandleAxis(void* data,
|
||||
|
||||
291
glfw/xkb_glfw.c
vendored
291
glfw/xkb_glfw.c
vendored
@ -32,6 +32,7 @@
|
||||
|
||||
#define debug(...) if (_glfw.hints.init.debugKeyboard) printf(__VA_ARGS__);
|
||||
|
||||
|
||||
#define map_key(key) { \
|
||||
switch(key) { \
|
||||
S(space, SPACE); \
|
||||
@ -126,6 +127,7 @@ glfw_xkb_sym_for_key(int key) {
|
||||
}
|
||||
|
||||
#ifdef _GLFW_X11
|
||||
#define XKB_POINTER (&_glfw.x11.xkb)
|
||||
|
||||
GLFWbool
|
||||
glfw_xkb_set_x11_events_mask(void) {
|
||||
@ -165,37 +167,31 @@ glfw_xkb_update_x11_keyboard_id(_GLFWXKBData *xkb) {
|
||||
|
||||
#else
|
||||
|
||||
#define XKB_POINTER (&_glfw.wl.xkb)
|
||||
#define xkb_glfw_load_keymap(keymap, map_str) keymap = xkb_keymap_new_from_string(xkb->context, map_str, XKB_KEYMAP_FORMAT_TEXT_V1, 0);
|
||||
#define xkb_glfw_load_state(keymap, state, ...) state = xkb_state_new(keymap);
|
||||
|
||||
#endif
|
||||
|
||||
static void
|
||||
release_keyboard_data(_GLFWXKBData *xkb) {
|
||||
#define US(group, state, unref) if (xkb->group.state) { unref(xkb->group.state); xkb->group.state = NULL; }
|
||||
#define UK(keymap) if(xkb->keymap) { xkb_keymap_unref(xkb->keymap); xkb->keymap = NULL; }
|
||||
US(states, composeState, xkb_compose_state_unref);
|
||||
US(ime_states, composeState, xkb_compose_state_unref);
|
||||
UK(keymap);
|
||||
UK(default_keymap);
|
||||
US(states, state, xkb_state_unref);
|
||||
US(states, clean_state, xkb_state_unref);
|
||||
US(states, default_state, xkb_state_unref);
|
||||
#undef US
|
||||
#undef UK
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
glfw_xkb_release(_GLFWXKBData *xkb) {
|
||||
if (xkb->composeState) {
|
||||
xkb_compose_state_unref(xkb->composeState);
|
||||
xkb->composeState = NULL;
|
||||
}
|
||||
if (xkb->keymap) {
|
||||
xkb_keymap_unref(xkb->keymap);
|
||||
xkb->keymap = NULL;
|
||||
}
|
||||
if (xkb->default_keymap) {
|
||||
xkb_keymap_unref(xkb->default_keymap);
|
||||
xkb->default_keymap = NULL;
|
||||
}
|
||||
if (xkb->state) {
|
||||
xkb_state_unref(xkb->state);
|
||||
xkb->state = NULL;
|
||||
}
|
||||
if (xkb->clean_state) {
|
||||
xkb_state_unref(xkb->clean_state);
|
||||
xkb->clean_state = NULL;
|
||||
}
|
||||
if (xkb->default_state) {
|
||||
xkb_state_unref(xkb->default_state);
|
||||
xkb->default_state = NULL;
|
||||
}
|
||||
release_keyboard_data(xkb);
|
||||
if (xkb->context) {
|
||||
xkb_context_unref(xkb->context);
|
||||
xkb->context = NULL;
|
||||
@ -216,113 +212,120 @@ glfw_xkb_create_context(_GLFWXKBData *xkb) {
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
static const char*
|
||||
load_keymaps(_GLFWXKBData *xkb, const char *map_str) {
|
||||
(void)(map_str); // not needed on X11
|
||||
xkb_glfw_load_keymap(xkb->keymap, map_str);
|
||||
if (!xkb->keymap) return "Failed to compile XKB keymap";
|
||||
// The system default keymap, can be overridden by the XKB_DEFAULT_RULES
|
||||
// env var, see
|
||||
// https://xkbcommon.org/doc/current/structxkb__rule__names.html
|
||||
static struct xkb_rule_names default_rule_names = {0};
|
||||
xkb->default_keymap = xkb_keymap_new_from_names(xkb->context, &default_rule_names, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
if (!xkb->default_keymap) return "Failed to create default XKB keymap";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char*
|
||||
load_states(_GLFWXKBData *xkb) {
|
||||
xkb_glfw_load_state(xkb->keymap, xkb->states.state);
|
||||
xkb_glfw_load_state(xkb->keymap, xkb->ime_states.state);
|
||||
xkb->states.clean_state = xkb_state_new(xkb->keymap);
|
||||
xkb->ime_states.clean_state = xkb_state_new(xkb->keymap);
|
||||
xkb->states.default_state = xkb_state_new(xkb->default_keymap);
|
||||
xkb->ime_states.default_state = xkb_state_new(xkb->default_keymap);
|
||||
if (!xkb->states.state || !xkb->ime_states.state || !xkb->states.clean_state || !xkb->ime_states.clean_state || !xkb->states.default_state || !xkb->ime_states.default_state) return "Failed to create XKB state";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
load_compose_tables(_GLFWXKBData *xkb) {
|
||||
/* Look up the preferred locale, falling back to "C" as default. */
|
||||
struct xkb_compose_table* compose_table = NULL;
|
||||
const char *locale = getenv("LC_ALL");
|
||||
if (!locale) locale = getenv("LC_CTYPE");
|
||||
if (!locale) locale = getenv("LANG");
|
||||
if (!locale) locale = "C";
|
||||
compose_table = xkb_compose_table_new_from_locale(xkb->context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
if (!compose_table) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB compose table for locale %s", locale);
|
||||
return;
|
||||
}
|
||||
xkb->states.composeState = xkb_compose_state_new(compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
|
||||
xkb->ime_states.composeState = xkb_compose_state_new(compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
|
||||
if (!xkb->states.composeState || !xkb->ime_states.composeState) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB compose state");
|
||||
}
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
glfw_xkb_compile_keymap(_GLFWXKBData *xkb, const char *map_str) {
|
||||
const char* locale = NULL;
|
||||
struct xkb_state* state = NULL, *clean_state = NULL;
|
||||
struct xkb_keymap* keymap = NULL;
|
||||
struct xkb_compose_table* compose_table = NULL;
|
||||
struct xkb_compose_state* compose_state = NULL;
|
||||
(void)(map_str); // not needed on X11
|
||||
GLFWbool ok = GLFW_FALSE;
|
||||
|
||||
xkb_glfw_load_keymap(keymap, map_str);
|
||||
if (!keymap) _glfwInputError(GLFW_PLATFORM_ERROR, "Failed to compile XKB keymap");
|
||||
else {
|
||||
xkb_glfw_load_state(keymap, state);
|
||||
clean_state = xkb_state_new(keymap);
|
||||
if (!state || !clean_state) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB state");
|
||||
xkb_keymap_unref(keymap); keymap = NULL;
|
||||
} else {
|
||||
ok = GLFW_TRUE;
|
||||
/* Look up the preferred locale, falling back to "C" as default. */
|
||||
locale = getenv("LC_ALL");
|
||||
if (!locale) locale = getenv("LC_CTYPE");
|
||||
if (!locale) locale = getenv("LANG");
|
||||
if (!locale) locale = "C";
|
||||
compose_table = xkb_compose_table_new_from_locale(xkb->context, locale, XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||
if (!compose_table) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB compose table");
|
||||
} else {
|
||||
compose_state = xkb_compose_state_new(compose_table, XKB_COMPOSE_STATE_NO_FLAGS);
|
||||
xkb_compose_table_unref(compose_table); compose_table = NULL;
|
||||
if (!compose_state) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create XKB compose state");
|
||||
}
|
||||
}
|
||||
}
|
||||
const char *err;
|
||||
release_keyboard_data(xkb);
|
||||
err = load_keymaps(xkb, map_str);
|
||||
if (err) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "%s", err);
|
||||
release_keyboard_data(xkb);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
if (keymap && state && clean_state) {
|
||||
if (xkb->composeState) xkb_compose_state_unref(xkb->composeState);
|
||||
xkb->composeState = compose_state;
|
||||
if (xkb->keymap) xkb_keymap_unref(xkb->keymap);
|
||||
xkb->keymap = keymap;
|
||||
if (xkb->state) xkb_state_unref(xkb->state);
|
||||
xkb->state = state;
|
||||
if (xkb->clean_state) xkb_state_unref(xkb->clean_state);
|
||||
xkb->clean_state = clean_state;
|
||||
err = load_states(xkb);
|
||||
if (err) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "%s", err);
|
||||
release_keyboard_data(xkb);
|
||||
return GLFW_FALSE;
|
||||
}
|
||||
if (xkb->keymap) {
|
||||
load_compose_tables(xkb);
|
||||
#define S(a, n) xkb->a##Idx = xkb_keymap_mod_get_index(xkb->keymap, n); xkb->a##Mask = 1 << xkb->a##Idx;
|
||||
S(control, XKB_MOD_NAME_CTRL);
|
||||
S(alt, XKB_MOD_NAME_ALT);
|
||||
S(shift, XKB_MOD_NAME_SHIFT);
|
||||
S(super, XKB_MOD_NAME_LOGO);
|
||||
S(capsLock, XKB_MOD_NAME_CAPS);
|
||||
S(numLock, XKB_MOD_NAME_NUM);
|
||||
S(control, XKB_MOD_NAME_CTRL);
|
||||
S(alt, XKB_MOD_NAME_ALT);
|
||||
S(shift, XKB_MOD_NAME_SHIFT);
|
||||
S(super, XKB_MOD_NAME_LOGO);
|
||||
S(capsLock, XKB_MOD_NAME_CAPS);
|
||||
S(numLock, XKB_MOD_NAME_NUM);
|
||||
#undef S
|
||||
size_t capacity = sizeof(xkb->unknownModifiers)/sizeof(xkb->unknownModifiers[0]), j = 0;
|
||||
for (xkb_mod_index_t i = 0; i < capacity; i++) xkb->unknownModifiers[i] = XKB_MOD_INVALID;
|
||||
for (xkb_mod_index_t i = 0; i < xkb_keymap_num_mods(xkb->keymap) && j < capacity - 1; i++) {
|
||||
if (i != xkb->controlIdx && i != xkb->altIdx && i != xkb->shiftIdx && i != xkb->superIdx && i != xkb->capsLockIdx && i != xkb->numLockIdx) xkb->unknownModifiers[j++] = i;
|
||||
}
|
||||
xkb->modifiers = 0;
|
||||
xkb->activeUnknownModifiers = 0;
|
||||
size_t capacity = sizeof(xkb->unknownModifiers)/sizeof(xkb->unknownModifiers[0]), j = 0;
|
||||
for (xkb_mod_index_t i = 0; i < capacity; i++) xkb->unknownModifiers[i] = XKB_MOD_INVALID;
|
||||
for (xkb_mod_index_t i = 0; i < xkb_keymap_num_mods(xkb->keymap) && j < capacity - 1; i++) {
|
||||
if (i != xkb->controlIdx && i != xkb->altIdx && i != xkb->shiftIdx && i != xkb->superIdx && i != xkb->capsLockIdx && i != xkb->numLockIdx) xkb->unknownModifiers[j++] = i;
|
||||
}
|
||||
if (!xkb->default_keymap && xkb->context) {
|
||||
// The system default keymap, can be overridden by the XKB_DEFAULT_RULES
|
||||
// env var, see
|
||||
// https://xkbcommon.org/doc/current/structxkb__rule__names.html
|
||||
static struct xkb_rule_names default_rule_names = {0};
|
||||
xkb->default_keymap = xkb_keymap_new_from_names(xkb->context, &default_rule_names, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
if (xkb->default_keymap) {
|
||||
xkb->default_state = xkb_state_new(keymap);
|
||||
if (!xkb->default_state) {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create default XKB state, fallback key processing is unavailable");
|
||||
}
|
||||
} else {
|
||||
_glfwInputError(GLFW_PLATFORM_ERROR, "Failed to create default XKB keymap, fallback key processing is unavailable");
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
xkb->states.modifiers = 0;
|
||||
xkb->states.activeUnknownModifiers = 0;
|
||||
xkb->ime_states.modifiers = 0;
|
||||
xkb->ime_states.activeUnknownModifiers = 0;
|
||||
return GLFW_TRUE;
|
||||
}
|
||||
|
||||
static inline xkb_mod_mask_t
|
||||
active_unknown_modifiers(_GLFWXKBData *xkb) {
|
||||
active_unknown_modifiers(_GLFWXKBData *xkb, struct xkb_state *state) {
|
||||
size_t i = 0;
|
||||
xkb_mod_mask_t ans = 0;
|
||||
while (xkb->unknownModifiers[i] != XKB_MOD_INVALID) {
|
||||
if (xkb_state_mod_index_is_active(xkb->state, xkb->unknownModifiers[i], XKB_STATE_MODS_EFFECTIVE)) ans |= (1 << xkb->unknownModifiers[i]);
|
||||
if (xkb_state_mod_index_is_active(state, xkb->unknownModifiers[i], XKB_STATE_MODS_EFFECTIVE)) ans |= (1 << xkb->unknownModifiers[i]);
|
||||
i++;
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
|
||||
static void
|
||||
update_modifiers(_GLFWXKBData *xkb, XKBStateGroup *group) {
|
||||
#define S(attr, name) if (xkb_state_mod_index_is_active(group->state, xkb->attr##Idx, XKB_STATE_MODS_EFFECTIVE)) group->modifiers |= GLFW_MOD_##name
|
||||
S(control, CONTROL); S(alt, ALT); S(shift, SHIFT); S(super, SUPER); S(capsLock, CAPS_LOCK); S(numLock, NUM_LOCK);
|
||||
#undef S
|
||||
xkb->states.activeUnknownModifiers = active_unknown_modifiers(xkb, xkb->states.state);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
glfw_xkb_update_modifiers(_GLFWXKBData *xkb, xkb_mod_mask_t depressed, xkb_mod_mask_t latched, xkb_mod_mask_t locked, xkb_layout_index_t base_group, xkb_layout_index_t latched_group, xkb_layout_index_t locked_group) {
|
||||
if (!xkb->keymap) return;
|
||||
xkb->modifiers = 0;
|
||||
xkb_state_update_mask(xkb->state, depressed, latched, locked, base_group, latched_group, locked_group);
|
||||
xkb->states.modifiers = 0;
|
||||
xkb_state_update_mask(xkb->states.state, depressed, latched, locked, base_group, latched_group, locked_group);
|
||||
// We have to update the groups in clean_state, as they change for
|
||||
// different keyboard layouts, see https://github.com/kovidgoyal/kitty/issues/488
|
||||
xkb_state_update_mask(xkb->clean_state, 0, 0, 0, base_group, latched_group, locked_group);
|
||||
#define S(attr, name) if (xkb_state_mod_index_is_active(xkb->state, xkb->attr##Idx, XKB_STATE_MODS_EFFECTIVE)) xkb->modifiers |= GLFW_MOD_##name
|
||||
S(control, CONTROL); S(alt, ALT); S(shift, SHIFT); S(super, SUPER); S(capsLock, CAPS_LOCK); S(numLock, NUM_LOCK);
|
||||
#undef S
|
||||
xkb->activeUnknownModifiers = active_unknown_modifiers(xkb);
|
||||
xkb_state_update_mask(xkb->states.clean_state, 0, 0, 0, base_group, latched_group, locked_group);
|
||||
xkb_state_update_mask(xkb->ime_states.state, 0, 0, 0, base_group, latched_group, locked_group);
|
||||
xkb_state_update_mask(xkb->ime_states.clean_state, 0, 0, 0, base_group, latched_group, locked_group);
|
||||
update_modifiers(xkb, &xkb->states);
|
||||
}
|
||||
|
||||
GLFWbool
|
||||
@ -337,13 +340,13 @@ glfw_xkb_should_repeat(_GLFWXKBData *xkb, xkb_keycode_t scancode) {
|
||||
static char text[256];
|
||||
|
||||
static inline xkb_keysym_t
|
||||
compose_symbol(_GLFWXKBData *xkb, xkb_keysym_t sym) {
|
||||
if (sym == XKB_KEY_NoSymbol || !xkb->composeState) return sym;
|
||||
if (xkb_compose_state_feed(xkb->composeState, sym) != XKB_COMPOSE_FEED_ACCEPTED) return sym;
|
||||
switch (xkb_compose_state_get_status(xkb->composeState)) {
|
||||
compose_symbol(struct xkb_compose_state *composeState, xkb_keysym_t sym) {
|
||||
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(xkb->composeState, text, sizeof(text));
|
||||
return xkb_compose_state_get_one_sym(xkb->composeState);
|
||||
xkb_compose_state_get_utf8(composeState, text, sizeof(text));
|
||||
return xkb_compose_state_get_one_sym(composeState);
|
||||
case XKB_COMPOSE_COMPOSING:
|
||||
case XKB_COMPOSE_CANCELLED:
|
||||
return XKB_KEY_NoSymbol;
|
||||
@ -420,8 +423,8 @@ glfw_xkb_update_ime_state(_GLFWwindow *w, _GLFWXKBData *xkb, int which, int a, i
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action) {
|
||||
static inline void
|
||||
handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action, GLFWbool from_ime) {
|
||||
const xkb_keysym_t *syms, *clean_syms, *default_syms;
|
||||
static KeyEvent ev;
|
||||
xkb_keysym_t glfw_sym;
|
||||
@ -429,27 +432,29 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
|
||||
#ifdef _GLFW_WAYLAND
|
||||
code_for_sym += 8;
|
||||
#endif
|
||||
debug("scancode: 0x%x release: %d ", scancode, action == GLFW_RELEASE);
|
||||
int num_syms = xkb_state_key_get_syms(xkb->state, code_for_sym, &syms);
|
||||
int num_clean_syms = xkb_state_key_get_syms(xkb->clean_state, code_for_sym, &clean_syms);
|
||||
debug("%sscancode: 0x%x release: %d ", from_ime ? "From IBUS-> ": "", scancode, action == GLFW_RELEASE);
|
||||
XKBStateGroup *sg = from_ime ? &xkb->ime_states : &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);
|
||||
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("scancode: 0x%x num_syms: %d num_clean_syms: %d ignoring event\n", scancode, num_syms, num_clean_syms);
|
||||
debug("num_syms: %d num_clean_syms: %d ignoring event\n", num_syms, num_clean_syms);
|
||||
return;
|
||||
}
|
||||
glfw_sym = clean_syms[0];
|
||||
debug("clean_sym: %s ", glfw_xkb_keysym_name(clean_syms[0]));
|
||||
ev.action = action; ev.glfw_modifiers = xkb->modifiers; ev.keycode = scancode; ev.keysym = glfw_sym;
|
||||
ev.ibus = &xkb->ibus;
|
||||
if (ibus_process_key(&ev)) {
|
||||
debug(" queued in IBUS\n");
|
||||
return;
|
||||
if (!from_ime) {
|
||||
ev.action = action; ev.glfw_modifiers = sg->modifiers; ev.keycode = scancode; ev.keysym = glfw_sym; ev.window_id = window->id;
|
||||
if (ibus_process_key(&ev, &xkb->ibus)) {
|
||||
debug(" queued in IBUS\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
|
||||
const char *text_type = "composed_text";
|
||||
glfw_sym = compose_symbol(xkb, syms[0]);
|
||||
glfw_sym = compose_symbol(sg->composeState, syms[0]);
|
||||
if (glfw_sym == XKB_KEY_NoSymbol) {
|
||||
debug("compose not complete, ignoring.\n");
|
||||
return;
|
||||
@ -460,12 +465,12 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
|
||||
// are active (for example if ISO_Shift_Level_* mods are active
|
||||
// they are not reported by GLFW so the key should be the shifted
|
||||
// key). See https://github.com/kovidgoyal/kitty/issues/171#issuecomment-377557053
|
||||
xkb_mod_mask_t consumed_unknown_mods = xkb_state_key_get_consumed_mods(xkb->state, code_for_sym) & xkb->activeUnknownModifiers;
|
||||
if (xkb->activeUnknownModifiers) debug("%s", format_xkb_mods(xkb, "active_unknown_mods", xkb->activeUnknownModifiers));
|
||||
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];
|
||||
// xkb returns text even if alt and/or super are pressed
|
||||
if ( ((GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER) & xkb->modifiers) == 0) xkb_state_key_get_utf8(xkb->state, code_for_sym, text, sizeof(text));
|
||||
if ( ((GLFW_MOD_CONTROL | GLFW_MOD_ALT | GLFW_MOD_SUPER) & sg->modifiers) == 0) xkb_state_key_get_utf8(sg->state, code_for_sym, text, sizeof(text));
|
||||
text_type = "text";
|
||||
}
|
||||
if ((1 <= text[0] && text[0] <= 31) || text[0] == 127) text[0] = 0; // dont send text for ascii control codes
|
||||
@ -474,7 +479,7 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
|
||||
int glfw_keycode = glfw_key_for_sym(glfw_sym);
|
||||
GLFWbool is_fallback = GLFW_FALSE;
|
||||
if (glfw_keycode == GLFW_KEY_UNKNOWN && !text[0]) {
|
||||
int num_default_syms = xkb_state_key_get_syms(xkb->default_state, code_for_sym, &default_syms);
|
||||
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);
|
||||
@ -483,9 +488,35 @@ glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t
|
||||
}
|
||||
debug(
|
||||
"%s%s: %s xkb_key_name: %s\n",
|
||||
format_mods(xkb->modifiers),
|
||||
format_mods(sg->modifiers),
|
||||
is_fallback ? "glfw_fallback_key" : "glfw_key", _glfwGetKeyName(glfw_keycode),
|
||||
glfw_xkb_keysym_name(glfw_sym)
|
||||
);
|
||||
_glfwInputKeyboard(window, glfw_keycode, glfw_sym, action, xkb->modifiers, text, 0);
|
||||
_glfwInputKeyboard(window, glfw_keycode, glfw_sym, action, sg->modifiers, text, 0);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
glfw_xkb_key_from_ime(KeyEvent *ev, GLFWbool handled_by_ime) {
|
||||
_GLFWXKBData *xkb = XKB_POINTER;
|
||||
_GLFWwindow *window = _glfwWindowForId(ev->window_id);
|
||||
static xkb_keycode_t last_handled_press_keycode = 0;
|
||||
// We filter out release events that correspond to the last press event
|
||||
// handled by the IME system. This wont fix the case of multiple key
|
||||
// presses before a release, but is better than nothing. For that case
|
||||
// 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;
|
||||
GLFWbool is_release = ev->action == GLFW_RELEASE;
|
||||
if (window && !handled_by_ime && !(is_release && ev->keycode == prev_handled_press)) {
|
||||
handle_key_event(window, xkb, ev->keycode, ev->action, GLFW_TRUE);
|
||||
}
|
||||
if (!is_release && handled_by_ime) last_handled_press_keycode = ev->keycode;
|
||||
xkb_state_update_key(xkb->ime_states.state, ev->keycode, is_release ? XKB_KEY_UP : XKB_KEY_DOWN);
|
||||
update_modifiers(xkb, &xkb->ime_states);
|
||||
}
|
||||
|
||||
void
|
||||
glfw_xkb_handle_key_event(_GLFWwindow *window, _GLFWXKBData *xkb, xkb_keycode_t scancode, int action) {
|
||||
handle_key_event(window, xkb, scancode, action, GLFW_FALSE);
|
||||
}
|
||||
|
||||
16
glfw/xkb_glfw.h
vendored
16
glfw/xkb_glfw.h
vendored
@ -35,13 +35,20 @@
|
||||
#include "ibus_glfw.h"
|
||||
|
||||
typedef struct {
|
||||
struct xkb_context* context;
|
||||
struct xkb_keymap* keymap;
|
||||
struct xkb_keymap* default_keymap;
|
||||
struct xkb_state* state;
|
||||
struct xkb_state* clean_state;
|
||||
struct xkb_state* default_state;
|
||||
struct xkb_compose_state* composeState;
|
||||
xkb_mod_mask_t activeUnknownModifiers;
|
||||
unsigned int modifiers;
|
||||
} XKBStateGroup;
|
||||
|
||||
|
||||
typedef struct {
|
||||
struct xkb_context* context;
|
||||
struct xkb_keymap* keymap;
|
||||
struct xkb_keymap* default_keymap;
|
||||
XKBStateGroup states, ime_states;
|
||||
|
||||
xkb_mod_index_t controlIdx;
|
||||
xkb_mod_index_t altIdx;
|
||||
@ -55,8 +62,6 @@ typedef struct {
|
||||
xkb_mod_mask_t superMask;
|
||||
xkb_mod_mask_t capsLockMask;
|
||||
xkb_mod_mask_t numLockMask;
|
||||
xkb_mod_mask_t activeUnknownModifiers;
|
||||
unsigned int modifiers;
|
||||
xkb_mod_index_t unknownModifiers[256];
|
||||
_GLFWIBUSData ibus;
|
||||
|
||||
@ -88,3 +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, GLFWbool 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, GLFWbool handled_by_ime);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user