Wayland: Implement compose key for character input

This commit has been copied almost verbatim from Bryce Harrington’s
patch against Weston’s toytoolkit[1].  He gave his agreement to
relicense it under zlib[2].

[1] https://patchwork.freedesktop.org/patch/114661/
[2] https://github.com/glfw/glfw/pull/879#issuecomment-252988257
This commit is contained in:
Emmanuel Gil Peyrot 2016-10-11 00:02:15 +01:00 committed by linkmauve
parent efc6b35615
commit 046d281abc
2 changed files with 58 additions and 1 deletions

View File

@ -172,7 +172,10 @@ static void keyboardHandleKeymap(void* data,
{ {
struct xkb_keymap* keymap; struct xkb_keymap* keymap;
struct xkb_state* state; struct xkb_state* state;
struct xkb_compose_table* composeTable;
struct xkb_compose_state* composeState;
char* mapStr; char* mapStr;
const char* locale;
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
{ {
@ -209,6 +212,35 @@ static void keyboardHandleKeymap(void* data,
return; return;
} }
// 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";
composeTable =
xkb_compose_table_new_from_locale(_glfw.wl.xkb.context, locale,
XKB_COMPOSE_COMPILE_NO_FLAGS);
if (composeTable)
{
composeState =
xkb_compose_state_new(composeTable, XKB_COMPOSE_STATE_NO_FLAGS);
xkb_compose_table_unref(composeTable);
if (composeState)
_glfw.wl.xkb.composeState = composeState;
else
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to create XKB compose state");
}
else
{
_glfwInputError(GLFW_PLATFORM_ERROR,
"Wayland: Failed to create XKB compose table");
}
xkb_keymap_unref(_glfw.wl.xkb.keymap); xkb_keymap_unref(_glfw.wl.xkb.keymap);
xkb_state_unref(_glfw.wl.xkb.state); xkb_state_unref(_glfw.wl.xkb.state);
_glfw.wl.xkb.keymap = keymap; _glfw.wl.xkb.keymap = keymap;
@ -258,18 +290,40 @@ static int toGLFWKeyCode(uint32_t key)
return GLFW_KEY_UNKNOWN; return GLFW_KEY_UNKNOWN;
} }
static xkb_keysym_t composeSymbol(xkb_keysym_t sym)
{
if (sym == XKB_KEY_NoSymbol)
return sym;
if (xkb_compose_state_feed(_glfw.wl.xkb.composeState, sym)
!= XKB_COMPOSE_FEED_ACCEPTED)
return sym;
switch (xkb_compose_state_get_status(_glfw.wl.xkb.composeState))
{
case XKB_COMPOSE_COMPOSED:
return xkb_compose_state_get_one_sym(_glfw.wl.xkb.composeState);
case XKB_COMPOSE_COMPOSING:
case XKB_COMPOSE_CANCELLED:
return XKB_KEY_NoSymbol;
case XKB_COMPOSE_NOTHING:
default:
return sym;
}
}
static void inputChar(_GLFWwindow* window, uint32_t key) static void inputChar(_GLFWwindow* window, uint32_t key)
{ {
uint32_t code, numSyms; uint32_t code, numSyms;
long cp; long cp;
const xkb_keysym_t *syms; const xkb_keysym_t *syms;
xkb_keysym_t sym;
code = key + 8; code = key + 8;
numSyms = xkb_state_key_get_syms(_glfw.wl.xkb.state, code, &syms); numSyms = xkb_state_key_get_syms(_glfw.wl.xkb.state, code, &syms);
if (numSyms == 1) if (numSyms == 1)
{ {
cp = _glfwKeySym2Unicode(syms[0]); sym = composeSymbol(syms[0]);
cp = _glfwKeySym2Unicode(sym);
if (cp != -1) if (cp != -1)
{ {
const int mods = _glfw.wl.xkb.modifiers; const int mods = _glfw.wl.xkb.modifiers;
@ -645,6 +699,7 @@ void _glfwPlatformTerminate(void)
_glfwTerminateJoysticksLinux(); _glfwTerminateJoysticksLinux();
_glfwTerminateThreadLocalStoragePOSIX(); _glfwTerminateThreadLocalStoragePOSIX();
xkb_compose_state_unref(_glfw.wl.xkb.composeState);
xkb_keymap_unref(_glfw.wl.xkb.keymap); xkb_keymap_unref(_glfw.wl.xkb.keymap);
xkb_state_unref(_glfw.wl.xkb.state); xkb_state_unref(_glfw.wl.xkb.state);
xkb_context_unref(_glfw.wl.xkb.context); xkb_context_unref(_glfw.wl.xkb.context);

View File

@ -29,6 +29,7 @@
#include <wayland-client.h> #include <wayland-client.h>
#include <xkbcommon/xkbcommon.h> #include <xkbcommon/xkbcommon.h>
#include <xkbcommon/xkbcommon-compose.h>
#include <dlfcn.h> #include <dlfcn.h>
typedef VkFlags VkWaylandSurfaceCreateFlagsKHR; typedef VkFlags VkWaylandSurfaceCreateFlagsKHR;
@ -136,6 +137,7 @@ typedef struct _GLFWlibraryWayland
struct xkb_context* context; struct xkb_context* context;
struct xkb_keymap* keymap; struct xkb_keymap* keymap;
struct xkb_state* state; struct xkb_state* state;
struct xkb_compose_state* composeState;
xkb_mod_mask_t controlMask; xkb_mod_mask_t controlMask;
xkb_mod_mask_t altMask; xkb_mod_mask_t altMask;
xkb_mod_mask_t shiftMask; xkb_mod_mask_t shiftMask;