* DEALINGS IN THE SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include "xkbcommon/xkbcommon.h"
#include "utils.h"
#include "keysym.h"
#include "ks_tables.h"
-static int
-compare_by_keysym(const void *a, const void *b)
-{
- const struct name_keysym *key = a, *entry = b;
- return key->keysym - (int32_t)entry->keysym;
-}
-
-static int
-compare_by_name(const void *a, const void *b)
+static inline const char *
+get_name(const struct name_keysym *entry)
{
- const struct name_keysym *key = a, *entry = b;
- return strcasecmp(key->name, entry->name);
+ return keysym_names + entry->offset;
}
XKB_EXPORT int
xkb_keysym_get_name(xkb_keysym_t ks, char *buffer, size_t size)
{
- const struct name_keysym search = { .name = NULL, .keysym = ks };
- const struct name_keysym *entry;
-
if ((ks & ((unsigned long) ~0x1fffffff)) != 0) {
snprintf(buffer, size, "Invalid");
return -1;
}
- entry = bsearch(&search, keysym_to_name,
- ARRAY_SIZE(keysym_to_name),
- sizeof(*keysym_to_name),
- compare_by_keysym);
- if (entry)
- return snprintf(buffer, size, "%s", entry->name);
+ size_t lo = 0, hi = ARRAY_SIZE(keysym_to_name) - 1;
+ while (hi >= lo) {
+ size_t mid = (lo + hi) / 2;
+ if (ks > keysym_to_name[mid].keysym) {
+ lo = mid + 1;
+ } else if (ks < keysym_to_name[mid].keysym) {
+ hi = mid - 1;
+ } else {
+ return snprintf(buffer, size, "%s", get_name(&keysym_to_name[mid]));
+ }
+ }
/* Unnamed Unicode codepoint. */
if (ks >= 0x01000100 && ks <= 0x0110ffff) {
/*
* Find the correct keysym if one case-insensitive match is given.
*
- * The name_to_keysym table is sorted by strcasecmp(). So bsearch() may return
+ * The name_to_keysym table is sorted by istrcmp(). So the binary search may return
* _any_ of all possible case-insensitive duplicates. This function searches the
* returned entry @entry, all previous and all next entries that match by
* case-insensitive comparison and returns the exact match to @name. If @icase
if (!entry)
return NULL;
- if (!icase && strcmp(entry->name, name) == 0)
+ if (!icase && strcmp(get_name(entry), name) == 0)
return entry;
if (icase && xkb_keysym_is_lower(entry->keysym))
return entry;
for (iter = entry - 1; iter >= name_to_keysym; --iter) {
- if (!icase && strcmp(iter->name, name) == 0)
+ if (!icase && strcmp(get_name(iter), name) == 0)
return iter;
- if (strcasecmp(iter->name, entry->name) != 0)
+ if (istrcmp(get_name(iter), get_name(entry)) != 0)
break;
if (icase && xkb_keysym_is_lower(iter->keysym))
return iter;
}
last = name_to_keysym + len;
- for (iter = entry + 1; iter < last; --iter) {
- if (!icase && strcmp(iter->name, name) == 0)
+ for (iter = entry + 1; iter < last; ++iter) {
+ if (!icase && strcmp(get_name(iter), name) == 0)
return iter;
- if (strcasecmp(iter->name, entry->name) != 0)
+ if (istrcmp(get_name(iter), get_name(entry)) != 0)
break;
if (icase && xkb_keysym_is_lower(iter->keysym))
return iter;
}
XKB_EXPORT xkb_keysym_t
-xkb_keysym_from_name(const char *s, enum xkb_keysym_flags flags)
+xkb_keysym_from_name(const char *name, enum xkb_keysym_flags flags)
{
- const struct name_keysym search = { .name = s, .keysym = 0 };
- const struct name_keysym *entry;
+ const struct name_keysym *entry = NULL;
char *tmp;
xkb_keysym_t val;
- bool icase = !!(flags & XKB_KEYSYM_CASE_INSENSITIVE);
+ bool icase = (flags & XKB_KEYSYM_CASE_INSENSITIVE);
if (flags & ~XKB_KEYSYM_CASE_INSENSITIVE)
return XKB_KEY_NoSymbol;
- entry = bsearch(&search, name_to_keysym,
- ARRAY_SIZE(name_to_keysym),
- sizeof(*name_to_keysym),
- compare_by_name);
- entry = find_sym(entry, s, icase);
+ size_t lo = 0, hi = ARRAY_SIZE(name_to_keysym) - 1;
+ while (hi >= lo) {
+ size_t mid = (lo + hi) / 2;
+ int cmp = istrcmp(name, get_name(&name_to_keysym[mid]));
+ if (cmp > 0) {
+ lo = mid + 1;
+ } else if (cmp < 0) {
+ hi = mid - 1;
+ } else {
+ entry = &name_to_keysym[mid];
+ break;
+ }
+ }
+ entry = find_sym(entry, name, icase);
if (entry)
return entry->keysym;
- if (*s == 'U' || (icase && *s == 'u')) {
- val = strtoul(&s[1], &tmp, 16);
+ if (*name == 'U' || (icase && *name == 'u')) {
+ val = strtoul(&name[1], &tmp, 16);
if (tmp && *tmp != '\0')
return XKB_KEY_NoSymbol;
return XKB_KEY_NoSymbol;
return val | 0x01000000;
}
- else if (s[0] == '0' && (s[1] == 'x' || (icase && s[1] == 'X'))) {
- val = strtoul(&s[2], &tmp, 16);
+ else if (name[0] == '0' && (name[1] == 'x' || (icase && name[1] == 'X'))) {
+ val = strtoul(&name[2], &tmp, 16);
if (tmp && *tmp != '\0')
return XKB_KEY_NoSymbol;
/* Stupid inconsistency between the headers and XKeysymDB: the former has
* no separating underscore, while some XF86* syms in the latter did.
* As a last ditch effort, try without. */
- if (strncmp(s, "XF86_", 5) == 0 ||
- (icase && strncasecmp(s, "XF86_", 5) == 0)) {
+ if (strncmp(name, "XF86_", 5) == 0 ||
+ (icase && istrncmp(name, "XF86_", 5) == 0)) {
xkb_keysym_t ret;
- tmp = strdup(s);
+ tmp = strdup(name);
if (!tmp)
return XKB_KEY_NoSymbol;
- memmove(&tmp[4], &tmp[5], strlen(s) - 5 + 1);
+ memmove(&tmp[4], &tmp[5], strlen(name) - 5 + 1);
ret = xkb_keysym_from_name(tmp, flags);
free(tmp);
return ret;
return keysym >= XKB_KEY_KP_Space && keysym <= XKB_KEY_KP_Equal;
}
+
+bool
+xkb_keysym_is_modifier(xkb_keysym_t keysym)
+{
+ return
+ (keysym >= XKB_KEY_Shift_L && keysym <= XKB_KEY_Hyper_R) ||
+ /* libX11 only goes upto XKB_KEY_ISO_Level5_Lock. */
+ (keysym >= XKB_KEY_ISO_Lock && keysym <= XKB_KEY_ISO_Last_Group_Lock) ||
+ keysym == XKB_KEY_Mode_switch ||
+ keysym == XKB_KEY_Num_Lock;
+}
+
static void
XConvertCase(xkb_keysym_t sym, xkb_keysym_t *lower, xkb_keysym_t *upper);
return (ks == upper ? true : false);
}
+XKB_EXPORT xkb_keysym_t
+xkb_keysym_to_lower(xkb_keysym_t ks)
+{
+ xkb_keysym_t lower, upper;
+
+ XConvertCase(ks, &lower, &upper);
+
+ return lower;
+}
+
+XKB_EXPORT xkb_keysym_t
+xkb_keysym_to_upper(xkb_keysym_t ks)
+{
+ xkb_keysym_t lower, upper;
+
+ XConvertCase(ks, &lower, &upper);
+
+ return upper;
+}
+
/*
* The following is copied verbatim from libX11:src/KeyBind.c, commit
* d45b3fc19fbe95c41afc4e51d768df6d42332010, with the following changes:
*upper = 0x0178;
else if (code == 0x00b5) /* micro sign */
*upper = 0x039c;
+ else if (code == 0x00df) /* ssharp */
+ *upper = 0x1e9e;
return;
}
}
else if (code == 0x1e9b)
*upper = 0x1e60;
+ else if (code == 0x1e9e)
+ *lower = 0x00df; /* ssharp */
}
/* Greek Extended, U+1F00 to U+1FFF */