TUI: kitty keyboard protocol, word movement and deletion keys
Query CSI ? u at startup and push the disambiguate flag on the alternate screen when the terminal answers; CSI u reports are mapped back to legacy input (Shift/Ctrl+Enter insert a newline, Ctrl+Backspace deletes a word). Ctrl/Alt+Left/Right move by word, Ctrl/Alt+Delete delete the next word. Our define_key codes move above the range ncurses uses for terminfo extended keys.
This commit is contained in:
@@ -291,6 +291,70 @@ const char *cst_key_name(int code, char *buf, size_t n) {
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Shift on a US layout; the kitty report names the unshifted key. */
|
||||
static int us_shift(int c) {
|
||||
static const char PLAIN[] = "`1234567890-=[]\\;',./";
|
||||
static const char SHIFTED[] = "~!@#$%^&*()_+{}|:\"<>?";
|
||||
if (c >= 'a' && c <= 'z')
|
||||
return c - 'a' + 'A';
|
||||
const char *p = c > 0 && c < 0x80 ? strchr(PLAIN, c) : NULL;
|
||||
return p ? SHIFTED[p - PLAIN] : c;
|
||||
}
|
||||
|
||||
/* The control character xterm sends for ctrl+c, or c when there is none. */
|
||||
static int ctrl_char(int c) {
|
||||
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
|
||||
return c & 0x1f;
|
||||
switch (c) {
|
||||
case ' ': case '2': case '@': return 0;
|
||||
case '3': case '[': return 27;
|
||||
case '4': case '\\': return 28;
|
||||
case '5': case ']': return 29;
|
||||
case '6': case '^': return 30;
|
||||
case '7': case '-': case '_': case '/': return 31;
|
||||
case '8': case '?': return 127;
|
||||
default: return c;
|
||||
}
|
||||
}
|
||||
|
||||
int cst_key_from_kitty(int cp, int mods, int out[2]) {
|
||||
int shift = mods & 1, alt = mods & 2, ctrl = mods & 4;
|
||||
if (mods & ~7)
|
||||
return 0; /* super, hyper, meta, caps/num lock: not ours */
|
||||
int c;
|
||||
switch (cp) {
|
||||
case 13:
|
||||
if (!mods)
|
||||
return out[0] = 13, 1;
|
||||
out[0] = 27, out[1] = 13; /* newline */
|
||||
return 2;
|
||||
case 127:
|
||||
if (!alt && !ctrl)
|
||||
return out[0] = 127, 1;
|
||||
out[0] = 27, out[1] = 127; /* delete word */
|
||||
return 2;
|
||||
case 9:
|
||||
if (shift && !alt && !ctrl)
|
||||
return out[0] = CST_K_BTAB, 1;
|
||||
c = 9;
|
||||
break;
|
||||
case 27:
|
||||
c = 27;
|
||||
break;
|
||||
default:
|
||||
if (cp < ' ' || cp > 0x10FFFF)
|
||||
return 0;
|
||||
c = shift ? us_shift(cp) : cp;
|
||||
if (ctrl)
|
||||
c = ctrl_char(c);
|
||||
break;
|
||||
}
|
||||
if (!alt)
|
||||
return out[0] = c, 1;
|
||||
out[0] = 27, out[1] = c;
|
||||
return 2;
|
||||
}
|
||||
|
||||
/* "ctrl+x n", "<leader> n" or "f2" → keys; returns the count (0 on error). */
|
||||
static int parse_seq(const cst_keymap_t *km, const char *s, int keys[2]) {
|
||||
int n = 0;
|
||||
|
||||
Reference in New Issue
Block a user