Skip to content

Commit

Permalink
build: Use libxkbcommon to resolve keysyms
Browse files Browse the repository at this point in the history
  • Loading branch information
ueno committed Aug 20, 2018
1 parent c15f2a2 commit 4eb2cad
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 85 deletions.
8 changes: 6 additions & 2 deletions configure.ac
Expand Up @@ -78,9 +78,13 @@ PKG_CHECK_MODULES([GEE], [gee-0.8], ,
PKG_CHECK_MODULES([JSON_GLIB], [json-glib-1.0], ,
[AC_MSG_ERROR([can't find json-glib-1.0])])

LIBSKK_CFLAGS="$GIO_CFLAGS $GEE_CFLAGS $JSON_GLIB_CFLAGS"
# check xkbcommon
PKG_CHECK_MODULES([XKBCOMMON], [xkbcommon], ,
[AC_MSG_ERROR([can't find xkbcommon])])

LIBSKK_CFLAGS="$GIO_CFLAGS $GEE_CFLAGS $JSON_GLIB_CFLAGS $XKBCOMMON_CFLAGS"
AC_SUBST(LIBSKK_CFLAGS)
LIBSKK_LIBS="$GIO_LIBS $GEE_LIBS $JSON_GLIB_LIBS"
LIBSKK_LIBS="$GIO_LIBS $GEE_LIBS $JSON_GLIB_LIBS $XKBCOMMON_LIBS"
AC_SUBST(LIBSKK_LIBS)

GOBJECT_INTROSPECTION_CHECK([0.9.0])
Expand Down
1 change: 1 addition & 0 deletions docs/Makefile.am
Expand Up @@ -62,6 +62,7 @@ libskk_doc_deps = \
gee-0.8 \
posix \
json-glib-1.0 \
xkbcommon \
$(NULL)
valadoc_flags_libskk = \
$(valadoc_flags) \
Expand Down
3 changes: 2 additions & 1 deletion libskk/Makefile.am
Expand Up @@ -31,6 +31,7 @@ libskk_la_VALAFLAGS = \
--pkg gee-0.8 \
--pkg posix \
--pkg json-glib-1.0 \
--pkg xkbcommon \
--internal-vapi skk-internals-@SKK_API_VERSION@.vapi \
--library skk-@SKK_API_VERSION@ \
--gir Skk-@SKK_API_VERSION@.gir \
Expand Down Expand Up @@ -112,6 +113,6 @@ pkgconfig_DATA = libskk.pc
vapi_DATA = skk-1.0.vapi skk-1.0.deps
vapidir = $(datadir)/vala/vapi

EXTRA_DIST = config.vapi skk-1.0.deps libskk.symbols
EXTRA_DIST = config.vapi skk-1.0.deps libskk.symbols xkbcommon.vapi

-include $(top_srcdir)/git.mk
144 changes: 66 additions & 78 deletions libskk/key-event.vala
Expand Up @@ -106,59 +106,96 @@ namespace Skk {
* @return a new KeyEvent
*/
public KeyEvent.from_string (string key) throws KeyEventFormatError {
if (key.has_prefix ("(") && key.has_suffix (")")) {
ModifierType _modifiers = 0;
uint _keyval = Keysyms.VoidSymbol;
if (key.has_prefix ("(usleep ") && key.has_suffix (")")) {
// special key event for SKK-NICOLA
var strv = key[1:-1].split (" ");
if (strv.length != 2) {
throw new KeyEventFormatError.PARSE_FAILED (
"usleep requires duration");
}
name = strv[1];
code = '\0';
modifiers |= ModifierType.USLEEP_MASK;
} else if (key.has_prefix ("(") && key.has_suffix (")")) {
var strv = key[1:-1].split (" ");
int index = 0;
for (; index < strv.length - 1; index++) {
if (strv[index] == "control") {
modifiers |= ModifierType.CONTROL_MASK;
if (strv[index] == "shift") {
_modifiers |= ModifierType.SHIFT_MASK;
} else if (strv[index] == "control") {
_modifiers |= ModifierType.CONTROL_MASK;
} else if (strv[index] == "meta") {
modifiers |= ModifierType.META_MASK;
_modifiers |= ModifierType.META_MASK;
} else if (strv[index] == "hyper") {
modifiers |= ModifierType.HYPER_MASK;
_modifiers |= ModifierType.HYPER_MASK;
} else if (strv[index] == "super") {
modifiers |= ModifierType.SUPER_MASK;
_modifiers |= ModifierType.SUPER_MASK;
} else if (strv[index] == "alt") {
modifiers |= ModifierType.MOD1_MASK;
_modifiers |= ModifierType.MOD1_MASK;
} else if (strv[index] == "lshift") {
modifiers |= ModifierType.LSHIFT_MASK;
_modifiers |= ModifierType.LSHIFT_MASK;
} else if (strv[index] == "rshift") {
modifiers |= ModifierType.RSHIFT_MASK;
} else if (strv[index] == "usleep") {
modifiers |= ModifierType.USLEEP_MASK;
_modifiers |= ModifierType.RSHIFT_MASK;
} else if (strv[index] == "release") {
modifiers |= ModifierType.RELEASE_MASK;
_modifiers |= ModifierType.RELEASE_MASK;
} else {
throw new KeyEventFormatError.PARSE_FAILED (
"unknown modifier %s", strv[index]);
}
}
name = strv[index];
code = name.char_count () == 1 ? name.get_char () : '\0';
}
else {
// special key event for SKK-NICOLA
if (strv[index] == "lshift" || strv[index] == "rshift") {
name = strv[index];
code = '\0';
modifiers = ModifierType.NONE;
} else {
_keyval = KeyEventUtils.keyval_from_name (strv[index]);
if (_keyval == Keysyms.VoidSymbol)
throw new KeyEventFormatError.PARSE_FAILED (
"unknown keyval %s", strv[index]);
name = KeyEventUtils.keyval_name (_keyval);
code = KeyEventUtils.keyval_unicode (_keyval);
modifiers = _modifiers;
}
} else if (key.has_prefix ("[") && key.has_suffix ("]") &&
key.char_count () == 4) {
// special double key press events (SKK-NICOLA extension)
name = key;
code = '\0';
modifiers = ModifierType.NONE;
} else {
int index = key.last_index_of ("-");
string? _name = null;
if (index > 0) {
// support only limited modifiers in this form
string[] mods = key.substring (0, index).split ("-");
foreach (var mod in mods) {
if (mod == "C") {
modifiers |= ModifierType.CONTROL_MASK;
if (mod == "S") {
_modifiers |= ModifierType.SHIFT_MASK;
} else if (mod == "C") {
_modifiers |= ModifierType.CONTROL_MASK;
} else if (mod == "A") {
modifiers |= ModifierType.MOD1_MASK;
_modifiers |= ModifierType.MOD1_MASK;
} else if (mod == "M") {
modifiers |= ModifierType.META_MASK;
_modifiers |= ModifierType.META_MASK;
} else if (mod == "G") {
modifiers |= ModifierType.MOD5_MASK;
_modifiers |= ModifierType.MOD5_MASK;
}
}
name = key.substring (index + 1);
code = name.char_count () == 1 ? name.get_char () : '\0';
_name = key.substring (index + 1);
} else {
modifiers = ModifierType.NONE;
name = key;
code = name.char_count () == 1 ? name.get_char () : '\0';
_modifiers = ModifierType.NONE;
_name = key;
}
_keyval = KeyEventUtils.keyval_from_name (_name);
if (_keyval == Keysyms.VoidSymbol)
throw new KeyEventFormatError.PARSE_FAILED (
"unknown keyval %s", _name);
name = KeyEventUtils.keyval_name (_keyval);
code = KeyEventUtils.keyval_unicode (_keyval);
modifiers = _modifiers;
}
}

Expand Down Expand Up @@ -215,37 +252,6 @@ namespace Skk {
}
}

// We can't use Entry<uint,*> here because of Vala bug:
// https://bugzilla.gnome.org/show_bug.cgi?id=684262
struct CodeKeyvalEntry {
uint key;
unichar value;
}

const CodeKeyvalEntry[] CODE_KEYVALS = {
{ Keysyms.Tab, '\t' },
{ Keysyms.Return, '\n' },
{ Keysyms.BackSpace, '\b' }
};

struct NameKeyvalEntry {
uint key;
string value;
}

const NameKeyvalEntry[] NAME_KEYVALS = {
{ Keysyms.Up, "Up" },
{ Keysyms.Down, "Down" },
{ Keysyms.Left, "Left" },
{ Keysyms.Right, "Right" },
{ Keysyms.Page_Up, "Page_Up" },
{ Keysyms.KP_Page_Up, "Page_Up" },
{ Keysyms.Page_Down, "Page_Down" },
{ Keysyms.KP_Page_Down, "Page_Down" },
{ Keysyms.Muhenkan, "lshift" },
{ Keysyms.Henkan, "rshift" }
};

/**
* Create a key event from an X keysym and modifiers.
*
Expand All @@ -256,27 +262,9 @@ namespace Skk {
*/
public KeyEvent.from_x_keysym (uint keyval,
ModifierType modifiers) throws KeyEventFormatError {
foreach (var entry in NAME_KEYVALS) {
if (entry.key == keyval) {
name = entry.value;
break;
}
}
foreach (var entry in CODE_KEYVALS) {
if (entry.key == keyval) {
code = entry.value;
break;
}
}
assert (name == null || code == '\0');
if (name == null && code == '\0') {
if (0x20 <= keyval && keyval < 0x7F) {
code = (unichar) keyval;
} else {
throw new KeyEventFormatError.KEYSYM_NOT_FOUND (
"unknown keysym %u", keyval);
}
}
name = KeyEventUtils.keyval_name (keyval);
code = KeyEventUtils.keyval_unicode (keyval);

this.modifiers = modifiers;
}

Expand Down
8 changes: 4 additions & 4 deletions libskk/nicola.vala
Expand Up @@ -91,11 +91,11 @@ namespace Skk {
}

static bool is_lshift (KeyEvent key) {
return key.name == "lshift";
return key.name == "lshift" || key.name == "Muhenkan";
}

static bool is_rshift (KeyEvent key) {
return key.name == "rshift";
return key.name == "rshift" || key.name == "Henkan";
}

static bool is_shift (KeyEvent key) {
Expand Down Expand Up @@ -180,9 +180,9 @@ namespace Skk {
}

void apply_shift (KeyEvent s, KeyEvent c) {
if (s.name == "lshift") {
if (is_lshift (s)) {
c.modifiers |= ModifierType.LSHIFT_MASK;
} else if (s.name == "rshift") {
} else if (is_rshift (s)) {
c.modifiers |= ModifierType.RSHIFT_MASK;
}
}
Expand Down
66 changes: 66 additions & 0 deletions libskk/util.vala
Expand Up @@ -494,4 +494,70 @@ namespace Skk {
_length = stat.st_size;
}
}

abstract class KeyEventUtils : Object {
public static string? keyval_name (uint keyval) {
uint8[] buffer = new uint8[64];
int ret = -1;

do {
ret = Xkb.keysym_get_name ((uint32) keyval, buffer);
if (ret == -1)
return null;
if (ret < buffer.length)
return (string) buffer;
buffer = new uint8[buffer.length * 2];
} while (ret >= buffer.length);

return null;
}

public static uint keyval_from_name (string name) {
// special cases for compatibilty with older libskk
if (name == " ")
name = "space";
else if (name == "\t")
name = "Tab";
else if (name == "\n")
name = "Return";
else if (name == "\b")
name = "BackSpace";

var keysym = Xkb.keysym_from_name (name, Xkb.KeysymFlags.NO_FLAGS);
if (keysym == Xkb.Keysym.NoSymbol) {
// handle ASCII keyvals with differnet name (e.g. at,
// percent, etc.)
if (name.char_count () == 1) {
unichar code = name.get_char ();
if (0x20 <= code && code < 0x7F)
return code;
}
return Keysyms.VoidSymbol;
}
return (uint) keysym;
}

public static unichar keyval_unicode (uint keyval) {
// handle ASCII keyvals with differnet name (e.g. at,
// percent, etc.)
if (0x20 <= keyval && keyval < 0x7F)
return keyval;

// special case
if (keyval == Keysyms.yen)
return "\xc2\xa5".get_char ();

uint8[] buffer = new uint8[8];
int ret = -1;

do {
ret = Xkb.keysym_to_utf8 ((uint32) keyval, buffer);
if (ret == 0)
return '\0';
buffer = new uint8[buffer.length * 2];
} while (ret == -1);

return '\0';
}
}
}
18 changes: 18 additions & 0 deletions libskk/xkbcommon.vapi
@@ -0,0 +1,18 @@
[CCode (cprefix = "xkb_", lower_case_cprefix = "xkb_", cheader_filename = "xkbcommon/xkbcommon.h")]
namespace Xkb
{
namespace Keysym {
[CCode (cname = "XKB_KEY_NoSymbol")]
public const uint32 NoSymbol;
}

public enum KeysymFlags {
[CCode (cname = "XKB_KEYSYM_NO_FLAGS")]
NO_FLAGS = 0,
CASE_INSENSITIVE = (1 << 0)
}

public int keysym_get_name(uint32 keysym, [CCode (array_length_cname = "size", array_length_pos = 2.1, array_length_type = "size_t")] uint8[] buffer);
public uint32 keysym_from_name(string name, KeysymFlags flags);
public int keysym_to_utf8(uint32 keysym, [CCode (array_length_cname = "size", array_length_pos = 2.1, array_length_type = "size_t")] uint8[] buffer);
}

0 comments on commit 4eb2cad

Please sign in to comment.