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