heartbeat

Log

Files

Refs

README

input.h (5264B)

     1 // if s1 starts with s2 returns true, else false
     2 // len is the length of s1
     3 // s2 should be null-terminated
     4 static bool starts_with(const char *s1, int len, const char *s2)
     5 {
     6         int n = 0;
     7         while (*s2 && n < len) {
     8                 if (*s1++ != *s2++)
     9                         return false;
    10                 n++;
    11         }
    12         return *s2 == 0;
    13 }
    14 
    15 static int parse_mouse_event(struct tb_event *event, const char *buf, int len) {
    16         if (len >= 6 && starts_with(buf, len, "\033[M")) {
    17                 // X10 mouse encoding, the simplest one
    18                 // \033 [ M Cb Cx Cy
    19                 int b = buf[3] - 32;
    20                 switch (b & 3) {
    21                 case 0:
    22                         if ((b & 64) != 0)
    23                                 event->key = TB_KEY_MOUSE_WHEEL_UP;
    24                         else
    25                                 event->key = TB_KEY_MOUSE_LEFT;
    26                         break;
    27                 case 1:
    28                         if ((b & 64) != 0)
    29                                 event->key = TB_KEY_MOUSE_WHEEL_DOWN;
    30                         else
    31                                 event->key = TB_KEY_MOUSE_MIDDLE;
    32                         break;
    33                 case 2:
    34                         event->key = TB_KEY_MOUSE_RIGHT;
    35                         break;
    36                 case 3:
    37                         event->key = TB_KEY_MOUSE_RELEASE;
    38                         break;
    39                 default:
    40                         return -6;
    41                 }
    42                 event->type = TB_EVENT_MOUSE; // TB_EVENT_KEY by default
    43                 if ((b & 32) != 0)
    44                         event->mod |= TB_MOD_MOTION;
    45 
    46                 // the coord is 1,1 for upper left
    47                 event->x = (uint8_t)buf[4] - 1 - 32;
    48                 event->y = (uint8_t)buf[5] - 1 - 32;
    49 
    50                 return 6;
    51         } else if (starts_with(buf, len, "\033[<") || starts_with(buf, len, "\033[")) {
    52                 // xterm 1006 extended mode or urxvt 1015 extended mode
    53                 // xterm: \033 [ < Cb ; Cx ; Cy (M or m)
    54                 // urxvt: \033 [ Cb ; Cx ; Cy M
    55                 int i, mi = -1, starti = -1;
    56                 int isM, isU, s1 = -1, s2 = -1;
    57                 int n1 = 0, n2 = 0, n3 = 0;
    58 
    59                 for (i = 0; i < len; i++) {
    60                         // We search the first (s1) and the last (s2) ';'
    61                         if (buf[i] == ';') {
    62                                 if (s1 == -1)
    63                                         s1 = i;
    64                                 s2 = i;
    65                         }
    66 
    67                         // We search for the first 'm' or 'M'
    68                         if ((buf[i] == 'm' || buf[i] == 'M') && mi == -1) {
    69                                 mi = i;
    70                                 break;
    71                         }
    72                 }
    73                 if (mi == -1)
    74                         return 0;
    75 
    76                 // whether it's a capital M or not
    77                 isM = (buf[mi] == 'M');
    78 
    79                 if (buf[2] == '<') {
    80                         isU = 0;
    81                         starti = 3;
    82                 } else {
    83                         isU = 1;
    84                         starti = 2;
    85                 }
    86 
    87                 if (s1 == -1 || s2 == -1 || s1 == s2)
    88                         return 0;
    89 
    90                 n1 = strtoul(&buf[starti], NULL, 10);
    91                 n2 = strtoul(&buf[s1 + 1], NULL, 10);
    92                 n3 = strtoul(&buf[s2 + 1], NULL, 10);
    93 
    94                 if (isU)
    95                         n1 -= 32;
    96 
    97                 switch (n1 & 3) {
    98                 case 0:
    99                         if ((n1&64) != 0) {
   100                                 event->key = TB_KEY_MOUSE_WHEEL_UP;
   101                         } else {
   102                                 event->key = TB_KEY_MOUSE_LEFT;
   103                         }
   104                         break;
   105                 case 1:
   106                         if ((n1&64) != 0) {
   107                                 event->key = TB_KEY_MOUSE_WHEEL_DOWN;
   108                         } else {
   109                                 event->key = TB_KEY_MOUSE_MIDDLE;
   110                         }
   111                         break;
   112                 case 2:
   113                         event->key = TB_KEY_MOUSE_RIGHT;
   114                         break;
   115                 case 3:
   116                         event->key = TB_KEY_MOUSE_RELEASE;
   117                         break;
   118                 default:
   119                         return mi + 1;
   120                 }
   121 
   122                 if (!isM) {
   123                         // on xterm mouse release is signaled by lowercase m
   124                         event->key = TB_KEY_MOUSE_RELEASE;
   125                 }
   126 
   127                 event->type = TB_EVENT_MOUSE; // TB_EVENT_KEY by default
   128                 if ((n1&32) != 0)
   129                         event->mod |= TB_MOD_MOTION;
   130 
   131                 event->x = n2 - 1;
   132                 event->y = n3 - 1;
   133 
   134                 return mi + 1;
   135         }
   136 
   137         return 0;
   138 }
   139 
   140 // convert escape sequence to event, and return consumed bytes on success (failure == 0)
   141 static int parse_escape_seq(struct tb_event *event, const char *buf, int len)
   142 {
   143         int mouse_parsed = parse_mouse_event(event, buf, len);
   144 
   145         if (mouse_parsed != 0)
   146                 return mouse_parsed;
   147 
   148         // it's pretty simple here, find 'starts_with' match and return
   149         // success, else return failure
   150         int i;
   151         for (i = 0; keys[i]; i++) {
   152                 if (starts_with(buf, len, keys[i])) {
   153                         event->ch = 0;
   154                         event->key = 0xFFFF-i;
   155                         return strlen(keys[i]);
   156                 }
   157         }
   158         return 0;
   159 }
   160 
   161 static bool extract_event(struct tb_event *event, struct bytebuffer *inbuf, int inputmode)
   162 {
   163         const char *buf = inbuf->buf;
   164         const int len = inbuf->len;
   165         if (len == 0)
   166                 return false;
   167 
   168         if (buf[0] == '\033') {
   169                 int n = parse_escape_seq(event, buf, len);
   170                 if (n != 0) {
   171                         bool success = true;
   172                         if (n < 0) {
   173                                 success = false;
   174                                 n = -n;
   175                         }
   176                         bytebuffer_truncate(inbuf, n);
   177                         return success;
   178                 } else {
   179                         // it's not escape sequence, then it's ALT or ESC,
   180                         // check inputmode
   181                         if (inputmode&TB_INPUT_ESC) {
   182                                 // if we're in escape mode, fill ESC event, pop
   183                                 // buffer, return success
   184                                 event->ch = 0;
   185                                 event->key = TB_KEY_ESC;
   186                                 event->mod = 0;
   187                                 bytebuffer_truncate(inbuf, 1);
   188                                 return true;
   189                         } else if (inputmode&TB_INPUT_ALT) {
   190                                 // if we're in alt mode, set ALT modifier to
   191                                 // event and redo parsing
   192                                 event->mod = TB_MOD_ALT;
   193                                 bytebuffer_truncate(inbuf, 1);
   194                                 return extract_event(event, inbuf, inputmode);
   195                         }
   196                         assert(!"never got here");
   197                 }
   198         }
   199 
   200         // if we're here, this is not an escape sequence and not an alt sequence
   201         // so, it's a FUNCTIONAL KEY or a UNICODE character
   202 
   203         // first of all check if it's a functional key
   204         if ((unsigned char)buf[0] <= TB_KEY_SPACE ||
   205             (unsigned char)buf[0] == TB_KEY_BACKSPACE2)
   206         {
   207                 // fill event, pop buffer, return success */
   208                 event->ch = 0;
   209                 event->key = (uint16_t)buf[0];
   210                 bytebuffer_truncate(inbuf, 1);
   211                 return true;
   212         }
   213 
   214         // feh... we got utf8 here
   215 
   216         // check if there is all bytes
   217         if (len >= tb_utf8_char_length(buf[0])) {
   218                 /* everything ok, fill event, pop buffer, return success */
   219                 tb_utf8_char_to_unicode(&event->ch, buf);
   220                 event->key = 0;
   221                 bytebuffer_truncate(inbuf, tb_utf8_char_length(buf[0]));
   222                 return true;
   223         }
   224 
   225         // event isn't recognized, perhaps there is not enough bytes in utf8
   226         // sequence
   227         return false;
   228 }