1 #include "vterm_internal.h" 2 3 #include <stdio.h> 4 5 #include "utf8.h" 6 7 void vterm_keyboard_unichar(VTerm *vt, uint32_t c, VTermModifier mod) 8 { 9 /* The shift modifier is never important for Unicode characters 10 * apart from Space 11 */ 12 if(c != ' ') 13 mod &= ~VTERM_MOD_SHIFT; 14 15 if(mod == 0) { 16 // Normal text - ignore just shift 17 char str[6]; 18 int seqlen = fill_utf8(c, str); 19 vterm_push_output_bytes(vt, str, seqlen); 20 return; 21 } 22 23 int needs_CSIu; 24 switch(c) { 25 /* Special Ctrl- letters that can't be represented elsewise */ 26 case 'i': case 'j': case 'm': case '[': 27 needs_CSIu = 1; 28 break; 29 /* Ctrl-\ ] ^ _ don't need CSUu */ 30 case '\\': case ']': case '^': case '_': 31 needs_CSIu = 0; 32 break; 33 /* Shift-space needs CSIu */ 34 case ' ': 35 needs_CSIu = !!(mod & VTERM_MOD_SHIFT); 36 break; 37 /* All other characters needs CSIu except for letters a-z */ 38 default: 39 needs_CSIu = (c < 'a' || c > 'z'); 40 } 41 42 /* ALT we can just prefix with ESC; anything else requires CSI u */ 43 if(needs_CSIu && (mod & ~VTERM_MOD_ALT)) { 44 vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", c, mod+1); 45 return; 46 } 47 48 if(mod & VTERM_MOD_CTRL) 49 c &= 0x1f; 50 51 vterm_push_output_sprintf(vt, "%s%c", mod & VTERM_MOD_ALT ? ESC_S : "", c); 52 } 53 54 typedef struct { 55 enum { 56 KEYCODE_NONE, 57 KEYCODE_LITERAL, 58 KEYCODE_TAB, 59 KEYCODE_ENTER, 60 KEYCODE_SS3, 61 KEYCODE_CSI, 62 KEYCODE_CSI_CURSOR, 63 KEYCODE_CSINUM, 64 KEYCODE_KEYPAD, 65 } type; 66 char literal; 67 int csinum; 68 } keycodes_s; 69 70 static keycodes_s keycodes[] = { 71 { KEYCODE_NONE }, // NONE 72 73 { KEYCODE_ENTER, '\r' }, // ENTER 74 { KEYCODE_TAB, '\t' }, // TAB 75 { KEYCODE_LITERAL, '\x7f' }, // BACKSPACE == ASCII DEL 76 { KEYCODE_LITERAL, '\x1b' }, // ESCAPE 77 78 { KEYCODE_CSI_CURSOR, 'A' }, // UP 79 { KEYCODE_CSI_CURSOR, 'B' }, // DOWN 80 { KEYCODE_CSI_CURSOR, 'D' }, // LEFT 81 { KEYCODE_CSI_CURSOR, 'C' }, // RIGHT 82 83 { KEYCODE_CSINUM, '~', 2 }, // INS 84 { KEYCODE_CSINUM, '~', 3 }, // DEL 85 { KEYCODE_CSI_CURSOR, 'H' }, // HOME 86 { KEYCODE_CSI_CURSOR, 'F' }, // END 87 { KEYCODE_CSINUM, '~', 5 }, // PAGEUP 88 { KEYCODE_CSINUM, '~', 6 }, // PAGEDOWN 89 }; 90 91 static keycodes_s keycodes_fn[] = { 92 { KEYCODE_NONE }, // F0 - shouldn't happen 93 { KEYCODE_CSI_CURSOR, 'P' }, // F1 94 { KEYCODE_CSI_CURSOR, 'Q' }, // F2 95 { KEYCODE_CSI_CURSOR, 'R' }, // F3 96 { KEYCODE_CSI_CURSOR, 'S' }, // F4 97 { KEYCODE_CSINUM, '~', 15 }, // F5 98 { KEYCODE_CSINUM, '~', 17 }, // F6 99 { KEYCODE_CSINUM, '~', 18 }, // F7 100 { KEYCODE_CSINUM, '~', 19 }, // F8 101 { KEYCODE_CSINUM, '~', 20 }, // F9 102 { KEYCODE_CSINUM, '~', 21 }, // F10 103 { KEYCODE_CSINUM, '~', 23 }, // F11 104 { KEYCODE_CSINUM, '~', 24 }, // F12 105 }; 106 107 static keycodes_s keycodes_kp[] = { 108 { KEYCODE_KEYPAD, '0', 'p' }, // KP_0 109 { KEYCODE_KEYPAD, '1', 'q' }, // KP_1 110 { KEYCODE_KEYPAD, '2', 'r' }, // KP_2 111 { KEYCODE_KEYPAD, '3', 's' }, // KP_3 112 { KEYCODE_KEYPAD, '4', 't' }, // KP_4 113 { KEYCODE_KEYPAD, '5', 'u' }, // KP_5 114 { KEYCODE_KEYPAD, '6', 'v' }, // KP_6 115 { KEYCODE_KEYPAD, '7', 'w' }, // KP_7 116 { KEYCODE_KEYPAD, '8', 'x' }, // KP_8 117 { KEYCODE_KEYPAD, '9', 'y' }, // KP_9 118 { KEYCODE_KEYPAD, '*', 'j' }, // KP_MULT 119 { KEYCODE_KEYPAD, '+', 'k' }, // KP_PLUS 120 { KEYCODE_KEYPAD, ',', 'l' }, // KP_COMMA 121 { KEYCODE_KEYPAD, '-', 'm' }, // KP_MINUS 122 { KEYCODE_KEYPAD, '.', 'n' }, // KP_PERIOD 123 { KEYCODE_KEYPAD, '/', 'o' }, // KP_DIVIDE 124 { KEYCODE_KEYPAD, '\n', 'M' }, // KP_ENTER 125 { KEYCODE_KEYPAD, '=', 'X' }, // KP_EQUAL 126 }; 127 128 void vterm_keyboard_key(VTerm *vt, VTermKey key, VTermModifier mod) 129 { 130 if(key == VTERM_KEY_NONE) 131 return; 132 133 keycodes_s k; 134 if(key < VTERM_KEY_FUNCTION_0) { 135 if(key >= sizeof(keycodes)/sizeof(keycodes[0])) 136 return; 137 k = keycodes[key]; 138 } 139 else if(key >= VTERM_KEY_FUNCTION_0 && key <= VTERM_KEY_FUNCTION_MAX) { 140 if((key - VTERM_KEY_FUNCTION_0) >= sizeof(keycodes_fn)/sizeof(keycodes_fn[0])) 141 return; 142 k = keycodes_fn[key - VTERM_KEY_FUNCTION_0]; 143 } 144 else if(key >= VTERM_KEY_KP_0) { 145 if((key - VTERM_KEY_KP_0) >= sizeof(keycodes_kp)/sizeof(keycodes_kp[0])) 146 return; 147 k = keycodes_kp[key - VTERM_KEY_KP_0]; 148 } 149 150 switch(k.type) { 151 case KEYCODE_NONE: 152 break; 153 154 case KEYCODE_TAB: 155 /* Shift-Tab is CSI Z but plain Tab is 0x09 */ 156 if(mod == VTERM_MOD_SHIFT) 157 vterm_push_output_sprintf_ctrl(vt, C1_CSI, "Z"); 158 else if(mod & VTERM_MOD_SHIFT) 159 vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%dZ", mod+1); 160 else 161 goto case_LITERAL; 162 break; 163 164 case KEYCODE_ENTER: 165 /* Enter is CRLF in newline mode, but just LF in linefeed */ 166 if(vt->state->mode.newline) 167 vterm_push_output_sprintf(vt, "\r\n"); 168 else 169 goto case_LITERAL; 170 break; 171 172 case KEYCODE_LITERAL: case_LITERAL: 173 if(mod & (VTERM_MOD_SHIFT|VTERM_MOD_CTRL)) 174 vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%du", k.literal, mod+1); 175 else 176 vterm_push_output_sprintf(vt, mod & VTERM_MOD_ALT ? ESC_S "%c" : "%c", k.literal); 177 break; 178 179 case KEYCODE_SS3: case_SS3: 180 if(mod == 0) 181 vterm_push_output_sprintf_ctrl(vt, C1_SS3, "%c", k.literal); 182 else 183 goto case_CSI; 184 break; 185 186 case KEYCODE_CSI: case_CSI: 187 if(mod == 0) 188 vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%c", k.literal); 189 else 190 vterm_push_output_sprintf_ctrl(vt, C1_CSI, "1;%d%c", mod + 1, k.literal); 191 break; 192 193 case KEYCODE_CSINUM: 194 if(mod == 0) 195 vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d%c", k.csinum, k.literal); 196 else 197 vterm_push_output_sprintf_ctrl(vt, C1_CSI, "%d;%d%c", k.csinum, mod + 1, k.literal); 198 break; 199 200 case KEYCODE_CSI_CURSOR: 201 if(vt->state->mode.cursor) 202 goto case_SS3; 203 else 204 goto case_CSI; 205 206 case KEYCODE_KEYPAD: 207 if(vt->state->mode.keypad) { 208 k.literal = k.csinum; 209 goto case_SS3; 210 } 211 else 212 goto case_LITERAL; 213 } 214 } 215 216 void vterm_keyboard_start_paste(VTerm *vt) 217 { 218 if(vt->state->mode.bracketpaste) 219 vterm_push_output_sprintf_ctrl(vt, C1_CSI, "200~"); 220 } 221 222 void vterm_keyboard_end_paste(VTerm *vt) 223 { 224 if(vt->state->mode.bracketpaste) 225 vterm_push_output_sprintf_ctrl(vt, C1_CSI, "201~"); 226 } 227