helos1/extlib/libvterm/keyboard.c
2021-10-10 14:39:17 +08:00

229 lines
5.8 KiB
C

#include "vterm_internal.h"
#include <stdio.h>
#include "utf8.h"
void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) {
/* The shift modifier is never important for Unicode characters
* apart from Space
*/
if (c != ' ')
mod &= ~VTERM_MOD_SHIFT;
if (mod == 0) {
// Normal text - ignore just shift
char str[6];
int seqlen = fill_utf8(c, str);
vterm_push_output_bytes(vt, str, seqlen);
return;
}
int needs_CSIu;
switch (c) {
/* Special Ctrl- letters that can't be represented elsewise */
case 'i':
case 'j':
case 'm':
case '[':
needs_CSIu = 1;
break;
/* Ctrl-\ ] ^ _ don't need CSUu */
case '\\':
case ']':
case '^':
case '_':
needs_CSIu = 0;
break;
/* Shift-space needs CSIu */
case ' ':
needs_CSIu = !!(mod & VTERM_MOD_SHIFT);
break;
/* All other characters needs CSIu except for letters a-z */
default:
needs_CSIu = (c < 'a' || c > 'z');
}
/* ALT we can just prefix with ESC; anything else requires CSI u */
if (needs_CSIu && (mod & ~VTERM_MOD_ALT)) {
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod + 1);
return;
}
if (mod & VTERM_MOD_CTRL)
c &= 0x1f;
vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? ESC_S : "", c);
}
typedef struct {
enum {
KEYCODE_NONE,
KEYCODE_LITERAL,
KEYCODE_TAB,
KEYCODE_ENTER,
KEYCODE_SS3,
KEYCODE_CSI,
KEYCODE_CSI_CURSOR,
KEYCODE_CSINUM,
KEYCODE_KEYPAD,
} type;
char literal;
int csinum;
} keycodes_s;
static keycodes_s keycodes[] = {
{KEYCODE_NONE}, // NONE
{KEYCODE_ENTER, '\r'}, // ENTER
{KEYCODE_TAB, '\t'}, // TAB
{KEYCODE_LITERAL, '\x7f'}, // BACKSPACE == ASCII DEL
{KEYCODE_LITERAL, '\x1b'}, // ESCAPE
{KEYCODE_CSI_CURSOR, 'A'}, // UP
{KEYCODE_CSI_CURSOR, 'B'}, // DOWN
{KEYCODE_CSI_CURSOR, 'D'}, // LEFT
{KEYCODE_CSI_CURSOR, 'C'}, // RIGHT
{KEYCODE_CSINUM, '~', 2}, // INS
{KEYCODE_CSINUM, '~', 3}, // DEL
{KEYCODE_CSI_CURSOR, 'H'}, // HOME
{KEYCODE_CSI_CURSOR, 'F'}, // END
{KEYCODE_CSINUM, '~', 5}, // PAGEUP
{KEYCODE_CSINUM, '~', 6}, // PAGEDOWN
};
static keycodes_s keycodes_fn[] = {
{KEYCODE_NONE}, // F0 - shouldn't happen
{KEYCODE_SS3, 'P'}, // F1
{KEYCODE_SS3, 'Q'}, // F2
{KEYCODE_SS3, 'R'}, // F3
{KEYCODE_SS3, 'S'}, // F4
{KEYCODE_CSINUM, '~', 15}, // F5
{KEYCODE_CSINUM, '~', 17}, // F6
{KEYCODE_CSINUM, '~', 18}, // F7
{KEYCODE_CSINUM, '~', 19}, // F8
{KEYCODE_CSINUM, '~', 20}, // F9
{KEYCODE_CSINUM, '~', 21}, // F10
{KEYCODE_CSINUM, '~', 23}, // F11
{KEYCODE_CSINUM, '~', 24}, // F12
};
static keycodes_s keycodes_kp[] = {
{KEYCODE_KEYPAD, '0', 'p'}, // KP_0
{KEYCODE_KEYPAD, '1', 'q'}, // KP_1
{KEYCODE_KEYPAD, '2', 'r'}, // KP_2
{KEYCODE_KEYPAD, '3', 's'}, // KP_3
{KEYCODE_KEYPAD, '4', 't'}, // KP_4
{KEYCODE_KEYPAD, '5', 'u'}, // KP_5
{KEYCODE_KEYPAD, '6', 'v'}, // KP_6
{KEYCODE_KEYPAD, '7', 'w'}, // KP_7
{KEYCODE_KEYPAD, '8', 'x'}, // KP_8
{KEYCODE_KEYPAD, '9', 'y'}, // KP_9
{KEYCODE_KEYPAD, '*', 'j'}, // KP_MULT
{KEYCODE_KEYPAD, '+', 'k'}, // KP_PLUS
{KEYCODE_KEYPAD, ',', 'l'}, // KP_COMMA
{KEYCODE_KEYPAD, '-', 'm'}, // KP_MINUS
{KEYCODE_KEYPAD, '.', 'n'}, // KP_PERIOD
{KEYCODE_KEYPAD, '/', 'o'}, // KP_DIVIDE
{KEYCODE_KEYPAD, '\n', 'M'}, // KP_ENTER
{KEYCODE_KEYPAD, '=', 'X'}, // KP_EQUAL
};
void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) {
if (key == VTERM_KEY_NONE)
return;
keycodes_s k;
if (key < VTERM_KEY_FUNCTION_0) {
if (key >= sizeof(keycodes) / sizeof(keycodes[0]))
return;
k = keycodes[key];
} else if (key >= VTERM_KEY_FUNCTION_0 && key <= VTERM_KEY_FUNCTION_MAX) {
if ((key - VTERM_KEY_FUNCTION_0) >= sizeof(keycodes_fn) / sizeof(keycodes_fn[0]))
return;
k = keycodes_fn[key - VTERM_KEY_FUNCTION_0];
} else if (key >= VTERM_KEY_KP_0) {
if ((key - VTERM_KEY_KP_0) >= sizeof(keycodes_kp) / sizeof(keycodes_kp[0]))
return;
k = keycodes_kp[key - VTERM_KEY_KP_0];
}
switch (k.type) {
case KEYCODE_NONE:
break;
case KEYCODE_TAB:
/* Shift-Tab is CSI Z but plain Tab is 0x09 */
if (mod == VTERM_MOD_SHIFT)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z");
else if (mod & VTERM_MOD_SHIFT)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%dZ", mod + 1);
else
goto case_LITERAL;
break;
case KEYCODE_ENTER:
/* Enter is CRLF in newline mode, but just LF in linefeed */
if (vt->state->mode.newline)
vterm_push_output_sprintf(vt, "\r\n");
else
goto case_LITERAL;
break;
case KEYCODE_LITERAL:
case_LITERAL:
if (mod & (VTERM_MOD_SHIFT | VTERM_MOD_CTRL))
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod + 1);
else
vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? ESC_S "%c" : "%c", k.literal);
break;
case KEYCODE_SS3:
case_SS3:
if (mod == 0)
vterm_push_output_sprintf_ctrl(vt, C1_SS3, "%c", k.literal);
else
goto case_CSI;
break;
case KEYCODE_CSI:
case_CSI:
if (mod == 0)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%c", k.literal);
else
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%d%c", mod + 1, k.literal);
break;
case KEYCODE_CSINUM:
if (mod == 0)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d%c", k.csinum, k.literal);
else
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%d%c", k.csinum, mod + 1, k.literal);
break;
case KEYCODE_CSI_CURSOR:
if (vt->state->mode.cursor)
goto case_SS3;
else
goto case_CSI;
case KEYCODE_KEYPAD:
if (vt->state->mode.keypad) {
k.literal = k.csinum;
goto case_SS3;
} else
goto case_LITERAL;
}
}
void vterm_keyboard_start_paste(VTerm *vt) {
if (vt->state->mode.bracketpaste)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "200~");
}
void vterm_keyboard_end_paste(VTerm *vt) {
if (vt->state->mode.bracketpaste)
vterm_push_output_sprintf_ctrl(vt, C1_CSI, "201~");
}