Code to encode key events
This commit is contained in:
parent
c0b6078438
commit
c8a9336160
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1,6 +1,5 @@
|
||||
kitty/wcwidth-std.h linguist-generated=true
|
||||
kitty/emoji.h linguist-generated=true
|
||||
kitty/keys.h linguist-generated=true
|
||||
kitty/charsets.c linguist-generated=true
|
||||
kitty/key_encoding.py linguist-generated=true
|
||||
kitty/unicode-data.c linguist-generated=true
|
||||
|
||||
@ -5,7 +5,6 @@ import subprocess
|
||||
files_to_exclude = '''\
|
||||
kitty/wcwidth-std.h
|
||||
kitty/glfw.c
|
||||
kitty/keys.h
|
||||
kitty/charsets.c
|
||||
kitty/unicode-data.c
|
||||
kitty/key_encoding.py
|
||||
|
||||
@ -1,128 +0,0 @@
|
||||
Key encoding for extended keyboard protocol
|
||||
===============================================
|
||||
|
||||
See :ref:`extended-key-protocol` for more information and `this table in JSON
|
||||
format <https://github.com/kovidgoyal/kitty/blob/master/key_encoding.json>`_.
|
||||
|
||||
===================== ======================
|
||||
Name Encoded representation
|
||||
0 ``G``
|
||||
1 ``H``
|
||||
2 ``I``
|
||||
3 ``J``
|
||||
4 ``K``
|
||||
5 ``L``
|
||||
6 ``M``
|
||||
7 ``N``
|
||||
8 ``O``
|
||||
9 ``P``
|
||||
A ``S``
|
||||
APOSTROPHE ``B``
|
||||
B ``T``
|
||||
BACKSLASH ``t``
|
||||
BACKSPACE ``1``
|
||||
C ``U``
|
||||
CAPS LOCK ``:``
|
||||
COMMA ``C``
|
||||
D ``V``
|
||||
DELETE ``3``
|
||||
DOWN ``6``
|
||||
E ``W``
|
||||
END ``-``
|
||||
ENTER ``z``
|
||||
EQUAL ``R``
|
||||
ESCAPE ``y``
|
||||
F ``X``
|
||||
F1 ``/``
|
||||
F10 ``]``
|
||||
F11 ``{``
|
||||
F12 ``}``
|
||||
F13 ``@``
|
||||
F14 ``%``
|
||||
F15 ``$``
|
||||
F16 ``#``
|
||||
F17 ``BA``
|
||||
F18 ``BB``
|
||||
F19 ``BC``
|
||||
F2 ``*``
|
||||
F20 ``BD``
|
||||
F21 ``BE``
|
||||
F22 ``BF``
|
||||
F23 ``BG``
|
||||
F24 ``BH``
|
||||
F25 ``BI``
|
||||
F3 ``?``
|
||||
F4 ``&``
|
||||
F5 ``<``
|
||||
F6 ``>``
|
||||
F7 ``(``
|
||||
F8 ``)``
|
||||
F9 ``[``
|
||||
G ``Y``
|
||||
GRAVE ACCENT ``v``
|
||||
H ``Z``
|
||||
HOME ``.``
|
||||
I ``a``
|
||||
INSERT ``2``
|
||||
J ``b``
|
||||
K ``c``
|
||||
KP 0 ``BJ``
|
||||
KP 1 ``BK``
|
||||
KP 2 ``BL``
|
||||
KP 3 ``BM``
|
||||
KP 4 ``BN``
|
||||
KP 5 ``BO``
|
||||
KP 6 ``BP``
|
||||
KP 7 ``BQ``
|
||||
KP 8 ``BR``
|
||||
KP 9 ``BS``
|
||||
KP ADD ``BX``
|
||||
KP DECIMAL ``BT``
|
||||
KP DIVIDE ``BU``
|
||||
KP ENTER ``BY``
|
||||
KP EQUAL ``BZ``
|
||||
KP MULTIPLY ``BV``
|
||||
KP SUBTRACT ``BW``
|
||||
L ``d``
|
||||
LEFT ``5``
|
||||
LEFT ALT ``Bc``
|
||||
LEFT BRACKET ``s``
|
||||
LEFT CONTROL ``Bb``
|
||||
LEFT SHIFT ``Ba``
|
||||
LEFT SUPER ``Bd``
|
||||
M ``e``
|
||||
MINUS ``D``
|
||||
N ``f``
|
||||
NUM LOCK ``=``
|
||||
O ``g``
|
||||
P ``h``
|
||||
PAGE DOWN ``9``
|
||||
PAGE UP ``8``
|
||||
PAUSE ``!``
|
||||
PERIOD ``E``
|
||||
PRINT SCREEN ``^``
|
||||
Q ``i``
|
||||
R ``j``
|
||||
RIGHT ``4``
|
||||
RIGHT ALT ``Bg``
|
||||
RIGHT BRACKET ``u``
|
||||
RIGHT CONTROL ``Bf``
|
||||
RIGHT SHIFT ``Be``
|
||||
RIGHT SUPER ``Bh``
|
||||
S ``k``
|
||||
SCROLL LOCK ``+``
|
||||
SEMICOLON ``Q``
|
||||
SLASH ``F``
|
||||
SPACE ``A``
|
||||
T ``l``
|
||||
TAB ``0``
|
||||
U ``m``
|
||||
UP ``7``
|
||||
V ``n``
|
||||
W ``o``
|
||||
WORLD 1 ``w``
|
||||
WORLD 2 ``x``
|
||||
X ``p``
|
||||
Y ``q``
|
||||
Z ``r``
|
||||
===================== ======================
|
||||
2
glfw/glfw3.h
vendored
2
glfw/glfw3.h
vendored
@ -1379,7 +1379,7 @@ typedef enum {
|
||||
typedef struct GLFWkeyevent
|
||||
{
|
||||
// The [keyboard key](@ref keys) that was pressed or released.
|
||||
uint32_t key;
|
||||
uint32_t key, shifted_key, alternate_key;
|
||||
|
||||
// The platform-specific identifier of the key.
|
||||
int native_key;
|
||||
|
||||
2
kitty/glfw-wrapper.h
generated
2
kitty/glfw-wrapper.h
generated
@ -1117,7 +1117,7 @@ typedef enum {
|
||||
typedef struct GLFWkeyevent
|
||||
{
|
||||
// The [keyboard key](@ref keys) that was pressed or released.
|
||||
uint32_t key;
|
||||
uint32_t key, shifted_key, alternate_key;
|
||||
|
||||
// The platform-specific identifier of the key.
|
||||
int native_key;
|
||||
|
||||
224
kitty/key_encoding.c
Normal file
224
kitty/key_encoding.c
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
* key_encoding.c
|
||||
* Copyright (C) 2021 Kovid Goyal <kovid at kovidgoyal.net>
|
||||
*
|
||||
* Distributed under terms of the GPL3 license.
|
||||
*/
|
||||
|
||||
#include "keys.h"
|
||||
#include "charsets.h"
|
||||
|
||||
typedef enum { SHIFT=1, ALT=2, CTRL=4, SUPER=8 } ModifierMasks;
|
||||
typedef enum { PRESS = 0, REPEAT = 1, RELEASE = 2} KeyAction;
|
||||
typedef struct {
|
||||
uint32_t key, shifted_key, alternate_key;
|
||||
struct {
|
||||
bool shift, alt, ctrl, super;
|
||||
unsigned value;
|
||||
char encoded[4];
|
||||
} mods;
|
||||
KeyAction action;
|
||||
bool cursor_key_mode, disambiguate, report_all_event_types, report_alternate_key;
|
||||
const char *text;
|
||||
bool has_text;
|
||||
} KeyEvent;
|
||||
|
||||
typedef struct {
|
||||
uint32_t key, shifted_key, alternate_key;
|
||||
bool add_alternates, has_mods, add_actions;
|
||||
char encoded_mods[4];
|
||||
KeyAction action;
|
||||
} EncodingData;
|
||||
|
||||
|
||||
static inline void
|
||||
convert_glfw_mods(int mods, KeyEvent *ev) {
|
||||
ev->mods.alt = (mods & GLFW_MOD_ALT) > 0, ev->mods.ctrl = (mods & GLFW_MOD_CONTROL) > 0, ev->mods.shift = (mods & GLFW_MOD_SHIFT) > 0, ev->mods.super = (mods & GLFW_MOD_SUPER) > 0;
|
||||
ev->mods.value = ev->mods.shift ? SHIFT : 0;
|
||||
if (ev->mods.alt) ev->mods.value |= ALT;
|
||||
if (ev->mods.ctrl) ev->mods.value |= CTRL;
|
||||
if (ev->mods.super) ev->mods.value |= SUPER;
|
||||
snprintf(ev->mods.encoded, sizeof(ev->mods.encoded), "%u", ev->mods.value + 1);
|
||||
}
|
||||
|
||||
|
||||
static inline int
|
||||
encode_csi_string(const char csi_trailer, const char *payload, char *output) {
|
||||
return snprintf(output, KEY_BUFFER_SIZE, "\x1b[%s%c", payload, csi_trailer);
|
||||
}
|
||||
|
||||
static inline void
|
||||
init_encoding_data(EncodingData *ans, const KeyEvent *ev) {
|
||||
ans->add_actions = ev->report_all_event_types && ev->action != PRESS;
|
||||
ans->has_mods = ev->mods.encoded[0] && ev->mods.encoded[0] != '1';
|
||||
ans->add_alternates = ev->report_alternate_key && (ev->shifted_key > 0 || ev->alternate_key > 0);
|
||||
if (ans->add_alternates) { ans->shifted_key = ev->shifted_key; ans->alternate_key = ev->alternate_key; }
|
||||
ans->key = ev->key;
|
||||
memcpy(ans->encoded_mods, ev->mods.encoded, sizeof(ans->encoded_mods));
|
||||
}
|
||||
|
||||
static inline int
|
||||
serialize(const EncodingData *data, char *output, const char csi_trailer) {
|
||||
int pos = 0;
|
||||
#define P(fmt, ...) pos += snprintf(output + pos, KEY_BUFFER_SIZE - 2 - pos, fmt, __VA_ARGS__)
|
||||
P("\x1b[%u", data->key);
|
||||
if (data->add_alternates && (data->shifted_key || data->alternate_key)) {
|
||||
P("%s", ":");
|
||||
if (data->shifted_key) P("%u", data->shifted_key);
|
||||
if (data->alternate_key) P(":%u", data->alternate_key);
|
||||
}
|
||||
if (data->has_mods || data->add_actions) {
|
||||
P(";%s", data->encoded_mods);
|
||||
if (data->add_actions) P(":%u", data->action + 1);
|
||||
}
|
||||
#undef P
|
||||
output[pos++] = csi_trailer;
|
||||
output[pos] = 0;
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int
|
||||
encode_function_key(const KeyEvent *ev, char *output) {
|
||||
#define SIMPLE(val) return snprintf(output, KEY_BUFFER_SIZE, "%s", val);
|
||||
char csi_trailer = 'u';
|
||||
uint32_t key_number = ev->key;
|
||||
switch(key_number) {
|
||||
#define S(x) case GLFW_FKEY_KP_##x: key_number = GLFW_FKEY_##x; break;
|
||||
S(ENTER) S(HOME) S(END) S(INSERT) S(DELETE) S(PAGE_UP) S(PAGE_DOWN)
|
||||
#undef S
|
||||
}
|
||||
|
||||
if (ev->cursor_key_mode && !ev->disambiguate && !ev->report_all_event_types) {
|
||||
switch(key_number) {
|
||||
case GLFW_FKEY_UP: SIMPLE("\x1bOA");
|
||||
case GLFW_FKEY_DOWN: SIMPLE("\x1bOB");
|
||||
case GLFW_FKEY_LEFT: SIMPLE("\x1bOD");
|
||||
case GLFW_FKEY_RIGHT: SIMPLE("\x1bOC");
|
||||
case GLFW_FKEY_HOME: SIMPLE("\x1bOH");
|
||||
case GLFW_FKEY_END: SIMPLE("\x1bOF");
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (!ev->mods.value) {
|
||||
switch(key_number) {
|
||||
case GLFW_FKEY_ENTER: SIMPLE("\r");
|
||||
case GLFW_FKEY_ESCAPE: {
|
||||
if (ev->disambiguate) { return encode_csi_string('u', "27u", output); }
|
||||
SIMPLE("\x1b");
|
||||
}
|
||||
case GLFW_FKEY_BACKSPACE: SIMPLE("\x7f");
|
||||
case GLFW_FKEY_TAB: SIMPLE("\t");
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (key_number == GLFW_FKEY_TAB) {
|
||||
if (ev->mods.value == SHIFT) return encode_csi_string('Z', "", output);
|
||||
if (ev->mods.value == (CTRL | SHIFT)) return encode_csi_string('Z', "1;5", output);
|
||||
if (ev->mods.value == ALT) SIMPLE("\x1b\t");
|
||||
}
|
||||
if (ev->mods.value == ALT) {
|
||||
switch(key_number) {
|
||||
case GLFW_FKEY_TAB: SIMPLE("\x1b\t");
|
||||
case GLFW_FKEY_ENTER: SIMPLE("\x1b\r");
|
||||
case GLFW_FKEY_BACKSPACE: SIMPLE("\x1b\x7f");
|
||||
}
|
||||
}
|
||||
#undef SIMPLE
|
||||
|
||||
#define S(number, trailer) key_number = number; csi_trailer = trailer; break
|
||||
switch(key_number) {
|
||||
case GLFW_FKEY_UP: S(1, 'A');
|
||||
case GLFW_FKEY_DOWN: S(1, 'B');
|
||||
case GLFW_FKEY_LEFT: S(1, 'C');
|
||||
case GLFW_FKEY_RIGHT: S(1, 'D');
|
||||
case GLFW_FKEY_HOME: S(1, 'H');
|
||||
case GLFW_FKEY_END: S(1, 'F');
|
||||
case GLFW_FKEY_F1: S(1, 'P');
|
||||
case GLFW_FKEY_F2: S(1, 'Q');
|
||||
case GLFW_FKEY_F3: S(1, 'R');
|
||||
case GLFW_FKEY_F4: S(1, 'S');
|
||||
case GLFW_FKEY_INSERT: S(2, '~');
|
||||
case GLFW_FKEY_DELETE: S(3, '~');
|
||||
case GLFW_FKEY_PAGE_UP: S(5, '~');
|
||||
case GLFW_FKEY_PAGE_DOWN: S(6, '~');
|
||||
case GLFW_FKEY_F5: S(15, '~');
|
||||
case GLFW_FKEY_F6: S(17, '~');
|
||||
case GLFW_FKEY_F7: S(18, '~');
|
||||
case GLFW_FKEY_F8: S(19, '~');
|
||||
case GLFW_FKEY_F9: S(20, '~');
|
||||
case GLFW_FKEY_F10: S(21, '~');
|
||||
case GLFW_FKEY_F11: S(23, '~');
|
||||
case GLFW_FKEY_F12: S(24, '~');
|
||||
default: break;
|
||||
}
|
||||
#undef S
|
||||
EncodingData ed = {0};
|
||||
init_encoding_data(&ed, ev);
|
||||
ed.add_alternates = false;
|
||||
return serialize(&ed, output, csi_trailer);
|
||||
}
|
||||
|
||||
static int
|
||||
encode_printable_ascii_key_legacy(const KeyEvent *ev, char *output) {
|
||||
char shifted_key = 0;
|
||||
|
||||
if ('a' <= ev->key && ev->key <= 'z') shifted_key = ev->key + ('A' - 'a');
|
||||
switch(ev->key) {
|
||||
#define S(which, val) case which: shifted_key = val; break;
|
||||
S('0', ')') S('9', '(') S('8', '*') S('7', '&') S('6', '^') S('5', '%') S('4', '$') S('3', '#') S('2', '@') S('1', '!')
|
||||
S('`', '~') S('-', '_') S('=', '+') S('[', '{') S(']', '}') S('\\', '|') S(';', ':') S('\'', '"') S(',', '<') S('.', '>') S('/', '?')
|
||||
#undef S
|
||||
}
|
||||
|
||||
if (!ev->mods.value) return snprintf(output, KEY_BUFFER_SIZE, "%c", (char)ev->key);
|
||||
if (!ev->disambiguate) {
|
||||
if ((ev->mods.value == ALT || ev->mods.value == (SHIFT | ALT)))
|
||||
return snprintf(output, KEY_BUFFER_SIZE, "\x1b%c", (shifted_key && ev->mods.shift) ? shifted_key : (char)ev->key);
|
||||
}
|
||||
if (ev->mods.value == CTRL && (ev->key != 'i' && ev->key != 'm' && ev->key != '[' && ev->key != '@'))
|
||||
return snprintf(output, KEY_BUFFER_SIZE, "%c", ev->key & 0x7f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
encode_key(const KeyEvent *ev, char *output) {
|
||||
if (!ev->report_all_event_types && ev->action == RELEASE) return 0;
|
||||
if (GLFW_FKEY_FIRST <= ev->key && ev->key <= GLFW_FKEY_LAST) return encode_function_key(ev, output);
|
||||
EncodingData ed = {0};
|
||||
init_encoding_data(&ed, ev);
|
||||
bool simple_encoding_ok = !ed.add_actions && !ed.add_alternates;
|
||||
|
||||
if (32 <= ev->key && ev->key <= 126 && simple_encoding_ok) {
|
||||
int ret = encode_printable_ascii_key_legacy(ev, output);
|
||||
if (ret > 0) return ret;
|
||||
}
|
||||
|
||||
if (simple_encoding_ok && !ed.has_mods) return encode_utf8(ev->key, output);
|
||||
return serialize(&ed, output, 'u');
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_ascii_control_char(char c) {
|
||||
return (0 <= c && c <= 31) || c == 127;
|
||||
}
|
||||
|
||||
int
|
||||
encode_glfw_key_event(const GLFWkeyevent *e, const bool cursor_key_mode, const unsigned key_encoding_flags, char *output) {
|
||||
KeyEvent ev = {
|
||||
.key = e->key, .shifted_key = e->shifted_key, .alternate_key = e->alternate_key,
|
||||
.text = e->text,
|
||||
.cursor_key_mode = cursor_key_mode,
|
||||
.disambiguate = key_encoding_flags & 1,
|
||||
.report_all_event_types = key_encoding_flags & 2,
|
||||
.report_alternate_key = key_encoding_flags & 4
|
||||
};
|
||||
ev.has_text = e->text && !is_ascii_control_char(e->text[0]);
|
||||
switch (e->action) {
|
||||
case GLFW_PRESS: ev.action = PRESS; break;
|
||||
case GLFW_REPEAT: ev.action = REPEAT; break;
|
||||
case GLFW_RELEASE: ev.action = RELEASE; break;
|
||||
}
|
||||
if (ev.has_text && (ev.action == PRESS || ev.action == REPEAT)) return SEND_TEXT_TO_CHILD;
|
||||
convert_glfw_mods(e->mods, &ev);
|
||||
return encode_key(&ev, output);
|
||||
}
|
||||
138
kitty/keys.c
138
kitty/keys.c
@ -11,44 +11,6 @@
|
||||
#include "glfw-wrapper.h"
|
||||
#include "control-codes.h"
|
||||
|
||||
static bool needs_special_handling[128 * 16] = {0};
|
||||
|
||||
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;
|
||||
KeyboardMode mode = extended ? EXTENDED : (smkx ? APPLICATION : NORMAL);
|
||||
return key_lookup(key, mode, mods, action);
|
||||
}
|
||||
|
||||
#define SPECIAL_INDEX(key) ((key & 0x7f) | ( (mods & 0xF) << 7))
|
||||
#define IS_ALT_MODS(mods) (mods == GLFW_MOD_ALT || mods == (GLFW_MOD_ALT | GLFW_MOD_SHIFT))
|
||||
|
||||
typedef struct { int mods, native_key; } NativeKey;
|
||||
static NativeKey *native_special_keys = NULL;
|
||||
static size_t native_special_keys_capacity = 0, native_special_keys_count = 0;
|
||||
|
||||
void
|
||||
set_special_key_combo(int glfw_key, int mods, bool is_native) {
|
||||
if (is_native) {
|
||||
if (native_special_keys_count >= native_special_keys_capacity) {
|
||||
native_special_keys_capacity = MAX(128u, 2 * native_special_keys_capacity);
|
||||
native_special_keys = realloc(native_special_keys, sizeof(native_special_keys[0]) * native_special_keys_capacity);
|
||||
if (native_special_keys == NULL) fatal("Out of memory");
|
||||
}
|
||||
native_special_keys[native_special_keys_count].mods = mods;
|
||||
native_special_keys[native_special_keys_count++].native_key = glfw_key;
|
||||
} else {
|
||||
uint16_t key = key_map[glfw_key];
|
||||
if (key != UINT8_MAX) {
|
||||
key = SPECIAL_INDEX(key);
|
||||
needs_special_handling[key] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline Window*
|
||||
active_window(void) {
|
||||
Tab *t = global_state.callback_os_window->tabs + global_state.callback_os_window->active_tab;
|
||||
@ -75,42 +37,6 @@ is_modifier_key(int key) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
send_key_to_child(Window *w, int key, int mods, int action) {
|
||||
Screen *screen = w->render_data.screen;
|
||||
const char *data = key_to_bytes(key, screen->modes.mDECCKM, screen->modes.mEXTENDED_KEYBOARD, mods, action);
|
||||
if (data) {
|
||||
if (screen->modes.mEXTENDED_KEYBOARD) {
|
||||
if (*data == 1) schedule_write_to_child(w->id, 1, (data + 1), 1);
|
||||
else write_escape_code_to_child(screen, APC, data + 1);
|
||||
} else {
|
||||
if (*data > 2 && data[1] == 0x1b && data[2] == '[') { // CSI code
|
||||
write_escape_code_to_child(screen, CSI, data + 3);
|
||||
} else schedule_write_to_child(w->id, 1, (data + 1), *data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_ascii_control_char(char c) {
|
||||
return c == 0 || (1 <= c && c <= 31) || c == 127;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
check_if_special(int key, int mods, int native_key) {
|
||||
uint16_t qkey = (0 <= key && key < (ssize_t)arraysz(key_map)) ? key_map[key] : UINT8_MAX;
|
||||
bool special = false;
|
||||
if (qkey != UINT8_MAX) {
|
||||
qkey = SPECIAL_INDEX(qkey);
|
||||
special = needs_special_handling[qkey];
|
||||
}
|
||||
for (size_t i = 0; !special && i < native_special_keys_count; i++) {
|
||||
if (native_key == native_special_keys[i].native_key && mods == native_special_keys[i].mods)
|
||||
special = true;
|
||||
}
|
||||
return special;
|
||||
}
|
||||
|
||||
static inline void
|
||||
update_ime_position(OSWindow *os_window, Window* w, Screen *screen) {
|
||||
unsigned int cell_width = os_window->fonts_data->cell_width, cell_height = os_window->fonts_data->cell_height;
|
||||
@ -120,12 +46,10 @@ update_ime_position(OSWindow *os_window, Window* w, Screen *screen) {
|
||||
glfwUpdateIMEState(global_state.callback_os_window->handle, 2, left, top, cell_width, cell_height);
|
||||
}
|
||||
|
||||
#define debug(...) if (OPT(debug_keyboard)) printf(__VA_ARGS__);
|
||||
|
||||
void
|
||||
on_key_input(GLFWkeyevent *ev) {
|
||||
Window *w = active_window();
|
||||
int action = ev->action, native_key = ev->native_key, key = ev->key, mods = ev->mods;
|
||||
const int action = ev->action, native_key = ev->native_key, key = ev->key, mods = ev->mods;
|
||||
const char *text = ev->text ? ev->text : "";
|
||||
|
||||
debug("on_key_input: glfw key: %d native_code: 0x%x action: %s mods: 0x%x text: '%s' state: %d ",
|
||||
@ -167,10 +91,8 @@ on_key_input(GLFWkeyevent *ev) {
|
||||
) call_boss(process_sequence, "iiii", key, native_key, action, mods);
|
||||
return;
|
||||
}
|
||||
bool has_text = text[0] && !is_ascii_control_char(text[0]);
|
||||
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
|
||||
if (check_if_special(key, mods, native_key)) {
|
||||
PyObject *ret = PyObject_CallMethod(global_state.boss, "dispatch_special_key", "iiii", key, native_key, action, mods);
|
||||
PyObject *ret = PyObject_CallMethod(global_state.boss, "dispatch_possible_special_key", "iiii", key, native_key, action, mods);
|
||||
if (ret == NULL) { PyErr_Print(); }
|
||||
else {
|
||||
bool consumed = ret == Py_True;
|
||||
@ -181,7 +103,6 @@ on_key_input(GLFWkeyevent *ev) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (action == GLFW_REPEAT && !screen->modes.mDECARM) {
|
||||
debug("discarding repeat key event as DECARM is off\n");
|
||||
return;
|
||||
@ -189,15 +110,14 @@ on_key_input(GLFWkeyevent *ev) {
|
||||
if (screen->scrolled_by && action == GLFW_PRESS && !is_modifier_key(key)) {
|
||||
screen_history_scroll(screen, SCROLL_FULL, false); // scroll back to bottom
|
||||
}
|
||||
bool ok_to_send = action == GLFW_PRESS || action == GLFW_REPEAT || screen->modes.mEXTENDED_KEYBOARD;
|
||||
if (ok_to_send) {
|
||||
if (has_text) {
|
||||
char encoded_key[KEY_BUFFER_SIZE] = {0};
|
||||
int size = encode_glfw_key_event(ev, screen->modes.mDECCKM, screen->key_encoding_flags, encoded_key);
|
||||
if (size == SEND_TEXT_TO_CHILD) {
|
||||
schedule_write_to_child(w->id, 1, text, strlen(text));
|
||||
debug("sent text to child\n");
|
||||
} else {
|
||||
send_key_to_child(w, key, mods, action);
|
||||
} else if (size > 0) {
|
||||
schedule_write_to_child(w->id, 1, encoded_key, size);
|
||||
debug("sent key to child\n");
|
||||
}
|
||||
} else {
|
||||
debug("ignoring as keyboard mode does not allow %s events\n", action == GLFW_RELEASE ? "release" : "repeat");
|
||||
}
|
||||
@ -207,9 +127,16 @@ void
|
||||
fake_scroll(Window *w, int amount, bool upwards) {
|
||||
if (!w) return;
|
||||
int key = upwards ? GLFW_KEY_UP : GLFW_KEY_DOWN;
|
||||
GLFWkeyevent ev = {.key = key };
|
||||
char encoded_key[KEY_BUFFER_SIZE] = {0};
|
||||
Screen *screen = w->render_data.screen;
|
||||
while (amount-- > 0) {
|
||||
send_key_to_child(w, key, 0, GLFW_PRESS);
|
||||
send_key_to_child(w, key, 0, GLFW_RELEASE);
|
||||
ev.action = GLFW_PRESS;
|
||||
int size = encode_glfw_key_event(&ev, screen->modes.mDECCKM, screen->key_encoding_flags, encoded_key);
|
||||
if (size > 0) schedule_write_to_child(w->id, 1, encoded_key, size);
|
||||
ev.action = GLFW_RELEASE;
|
||||
size = encode_glfw_key_event(&ev, screen->modes.mDECCKM, screen->key_encoding_flags, encoded_key);
|
||||
if (size > 0) schedule_write_to_child(w->id, 1, encoded_key, size);
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,14 +144,6 @@ fake_scroll(Window *w, int amount, bool upwards) {
|
||||
#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 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);
|
||||
}
|
||||
|
||||
PYWRAP1(key_for_native_key_name) {
|
||||
const char *name;
|
||||
int case_sensitive = 0;
|
||||
@ -238,23 +157,28 @@ PYWRAP1(key_for_native_key_name) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
pyencode_key_for_tty(PyObject *self UNUSED, PyObject *args, PyObject *kw) {
|
||||
char *kwds[] = {"key", "shifted_key", "alternate_key", "mods", "action", "text", "cursor_key_mode", "key_encoding_flags"};
|
||||
unsigned int key = 0, shifted_key = 0, alternate_key = 0, mods = 0, action = 0, key_encoding_flags = 0;
|
||||
const char *text = NULL;
|
||||
int cursor_key_mode = 0;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kw, "IIIIIspI", kwds, &key, &shifted_key, &alternate_key, &mods, &action, &text, &cursor_key_mode, &key_encoding_flags)) return NULL;
|
||||
GLFWkeyevent ev = { .key = key, .shifted_key = shifted_key, .alternate_key = alternate_key, .text = text, .action = action, .mods = mods };
|
||||
char output[KEY_BUFFER_SIZE+1] = {0};
|
||||
int num = encode_glfw_key_event(&ev, cursor_key_mode, key_encoding_flags, output);
|
||||
if (num == SEND_TEXT_TO_CHILD) return PyUnicode_FromString(text);
|
||||
return PyUnicode_FromString(output);
|
||||
}
|
||||
|
||||
static PyMethodDef module_methods[] = {
|
||||
M(key_to_bytes, METH_VARARGS),
|
||||
M(key_for_native_key_name, METH_VARARGS),
|
||||
M(encode_key_for_tty, METH_VARARGS | METH_KEYWORDS),
|
||||
{0}
|
||||
};
|
||||
|
||||
void
|
||||
finalize(void) {
|
||||
free(native_special_keys);
|
||||
}
|
||||
|
||||
bool
|
||||
init_keys(PyObject *module) {
|
||||
if (PyModule_AddFunctions(module, module_methods) != 0) return false;
|
||||
if (Py_AtExit(finalize) != 0) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Failed to register the keys at exit handler");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
23420
kitty/keys.h
23420
kitty/keys.h
File diff suppressed because it is too large
Load Diff
@ -80,6 +80,3 @@
|
||||
#define BRACKETED_PASTE (2004 << 5)
|
||||
#define BRACKETED_PASTE_START "200~"
|
||||
#define BRACKETED_PASTE_END "201~"
|
||||
|
||||
// Extended keyboard protocol
|
||||
#define EXTENDED_KEYBOARD (2017 << 5)
|
||||
|
||||
@ -150,6 +150,7 @@ void
|
||||
screen_reset(Screen *self) {
|
||||
if (self->linebuf == self->alt_linebuf) screen_toggle_screen_buffer(self, true, true);
|
||||
if (self->overlay_line.is_active) deactivate_overlay_line(self);
|
||||
self->key_encoding_flags = 0;
|
||||
self->last_graphic_char = 0;
|
||||
self->main_savepoint.is_valid = false;
|
||||
self->alt_savepoint.is_valid = false;
|
||||
@ -750,7 +751,6 @@ set_mode_from_const(Screen *self, unsigned int mode, bool val) {
|
||||
SIMPLE_MODE(IRM)
|
||||
SIMPLE_MODE(DECARM)
|
||||
SIMPLE_MODE(BRACKETED_PASTE)
|
||||
SIMPLE_MODE(EXTENDED_KEYBOARD)
|
||||
SIMPLE_MODE(FOCUS_TRACKING)
|
||||
MOUSE_MODE(MOUSE_BUTTON_TRACKING, mouse_tracking_mode, BUTTON_MODE)
|
||||
MOUSE_MODE(MOUSE_MOTION_TRACKING, mouse_tracking_mode, MOTION_MODE)
|
||||
@ -1143,7 +1143,7 @@ screen_restore_modes(Screen *self) {
|
||||
if (m == NULL) m = &empty_modes;
|
||||
#define S(name) set_mode_from_const(self, name, m->m##name)
|
||||
S(DECTCEM); S(DECSCNM); S(DECSCNM); S(DECOM); S(DECAWM); S(DECARM); S(DECCKM);
|
||||
S(BRACKETED_PASTE); S(FOCUS_TRACKING); S(EXTENDED_KEYBOARD);
|
||||
S(BRACKETED_PASTE); S(FOCUS_TRACKING);
|
||||
self->modes.mouse_tracking_mode = m->mouse_tracking_mode;
|
||||
self->modes.mouse_tracking_protocol = m->mouse_tracking_protocol;
|
||||
#undef S
|
||||
@ -1490,7 +1490,6 @@ report_mode_status(Screen *self, unsigned int which, bool private) {
|
||||
KNOWN_MODE(DECARM);
|
||||
KNOWN_MODE(DECCKM);
|
||||
KNOWN_MODE(BRACKETED_PASTE);
|
||||
KNOWN_MODE(EXTENDED_KEYBOARD);
|
||||
KNOWN_MODE(FOCUS_TRACKING);
|
||||
#undef KNOWN_MODE
|
||||
case ALTERNATE_SCREEN:
|
||||
@ -2201,7 +2200,6 @@ WRAP0(scroll_until_cursor)
|
||||
static int name##_set(Screen *self, PyObject *val, void UNUSED *closure) { if (val == NULL) { PyErr_SetString(PyExc_TypeError, "Cannot delete attribute"); return -1; } set_mode_from_const(self, uname, PyObject_IsTrue(val) ? true : false); return 0; }
|
||||
|
||||
MODE_GETSET(in_bracketed_paste_mode, BRACKETED_PASTE)
|
||||
MODE_GETSET(extended_keyboard, EXTENDED_KEYBOARD)
|
||||
MODE_GETSET(focus_tracking_enabled, FOCUS_TRACKING)
|
||||
MODE_GETSET(auto_repeat_enabled, DECARM)
|
||||
MODE_GETSET(cursor_visible, DECTCEM)
|
||||
@ -2859,7 +2857,6 @@ static PyMethodDef methods[] = {
|
||||
|
||||
static PyGetSetDef getsetters[] = {
|
||||
GETSET(in_bracketed_paste_mode)
|
||||
GETSET(extended_keyboard)
|
||||
GETSET(auto_repeat_enabled)
|
||||
GETSET(focus_tracking_enabled)
|
||||
GETSET(cursor_visible)
|
||||
|
||||
@ -14,7 +14,7 @@ typedef enum ScrollTypes { SCROLL_LINE = -999999, SCROLL_PAGE, SCROLL_FULL } Scr
|
||||
|
||||
typedef struct {
|
||||
bool mLNM, mIRM, mDECTCEM, mDECSCNM, mDECOM, mDECAWM, mDECCOLM, mDECARM, mDECCKM,
|
||||
mBRACKETED_PASTE, mFOCUS_TRACKING, mEXTENDED_KEYBOARD, mDECSACE;
|
||||
mBRACKETED_PASTE, mFOCUS_TRACKING, mDECSACE;
|
||||
MouseTrackingMode mouse_tracking_mode;
|
||||
MouseTrackingProtocol mouse_tracking_protocol;
|
||||
bool eight_bit_controls; // S8C1T
|
||||
@ -129,6 +129,7 @@ typedef struct {
|
||||
HYPERLINK_POOL_HANDLE hyperlink_pool;
|
||||
ANSIBuf as_ansi_buf;
|
||||
char_type last_graphic_char;
|
||||
unsigned key_encoding_flags;
|
||||
} Screen;
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user