bool getch2(struct input_ctx *input_ctx) { int retval = read(0, &getch2_buf[getch2_pos], BUF_LEN - getch2_len - getch2_pos); /* Return false on EOF to stop running select() on the FD, as it'd * trigger all the time. Note that it's possible to get temporary * EOF on terminal if the user presses ctrl-d, but that shouldn't * happen if the terminal state change done in getch2_enable() * works. */ if (retval == 0) return false; if (retval == -1) return errno != EBADF && errno != EINVAL; getch2_len += retval; while (getch2_pos < getch2_len) { unsigned char c = getch2_buf[getch2_pos++]; switch (state) { case STATE_INITIAL: { int match_count = keys_count_matches(&getch2_buf[0], getch2_len); if (match_count == 1) { keycode_st *st = keys_search(&getch2_buf[0], getch2_len); if (st) { mp_input_put_key(input_ctx, st->code); walk_buf(st->len); } /* else this is still a partial (but unique) match */ continue; } else if (match_count > 1) { continue; /* need more bytes to disambiguate */ } else { /* backtrack, send as UTF-8 */ getch2_pos = 1; c = getch2_buf[0]; } utf8_len = bstr_parse_utf8_code_length(c); if (utf8_len > 1) { state = STATE_UTF8; } else if (utf8_len == 1) { switch (c) { case 0x1b: /* ESC that's not part of escape sequence */ /* only if ESC was typed twice, otherwise ignore it */ if (getch2_len > 1 && getch2_buf[1] == 0x1b) { walk_buf(1); /* eat the second ESC */ mp_input_put_key(input_ctx, MP_KEY_ESC); } break; default: mp_input_put_key(input_ctx, c); } walk_buf(1); } else walk_buf(getch2_pos); break; } case STATE_UTF8: { if (getch2_pos < utf8_len) /* need more bytes */ continue; struct bstr s = {getch2_buf, utf8_len}; int unicode = bstr_decode_utf8(s, NULL); if (unicode > 0) { mp_input_put_key(input_ctx, unicode); } walk_buf(utf8_len); state = STATE_INITIAL; continue; } } } return true; }
bool getch2(struct mp_fifo *fifo) { int retval = read(0, &getch2_buf[getch2_len], BUF_LEN-getch2_len); /* Return false on EOF to stop running select() on the FD, as it'd * trigger all the time. Note that it's possible to get temporary * EOF on terminal if the user presses ctrl-d, but that shouldn't * happen if the terminal state change done in getch2_enable() * works. */ if (retval < 1) return retval; getch2_len += retval; while (getch2_len > 0 && (getch2_len > 1 || getch2_buf[0] != 27)) { int i, len, code; /* First find in the TERMCAP database: */ for (i = 0; i < getch2_key_db; i++) { if ((len = getch2_keys[i].len) <= getch2_len) if(memcmp(getch2_keys[i].chars, getch2_buf, len) == 0) { code = getch2_keys[i].code; goto found; } } /* We always match some keypress here, with length 1 if nothing else. * Since some of the cases explicitly test remaining buffer length * having a keycode only partially read in the buffer could incorrectly * use the first byte as an independent character. * However the buffer is big enough that this shouldn't happen too * easily, and it's been this way for years without many complaints. * I see no simple fix as there's no easy test which would tell * whether a string must be part of a longer keycode. */ len = 1; code = getch2_buf[0]; /* Check the well-known codes... */ if (code != 27) { if (code == 'A'-64) code = MP_KEY_HOME; else if (code == 'E'-64) code = MP_KEY_END; else if (code == 'D'-64) code = MP_KEY_DEL; else if (code == 'H'-64) code = MP_KEY_BS; else if (code == 'U'-64) code = MP_KEY_PGUP; else if (code == 'V'-64) code = MP_KEY_PGDWN; else if (code == 8 || code==127) code = MP_KEY_BS; else if (code == 10 || code==13) { if (getch2_len > 1) { int c = getch2_buf[1]; if ((c == 10 || c == 13) && (c != code)) len = 2; } code = MP_KEY_ENTER; } else { int utf8len = bstr_parse_utf8_code_length(code); if (utf8len > 0 && utf8len <= getch2_len) { struct bstr s = { getch2_buf, utf8len }; int unicode = bstr_decode_utf8(s, NULL); if (unicode > 0) { len = utf8len; code = unicode; } } } } else if (getch2_len > 1) { int c = getch2_buf[1]; if (c == 27) { code = MP_KEY_ESC; len = 2; goto found; } if (c >= '0' && c <= '9') { code = c-'0'+MP_KEY_F; len = 2; goto found; } if (getch2_len >= 4 && c == '[' && getch2_buf[2] == '[') { int c = getch2_buf[3]; if (c >= 'A' && c < 'A'+12) { code = MP_KEY_F+1 + c-'A'; len = 4; goto found; } } if ((c == '[' || c == 'O') && getch2_len >= 3) { int c = getch2_buf[2]; const int ctable[] = { MP_KEY_UP, MP_KEY_DOWN, MP_KEY_RIGHT, MP_KEY_LEFT, 0, MP_KEY_END, MP_KEY_PGDWN, MP_KEY_HOME, MP_KEY_PGUP, 0, 0, MP_KEY_INS, 0, 0, 0, MP_KEY_F+1, MP_KEY_F+2, MP_KEY_F+3, MP_KEY_F+4}; if (c >= 'A' && c <= 'S') if (ctable[c - 'A']) { code = ctable[c - 'A']; len = 3; goto found; } } if (getch2_len >= 4 && c == '[' && getch2_buf[3] == '~') { int c = getch2_buf[2]; const int ctable[8] = {MP_KEY_HOME, MP_KEY_INS, MP_KEY_DEL, MP_KEY_END, MP_KEY_PGUP, MP_KEY_PGDWN, MP_KEY_HOME, MP_KEY_END}; if (c >= '1' && c <= '8') { code = ctable[c - '1']; len = 4; goto found; } } if (getch2_len >= 5 && c == '[' && getch2_buf[4] == '~') { int i = getch2_buf[2] - '0'; int j = getch2_buf[3] - '0'; if (i >= 0 && i <= 9 && j >= 0 && j <= 9) { const short ftable[20] = { 11,12,13,14,15, 17,18,19,20,21, 23,24,25,26,28, 29,31,32,33,34 }; int a = i*10 + j; for (i = 0; i < 20; i++) if (ftable[i] == a) { code = MP_KEY_F+1 + i; len = 5; goto found; } } } } found: getch2_len -= len; for (i = 0; i < getch2_len; i++) getch2_buf[i] = getch2_buf[len+i]; mplayer_put_key(fifo, code); } return true; }