clients: Add XKB compose key support
This adds single-symbol compose support using libxkbcommon's compose functionality. E.g., assuming you have the right alt key defined as your compose key, typing <RAlt>+i+' will produce í, and <RAlt>+y+= will produce ¥. This makes compose key work for weston-editor, weston-terminal, weston-eventdemo, and any other clients that use Weston's window.* routines for accepting and managing keyboard input. Compose sequences are loaded from the system's standard tables. As well, libxkbcommon will transparently load custom sequences from the user's ~/.XCompose file. Note that due to limitations in toytoolkit's key handler interface, only compose sequences resulting in single symbols are supported. While libxkbcommon supports multi-symbol compose strings, support for passing text buffers to Weston clients is left as future work. This largely obviates the need for the weston-simple-im input method client, which had provided a very limited compose functionality that was only available in clients implementing the zwp_input_method protocol, and with no mechanism to load system or user-specified compose keys. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=53648 Signed-off-by: Bryce Harrington <bryce@osg.samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Eric Engestrom <eric.engestrom@imgtec.com> Reviewed-by: Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
This commit is contained in:
@@ -63,6 +63,7 @@ typedef void *EGLContext;
|
|||||||
#endif /* no HAVE_CAIRO_EGL */
|
#endif /* no HAVE_CAIRO_EGL */
|
||||||
|
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
|
#include <xkbcommon/xkbcommon-compose.h>
|
||||||
#include <wayland-cursor.h>
|
#include <wayland-cursor.h>
|
||||||
|
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
@@ -372,6 +373,8 @@ struct input {
|
|||||||
struct {
|
struct {
|
||||||
struct xkb_keymap *keymap;
|
struct xkb_keymap *keymap;
|
||||||
struct xkb_state *state;
|
struct xkb_state *state;
|
||||||
|
struct xkb_compose_table *compose_table;
|
||||||
|
struct xkb_compose_state *compose_state;
|
||||||
xkb_mod_mask_t control_mask;
|
xkb_mod_mask_t control_mask;
|
||||||
xkb_mod_mask_t alt_mask;
|
xkb_mod_mask_t alt_mask;
|
||||||
xkb_mod_mask_t shift_mask;
|
xkb_mod_mask_t shift_mask;
|
||||||
@@ -2979,6 +2982,9 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|||||||
struct input *input = data;
|
struct input *input = data;
|
||||||
struct xkb_keymap *keymap;
|
struct xkb_keymap *keymap;
|
||||||
struct xkb_state *state;
|
struct xkb_state *state;
|
||||||
|
struct xkb_compose_table *compose_table;
|
||||||
|
struct xkb_compose_state *compose_state;
|
||||||
|
char *locale;
|
||||||
char *map_str;
|
char *map_str;
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
@@ -2997,6 +3003,7 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set up XKB keymap */
|
||||||
keymap = xkb_keymap_new_from_string(input->display->xkb_context,
|
keymap = xkb_keymap_new_from_string(input->display->xkb_context,
|
||||||
map_str,
|
map_str,
|
||||||
XKB_KEYMAP_FORMAT_TEXT_V1,
|
XKB_KEYMAP_FORMAT_TEXT_V1,
|
||||||
@@ -3009,6 +3016,7 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set up XKB state */
|
||||||
state = xkb_state_new(keymap);
|
state = xkb_state_new(keymap);
|
||||||
if (!state) {
|
if (!state) {
|
||||||
fprintf(stderr, "failed to create XKB state\n");
|
fprintf(stderr, "failed to create XKB state\n");
|
||||||
@@ -3016,6 +3024,37 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Look up the preferred locale, falling back to "C" as default */
|
||||||
|
if (!(locale = getenv("LC_ALL")))
|
||||||
|
if (!(locale = getenv("LC_CTYPE")))
|
||||||
|
if (!(locale = getenv("LANG")))
|
||||||
|
locale = "C";
|
||||||
|
|
||||||
|
/* Set up XKB compose table */
|
||||||
|
compose_table =
|
||||||
|
xkb_compose_table_new_from_locale(input->display->xkb_context,
|
||||||
|
locale,
|
||||||
|
XKB_COMPOSE_COMPILE_NO_FLAGS);
|
||||||
|
if (compose_table) {
|
||||||
|
/* Set up XKB compose state */
|
||||||
|
compose_state = xkb_compose_state_new(compose_table,
|
||||||
|
XKB_COMPOSE_STATE_NO_FLAGS);
|
||||||
|
if (compose_state) {
|
||||||
|
xkb_compose_state_unref(input->xkb.compose_state);
|
||||||
|
xkb_compose_table_unref(input->xkb.compose_table);
|
||||||
|
input->xkb.compose_state = compose_state;
|
||||||
|
input->xkb.compose_table = compose_table;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "could not create XKB compose state. "
|
||||||
|
"Disabiling compose.\n");
|
||||||
|
xkb_compose_table_unref(compose_table);
|
||||||
|
compose_table = NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "could not create XKB compose table for locale '%s'. "
|
||||||
|
"Disabiling compose\n", locale);
|
||||||
|
}
|
||||||
|
|
||||||
xkb_keymap_unref(input->xkb.keymap);
|
xkb_keymap_unref(input->xkb.keymap);
|
||||||
xkb_state_unref(input->xkb.state);
|
xkb_state_unref(input->xkb.state);
|
||||||
input->xkb.keymap = keymap;
|
input->xkb.keymap = keymap;
|
||||||
@@ -3056,6 +3095,30 @@ keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
|||||||
input_remove_keyboard_focus(input);
|
input_remove_keyboard_focus(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Translate symbols appropriately if a compose sequence is being entered */
|
||||||
|
static xkb_keysym_t
|
||||||
|
process_key_press(xkb_keysym_t sym, struct input *input)
|
||||||
|
{
|
||||||
|
if (sym == XKB_KEY_NoSymbol)
|
||||||
|
return sym;
|
||||||
|
if (xkb_compose_state_feed(input->xkb.compose_state,
|
||||||
|
sym) != XKB_COMPOSE_FEED_ACCEPTED)
|
||||||
|
return sym;
|
||||||
|
|
||||||
|
switch (xkb_compose_state_get_status(input->xkb.compose_state)) {
|
||||||
|
case XKB_COMPOSE_COMPOSING:
|
||||||
|
return XKB_KEY_NoSymbol;
|
||||||
|
case XKB_COMPOSE_COMPOSED:
|
||||||
|
return xkb_compose_state_get_one_sym(input->xkb.compose_state);
|
||||||
|
case XKB_COMPOSE_CANCELLED:
|
||||||
|
return XKB_KEY_NoSymbol;
|
||||||
|
case XKB_COMPOSE_NOTHING:
|
||||||
|
return sym;
|
||||||
|
default:
|
||||||
|
return sym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
||||||
uint32_t serial, uint32_t time, uint32_t key,
|
uint32_t serial, uint32_t time, uint32_t key,
|
||||||
@@ -3101,6 +3164,9 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
|||||||
state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||||
window_close(window);
|
window_close(window);
|
||||||
} else if (window->key_handler) {
|
} else if (window->key_handler) {
|
||||||
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
|
||||||
|
sym = process_key_press(sym, input);
|
||||||
|
|
||||||
(*window->key_handler)(window, input, time, key,
|
(*window->key_handler)(window, input, time, key,
|
||||||
sym, state, window->user_data);
|
sym, state, window->user_data);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user