Use nested switch statements for key lookup

Replace giant key look up table with nested switch statements.
A little slower, but reduces memory consumption and makes it easier to
add new keyboard modes in the future, if needed. Key lookup was not a
performance bottleneck, in any case.
This commit is contained in:
Kovid Goyal 2017-11-07 20:53:18 +05:30
parent f3c99546d7
commit 204b6fa3e8
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 16176 additions and 32824 deletions

View File

@ -10,19 +10,14 @@
#include "screen.h"
#include <GLFW/glfw3.h>
const uint8_t*
const char*
key_to_bytes(int glfw_key, bool smkx, bool extended, int mods, int action) {
if ((action & 3) == 3) return NULL;
if ((unsigned)glfw_key >= sizeof(key_map)/sizeof(key_map[0]) || glfw_key < 0) return NULL;
uint16_t key = key_map[glfw_key];
if (key == UINT8_MAX) return NULL;
mods &= 0xF;
key |= (mods & 0xF) << 7;
key |= (action & 3) << 11;
key |= (smkx & 1) << 13;
key |= (extended & 1) << 14;
if (key >= SIZE_OF_KEY_BYTES_MAP) return NULL;
return key_bytes[key];
KeyboardMode mode = extended ? EXTENDED : (smkx ? APPLICATION : NORMAL);
return key_lookup(key, mode, mods, action);
}
#define SPECIAL_INDEX(key) ((key & 0x7f) | ( (mods & 0xF) << 7))
@ -166,8 +161,8 @@ on_key_input(int key, int scancode, int action, int mods) {
(action == GLFW_REPEAT && screen->modes.mDECARM) ||
screen->modes.mEXTENDED_KEYBOARD
) {
const uint8_t *data = key_to_bytes(lkey, screen->modes.mDECCKM, screen->modes.mEXTENDED_KEYBOARD, mods, action);
if (data) schedule_write_to_child(w->id, (char*)(data + 1), *data);
const char *data = key_to_bytes(lkey, screen->modes.mDECCKM, screen->modes.mEXTENDED_KEYBOARD, mods, action);
if (data) schedule_write_to_child(w->id, (data + 1), *data);
}
}
@ -178,7 +173,7 @@ on_key_input(int key, int scancode, int action, int mods) {
PYWRAP1(key_to_bytes) {
int glfw_key, smkx, extended, mods, action;
PA("ippii", &glfw_key, &smkx, &extended, &mods, &action);
const uint8_t *ans = key_to_bytes(glfw_key, smkx & 1, extended & 1, mods, action);
const char *ans = key_to_bytes(glfw_key, smkx & 1, extended & 1, mods, action);
if (ans == NULL) return Py_BuildValue("y#", "", 0);
return Py_BuildValue("y#", ans + 1, *ans);
}

48883
kitty/keys.h

File diff suppressed because it is too large Load Diff

View File

@ -263,46 +263,62 @@ def generate_key_table():
if k is not None:
w('case %d: return "%s";' % (i, key_name(k)))
w('default: return NULL; }}\n')
number_entries = 128 * 256
inits = []
longest = 0
for i in range(number_entries):
key = i & 0x7f # lowest seven bits
if key < key_count:
glfw_key = key_rmap[key]
k = keys.get(glfw_key)
else:
k = None
if k is None:
inits.append(None)
else:
mods = (i >> 7) & 0b1111
rest = i >> 11
action = rest & 0b11
if action == 0b11: # no such action
inits.append(None)
w('typedef enum { NORMAL, APPLICATION, EXTENDED } KeyboardMode;\n')
w('static inline const char*\nkey_lookup(uint8_t key, KeyboardMode mode, uint8_t mods, uint8_t action) {')
i = 1
def ind(*a):
w((' ' * i)[:-1], *a)
ind('switch(mode) {')
mmap = [(False, False), (True, False), (False, True)]
for (smkx, extended), mode in zip(mmap, 'NORMAL APPLICATION EXTENDED'.split()):
i += 1
ind('case {}:'.format(mode))
i += 1
ind('switch(action & 3) { case 3: return NULL; ')
for action in (defines.GLFW_RELEASE, defines.GLFW_PRESS, defines.GLFW_REPEAT):
i += 1
ind('case {}: // {}'.format(action, 'RELEASE PRESS REPEAT'.split()[action]))
i += 1
if action != defines.GLFW_RELEASE or mode == 'EXTENDED':
ind('switch (mods & 0xf) { ')
i += 1
for mods in range(16):
key_bytes = {}
for key in range(key_count):
glfw_key = key_rmap[key]
data = key_to_bytes(glfw_key, smkx, extended, mods, action)
if data:
key_bytes[key] = data, glfw_key
i += 1
ind('case 0x{:x}:'.format(mods))
i += 1
if key_bytes:
ind('switch(key & 0x7f) { default: return NULL;')
i += 1
for key, (data, glfw_key) in key_bytes.items():
ind('case {}: // {}'.format(key, key_name(keys[glfw_key])))
i += 1
items = bytearray(data)
items.insert(0, len(items))
ind('return "{}";'.format(''.join('\\x{:02x}'.format(x) for x in items)))
i -= 1
i -= 1
ind('} // end switch(key)')
else:
ind('return NULL;')
i -= 2
i -= 1
ind('} // end switch(mods)\n')
i -= 1
else:
smkx = bool(rest & 0b100)
extended = bool(rest & 0b1000)
data = key_to_bytes(glfw_key, smkx, extended, mods, action)
if data:
longest = max(len(data), longest)
inits.append((data, k, mods, smkx, extended))
else:
inits.append(None)
longest += 1
w('#define SIZE_OF_KEY_BYTES_MAP %d\n' % number_entries)
w('static const uint8_t key_bytes[%d][%d] = {' % (number_entries, longest))
# empty = '{' + ('0, ' * longest) + '},'
empty = '{0},'
all_mods = {k.rpartition('_')[2]: v for k, v in vars(defines).items() if k.startswith('GLFW_MOD_')}
all_mods = {k: v for k, v in sorted(all_mods.items(), key=lambda x: x[0])}
for b in inits:
if b is None:
w(empty)
else:
b, k, mods, smkx, extended = b
b = bytearray(b)
name = '+'.join([k for k, v in all_mods.items() if v & mods] + [key_name(k)])
w('{%d, ' % len(b) + ', '.join(map(hex, b)) + '}, //', name, 'smkx:', smkx, 'extended:', extended)
w('};')
ind('return NULL;\n')
i -= 1
i -= 1
ind('}} // end switch(action) in mode {}\n\n'.format(mode))
i -= 1
i -= 1
ind('}')
ind('return NULL;')
i -= 1
w('}')