// if s1 starts with s2 returns true, else false // len is the length of s1 // s2 should be null-terminated static bool starts_with(const char *s1, int len, const char *s2) { int n = 0; while (*s2 && n < len) { if (*s1++ != *s2++) return false; n++; } return *s2 == 0; } #define FOO(...) { \ FILE* f = fopen("log", "a+"); \ fprintf(f, __VA_ARGS__); \ fclose(f); \ } // convert escape sequence to event, and return consumed bytes on success (failure == 0) static int parse_escape_seq(struct tb_event *event, const char *buf, int len) { static int parse_attempts = 0; static const int MAX_PARSE_ATTEMPTS = 2; //? int x = 0; //? FOO("-- %d\n", len); //? for (x = 0; x < len; ++x) { //? FOO("%d\n", (unsigned char)buf[x]); //? } if (len >= 6 && starts_with(buf, len, "\033[M")) { switch (buf[3] & 3) { case 0: if (buf[3] == 0x60) event->key = TB_KEY_MOUSE_WHEEL_UP; else event->key = TB_KEY_MOUSE_LEFT; break; case 1: if (buf[3] == 0x61) event->key = TB_KEY_MOUSE_WHEEL_DOWN; else event->key = TB_KEY_MOUSE_MIDDLE; break; case 2: event->key = TB_KEY_MOUSE_RIGHT; break; case 3: event->key = TB_KEY_MOUSE_RELEASE; break; default: parse_attempts = 0; return -6; } event->type = TB_EVENT_MOUSE; // TB_EVENT_KEY by default // the coord is 1,1 for upper left event->x = (uint8_t)buf[4] - 1 - 32; event->y = (uint8_t)buf[5] - 1 - 32; parse_attempts = 0; return 6; } // it's pretty simple here, find 'starts_with' match and return // success, else return failure int i; for (i = 0; keys[i]; i++) { if (starts_with(buf, len, keys[i])) { event->ch = 0; event->key = 0xFFFF-i; parse_attempts = 0; return strlen(keys[i]); } } if (starts_with(buf, len, "\033[200~")) { event->ch = 0; event->key = TB_KEY_START_PASTE; parse_attempts = 0; return strlen("\033[200~"); } if (starts_with(buf, len, "\033[201~")) { event->ch = 0; event->key = TB_KEY_END_PASTE; parse_attempts = 0; return strlen("\033[201~"); } if (starts_with(buf, len, "\033[1;5A")) { event->ch = 0; event->key = TB_KEY_CTRL_ARROW_UP; parse_attempts = 0; return strlen("\033[1;5A"); } if (starts_with(buf, len, "\033[1;5B")) { event->ch = 0; event->key = TB_KEY_CTRL_ARROW_DOWN; parse_attempts = 0; return strlen("\033[1;5B"); } if (starts_with(buf, len, "\033[1;5C")) { event->ch = 0; event->key = TB_KEY_CTRL_ARROW_RIGHT; parse_attempts = 0; return strlen("\033[1;5C"); } if (starts_with(buf, len, "\033[1;5D")) { event->ch = 0; event->key = TB_KEY_CTRL_ARROW_LEFT; parse_attempts = 0; return strlen("\033[1;5D"); } if (starts_with(buf, len, "\033[Z")) { event->ch = 0; event->key = TB_KEY_SHIFT_TAB; parse_attempts = 0; return strlen("\033[Z"); } // no escape sequence recognized? wait a bit in case our buffer is incomplete ++parse_attempts; if (parse_attempts < MAX_PARSE_ATTEMPTS) return 0; // still nothing? give up and consume just the esc event->ch = 0; event->key = TB_KEY_ESC; parse_attempts = 0; return 1; } static bool extract_event(struct tb_event *event, struct bytebuffer *inbuf) { const char *buf = inbuf->buf; const int len = inbuf->len; if (len == 0) return false; //? int x = 0; //? FOO("== %d\n", len); //? for (x = 0; x < len; ++x) { //? FOO("%x\n", (unsigned char)buf[x]); //? } if (buf[0] == '\033') { int n = parse_escape_seq(event, buf, len); if (n == 0) return false; //? FOO("parsed: %u %u %u %u\n", n, (unsigned int)event->type, (unsigned int)event->key, event->ch); bool success = true; if (n < 0) { success = false; n = -n; } bytebuffer_truncate(inbuf, n); return success; } // if we're here, this is not an escape sequence and not an alt sequence // so, it's a FUNCTIONAL KEY or a UNICODE character // first of all check if it's a functional key if ((unsigned char)buf[0] <= TB_KEY_SPACE || (unsigned char)buf[0] == TB_KEY_BACKSPACE2) { // fill event, pop buffer, return success */ event->ch = 0; event->key = (uint16_t)buf[0]; bytebuffer_truncate(inbuf, 1); return true; } // feh... we got utf8 here // check if there is all bytes if (len >= tb_utf8_char_length(buf[0])) { /* everything ok, fill event, pop buffer, return success */ tb_utf8_char_to_unicode(&event->ch, buf); event->key = 0; bytebuffer_truncate(inbuf, tb_utf8_char_length(buf[0])); return true; } // event isn't recognized, perhaps there is not enough bytes in utf8 // sequence return false; }