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