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 }