Created
May 24, 2025 14:47
-
-
Save adsr/126a22b01a34107a0d313ebb2212efbb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/termbox2.h b/termbox2.h | |
index 2d6775c..1b758ec 100644 | |
--- a/termbox2.h | |
+++ b/termbox2.h | |
@@ -780,20 +780,21 @@ struct cellbuf_t { | |
struct tb_cell *cells; | |
}; | |
struct cap_trie_t { | |
char c; | |
struct cap_trie_t *children; | |
size_t nchildren; | |
int is_leaf; | |
uint16_t key; | |
uint8_t mod; | |
+ uint32_t ch; | |
}; | |
struct tb_global_t { | |
int ttyfd; | |
int rfd; | |
int wfd; | |
int ttyfd_open; | |
int resize_pipefd[2]; | |
int width; | |
int height; | |
@@ -2250,21 +2251,22 @@ static struct { | |
}; | |
#define WCWIDTH_TABLE_LENGTH 2143 | |
#endif // ifndef TB_OPT_LIBC_WCHAR | |
static int tb_reset(void); | |
static int tb_printf_inner(int x, int y, uintattr_t fg, uintattr_t bg, | |
size_t *out_w, const char *fmt, va_list vl); | |
static int init_term_attrs(void); | |
static int init_term_caps(void); | |
static int init_cap_trie(void); | |
-static int cap_trie_add(const char *cap, uint16_t key, uint8_t mod); | |
+static int cap_trie_add(const char *cap, uint16_t key, uint32_t ch, | |
+ uint8_t mod); | |
static int cap_trie_find(const char *buf, size_t nbuf, struct cap_trie_t **last, | |
size_t *depth); | |
static int cap_trie_deinit(struct cap_trie_t *node); | |
static int init_resize_handler(void); | |
static int send_init_escape_codes(void); | |
static int send_clear(void); | |
static int update_term_size(void); | |
static int update_term_size_via_esc(void); | |
static int init_cellbuf(void); | |
static int tb_deinit(void); | |
@@ -2901,49 +2903,81 @@ int tb_printf_inner(int x, int y, uintattr_t fg, uintattr_t bg, size_t *out_w, | |
} | |
static int init_term_caps(void) { | |
if (load_terminfo() == TB_OK) { | |
return parse_terminfo_caps(); | |
} | |
return load_builtin_caps(); | |
} | |
static int init_cap_trie(void) { | |
- int rv, i; | |
+ int rv, i, j; | |
// Add caps from terminfo or built-in | |
// | |
// Collisions are expected as some terminfo entries have dupes. (For | |
// example, att605-pc collides on TB_CAP_F4 and TB_CAP_DELETE.) First cap | |
// in TB_CAP_* index order will win. | |
// | |
// TODO: Reorder TB_CAP_* so more critical caps come first. | |
for (i = 0; i < TB_CAP__COUNT_KEYS; i++) { | |
- rv = cap_trie_add(global.caps[i], tb_key_i(i), 0); | |
+ rv = cap_trie_add(global.caps[i], tb_key_i(i), 0, 0); | |
if (rv != TB_OK && rv != TB_ERR_CAP_COLLISION) return rv; | |
} | |
// Add built-in mod caps | |
// | |
// Collisions are OK here as well. This can happen if global.caps collides | |
// with builtin_mod_caps. It is desirable to give precedence to global.caps | |
// here. | |
for (i = 0; builtin_mod_caps[i].cap != NULL; i++) { | |
rv = cap_trie_add(builtin_mod_caps[i].cap, builtin_mod_caps[i].key, | |
- builtin_mod_caps[i].mod); | |
+ 0, builtin_mod_caps[i].mod); | |
if (rv != TB_OK && rv != TB_ERR_CAP_COLLISION) return rv; | |
} | |
+ // Add xterm modifyOtherKeys | |
+ // | |
+ // Rather than adding hundreds of entries to `builtin_mod_caps`, we add | |
+ // them here procedurally. It's likely xterm can't actually emit all of | |
+ // these. | |
+ char cap[16]; | |
+ int mod_map[] = {0, 0, TB_MOD_SHIFT, TB_MOD_ALT, TB_MOD_ALT | TB_MOD_SHIFT, | |
+ TB_MOD_CTRL, TB_MOD_CTRL | TB_MOD_SHIFT, TB_MOD_CTRL | TB_MOD_ALT, | |
+ TB_MOD_CTRL | TB_MOD_ALT | TB_MOD_SHIFT}; | |
+ uint16_t key; | |
+ uint32_t ch; | |
+ uint8_t mod; | |
+ for (i = 0x01; i <= 0x7f; i++) { | |
+ for (j = 2; j <= 8; j++) { | |
+ snprintf(cap, sizeof(cap), "\x1b[27;%d;%d~", j, i); | |
+ key = 0; | |
+ ch = 0; | |
+ mod = mod_map[j]; | |
+ if (i == 0x20) { | |
+ key = TB_KEY_SPACE; | |
+ } else if (i >= 0x21 && i <= 0x7e) { | |
+ ch = i; | |
+ if (mod & TB_MOD_SHIFT) mod &= ~TB_MOD_SHIFT; | |
+ } else { | |
+ key = i; | |
+ } | |
+ rv = cap_trie_add(cap, key, ch, mod); | |
+ if (rv != TB_OK && rv != TB_ERR_CAP_COLLISION) return rv; | |
+ } | |
+ } | |
+ | |
return TB_OK; | |
} | |
-static int cap_trie_add(const char *cap, uint16_t key, uint8_t mod) { | |
+static int cap_trie_add(const char *cap, uint16_t key, uint32_t ch, | |
+ uint8_t mod) { | |
struct cap_trie_t *next, *node = &global.cap_trie; | |
size_t i, j; | |
if (!cap || strlen(cap) <= 0) return TB_OK; // Nothing to do for empty caps | |
for (i = 0; cap[i] != '\0'; i++) { | |
char c = cap[i]; | |
next = NULL; | |
// Check if c is already a child of node | |
@@ -2970,20 +3004,21 @@ static int cap_trie_add(const char *cap, uint16_t key, uint8_t mod) { | |
node = next; | |
} | |
if (node->is_leaf) { | |
// Already a leaf here | |
return TB_ERR_CAP_COLLISION; | |
} | |
node->is_leaf = 1; | |
node->key = key; | |
+ node->ch = ch; | |
node->mod = mod; | |
return TB_OK; | |
} | |
static int cap_trie_find(const char *buf, size_t nbuf, struct cap_trie_t **last, | |
size_t *depth) { | |
struct cap_trie_t *next, *node = &global.cap_trie; | |
size_t i, j; | |
*last = node; | |
*depth = 0; | |
@@ -3564,21 +3599,21 @@ static int extract_esc_user(struct tb_event *event, int is_post) { | |
static int extract_esc_cap(struct tb_event *event) { | |
int rv; | |
struct bytebuf_t *in = &global.in; | |
struct cap_trie_t *node; | |
size_t depth; | |
if_err_return(rv, cap_trie_find(in->buf, in->len, &node, &depth)); | |
if (node->is_leaf) { | |
// Found a leaf node | |
event->type = TB_EVENT_KEY; | |
- event->ch = 0; | |
+ event->ch = node->ch; | |
event->key = node->key; | |
event->mod = node->mod; | |
bytebuf_shift(in, depth); | |
return TB_OK; | |
} else if (node->nchildren > 0 && in->len <= depth) { | |
// Found a branch node (not enough input) | |
return TB_ERR_NEED_MORE; | |
} | |
return TB_ERR; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment