Translate key presses to bytes using a lookup table

This commit is contained in:
Kovid Goyal 2017-09-15 10:32:10 +05:30
parent b5af266b87
commit 44c897a61a
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 32900 additions and 2 deletions

View File

@ -1,2 +1,2 @@
#!/bin/bash
cloc --exclude-list-file <(echo -e 'kitty/wcwidth9.h\nkitty/glfw.c\nkitty/glfw.h\nkitty/charsets.c\nkitty/key_encoding.py\nkitty/rgb.py') kitty
cloc --exclude-list-file <(echo -e 'kitty/wcwidth9.h\nkitty/glfw.c\nkitty/keys.h\nkitty/charsets.c\nkitty/key_encoding.py\nkitty/rgb.py') kitty

View File

@ -135,6 +135,7 @@ extern bool init_fontconfig_library(PyObject*);
extern bool init_glfw(PyObject *m);
extern bool init_sprites(PyObject *module);
extern bool init_state(PyObject *module);
extern bool init_keys(PyObject *module);
extern bool init_shaders(PyObject *module);
extern bool init_shaders_debug(PyObject *module);
#ifdef __APPLE__
@ -164,6 +165,7 @@ PyInit_fast_data_types(void) {
if (!init_glfw(m)) return NULL;
if (!init_sprites(m)) return NULL;
if (!init_state(m)) return NULL;
if (!init_keys(m)) return NULL;
if (PySys_GetObject("debug_gl") == Py_True) {
if (!init_shaders_debug(m)) return NULL;
} else {

47
kitty/keys.c Normal file
View File

@ -0,0 +1,47 @@
/*
* keys.c
* Copyright (C) 2017 Kovid Goyal <kovid at kovidgoyal.net>
*
* Distributed under terms of the GPL3 license.
*/
#include "keys.h"
#include "data-types.h"
const uint8_t*
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];
}
#define PYWRAP1(name) static PyObject* py##name(PyObject UNUSED *self, PyObject *args)
#define PA(fmt, ...) if(!PyArg_ParseTuple(args, fmt, __VA_ARGS__)) return NULL;
#define M(name, arg_type) {#name, (PyCFunction)py##name, arg_type, NULL}
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);
if (ans == NULL) return Py_BuildValue("y#", "", 0);
return Py_BuildValue("y#", ans + 1, *ans);
}
static PyMethodDef module_methods[] = {
M(key_to_bytes, METH_VARARGS),
{0}
};
bool
init_keys(PyObject *module) {
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
return true;
}

32778
kitty/keys.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -190,7 +190,7 @@ def interpret_key_event(key, scancode, mods, window, action, get_localized_key=g
screen.extended_keyboard
):
key = get_localized_key(key, scancode)
return key_to_bytes(key, screen.cursor_key_mode, screen.extended_keyboard, mods, action)
return defines.key_to_bytes(key, screen.cursor_key_mode, screen.extended_keyboard, mods, action)
return b''
@ -216,3 +216,74 @@ def get_sent_data(send_text_map, key, scancode, mods, window, action):
m = keyboard_mode_name(window.screen)
keymap = send_text_map[m]
return keymap.get((mods & 0b1111, key))
def generate_key_table():
# To run this, use: python3 . -c "from kitty.keys import *; generate_key_table()"
import os
from functools import partial
f = open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys.h'), 'w')
w = partial(print, file=f)
w('// auto-generated from keys.py, do not edit!')
w('#pragma once')
w('#include <stdint.h>')
w('#include <limits.h>')
number_of_keys = defines.GLFW_KEY_LAST + 1
w('static const uint8_t key_map[%d] = {' % number_of_keys)
key_count = 0
keys = {v: k for k, v in vars(defines).items() if k.startswith('GLFW_KEY_') and k not in 'GLFW_KEY_LAST GLFW_KEY_UNKNOWN'}
key_rmap = []
for i in range(number_of_keys):
k = keys.get(i)
if k is None:
w('UINT8_MAX,', end=' ')
else:
w('%d,' % key_count, end=' ')
key_rmap.append(i)
key_count += 1
if key_count > 128:
raise OverflowError('Too many keys')
w('};\n')
number_entries = 0x7f | (0xff << 7)
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)
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] + [k.rpartition('_')[2]])
w('{0x%x, ' % len(b) + ', '.join(map(str, b)) + '}, //', name, 'smkx:', smkx, 'extended:', extended)
w('};')