[PATCH weston] clients: Add compose key support for weston clients (wip)

Bryce Harrington bryce at osg.samsung.com
Fri Oct 7 04:17:06 UTC 2016


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 ¥.

The actual symbols available will depend on what the system makes
available in its default compose sequence tables.  Most systems provide
hundreds of symbols.

Since libxkbcommon transparently handles loading of the user's
~/.XCompose file, the user can customize and extend the compose
sequences in that file, beyond what the system provides by default.

Note this only permits insertion of single-symbol compose strings; while
libxkbcommon is able to handle translating multi-symbol compose strings
to the corresponding char* strings for the client, weston's client.c
does not currently have a mechanism for passing text buffers to the
clients, only individual symbols, so this feature will need to be left
for future work.

Previously, there was a limited compose functionality provided by the
weston-simple-im input method, however it only provided 18 compose key
sequences, and no mechanism to add more other than modifying source
code.  Further, it was only available when using that specific input
method and using a client like weston-editor that supports the
zwp_input_method protocol.

Notably, this enables compose key functionality in weston-terminal,
allowing entry of, for example, French letter symbols like è, á, ï, ê,
et al.  weston-eventdemo will also register the composed symbols if
entered, as should any other client that uses Weston's window.* routines
for accepting and managing keyboard input.

Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=53648
Signed-off-by: Bryce Harrington <bryce at osg.samsung.com>
---
 clients/window.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 66 insertions(+), 9 deletions(-)

diff --git a/clients/window.c b/clients/window.c
index 216ef96..f38b15a 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -63,6 +63,7 @@ typedef void *EGLContext;
 #endif /* no HAVE_CAIRO_EGL */
 
 #include <xkbcommon/xkbcommon.h>
+#include <xkbcommon/xkbcommon-compose.h>
 #include <wayland-cursor.h>
 
 #include <linux/input.h>
@@ -372,6 +373,8 @@ struct input {
 	struct {
 		struct xkb_keymap *keymap;
 		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 alt_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 xkb_keymap *keymap;
 	struct xkb_state *state;
+	struct xkb_compose_table *compose_table;
+	struct xkb_compose_state *compose_state;
+	char *locale;
 	char *map_str;
 
 	if (!data) {
@@ -2997,6 +3003,7 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
 		return;
 	}
 
+	/* Set up XKB keymap */
 	keymap = xkb_keymap_new_from_string(input->display->xkb_context,
 					    map_str,
 					    XKB_KEYMAP_FORMAT_TEXT_V1,
@@ -3009,6 +3016,7 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
 		return;
 	}
 
+	/* Set up XKB state */
 	state = xkb_state_new(keymap);
 	if (!state) {
 		fprintf(stderr, "failed to create XKB state\n");
@@ -3016,8 +3024,38 @@ keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
 		return;
 	}
 
+	/* Look up the appropriate locale, or use "C" as default */
+	locale = getenv("LC_ALL");
+	if (!locale)
+		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) {
+		fprintf(stderr, "could not create XKB compose table for locale '%s'\n", locale);
+		xkb_state_unref(state);
+		xkb_keymap_unref(keymap);
+		return;
+	}
+
+	/* Set up XKB compose state */
+	compose_state = xkb_compose_state_new(compose_table,
+					      XKB_COMPOSE_STATE_NO_FLAGS);
+	if (!compose_state) {
+		fprintf(stderr, "could not create XKB compose state\n");
+		xkb_compose_table_unref(compose_table);
+		xkb_state_unref(state);
+		xkb_keymap_unref(keymap);
+	}
+
+	xkb_compose_state_unref(input->xkb.compose_state);
+	xkb_compose_table_unref(input->xkb.compose_table);
 	xkb_keymap_unref(input->xkb.keymap);
 	xkb_state_unref(input->xkb.state);
+	input->xkb.compose_state = compose_state;
+	input->xkb.compose_table = compose_table;
 	input->xkb.keymap = keymap;
 	input->xkb.state = state;
 
@@ -3101,6 +3139,25 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
 		   state == WL_KEYBOARD_KEY_STATE_PRESSED) {
 		window_close(window);
 	} else if (window->key_handler) {
+		if ((sym != XKB_KEY_NoSymbol) &&
+		    (state == WL_KEYBOARD_KEY_STATE_PRESSED) &&
+		    (xkb_compose_state_feed(input->xkb.compose_state, sym) == XKB_COMPOSE_FEED_ACCEPTED)) {
+			switch (xkb_compose_state_get_status(input->xkb.compose_state))
+			{
+			case XKB_COMPOSE_COMPOSING:
+				sym = XKB_KEY_NoSymbol;
+				break;
+
+			case XKB_COMPOSE_COMPOSED:
+				sym = xkb_compose_state_get_one_sym(input->xkb.compose_state);
+				break;
+
+			case XKB_COMPOSE_CANCELLED:
+			case XKB_COMPOSE_NOTHING:
+				break;
+			}
+		}
+
 		(*window->key_handler)(window, input, time, key,
 				       sym, state, window->user_data);
 	}
@@ -5726,10 +5783,10 @@ output_get_allocation(struct output *output, struct rectangle *base)
 	case WL_OUTPUT_TRANSFORM_270:
 	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
 	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
-	        /* Swap width and height */
-	        allocation.width = output->allocation.height;
-	        allocation.height = output->allocation.width;
-	        break;
+		/* Swap width and height */
+		allocation.width = output->allocation.height;
+		allocation.height = output->allocation.width;
+		break;
 	}
 
 	*base = allocation;
-- 
1.9.1



More information about the wayland-devel mailing list