From 4db998fdf2f68f3b433e678294e41a49288a4832 Mon Sep 17 00:00:00 2001 From: Kazunobu Kuriyama Date: Sun, 18 Oct 2015 05:20:52 +0900 Subject: [PATCH] Accept keysym/unicode symbols on keys This is an enhancement to make non-ASCII symbol keys usable for implementation and configuration of Awesome. The enhancement was proposed and had been developed under the initiative of Daniel Hahler. Thanks to his sharing of his results with our community, we gradually deepened our understanding on the issue. This commit is the fruit his enthusiasm spawned. Closes https://github.com/awesomeWM/awesome/pull/538. --- objects/key.c | 132 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 106 insertions(+), 26 deletions(-) diff --git a/objects/key.c b/objects/key.c index dc847a7af..7c8c154af 100644 --- a/objects/key.c +++ b/objects/key.c @@ -42,6 +42,7 @@ /* XStringToKeysym() and XKeysymToString */ #include #include +#include /** Key object. * @@ -64,28 +65,80 @@ static void luaA_keystore(lua_State *L, int ud, const char *str, ssize_t len) { + if(len <= 0 || !str) + return; + keyb_t *key = luaA_checkudata(L, ud, &key_class); - if(len) + + if(len == 1) { - if(*str != '#') - { - key->keysym = XStringToKeysym(str); - if(!key->keysym) - { - if(len == 1) - key->keysym = *str; - else - warn("there's no keysym named \"%s\"", str); - } - key->keycode = 0; - } - else - { - key->keycode = atoi(str + 1); - key->keysym = 0; - } - luaA_object_emit_signal(L, ud, "property::key", 0); + key->keycode = 0; + key->keysym = str[0]; } + else if(str[0] == '#') + { + key->keycode = atoi(str + 1); + key->keysym = 0; + } + else + { + key->keycode = 0; + + if((key->keysym = XStringToKeysym(str)) == NoSymbol ) + { + glong length; + gunichar unicode; + + if(!g_utf8_validate(str, -1, NULL)) + { + warn("failed to convert \"%s\" into keysym (invalid UTF-8 string)", str); + return; + } + + length = g_utf8_strlen(str, -1); /* This function counts combining characters. */ + if(length <= 0) + { + warn("failed to convert \"%s\" into keysym (empty UTF-8 string)", str); + return; + } + else if(length > 1) + { + gchar *composed = g_utf8_normalize(str, -1, G_NORMALIZE_DEFAULT_COMPOSE); + if(g_utf8_strlen(composed, -1) != 1) + { + p_delete(&composed); + warn("failed to convert \"%s\" into keysym (failed to compose a single character)", str); + return; + } + unicode = g_utf8_get_char(composed); + p_delete(&composed); + } + else + unicode = g_utf8_get_char(str); + + if(unicode == (gunichar)-1 || unicode == (gunichar)-2) + { + warn("failed to convert \"%s\" into keysym (neither keysym nor single unicode)", str); + return; + } + + /* Unicode-to-Keysym Conversion + * + * http://www.x.org/releases/X11R7.7/doc/xproto/x11protocol.html#keysym_encoding + */ + if(unicode <= 0x0ff) + key->keysym = unicode; + else if(unicode >= 0x100 && unicode <= 0x10ffff) + key->keysym = unicode | (1 << 24); + else + { + warn("failed to convert \"%s\" into keysym (unicode out of range): \"%u\"", str, unicode); + return; + } + } + } + + luaA_object_emit_signal(L, ud, "property::key", 0); } /** Create a new key object. @@ -196,6 +249,31 @@ luaA_key_set_modifiers(lua_State *L, keyb_t *k) LUA_OBJECT_EXPORT_PROPERTY(key, keyb_t, modifiers, luaA_pushmodifiers) +/* It's caller's responsibility to release the returned string. */ +static char * +get_keysym_name(xkb_keysym_t keysym) +{ + const ssize_t bufsize = 64; + char *buf = p_new(char, bufsize); + ssize_t len; + + if((len = xkb_keysym_get_name(keysym, buf, bufsize)) == -1) + { + p_delete(&buf); + return NULL; + } + if(len + 1 > bufsize) + { + p_realloc(&buf, len + 1); + if(xkb_keysym_get_name(keysym, buf, len + 1) != len) + { + p_delete(&buf); + return NULL; + } + } + return buf; +} + static int luaA_key_get_key(lua_State *L, keyb_t *k) { @@ -207,13 +285,11 @@ luaA_key_get_key(lua_State *L, keyb_t *k) } else { - char buf[MAX(MB_LEN_MAX, 32)]; - - if (xkb_keysym_get_name(k->keysym, buf, countof(buf)) < 0) { + char *name = get_keysym_name(k->keysym); + if(!name) return 0; - } - - lua_pushstring(L, buf); + lua_pushstring(L, name); + p_delete(&name); } return 1; } @@ -221,7 +297,11 @@ luaA_key_get_key(lua_State *L, keyb_t *k) static int luaA_key_get_keysym(lua_State *L, keyb_t *k) { - lua_pushstring(L, XKeysymToString(k->keysym)); + char *name = get_keysym_name(k->keysym); + if(!name) + return 0; + lua_pushstring(L, name); + p_delete(&name); return 1; }