2009-03-01 13:13:25 +00:00
|
|
|
/*
|
|
|
|
* GyS-TermIO v2.0 (for GySmail v3)
|
|
|
|
* a very small replacement of ncurses library
|
|
|
|
*
|
|
|
|
* copyright (C) 1999 A'rpi/ESP-team
|
|
|
|
*
|
|
|
|
* This file is part of MPlayer.
|
|
|
|
*
|
|
|
|
* MPlayer is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* MPlayer is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with MPlayer; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
2001-02-24 20:28:24 +00:00
|
|
|
|
2005-11-14 00:30:37 +00:00
|
|
|
#include "config.h"
|
2001-02-24 20:28:24 +00:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
2013-07-22 01:27:58 +00:00
|
|
|
#include <stdint.h>
|
2001-02-24 20:28:24 +00:00
|
|
|
#include <string.h>
|
2012-02-25 14:05:12 +00:00
|
|
|
#include <signal.h>
|
2013-10-28 22:32:57 +00:00
|
|
|
#include <errno.h>
|
2001-02-24 20:28:24 +00:00
|
|
|
#include <sys/ioctl.h>
|
2014-08-21 20:15:32 +00:00
|
|
|
#include <assert.h>
|
2001-12-03 15:22:03 +00:00
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_TERMIOS
|
|
|
|
#if HAVE_TERMIOS_H
|
2001-12-03 15:22:03 +00:00
|
|
|
#include <termios.h>
|
|
|
|
#endif
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_SYS_TERMIOS_H
|
2001-02-24 20:28:24 +00:00
|
|
|
#include <sys/termios.h>
|
2001-11-19 17:03:38 +00:00
|
|
|
#endif
|
2001-12-03 15:22:03 +00:00
|
|
|
#endif
|
|
|
|
|
2001-02-24 20:28:24 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2013-12-17 01:39:45 +00:00
|
|
|
#include "common/common.h"
|
2014-08-29 10:09:04 +00:00
|
|
|
#include "misc/bstr.h"
|
2013-12-17 00:23:09 +00:00
|
|
|
#include "input/input.h"
|
|
|
|
#include "input/keycodes.h"
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
#include "misc/ctype.h"
|
2013-12-19 20:31:27 +00:00
|
|
|
#include "terminal.h"
|
2001-02-24 20:28:24 +00:00
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_TERMIOS
|
2013-01-23 14:47:49 +00:00
|
|
|
static volatile struct termios tio_orig;
|
|
|
|
static volatile int tio_orig_set;
|
2001-11-19 17:03:38 +00:00
|
|
|
#endif
|
2001-02-24 20:28:24 +00:00
|
|
|
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
#if !(HAVE_TERMINFO || HAVE_TERMCAP)
|
|
|
|
|
|
|
|
struct key_entry {
|
|
|
|
const char *seq;
|
|
|
|
int mpkey;
|
|
|
|
// If this is not NULL, then if seq is matched as unique prefix, the
|
|
|
|
// existing sequence is replaced by the following string. Matching
|
|
|
|
// continues normally, and mpkey is or-ed into the final result.
|
|
|
|
const char *replace;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct key_entry keys[] = {
|
|
|
|
{"\011", MP_KEY_TAB},
|
|
|
|
{"\012", MP_KEY_ENTER},
|
|
|
|
{"\177", MP_KEY_BS},
|
|
|
|
|
|
|
|
{"\033[1~", MP_KEY_HOME},
|
|
|
|
{"\033[2~", MP_KEY_INS},
|
|
|
|
{"\033[3~", MP_KEY_DEL},
|
|
|
|
{"\033[4~", MP_KEY_END},
|
|
|
|
{"\033[5~", MP_KEY_PGUP},
|
|
|
|
{"\033[6~", MP_KEY_PGDWN},
|
|
|
|
{"\033[7~", MP_KEY_HOME},
|
|
|
|
{"\033[8~", MP_KEY_END},
|
|
|
|
|
|
|
|
{"\033[11~", MP_KEY_F+1},
|
|
|
|
{"\033[12~", MP_KEY_F+2},
|
|
|
|
{"\033[13~", MP_KEY_F+3},
|
|
|
|
{"\033[14~", MP_KEY_F+4},
|
|
|
|
{"\033[15~", MP_KEY_F+5},
|
|
|
|
{"\033[17~", MP_KEY_F+6},
|
|
|
|
{"\033[18~", MP_KEY_F+7},
|
|
|
|
{"\033[19~", MP_KEY_F+8},
|
|
|
|
{"\033[20~", MP_KEY_F+9},
|
|
|
|
{"\033[21~", MP_KEY_F+10},
|
|
|
|
{"\033[23~", MP_KEY_F+11},
|
|
|
|
{"\033[24~", MP_KEY_F+12},
|
|
|
|
|
|
|
|
{"\033[A", MP_KEY_UP},
|
|
|
|
{"\033[B", MP_KEY_DOWN},
|
|
|
|
{"\033[C", MP_KEY_RIGHT},
|
|
|
|
{"\033[D", MP_KEY_LEFT},
|
|
|
|
{"\033[E", MP_KEY_KP5},
|
|
|
|
{"\033[F", MP_KEY_END},
|
|
|
|
{"\033[H", MP_KEY_HOME},
|
|
|
|
|
|
|
|
{"\033[[A", MP_KEY_F+1},
|
|
|
|
{"\033[[B", MP_KEY_F+2},
|
|
|
|
{"\033[[C", MP_KEY_F+3},
|
|
|
|
{"\033[[D", MP_KEY_F+4},
|
|
|
|
{"\033[[E", MP_KEY_F+5},
|
|
|
|
|
|
|
|
{"\033OE", MP_KEY_KP5}, // mintty?
|
|
|
|
{"\033OM", MP_KEY_KPENTER},
|
|
|
|
{"\033OP", MP_KEY_F+1},
|
|
|
|
{"\033OQ", MP_KEY_F+2},
|
|
|
|
{"\033OR", MP_KEY_F+3},
|
|
|
|
{"\033OS", MP_KEY_F+4},
|
|
|
|
|
|
|
|
{"\033Oa", MP_KEY_UP | MP_KEY_MODIFIER_CTRL}, // urxvt
|
|
|
|
{"\033Ob", MP_KEY_DOWN | MP_KEY_MODIFIER_CTRL},
|
|
|
|
{"\033Oc", MP_KEY_RIGHT | MP_KEY_MODIFIER_CTRL},
|
|
|
|
{"\033Od", MP_KEY_LEFT | MP_KEY_MODIFIER_CTRL},
|
|
|
|
{"\033Oj", '*'}, // also keypad, but we don't have separate codes for them
|
|
|
|
{"\033Ok", '+'},
|
|
|
|
{"\033Om", '-'},
|
|
|
|
{"\033On", MP_KEY_KPDEC},
|
|
|
|
{"\033Oo", '/'},
|
|
|
|
{"\033Op", MP_KEY_KP0},
|
|
|
|
{"\033Oq", MP_KEY_KP1},
|
|
|
|
{"\033Or", MP_KEY_KP2},
|
|
|
|
{"\033Os", MP_KEY_KP3},
|
|
|
|
{"\033Ot", MP_KEY_KP4},
|
|
|
|
{"\033Ou", MP_KEY_KP5},
|
|
|
|
{"\033Ov", MP_KEY_KP6},
|
|
|
|
{"\033Ow", MP_KEY_KP7},
|
|
|
|
{"\033Ox", MP_KEY_KP8},
|
|
|
|
{"\033Oy", MP_KEY_KP9},
|
|
|
|
|
|
|
|
{"\033[a", MP_KEY_UP | MP_KEY_MODIFIER_SHIFT}, // urxvt
|
|
|
|
{"\033[b", MP_KEY_DOWN | MP_KEY_MODIFIER_SHIFT},
|
|
|
|
{"\033[c", MP_KEY_RIGHT | MP_KEY_MODIFIER_SHIFT},
|
|
|
|
{"\033[d", MP_KEY_LEFT | MP_KEY_MODIFIER_SHIFT},
|
|
|
|
{"\033[2^", MP_KEY_INS | MP_KEY_MODIFIER_CTRL},
|
|
|
|
{"\033[3^", MP_KEY_DEL | MP_KEY_MODIFIER_CTRL},
|
|
|
|
{"\033[5^", MP_KEY_PGUP | MP_KEY_MODIFIER_CTRL},
|
|
|
|
{"\033[6^", MP_KEY_PGDWN | MP_KEY_MODIFIER_CTRL},
|
|
|
|
{"\033[7^", MP_KEY_HOME | MP_KEY_MODIFIER_CTRL},
|
|
|
|
{"\033[8^", MP_KEY_END | MP_KEY_MODIFIER_CTRL},
|
|
|
|
|
|
|
|
{"\033[1;2", MP_KEY_MODIFIER_SHIFT, .replace = "\033["}, // xterm
|
|
|
|
{"\033[1;3", MP_KEY_MODIFIER_ALT, .replace = "\033["},
|
|
|
|
{"\033[1;5", MP_KEY_MODIFIER_CTRL, .replace = "\033["},
|
|
|
|
{"\033[1;4", MP_KEY_MODIFIER_ALT | MP_KEY_MODIFIER_SHIFT, .replace = "\033["},
|
|
|
|
{"\033[1;6", MP_KEY_MODIFIER_CTRL | MP_KEY_MODIFIER_SHIFT, .replace = "\033["},
|
|
|
|
{"\033[1;7", MP_KEY_MODIFIER_CTRL | MP_KEY_MODIFIER_ALT, .replace = "\033["},
|
|
|
|
{"\033[1;8",
|
|
|
|
MP_KEY_MODIFIER_CTRL | MP_KEY_MODIFIER_ALT | MP_KEY_MODIFIER_SHIFT,
|
|
|
|
.replace = "\033["},
|
|
|
|
|
|
|
|
{"\033[29~", MP_KEY_MENU},
|
|
|
|
{"\033[Z", MP_KEY_TAB | MP_KEY_MODIFIER_SHIFT},
|
|
|
|
|
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
|
|
|
#define BUF_LEN 256
|
|
|
|
|
|
|
|
struct termbuf {
|
|
|
|
unsigned char b[BUF_LEN];
|
|
|
|
int len;
|
|
|
|
int mods;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void skip_buf(struct termbuf *b, unsigned int count)
|
|
|
|
{
|
|
|
|
assert(count <= b->len);
|
|
|
|
|
|
|
|
memmove(&b->b[0], &b->b[count], b->len - count);
|
|
|
|
b->len -= count;
|
|
|
|
b->mods = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct termbuf buf;
|
|
|
|
|
|
|
|
static bool getch2(struct input_ctx *input_ctx)
|
|
|
|
{
|
|
|
|
int retval = read(0, &buf.b[buf.len], BUF_LEN - buf.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 == 0)
|
|
|
|
return false;
|
|
|
|
if (retval == -1)
|
|
|
|
return errno != EBADF && errno != EINVAL;
|
|
|
|
buf.len += retval;
|
|
|
|
|
|
|
|
while (buf.len) {
|
|
|
|
int utf8_len = bstr_parse_utf8_code_length(buf.b[0]);
|
|
|
|
if (utf8_len > 1) {
|
|
|
|
if (buf.len < utf8_len)
|
|
|
|
goto read_more;
|
|
|
|
|
|
|
|
mp_input_put_key_utf8(input_ctx, buf.mods, (bstr){buf.b, utf8_len});
|
|
|
|
skip_buf(&buf, utf8_len);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct key_entry *match = NULL; // may be a partial match
|
|
|
|
for (int n = 0; keys[n].seq; n++) {
|
|
|
|
const struct key_entry *e = &keys[n];
|
|
|
|
if (memcmp(e->seq, buf.b, MPMIN(buf.len, strlen(e->seq))) == 0) {
|
|
|
|
if (match)
|
|
|
|
goto read_more; /* need more bytes to disambiguate */
|
|
|
|
match = e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!match) { // normal or unknown key
|
|
|
|
if (buf.b[0] == '\033') {
|
|
|
|
skip_buf(&buf, 1);
|
|
|
|
if (buf.len > 0 && mp_isalnum(buf.b[0])) { // meta+normal key
|
|
|
|
mp_input_put_key(input_ctx, buf.b[0] | MP_KEY_MODIFIER_ALT);
|
|
|
|
skip_buf(&buf, 1);
|
|
|
|
} else if (buf.len == 1 && buf.b[0] == '\033') {
|
|
|
|
mp_input_put_key(input_ctx, MP_KEY_ESC);
|
|
|
|
skip_buf(&buf, 1);
|
|
|
|
} else {
|
|
|
|
// Throw it away. Typically, this will be a complete,
|
|
|
|
// unsupported sequence, and dropping this will skip it.
|
|
|
|
skip_buf(&buf, buf.len);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
mp_input_put_key(input_ctx, buf.b[0]);
|
|
|
|
skip_buf(&buf, 1);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int seq_len = strlen(match->seq);
|
|
|
|
if (seq_len > buf.len)
|
|
|
|
goto read_more; /* partial match */
|
|
|
|
|
|
|
|
if (match->replace) {
|
|
|
|
int rep = strlen(match->replace);
|
|
|
|
assert(rep <= seq_len);
|
|
|
|
memcpy(buf.b, match->replace, rep);
|
|
|
|
memmove(buf.b + rep, buf.b + seq_len, buf.len - seq_len);
|
|
|
|
buf.len = rep + buf.len - seq_len;
|
|
|
|
buf.mods |= match->mpkey;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
mp_input_put_key(input_ctx, buf.mods | match->mpkey);
|
|
|
|
skip_buf(&buf, seq_len);
|
|
|
|
}
|
|
|
|
|
|
|
|
read_more: /* need more bytes */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void load_termcap(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static void enable_kx(bool enable)
|
|
|
|
{
|
2014-08-28 04:22:13 +00:00
|
|
|
if (isatty(STDOUT_FILENO)) {
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
char *cmd = enable ? "\033=" : "\033>";
|
|
|
|
printf("%s", cmd);
|
|
|
|
fflush(stdout);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* terminfo/termcap */
|
|
|
|
|
2001-02-24 20:28:24 +00:00
|
|
|
typedef struct {
|
2013-07-22 01:27:58 +00:00
|
|
|
char *cap;
|
|
|
|
int len;
|
|
|
|
int code;
|
|
|
|
char chars[8];
|
2001-02-24 20:28:24 +00:00
|
|
|
} keycode_st;
|
2013-07-22 01:27:58 +00:00
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
keycode_st *map;
|
|
|
|
int len;
|
|
|
|
int cap;
|
|
|
|
} keycode_map;
|
|
|
|
|
|
|
|
static keycode_map getch2_keys;
|
2001-02-24 20:28:24 +00:00
|
|
|
|
2013-07-22 01:27:58 +00:00
|
|
|
static char *term_rmkx = NULL;
|
|
|
|
static char *term_smkx = NULL;
|
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_TERMINFO
|
2013-07-22 01:27:58 +00:00
|
|
|
#include <curses.h>
|
|
|
|
#endif
|
|
|
|
#include <term.h>
|
|
|
|
|
|
|
|
static keycode_st *keys_push(char *p, int code) {
|
2014-04-09 22:15:11 +00:00
|
|
|
if (strlen(p) > 8)
|
|
|
|
return NULL;
|
|
|
|
|
2013-07-22 01:27:58 +00:00
|
|
|
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;
|
|
|
|
|
2001-02-24 20:28:24 +00:00
|
|
|
#if 0
|
2013-07-22 01:27:58 +00:00
|
|
|
#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);
|
|
|
|
}
|
2001-02-24 20:28:24 +00:00
|
|
|
#endif
|
|
|
|
|
2013-07-22 01:27:58 +00:00
|
|
|
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); */
|
|
|
|
}
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
|
|
|
|
2013-07-22 01:27:58 +00:00
|
|
|
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);
|
|
|
|
}
|
2001-02-24 20:28:24 +00:00
|
|
|
|
2013-07-22 01:27:58 +00:00
|
|
|
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 */
|
|
|
|
}
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
|
|
|
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
static void load_termcap(void)
|
|
|
|
{
|
|
|
|
char *termtype = NULL;
|
2013-07-22 01:27:58 +00:00
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_TERMINFO
|
2013-07-22 01:27:58 +00:00
|
|
|
use_env(TRUE);
|
2013-07-26 14:29:34 +00:00
|
|
|
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");
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
return;
|
2013-07-26 14:29:34 +00:00
|
|
|
} else {
|
|
|
|
printf("Couldn't use terminal `%s' for input.\n", termtype);
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
return;
|
2013-07-26 14:29:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-07-22 01:27:58 +00:00
|
|
|
#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");
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
return;
|
2013-07-22 01:27:58 +00:00
|
|
|
} else if (success == 0) {
|
|
|
|
printf("Terminal type `%s' is not defined.\n", termtype);
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
return;
|
2013-07-22 01:27:58 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
ensure_cap(&termcap_buf, 2048);
|
|
|
|
|
player: redo terminal OSD and status line handling
The terminal OSD code includes the handling of the terminal status line,
showing player OSD messages on the terminal, and showing subtitles on
terminal (the latter two only if there is no video window, or if
terminal OSD is forced).
This didn't handle some corner cases correctly. For example, showing an
OSD message on the terminal always cleared the previous line, even if
the line was an important message (or even just the command prompt, if
most other messages were silenced).
Attempt to handle this correctly by keeping track of how many lines the
terminal OSD currently consists of. Since there could be race conditions
with other messages being printed, implement this in msg.c. Now msg.c
expects that MSGL_STATUS messages rewrite the status line, so the caller
is forced to use a single mp_msg() call to set the status line.
Instead of littering print_status() all over the place, update the
status only once per playloop iteration in update_osd_msg(). In audio-
only mode, the status line might now be a little bit off, but it's
perhaps ok.
Print the status line only if it has changed, or if another message was
printed. This might help with extremely slow terminals, although in
audio+video mode, it'll still be updated very often (A-V sync display
changes on every frame).
Instead of hardcoding the terminal sequences, use
terminfo/termcap to get the sequences. Remove the --term-osd-esc option,
which allowed to override the hardcoded escapes - it's useless now.
The fallback for terminals with no escape sequences for moving the
cursor and clearing a line is removed. This somewhat breaks status line
display on these terminals, including the MS Windows console: instead of
querying the terminal size and clearing the line manually by padding the
output with spaces, the line is simply not cleared. I don't expect this
to be a problem on UNIX, and on MS Windows we could emulate escape
sequences. Note that terminal OSD (other than the status line) was
broken anyway on these terminals.
In osd.c, the function get_term_width() is not used anymore, so remove
it. To remind us that the MS Windows console apparently adds a line
break when writint the last column, adjust screen_width in terminal-
win.c accordingly.
2014-01-13 19:05:41 +00:00
|
|
|
static char term_buf[128];
|
2013-07-26 19:03:56 +00:00
|
|
|
char *buf_ptr = &term_buf[0];
|
player: redo terminal OSD and status line handling
The terminal OSD code includes the handling of the terminal status line,
showing player OSD messages on the terminal, and showing subtitles on
terminal (the latter two only if there is no video window, or if
terminal OSD is forced).
This didn't handle some corner cases correctly. For example, showing an
OSD message on the terminal always cleared the previous line, even if
the line was an important message (or even just the command prompt, if
most other messages were silenced).
Attempt to handle this correctly by keeping track of how many lines the
terminal OSD currently consists of. Since there could be race conditions
with other messages being printed, implement this in msg.c. Now msg.c
expects that MSGL_STATUS messages rewrite the status line, so the caller
is forced to use a single mp_msg() call to set the status line.
Instead of littering print_status() all over the place, update the
status only once per playloop iteration in update_osd_msg(). In audio-
only mode, the status line might now be a little bit off, but it's
perhaps ok.
Print the status line only if it has changed, or if another message was
printed. This might help with extremely slow terminals, although in
audio+video mode, it'll still be updated very often (A-V sync display
changes on every frame).
Instead of hardcoding the terminal sequences, use
terminfo/termcap to get the sequences. Remove the --term-osd-esc option,
which allowed to override the hardcoded escapes - it's useless now.
The fallback for terminals with no escape sequences for moving the
cursor and clearing a line is removed. This somewhat breaks status line
display on these terminals, including the MS Windows console: instead of
querying the terminal size and clearing the line manually by padding the
output with spaces, the line is simply not cleared. I don't expect this
to be a problem on UNIX, and on MS Windows we could emulate escape
sequences. Note that terminal OSD (other than the status line) was
broken anyway on these terminals.
In osd.c, the function get_term_width() is not used anymore, so remove
it. To remind us that the MS Windows console apparently adds a line
break when writint the last column, adjust screen_width in terminal-
win.c accordingly.
2014-01-13 19:05:41 +00:00
|
|
|
|
2014-01-13 19:13:16 +00:00
|
|
|
// References for terminfo/termcap codes:
|
|
|
|
// http://linux.die.net/man/5/termcap
|
|
|
|
// http://unixhelp.ed.ac.uk/CGI/man-cgi?terminfo+5
|
|
|
|
|
2013-07-26 19:03:56 +00:00
|
|
|
term_smkx = tgetstr("ks", &buf_ptr);
|
|
|
|
term_rmkx = tgetstr("ke", &buf_ptr);
|
2013-07-22 01:27:58 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2014-01-13 22:12:14 +00:00
|
|
|
/* fallback if terminfo and termcap are not available */
|
|
|
|
keys_push_once("\012", MP_KEY_ENTER);
|
2013-07-22 01:27:58 +00:00
|
|
|
}
|
|
|
|
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
static void enable_kx(bool enable)
|
2014-08-21 20:13:10 +00:00
|
|
|
{
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
char *cmd = enable ? term_smkx : term_rmkx;
|
|
|
|
if (cmd)
|
|
|
|
tputs(cmd, 1, putchar);
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
|
|
|
|
2013-07-22 01:27:58 +00:00
|
|
|
#define BUF_LEN 256
|
|
|
|
|
|
|
|
static unsigned char getch2_buf[BUF_LEN];
|
|
|
|
static int getch2_len = 0;
|
|
|
|
static int getch2_pos = 0;
|
2013-10-28 22:29:08 +00:00
|
|
|
static enum {
|
|
|
|
STATE_INITIAL,
|
|
|
|
STATE_UTF8,
|
|
|
|
} state = STATE_INITIAL;
|
|
|
|
static int utf8_len = 0;
|
2013-07-22 01:27:58 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-12-21 18:33:45 +00:00
|
|
|
static bool getch2(struct input_ctx *input_ctx)
|
2007-08-25 04:28:08 +00:00
|
|
|
{
|
2013-07-22 01:27:58 +00:00
|
|
|
int retval = read(0, &getch2_buf[getch2_pos], BUF_LEN - getch2_len - getch2_pos);
|
2012-04-06 11:24:26 +00:00
|
|
|
/* 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.
|
|
|
|
*/
|
2013-10-28 22:32:57 +00:00
|
|
|
if (retval == 0)
|
|
|
|
return false;
|
|
|
|
if (retval == -1)
|
|
|
|
return errno != EBADF && errno != EINVAL;
|
2007-08-25 04:28:09 +00:00
|
|
|
getch2_len += retval;
|
2001-02-24 20:28:24 +00:00
|
|
|
|
2013-07-22 01:27:58 +00:00
|
|
|
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);
|
|
|
|
|
2013-07-25 15:21:22 +00:00
|
|
|
if (st) {
|
|
|
|
mp_input_put_key(input_ctx, st->code);
|
|
|
|
walk_buf(st->len);
|
|
|
|
} /* else this is still a partial (but unique) match */
|
|
|
|
|
|
|
|
continue;
|
2013-07-22 01:27:58 +00:00
|
|
|
} else if (match_count > 1) {
|
|
|
|
continue; /* need more bytes to disambiguate */
|
|
|
|
} else {
|
2013-07-25 15:21:22 +00:00
|
|
|
/* backtrack, send as UTF-8 */
|
2013-07-25 16:29:10 +00:00
|
|
|
getch2_pos = 1;
|
2013-07-25 15:21:22 +00:00
|
|
|
c = getch2_buf[0];
|
2007-08-25 04:28:09 +00:00
|
|
|
}
|
2013-07-25 15:21:22 +00:00
|
|
|
utf8_len = bstr_parse_utf8_code_length(c);
|
|
|
|
|
|
|
|
if (utf8_len > 1) {
|
|
|
|
state = STATE_UTF8;
|
2013-07-25 16:26:19 +00:00
|
|
|
} else if (utf8_len == 1) {
|
2013-07-26 00:08:39 +00:00
|
|
|
switch (c) {
|
|
|
|
case 0x1b: /* ESC that's not part of escape sequence */
|
2013-07-26 14:30:10 +00:00
|
|
|
/* 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);
|
|
|
|
}
|
2013-07-26 00:08:39 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mp_input_put_key(input_ctx, c);
|
|
|
|
}
|
2013-07-25 16:26:19 +00:00
|
|
|
walk_buf(1);
|
|
|
|
} else
|
|
|
|
walk_buf(getch2_pos);
|
2013-07-25 15:21:22 +00:00
|
|
|
|
2013-07-22 01:27:58 +00:00
|
|
|
break;
|
2007-08-25 04:28:09 +00:00
|
|
|
}
|
2013-07-22 01:27:58 +00:00
|
|
|
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);
|
2007-08-25 04:28:09 +00:00
|
|
|
}
|
2013-07-22 01:27:58 +00:00
|
|
|
walk_buf(utf8_len);
|
|
|
|
state = STATE_INITIAL;
|
|
|
|
continue;
|
2007-08-25 04:28:09 +00:00
|
|
|
}
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
2007-08-25 04:28:08 +00:00
|
|
|
}
|
2013-07-22 01:27:58 +00:00
|
|
|
|
2012-04-06 11:24:26 +00:00
|
|
|
return true;
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
|
|
|
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
#endif /* terminfo/termcap */
|
|
|
|
|
2013-12-21 18:33:45 +00:00
|
|
|
static int read_keys(void *ctx, int fd)
|
|
|
|
{
|
|
|
|
if (getch2(ctx))
|
|
|
|
return MP_INPUT_NOTHING;
|
|
|
|
return MP_INPUT_DEAD;
|
|
|
|
}
|
|
|
|
|
2014-08-21 20:13:10 +00:00
|
|
|
static volatile int getch2_active = 0;
|
|
|
|
static volatile int getch2_enabled = 0;
|
|
|
|
|
2013-12-21 18:33:45 +00:00
|
|
|
void terminal_setup_getch(struct input_ctx *ictx)
|
|
|
|
{
|
2014-08-21 20:13:10 +00:00
|
|
|
if (!getch2_enabled)
|
|
|
|
return;
|
2013-12-21 18:33:45 +00:00
|
|
|
mp_input_add_fd(ictx, 0, 1, NULL, read_keys, NULL, ictx);
|
|
|
|
}
|
|
|
|
|
2013-01-23 14:47:49 +00:00
|
|
|
static void do_activate_getch2(void)
|
2012-02-25 14:05:12 +00:00
|
|
|
{
|
2014-08-28 04:22:13 +00:00
|
|
|
if (getch2_active || !isatty(STDOUT_FILENO))
|
2013-01-23 14:47:49 +00:00
|
|
|
return;
|
2013-07-22 01:27:58 +00:00
|
|
|
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
enable_kx(true);
|
2013-07-22 01:27:58 +00:00
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_TERMIOS
|
2012-02-25 14:05:12 +00:00
|
|
|
struct termios tio_new;
|
|
|
|
tcgetattr(0,&tio_new);
|
2013-07-22 01:27:58 +00:00
|
|
|
|
2013-01-23 14:47:49 +00:00
|
|
|
if (!tio_orig_set) {
|
|
|
|
tio_orig = tio_new;
|
|
|
|
tio_orig_set = 1;
|
|
|
|
}
|
2013-07-22 01:27:58 +00:00
|
|
|
|
2001-02-24 20:28:24 +00:00
|
|
|
tio_new.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
|
2012-09-17 09:12:51 +00:00
|
|
|
tio_new.c_cc[VMIN] = 1;
|
2001-02-24 20:28:24 +00:00
|
|
|
tio_new.c_cc[VTIME] = 0;
|
2001-06-05 18:40:44 +00:00
|
|
|
tcsetattr(0,TCSANOW,&tio_new);
|
2012-02-25 14:05:12 +00:00
|
|
|
#endif
|
2013-07-22 01:27:58 +00:00
|
|
|
|
|
|
|
getch2_active = 1;
|
2013-01-23 14:47:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void do_deactivate_getch2(void)
|
|
|
|
{
|
|
|
|
if (!getch2_active)
|
|
|
|
return;
|
2013-07-22 01:27:58 +00:00
|
|
|
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
enable_kx(false);
|
2013-07-22 01:27:58 +00:00
|
|
|
|
2013-07-16 11:28:28 +00:00
|
|
|
#if HAVE_TERMIOS
|
2013-01-23 14:47:49 +00:00
|
|
|
if (tio_orig_set) {
|
|
|
|
// once set, it will never be set again
|
|
|
|
// so we can cast away volatile here
|
|
|
|
tcsetattr(0, TCSANOW, (const struct termios *) &tio_orig);
|
|
|
|
}
|
|
|
|
#endif
|
2013-07-22 01:27:58 +00:00
|
|
|
|
|
|
|
getch2_active = 0;
|
2013-01-23 14:47:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// sigaction wrapper
|
|
|
|
static int setsigaction(int signo, void (*handler) (int),
|
|
|
|
int flags, bool do_mask)
|
|
|
|
{
|
|
|
|
struct sigaction sa;
|
|
|
|
sa.sa_handler = handler;
|
2013-07-22 01:27:58 +00:00
|
|
|
|
2013-01-23 14:47:49 +00:00
|
|
|
if(do_mask)
|
|
|
|
sigfillset(&sa.sa_mask);
|
|
|
|
else
|
|
|
|
sigemptyset(&sa.sa_mask);
|
2013-07-22 01:27:58 +00:00
|
|
|
|
2014-04-26 20:52:26 +00:00
|
|
|
sa.sa_flags = flags | SA_RESTART;
|
2013-01-23 14:47:49 +00:00
|
|
|
return sigaction(signo, &sa, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void getch2_poll(void){
|
|
|
|
if (!getch2_enabled)
|
|
|
|
return;
|
|
|
|
|
2013-03-18 19:33:29 +00:00
|
|
|
// check if stdin is in the foreground process group
|
2013-01-23 14:47:49 +00:00
|
|
|
int newstatus = (tcgetpgrp(0) == getpgrp());
|
|
|
|
|
2013-03-18 19:33:29 +00:00
|
|
|
// and activate getch2 if it is, deactivate otherwise
|
2013-01-23 14:47:49 +00:00
|
|
|
if (newstatus)
|
|
|
|
do_activate_getch2();
|
|
|
|
else
|
|
|
|
do_deactivate_getch2();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void stop_sighandler(int signum)
|
|
|
|
{
|
|
|
|
do_deactivate_getch2();
|
|
|
|
|
|
|
|
// note: for this signal, we use SA_RESETHAND but do NOT mask signals
|
|
|
|
// so this will invoke the default handler
|
|
|
|
raise(SIGTSTP);
|
2012-02-25 14:05:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void continue_sighandler(int signum)
|
|
|
|
{
|
2013-01-23 14:47:49 +00:00
|
|
|
// SA_RESETHAND has reset SIGTSTP, so we need to restore it here
|
|
|
|
setsigaction(SIGTSTP, stop_sighandler, SA_RESETHAND, false);
|
|
|
|
|
|
|
|
getch2_poll();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void quit_request_sighandler(int signum)
|
|
|
|
{
|
2013-07-26 18:51:48 +00:00
|
|
|
do_deactivate_getch2();
|
|
|
|
|
2013-01-23 14:47:49 +00:00
|
|
|
async_quit_request = 1;
|
2012-02-25 14:05:12 +00:00
|
|
|
}
|
|
|
|
|
2014-08-21 20:13:10 +00:00
|
|
|
static void getch2_enable(void)
|
|
|
|
{
|
2014-08-21 20:15:32 +00:00
|
|
|
assert(!getch2_enabled);
|
2013-01-23 14:47:49 +00:00
|
|
|
|
|
|
|
// handlers to fix terminal settings
|
|
|
|
setsigaction(SIGCONT, continue_sighandler, 0, true);
|
|
|
|
setsigaction(SIGTSTP, stop_sighandler, SA_RESETHAND, false);
|
2013-07-22 01:27:58 +00:00
|
|
|
setsigaction(SIGINT, quit_request_sighandler, SA_RESETHAND, false);
|
2013-07-26 18:51:48 +00:00
|
|
|
setsigaction(SIGQUIT, quit_request_sighandler, SA_RESETHAND, false);
|
2013-11-06 19:28:23 +00:00
|
|
|
setsigaction(SIGTERM, quit_request_sighandler, SA_RESETHAND, false);
|
2013-01-23 14:47:49 +00:00
|
|
|
setsigaction(SIGTTIN, SIG_IGN, 0, true);
|
2013-12-19 20:31:33 +00:00
|
|
|
setsigaction(SIGTTOU, SIG_IGN, 0, true);
|
2013-01-23 14:47:49 +00:00
|
|
|
|
|
|
|
do_activate_getch2();
|
|
|
|
|
|
|
|
getch2_enabled = 1;
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
|
|
|
|
2014-08-21 20:13:10 +00:00
|
|
|
void terminal_uninit(void)
|
|
|
|
{
|
2013-01-23 14:47:49 +00:00
|
|
|
if (!getch2_enabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// restore signals
|
|
|
|
setsigaction(SIGCONT, SIG_DFL, 0, false);
|
|
|
|
setsigaction(SIGTSTP, SIG_DFL, 0, false);
|
2013-07-22 01:27:58 +00:00
|
|
|
setsigaction(SIGINT, SIG_DFL, 0, false);
|
2013-07-26 18:51:48 +00:00
|
|
|
setsigaction(SIGQUIT, SIG_DFL, 0, false);
|
2013-11-06 19:28:23 +00:00
|
|
|
setsigaction(SIGTERM, SIG_DFL, 0, false);
|
2013-01-23 14:47:49 +00:00
|
|
|
setsigaction(SIGTTIN, SIG_DFL, 0, false);
|
2013-12-19 20:31:33 +00:00
|
|
|
setsigaction(SIGTTOU, SIG_DFL, 0, false);
|
2013-01-23 14:47:49 +00:00
|
|
|
|
|
|
|
do_deactivate_getch2();
|
|
|
|
|
|
|
|
getch2_enabled = 0;
|
2001-02-24 20:28:24 +00:00
|
|
|
}
|
2013-12-18 14:03:08 +00:00
|
|
|
|
|
|
|
bool terminal_in_background(void)
|
|
|
|
{
|
2014-08-28 04:22:13 +00:00
|
|
|
return isatty(STDERR_FILENO) && tcgetpgrp(STDERR_FILENO) != getpgrp();
|
2013-12-18 14:03:08 +00:00
|
|
|
}
|
|
|
|
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
void terminal_get_size(int *w, int *h)
|
|
|
|
{
|
|
|
|
struct winsize ws;
|
|
|
|
if (ioctl(0, TIOCGWINSZ, &ws) < 0 || !ws.ws_row || !ws.ws_col)
|
|
|
|
return;
|
|
|
|
|
|
|
|
*w = ws.ws_col;
|
|
|
|
*h = ws.ws_row;
|
|
|
|
}
|
|
|
|
|
2013-12-18 14:03:08 +00:00
|
|
|
int terminal_init(void)
|
|
|
|
{
|
2014-08-28 04:22:13 +00:00
|
|
|
if (isatty(STDOUT_FILENO))
|
terminal-unix: new input handling code
This is independent of terminfo/termcap, and supports more keys.
Originally, the goal was just extending the set of supported key
sequences, but since the terminfo stuff actually makes this much harder,
and since it's a big blob of bloated legacy crap, just drop it. Instead,
use hardcoded tables.
It's pretty easy to get on the same level as the old code (with fewer
LOC), and we avoid additional error situations, such as mallocs which
could fail (the old code just ignores malloc failures). We also try to
support some xterm escape sequences, which are in relatively widespread
use. (I'm not sure about the urxvt ones.)
Trying to deal with xterm shift/ctrl/alt modifiers is probably a bit
overcomplicated, and only deals with prefixes - xterm randomly uses
prefix sequences for some keys, and suffixes for others (what the heck).
Additionally, try to drop unknown escape codes. This basically relies
on a trick: in almost 100% of all situations, a read() call will
actually return complete sequences (possibly because of pipe semantics
and atomic writes from the terminal emulator?), so it's easy to drop
unknown sequences. This prevents that they trigger random key bindings
as the code interprets the part after ESC as normal keys.
This also drops the use of terminfo for sending smkx/rmkx. It seems
even vt100 (to which virtually everything non-legacy is reasonably
compatible with) supports the codes we hardcode, so it should be fine.
This commit actually changes only the code if terminfo/termcap are not
found. The next commit will make this code default.
2014-08-21 20:24:33 +00:00
|
|
|
load_termcap();
|
2014-08-21 20:13:10 +00:00
|
|
|
getch2_enable();
|
2013-12-18 14:03:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|