mirror of
https://github.com/mpv-player/mpv
synced 2024-12-23 15:22:09 +00:00
terminal: drop ncurses/terminfo/termcap support
It was disabled since the last release, and nobody complained loudly.
Further details see commit 4b5c3ea7
.
This commit is contained in:
parent
a037f7b464
commit
7593706af0
@ -162,8 +162,6 @@ options_state_machine() {
|
||||
|
||||
opt_yes_no _gl "OpenGL video output"
|
||||
opt_yes_no _libguess "libguess"
|
||||
opt_yes_no _terminfo "terminfo database for key codes" no
|
||||
opt_yes_no _termcap "termcap database for key codes" no
|
||||
opt_yes_no _termios "termios database for key codes"
|
||||
opt_yes_no _iconv "iconv for encoding conversion"
|
||||
opt_yes_no _lirc "LIRC (remote control) support"
|
||||
@ -533,10 +531,6 @@ test $(defretval) = yes && _soundcard_header=soundcard.h
|
||||
|
||||
check_statement_libs "sys/videoio.h" auto SYS_VIDEOIO_H sys/videoio.h
|
||||
|
||||
check_statement_libs "terminfo" $_terminfo TERMINFO term.h 'setupterm(0, 1, 0)' "-lncurses" "-lncursesw"
|
||||
|
||||
check_statement_libs "termcap" $_termcap TERMCAP term.h 'tgetent(0, 0)' " " "-lncurses" "-ltinfo" "-ltermcap"
|
||||
|
||||
_termios_ok=no
|
||||
check_statement_libs "termios.h" $_termios TERMIOS_H termios.h
|
||||
test $(defretval) = yes && _termios_ok=yes && _termios=no
|
||||
|
@ -59,8 +59,6 @@ static volatile struct termios tio_orig;
|
||||
static volatile int tio_orig_set;
|
||||
#endif
|
||||
|
||||
#if !(HAVE_TERMINFO || HAVE_TERMCAP)
|
||||
|
||||
struct key_entry {
|
||||
const char *seq;
|
||||
int mpkey;
|
||||
@ -264,9 +262,9 @@ read_more: /* need more bytes */
|
||||
return true;
|
||||
}
|
||||
|
||||
static void load_termcap(void)
|
||||
{
|
||||
}
|
||||
static volatile int getch2_active = 0;
|
||||
static volatile int getch2_enabled = 0;
|
||||
static bool read_terminal;
|
||||
|
||||
static void enable_kx(bool enable)
|
||||
{
|
||||
@ -277,384 +275,6 @@ static void enable_kx(bool enable)
|
||||
}
|
||||
}
|
||||
|
||||
#else /* terminfo/termcap */
|
||||
|
||||
typedef struct {
|
||||
char *cap;
|
||||
int len;
|
||||
int code;
|
||||
char chars[8];
|
||||
} keycode_st;
|
||||
|
||||
typedef struct {
|
||||
keycode_st *map;
|
||||
int len;
|
||||
int cap;
|
||||
} keycode_map;
|
||||
|
||||
static keycode_map getch2_keys;
|
||||
|
||||
static char *term_rmkx = NULL;
|
||||
static char *term_smkx = NULL;
|
||||
|
||||
#if HAVE_TERMINFO
|
||||
#include <curses.h>
|
||||
#endif
|
||||
#include <term.h>
|
||||
|
||||
static keycode_st *keys_push(char *p, int code) {
|
||||
if (strlen(p) > 8)
|
||||
return NULL;
|
||||
|
||||
if (getch2_keys.len == getch2_keys.cap) {
|
||||
getch2_keys.cap *= 2;
|
||||
if (getch2_keys.cap == 0)
|
||||
getch2_keys.cap = 32;
|
||||
|
||||
getch2_keys.map = realloc(getch2_keys.map, sizeof(keycode_st) * getch2_keys.cap);
|
||||
}
|
||||
|
||||
keycode_st *st = &getch2_keys.map[getch2_keys.len++];
|
||||
st->cap = NULL;
|
||||
st->len = strlen(p);
|
||||
st->code = code;
|
||||
strncpy(st->chars, p, 8);
|
||||
|
||||
return st;
|
||||
}
|
||||
|
||||
static int keys_count_matches(char *buf, int buflen) {
|
||||
int count = 0;
|
||||
if (buflen < 0)
|
||||
buflen = strlen(buf);
|
||||
|
||||
for (int i = 0; i < getch2_keys.len; i++) {
|
||||
keycode_st *st = &getch2_keys.map[i];
|
||||
int len = MPMIN(buflen, st->len);
|
||||
|
||||
if (memcmp(buf, st->chars, len) == 0)
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static keycode_st *keys_search(char *buf, int buflen) {
|
||||
if (buflen < 0)
|
||||
buflen = strlen(buf);
|
||||
|
||||
for (int i = 0; i < getch2_keys.len; i++) {
|
||||
keycode_st *st = &getch2_keys.map[i];
|
||||
|
||||
if (buflen >= st->len && memcmp(buf, st->chars, st->len) == 0)
|
||||
return st;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* pushes only if there is no duplicate.
|
||||
important as we only consider keys if the matches are unique. */
|
||||
static keycode_st* keys_push_once(char *p, int code) {
|
||||
keycode_st *st = keys_search(p, -1);
|
||||
if (!st)
|
||||
return keys_push(p, code);
|
||||
return st;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *buf;
|
||||
char *pos;
|
||||
int cap;
|
||||
} buf_st;
|
||||
static buf_st termcap_buf;
|
||||
|
||||
static void ensure_cap(buf_st *buf, int cap) {
|
||||
if (buf->pos - buf->buf < cap) {
|
||||
ptrdiff_t diff = buf->pos - buf->buf;
|
||||
buf->cap += cap;
|
||||
buf->buf = realloc(buf->buf, buf->cap);
|
||||
buf->pos = buf->buf + diff;
|
||||
}
|
||||
}
|
||||
|
||||
static char *termcap_get(char *id) {
|
||||
ensure_cap(&termcap_buf, 1024);
|
||||
return tgetstr(id, &termcap_buf.pos);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *id;
|
||||
int code;
|
||||
} cap_key_pair;
|
||||
|
||||
#if 0
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static void debug_keycode(keycode_st *st) {
|
||||
if (!st)
|
||||
return;
|
||||
|
||||
char buf[128]; /* worst case should be 70 bytes */
|
||||
unsigned char *b = &buf[0];
|
||||
unsigned char *p = &st->chars[0];
|
||||
|
||||
if (st->cap)
|
||||
b += sprintf(b, "%s: ", st->cap);
|
||||
|
||||
for(; *p; p++) {
|
||||
if (*p == 27)
|
||||
b += sprintf(b, "\\e");
|
||||
else if (*p < 27)
|
||||
b += sprintf(b, "^%c", '@' + *p);
|
||||
else if (!isgraph(*p))
|
||||
b += sprintf(b, "\\x%02x", (unsigned int)*p);
|
||||
else
|
||||
b += sprintf(b, "%c", *p);
|
||||
}
|
||||
fprintf(stderr, "%s\n", buf);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void termcap_add(cap_key_pair pair) {
|
||||
char *p = termcap_get(pair.id);
|
||||
if (p) {
|
||||
keycode_st *st = keys_push_once(p, pair.code);
|
||||
if (st)
|
||||
st->cap = pair.id;
|
||||
/* debug_keycode(st); */
|
||||
}
|
||||
}
|
||||
|
||||
static void termcap_add_extra_f_keys(void) {
|
||||
char capbuf[3];
|
||||
for (int i = 11; i < 0x20; i++) {
|
||||
unsigned char c;
|
||||
if (i < 20) { /* 1-9 */
|
||||
c = '0' + (i - 10);
|
||||
} else { /* A-Z */
|
||||
c = 'A' + (i - 20);
|
||||
}
|
||||
|
||||
sprintf(&capbuf[0], "F%c", c);
|
||||
|
||||
char *p = termcap_get(capbuf);
|
||||
if (p)
|
||||
keys_push_once(p, MP_KEY_F+i);
|
||||
else
|
||||
break; /* unlikely that the database has further keys */
|
||||
}
|
||||
}
|
||||
|
||||
static void load_termcap(void)
|
||||
{
|
||||
char *termtype = NULL;
|
||||
|
||||
#if HAVE_TERMINFO
|
||||
use_env(TRUE);
|
||||
int ret;
|
||||
if (setupterm(termtype, 1, &ret) != OK) {
|
||||
/* try again, with with "ansi" terminal if it was unset before */
|
||||
if (!termtype)
|
||||
termtype = getenv("TERM");
|
||||
if (!termtype || *termtype == '\0')
|
||||
termtype = "ansi";
|
||||
|
||||
if (setupterm(termtype, 1, &ret) != OK) {
|
||||
if (ret < 0) {
|
||||
printf("Could not access the 'terminfo' data base.\n");
|
||||
return;
|
||||
} else {
|
||||
printf("Couldn't use terminal `%s' for input.\n", termtype);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
static char term_buffer[2048];
|
||||
if (!termtype) termtype = getenv("TERM");
|
||||
if (!termtype) termtype = "ansi";
|
||||
int success = tgetent(term_buffer, termtype);
|
||||
if (success < 0) {
|
||||
printf("Could not access the 'termcap' data base.\n");
|
||||
return;
|
||||
} else if (success == 0) {
|
||||
printf("Terminal type `%s' is not defined.\n", termtype);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ensure_cap(&termcap_buf, 2048);
|
||||
|
||||
static char term_buf[128];
|
||||
char *buf_ptr = &term_buf[0];
|
||||
|
||||
// References for terminfo/termcap codes:
|
||||
// http://linux.die.net/man/5/termcap
|
||||
// http://unixhelp.ed.ac.uk/CGI/man-cgi?terminfo+5
|
||||
|
||||
term_smkx = tgetstr("ks", &buf_ptr);
|
||||
term_rmkx = tgetstr("ke", &buf_ptr);
|
||||
|
||||
cap_key_pair keys[] = {
|
||||
{"kP", MP_KEY_PGUP}, {"kN", MP_KEY_PGDWN}, {"kh", MP_KEY_HOME}, {"kH", MP_KEY_END},
|
||||
{"kI", MP_KEY_INS}, {"kD", MP_KEY_DEL}, /* on PC keyboards */ {"@7", MP_KEY_END},
|
||||
|
||||
{"kl", MP_KEY_LEFT}, {"kd", MP_KEY_DOWN}, {"ku", MP_KEY_UP}, {"kr", MP_KEY_RIGHT},
|
||||
|
||||
{"do", MP_KEY_ENTER},
|
||||
{"kb", MP_KEY_BS},
|
||||
|
||||
{"k1", MP_KEY_F+1}, {"k2", MP_KEY_F+2}, {"k3", MP_KEY_F+3},
|
||||
{"k4", MP_KEY_F+4}, {"k5", MP_KEY_F+5}, {"k6", MP_KEY_F+6},
|
||||
{"k7", MP_KEY_F+7}, {"k8", MP_KEY_F+8}, {"k9", MP_KEY_F+9},
|
||||
{"k;", MP_KEY_F+10}, {"k0", MP_KEY_F+0},
|
||||
|
||||
/* K2 is the keypad center */
|
||||
{"K2", MP_KEY_KP5},
|
||||
|
||||
/* EOL */
|
||||
{NULL},
|
||||
};
|
||||
for (int i = 0; keys[i].id; i++) {
|
||||
termcap_add(keys[i]);
|
||||
}
|
||||
termcap_add_extra_f_keys();
|
||||
|
||||
/* special cases (hardcoded, no need for HAVE_TERMCAP) */
|
||||
|
||||
/* it's important to use keys_push_once as we can't have duplicates */
|
||||
|
||||
/* many terminals, for emacs compatibility, use 0x7f instead of ^H
|
||||
when typing backspace, even when the 'kb' cap says otherwise. */
|
||||
keys_push_once("\177", MP_KEY_BS);
|
||||
|
||||
/* mintty always sends these when using the numpad arrows,
|
||||
even in application mode, for telling them from regular arrows. */
|
||||
keys_push_once("\033[A", MP_KEY_UP);
|
||||
keys_push_once("\033[B", MP_KEY_DOWN);
|
||||
keys_push_once("\033[C", MP_KEY_RIGHT);
|
||||
keys_push_once("\033[D", MP_KEY_LEFT);
|
||||
|
||||
/* mintty uses this instead of the "K2" cap for keypad center */
|
||||
keys_push_once("\033OE", MP_KEY_KP5);
|
||||
|
||||
/* fallback if terminfo and termcap are not available */
|
||||
keys_push_once("\012", MP_KEY_ENTER);
|
||||
}
|
||||
|
||||
static void enable_kx(bool enable)
|
||||
{
|
||||
char *cmd = enable ? term_smkx : term_rmkx;
|
||||
if (cmd)
|
||||
tputs(cmd, 1, putchar);
|
||||
}
|
||||
|
||||
#define BUF_LEN 256
|
||||
|
||||
static unsigned char getch2_buf[BUF_LEN];
|
||||
static int getch2_len = 0;
|
||||
static int getch2_pos = 0;
|
||||
static enum {
|
||||
STATE_INITIAL,
|
||||
STATE_UTF8,
|
||||
} state = STATE_INITIAL;
|
||||
static int utf8_len = 0;
|
||||
|
||||
static void walk_buf(unsigned int count) {
|
||||
if (!(count < BUF_LEN && count <= getch2_len))
|
||||
abort();
|
||||
|
||||
memmove(&getch2_buf[0], &getch2_buf[count], getch2_len - count);
|
||||
getch2_len -= count;
|
||||
getch2_pos -= count;
|
||||
if (getch2_pos < 0)
|
||||
getch2_pos = 0;
|
||||
}
|
||||
|
||||
static 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 terminal_init()
|
||||
* 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;
|
||||
}
|
||||
|
||||
#endif /* terminfo/termcap */
|
||||
|
||||
static volatile int getch2_active = 0;
|
||||
static volatile int getch2_enabled = 0;
|
||||
static bool read_terminal;
|
||||
|
||||
static void do_activate_getch2(void)
|
||||
{
|
||||
if (getch2_active || !read_terminal)
|
||||
@ -852,9 +472,6 @@ int terminal_init(void)
|
||||
assert(!getch2_enabled);
|
||||
getch2_enabled = 1;
|
||||
|
||||
if (isatty(STDOUT_FILENO))
|
||||
load_termcap();
|
||||
|
||||
read_terminal = isatty(STDIN_FILENO) && isatty(STDOUT_FILENO);
|
||||
|
||||
// handlers to fix terminal settings
|
||||
|
13
wscript
13
wscript
@ -174,19 +174,6 @@ iconv support use --disable-iconv.",
|
||||
'name': 'videoio',
|
||||
'desc': 'videoio.h',
|
||||
'func': check_headers('sys/videoio.h')
|
||||
}, {
|
||||
'name': '--terminfo',
|
||||
'desc': 'terminfo',
|
||||
'default': 'disable',
|
||||
'func': check_libs(['ncurses', 'ncursesw'],
|
||||
check_statement('term.h', 'setupterm(0, 1, 0)')),
|
||||
}, {
|
||||
'name': '--termcap',
|
||||
'desc': 'termcap',
|
||||
'deps_neg': ['terminfo'],
|
||||
'default': 'disable',
|
||||
'func': check_libs(['ncurses', 'tinfo', 'termcap'],
|
||||
check_statement('term.h', 'tgetent(0, 0)')),
|
||||
}, {
|
||||
'name': '--termios',
|
||||
'desc': 'termios',
|
||||
|
Loading…
Reference in New Issue
Block a user