#include "../config.h"
#include "rxvt.h"
-#include "keyboard.h"
-#include "command.h"
-#include <string.h>
-#include <X11/X.h>
#ifdef KEYSYM_RESOURCE
+#include <cstring>
+
+#include "keyboard.h"
+#include "command.h"
+
////////////////////////////////////////////////////////////////////////////////
// default keycode translation map and keyevent handlers
keysym_t keyboard_manager::stock_keymap[] = {
/* examples */
- /* keysym, state, range, handler, str */
-//{XK_ISO_Left_Tab, 0, 1, NORMAL, "\033[Z"},
-//{ 'a', 0, 26, RANGE_META8, "a" "%c"},
-//{ 'a', ControlMask, 26, RANGE_META8, "\ 1" "%c"},
-//{ XK_Left, 0, 4, LIST, "DACBZ" "\033[Z"},
-//{ XK_Left, ShiftMask, 4, LIST, "dacbZ" "\033[Z"},
-//{ XK_Left, ControlMask, 4, LIST, "dacbZ" "\033OZ"},
-//{ XK_Tab, ControlMask, 1, NORMAL, "\033<C-Tab>"},
-//{ XK_apostrophe, ControlMask, 1, NORMAL, "\033<C-'>"},
-//{ XK_slash, ControlMask, 1, NORMAL, "\033<C-/>"},
-//{ XK_semicolon, ControlMask, 1, NORMAL, "\033<C-;>"},
-//{ XK_grave, ControlMask, 1, NORMAL, "\033<C-`>"},
-//{ XK_comma, ControlMask, 1, NORMAL, "\033<C-\054>"},
-//{ XK_Return, ControlMask, 1, NORMAL, "\033<C-Return>"},
-//{ XK_Return, ShiftMask, 1, NORMAL, "\033<S-Return>"},
-//{ ' ', ShiftMask, 1, NORMAL, "\033<S-Space>"},
-//{ '.', ControlMask, 1, NORMAL, "\033<C-.>"},
-//{ '0', ControlMask, 10, RANGE, "0" "\033<C-%c>"},
-//{ '0', MetaMask|ControlMask, 10, RANGE, "0" "\033<M-C-%c>"},
-//{ 'a', MetaMask|ControlMask, 26, RANGE, "a" "\033<M-C-%c>"},
+ /* keysym, state, range, handler, str */
+//{XK_ISO_Left_Tab, 0, 1, keysym_t::NORMAL, "\033[Z"},
+//{ 'a', 0, 26, keysym_t::RANGE_META8, "a" "%c"},
+//{ 'a', ControlMask, 26, keysym_t::RANGE_META8, "\ 1" "%c"},
+//{ XK_Left, 0, 4, keysym_t::LIST, ".\033[.DACB."},
+//{ XK_Left, ShiftMask, 4, keysym_t::LIST, ".\033[.dacb."},
+//{ XK_Left, ControlMask, 4, keysym_t::LIST, ".\033O.dacb."},
+//{ XK_Tab, ControlMask, 1, keysym_t::NORMAL, "\033<C-Tab>"},
+//{ XK_apostrophe, ControlMask, 1, keysym_t::NORMAL, "\033<C-'>"},
+//{ XK_slash, ControlMask, 1, keysym_t::NORMAL, "\033<C-/>"},
+//{ XK_semicolon, ControlMask, 1, keysym_t::NORMAL, "\033<C-;>"},
+//{ XK_grave, ControlMask, 1, keysym_t::NORMAL, "\033<C-`>"},
+//{ XK_comma, ControlMask, 1, keysym_t::NORMAL, "\033<C-\054>"},
+//{ XK_Return, ControlMask, 1, keysym_t::NORMAL, "\033<C-Return>"},
+//{ XK_Return, ShiftMask, 1, keysym_t::NORMAL, "\033<S-Return>"},
+//{ ' ', ShiftMask, 1, keysym_t::NORMAL, "\033<S-Space>"},
+//{ '.', ControlMask, 1, keysym_t::NORMAL, "\033<C-.>"},
+//{ '0', ControlMask, 10, keysym_t::RANGE, "0" "\033<C-%c>"},
+//{ '0', MetaMask|ControlMask, 10, keysym_t::RANGE, "0" "\033<M-C-%c>"},
+//{ 'a', MetaMask|ControlMask, 26, keysym_t::RANGE, "a" "\033<M-C-%c>"},
};
static void
output_string (rxvt_term *rt, const char *str)
{
- assert (rt && str);
-
- if (strncmp (str, "proto:", 6) == 0)
- rt->cmd_write ((unsigned char *)str + 6, strlen (str) - 6);
+ if (strncmp (str, "command:", 8) == 0)
+ rt->cmd_write ((unsigned char *)str + 8, strlen (str) - 8);
else
rt->tt_write ((unsigned char *)str, strlen (str));
}
else if (rt->meta_char == C0_ESC) /* escape prefix */
#endif
{
- const unsigned char
- ch = C0_ESC;
+ const unsigned char ch = C0_ESC;
rt->tt_write (&ch, 1);
}
}
static int
format_keyrange_string (const char *str, int keysym_offset, char *buf, int bufsize)
{
- int len = snprintf (buf, bufsize, str + 1, keysym_offset + str [0]);
+ size_t len = snprintf (buf, bufsize, str + 1, keysym_offset + str [0]);
- if (len >= bufsize)
+ if (len >= (size_t)bufsize)
{
- fprintf (stderr, "buffer overflowed!\n");
- buf[bufsize - 1] = '\0';
- }
- else if (len < 0)
- {
- perror ("keyrange_translator()");
+ rxvt_warn ("format_keyrange_string: formatting failed, ignoring key.\n");
+ *buf = 0;
}
return len;
////////////////////////////////////////////////////////////////////////////////
// return: #bits of '1'
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3)
+# define bitcount(n) (__extension__ ({ uint32_t n__ = (n); __builtin_popcount (n); }))
+#else
static int
-bitcount (unsigned int n)
+bitcount (uint16_t n)
{
int i;
- for (i = 0; n; ++i, n &= (n - 1))
+ for (i = 0; n; ++i, n &= n - 1)
;
return i;
}
+#endif
// return: priority_of_a - priority_of_b
static int
compare_priority (keysym_t *a, keysym_t *b)
{
- assert (a && b);
-
// (the more '1's in state; the less range): the greater priority
int ca = bitcount (a->state /* & OtherModMask */);
int cb = bitcount (b->state /* & OtherModMask */);
keyboard_manager::keyboard_manager ()
{
keymap.reserve (256);
- hash[0] = 1; // hash[0] != 0 indicates uninitialized data
+ hash [0] = 1; // hash[0] != 0 indicates uninitialized data
}
keyboard_manager::~keyboard_manager ()
void
keyboard_manager::register_user_translation (KeySym keysym, unsigned int state, const char *trans)
{
- assert (trans);
-
keysym_t *key = new keysym_t;
wchar_t *wc = rxvt_mbstowcs (trans);
const char *translation = rxvt_wcstoutf8 (wc);
strcpy (translation, translation + 4);
}
else
- {
- key->range = 1;
- rxvt_warn ("cannot parse list-type keysym '%s', treating as normal keysym.\n", translation);
- }
+ rxvt_warn ("cannot parse list-type keysym '%s', treating as normal keysym.\n", translation);
}
- else
user_keymap.push_back (key);
user_translations.push_back (translation);
void
keyboard_manager::register_keymap (keysym_t *key)
{
- assert (key);
- assert (key->range >= 1);
-
if (keymap.size () == keymap.capacity ())
keymap.reserve (keymap.size () * 2);
{
assert (hash[0] == 0 && "register_done() need to be called");
- if (state & term->ModMetaMask)
- state |= MetaMask;
-
- if (state & term->ModNumLockMask)
- state |= NumLockMask;
+ if (state & term->ModMetaMask) state |= MetaMask;
+ if (state & term->ModNumLockMask) state |= NumLockMask;
+ if (state & term->ModLevel3Mask) state |= Level3Mask;
if (!!(term->priv_modes & PrivMode_aplKP) != !!(state & ShiftMask))
state |= AppKeypadMask;
if (index >= 0)
{
- assert (term && keymap [index]);
const keysym_t &key = *keymap [index];
int keysym_offset = keysym - key.keysym;
wchar_t *wc = rxvt_utf8towcs (key.str);
char *str = rxvt_wcstombs (wc);
- // TODO: do translations, unescaping etc, here (allow \u escape etc.)
+ // TODO: do (some) translations, unescaping etc, here (allow \u escape etc.)
free (wc);
switch (key.type)
return true;
}
else
- {
- // fprintf(stderr,"[%x:%x]",state,keysym);
- return false;
- }
+ return false;
}
// purge duplicate keymap entries
{
for (unsigned int j = 0; j < i; ++j)
{
- if (keymap[i] == keymap[j])
+ if (keymap [i] == keymap [j])
{
- while (keymap[i] == keymap.back ())
+ while (keymap [i] == keymap.back ())
keymap.pop_back ();
if (i < keymap.size ())
keymap[i] = keymap.back ();
keymap.pop_back ();
}
+
break;
}
}
memset (hash_budget_size, 0, sizeof (hash_budget_size));
memset (hash_budget_counter, 0, sizeof (hash_budget_counter));
- // count keysyms for corresponding hash budgets
+ // determine hash bucket size
for (i = 0; i < keymap.size (); ++i)
- {
- assert (keymap[i]);
- hashkey = (keymap[i]->keysym & KEYSYM_HASH_MASK);
- ++hash_budget_size[hashkey];
- }
-
- // keysym A with range>1 is counted one more time for
- // every keysym B lies in its range
- for (i = 0; i < keymap.size (); ++i)
- {
- if (keymap[i]->range > 1)
- {
- for (int j = min (keymap[i]->range, KEYSYM_HASH_BUDGETS) - 1; j > 0; --j)
- {
- hashkey = ((keymap[i]->keysym + j) & KEYSYM_HASH_MASK);
- if (hash_budget_size[hashkey])
- ++hash_budget_size[hashkey];
- }
- }
- }
+ for (int j = min (keymap [i]->range, KEYSYM_HASH_BUDGETS) - 1; j >= 0; --j)
+ {
+ hashkey = (keymap [i]->keysym + j) & KEYSYM_HASH_MASK;
+ ++hash_budget_size [hashkey];
+ }
// now we know the size of each budget
// compute the index of each budget
- hash[0] = 0;
+ hash [0] = 0;
for (index = 0, i = 1; i < KEYSYM_HASH_BUDGETS; ++i)
{
- index += hash_budget_size[i - 1];
- hash[i] = (hash_budget_size[i] ? index : hash[i - 1]);
+ index += hash_budget_size [i - 1];
+ hash [i] = index;
}
// and allocate just enough space
- //sorted_keymap.reserve (hash[i - 1] + hash_budget_size[i - 1]);
- sorted_keymap.insert (sorted_keymap.begin (), index + hash_budget_size[i - 1], 0);
+ sorted_keymap.insert (sorted_keymap.begin (), index + hash_budget_size [i - 1], 0);
// fill in sorted_keymap
// it is sorted in each budget
for (i = 0; i < keymap.size (); ++i)
- {
- for (int j = min (keymap[i]->range, KEYSYM_HASH_BUDGETS) - 1; j >= 0; --j)
- {
- hashkey = ((keymap[i]->keysym + j) & KEYSYM_HASH_MASK);
+ for (int j = min (keymap [i]->range, KEYSYM_HASH_BUDGETS) - 1; j >= 0; --j)
+ {
+ hashkey = (keymap [i]->keysym + j) & KEYSYM_HASH_MASK;
- if (hash_budget_size[hashkey])
- {
- index = hash[hashkey] + hash_budget_counter[hashkey];
+ index = hash [hashkey] + hash_budget_counter [hashkey];
- while (index > hash[hashkey]
- && compare_priority (keymap[i], sorted_keymap[index - 1]) > 0)
- {
- sorted_keymap[index] = sorted_keymap[index - 1];
- --index;
- }
+ while (index > hash [hashkey]
+ && compare_priority (keymap [i], sorted_keymap [index - 1]) > 0)
+ {
+ sorted_keymap [index] = sorted_keymap [index - 1];
+ --index;
+ }
- sorted_keymap[index] = keymap[i];
- ++hash_budget_counter[hashkey];
- }
- }
- }
+ sorted_keymap [index] = keymap [i];
+ ++hash_budget_counter [hashkey];
+ }
keymap.swap (sorted_keymap);
for (i = 0; i < KEYSYM_HASH_BUDGETS; ++i)
{
index = hash[i];
- for (int j = 0; j < hash_budget_size[i]; ++j)
+ for (int j = 0; j < hash_budget_size [i]; ++j)
{
- if (keymap[index + j]->range == 1)
- assert (i == (keymap[index + j]->keysym & KEYSYM_HASH_MASK));
+ if (keymap [index + j]->range == 1)
+ assert (i == (keymap [index + j]->keysym & KEYSYM_HASH_MASK));
if (j)
- assert (compare_priority (keymap[index + j - 1],
- keymap[index + j]) >= 0);
+ assert (compare_priority (keymap [index + j - 1],
+ keymap [index + j]) >= 0);
}
}
keysym_t *a = sorted_keymap[i];
for (int j = 0; j < a->range; ++j)
{
- int index = find_keysym (a->keysym + j, a->state & OtherModMask);
+ int index = find_keysym (a->keysym + j, a->state);
+
assert (index >= 0);
- keysym_t *b = keymap[index];
+ keysym_t *b = keymap [index];
assert (i == (signed) index || // the normally expected result
- (a->keysym + j) >= b->keysym && (a->keysym + j) <= (b->keysym + b->range) && compare_priority (a, b) <= 0); // is effectively the same
+ (a->keysym + j) >= b->keysym && (a->keysym + j) <= (b->keysym + b->range) && compare_priority (a, b) <= 0); // is effectively the same or a closer match
}
}
#endif
{
int hashkey = keysym & KEYSYM_HASH_MASK;
unsigned int index = hash [hashkey];
+ unsigned int end = hashkey < KEYSYM_HASH_BUDGETS - 1
+ ? hash [hashkey + 1]
+ : keymap.size ();
- for (; index < keymap.size (); ++index)
+ for (; index < end; ++index)
{
- keysym_t *key = keymap[index];
- assert (key);
+ keysym_t *key = keymap [index];
- if (key->keysym <= keysym && key->keysym + key->range > keysym
+ if (key->keysym <= keysym && keysym < key->keysym + key->range
// match only the specified bits in state and ignore others
- && (key->state & OtherModMask) == (key->state & state))
+ && (key->state & state) == key->state)
return index;
- else if (key->keysym > keysym && key->range == 1)
- return -1;
}
return -1;