Home | History | Annotate | Download | only in src
      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