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.
This commit is contained in:
Kazunobu Kuriyama 2015-10-18 05:20:52 +09:00 committed by Daniel Hahler
parent 035e905836
commit 4db998fdf2
1 changed files with 106 additions and 26 deletions

View File

@ -42,6 +42,7 @@
/* XStringToKeysym() and XKeysymToString */
#include <X11/Xlib.h>
#include <xkbcommon/xkbcommon.h>
#include <glib.h>
/** 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;
}