1428 lines
32 KiB
C
1428 lines
32 KiB
C
/* kbd.c
|
|
* (c) 2002 Mikulas Patocka
|
|
* This file is a part of the Links program, released under GPL.
|
|
*/
|
|
|
|
#include "links.h"
|
|
|
|
#define OUT_BUF_SIZE 10240
|
|
#define IN_BUF_SIZE 64
|
|
|
|
#define USE_TWIN_MOUSE 1
|
|
#define BRACKETED_PASTE 2
|
|
|
|
#define TW_BUTT_LEFT 1
|
|
#define TW_BUTT_MIDDLE 2
|
|
#define TW_BUTT_RIGHT 4
|
|
|
|
struct itrm {
|
|
int std_in;
|
|
int std_out;
|
|
int sock_in;
|
|
int sock_out;
|
|
int ctl_in;
|
|
int blocked;
|
|
int flags;
|
|
unsigned char kqueue[IN_BUF_SIZE];
|
|
int qlen;
|
|
struct timer *tm;
|
|
void (*queue_event)(struct itrm *, unsigned char *, int);
|
|
unsigned char *ev_queue;
|
|
int eqlen;
|
|
void *mouse_h;
|
|
unsigned char *orig_title;
|
|
void (*free_trm)(struct itrm *);
|
|
};
|
|
|
|
static void free_trm(struct itrm *);
|
|
static void in_kbd(void *);
|
|
static void in_sock(void *);
|
|
|
|
static struct itrm *ditrm = NULL;
|
|
|
|
|
|
int is_blocked(void)
|
|
{
|
|
#ifdef G
|
|
if (F) {
|
|
struct terminal *term;
|
|
struct list_head *lterm;
|
|
foreach(struct terminal, term, lterm, terminals)
|
|
if (term->blocked != -1)
|
|
return 1;
|
|
return 0;
|
|
}
|
|
#endif
|
|
return ditrm && ditrm->blocked;
|
|
}
|
|
|
|
void free_all_itrms(void)
|
|
{
|
|
if (ditrm) ditrm->free_trm(ditrm);
|
|
}
|
|
|
|
static void itrm_error(void *itrm_)
|
|
{
|
|
struct itrm *itrm = (struct itrm *)itrm_;
|
|
itrm->free_trm(itrm);
|
|
terminate_loop = 1;
|
|
}
|
|
|
|
static void write_ev_queue(void *itrm_)
|
|
{
|
|
struct itrm *itrm = (struct itrm *)itrm_;
|
|
int l, to_write;
|
|
if (!itrm->eqlen) internal_error("event queue empty");
|
|
to_write = itrm->eqlen;
|
|
retry:
|
|
EINTRLOOP(l, (int)write(itrm->sock_out, itrm->ev_queue, to_write));
|
|
if (l <= 0) {
|
|
if (to_write > 1) {
|
|
to_write >>= 1;
|
|
goto retry;
|
|
}
|
|
itrm_error(itrm);
|
|
}
|
|
memmove(itrm->ev_queue, itrm->ev_queue + l, itrm->eqlen -= l);
|
|
if (!itrm->eqlen) set_handlers(itrm->sock_out, get_handler(itrm->sock_out, H_READ), NULL, get_handler_data(itrm->sock_out));
|
|
}
|
|
|
|
static void queue_event(struct itrm *itrm, unsigned char *data, int len)
|
|
{
|
|
int w = 0;
|
|
if (!len) return;
|
|
if (!itrm->eqlen && can_write(itrm->sock_out)) {
|
|
int to_write = len;
|
|
retry:
|
|
EINTRLOOP(w, (int)write(itrm->sock_out, data, to_write));
|
|
if (w <= 0) {
|
|
if (to_write > 1) {
|
|
to_write >>= 1;
|
|
goto retry;
|
|
}
|
|
register_bottom_half(itrm_error, itrm);
|
|
return;
|
|
}
|
|
}
|
|
if (w < len) {
|
|
if ((unsigned)itrm->eqlen + (unsigned)(len - w) > MAXINT) overalloc();
|
|
itrm->ev_queue = mem_realloc(itrm->ev_queue, itrm->eqlen + len - w);
|
|
memcpy(itrm->ev_queue + itrm->eqlen, data + w, len - w);
|
|
itrm->eqlen += len - w;
|
|
set_handlers(itrm->sock_out, get_handler(itrm->sock_out, H_READ), write_ev_queue, itrm);
|
|
}
|
|
}
|
|
|
|
static void mouse_queue_event(void *itrm_, unsigned char *data, int len)
|
|
{
|
|
struct itrm *itrm = (struct itrm *)itrm_;
|
|
if (itrm->blocked) return;
|
|
queue_event(itrm, data, len);
|
|
}
|
|
|
|
void kbd_ctrl_c(void)
|
|
{
|
|
struct links_event ev = { EV_KBD, KBD_CTRL_C, 0, 0 };
|
|
if (ditrm) ditrm->queue_event(ditrm, (unsigned char *)&ev, sizeof(struct links_event));
|
|
}
|
|
|
|
unsigned char init_seq[] = "\033)0\0337";
|
|
unsigned char init_seq_x_mouse[] = "\033[?1000h\033[?1002h\033[?1005l\033[?1015l\033[?1006h\033[?2004h";
|
|
unsigned char init_seq_tw_mouse[] = "\033[?9h";
|
|
unsigned char init_seq_xterm[] = "\033[?1049h";
|
|
unsigned char term_seq[] = "\033[2J\0338\r \b";
|
|
unsigned char term_seq_x_mouse[] = "\033[?1000l\r \r\033[?1002l\r \r\033[?1006l\r \r\033[?2004l\r \r";
|
|
unsigned char term_seq_tw_mouse[] = "\033[?9l";
|
|
unsigned char term_seq_xterm[] = "\033[?1049l";
|
|
|
|
static int use_xterm_save_restore(void)
|
|
{
|
|
unsigned char *e;
|
|
return (e = cast_uchar getenv("TERM")) && !casecmp(e, cast_uchar "xterm", 5);
|
|
}
|
|
|
|
static void send_init_sequence(int h, int flags)
|
|
{
|
|
save_terminal();
|
|
want_draw();
|
|
if (use_xterm_save_restore())
|
|
hard_write(h, init_seq_xterm, (int)strlen(cast_const_char init_seq_xterm));
|
|
hard_write(h, init_seq, (int)strlen(cast_const_char init_seq));
|
|
#if !defined(DOS) && !defined(HAIKU)
|
|
if (flags & USE_TWIN_MOUSE) {
|
|
hard_write(h, init_seq_tw_mouse, (int)strlen(cast_const_char init_seq_tw_mouse));
|
|
} else {
|
|
hard_write(h, init_seq_x_mouse, (int)strlen(cast_const_char init_seq_x_mouse));
|
|
}
|
|
#endif
|
|
done_draw();
|
|
}
|
|
|
|
static void send_term_sequence(int h, int flags)
|
|
{
|
|
want_draw();
|
|
#if !defined(DOS) && !defined(HAIKU)
|
|
if (flags & USE_TWIN_MOUSE) {
|
|
hard_write(h, term_seq_tw_mouse, (int)strlen(cast_const_char term_seq_tw_mouse));
|
|
} else {
|
|
hard_write(h, term_seq_x_mouse, (int)strlen(cast_const_char term_seq_x_mouse));
|
|
}
|
|
#endif
|
|
hard_write(h, term_seq, (int)strlen(cast_const_char term_seq));
|
|
if (use_xterm_save_restore())
|
|
hard_write(h, term_seq_xterm, (int)strlen(cast_const_char term_seq_xterm));
|
|
done_draw();
|
|
restore_terminal();
|
|
}
|
|
|
|
static void resize_terminal(int x, int y)
|
|
{
|
|
struct links_event ev = { EV_RESIZE, 0, 0, 0 };
|
|
ev.x = x;
|
|
ev.y = y;
|
|
queue_event(ditrm, (unsigned char *)&ev, sizeof(struct links_event));
|
|
}
|
|
|
|
#if defined(OS_SETRAW)
|
|
|
|
#elif defined(HAVE_TERMIOS_H)
|
|
|
|
static void os_cfmakeraw(struct termios *t)
|
|
{
|
|
#ifdef HAVE_CFMAKERAW
|
|
cfmakeraw(t);
|
|
#ifdef VMIN
|
|
t->c_cc[VMIN] = 1;
|
|
#endif
|
|
#else
|
|
t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
|
|
t->c_oflag &= ~OPOST;
|
|
t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
|
t->c_cflag &= ~(CSIZE|PARENB);
|
|
t->c_cflag |= CS8;
|
|
t->c_cc[VMIN] = 1;
|
|
t->c_cc[VTIME] = 0;
|
|
#endif
|
|
#if defined(NO_CTRL_Z) && defined(VSUSP)
|
|
t->c_cc[VSUSP] = 0;
|
|
#endif
|
|
/*fprintf(stderr, "\n");
|
|
fprintf(stderr, "%08x %08x %08x\n", t->c_iflag, t->c_oflag, t->c_lflag);
|
|
{
|
|
int i;
|
|
for (i = 0; i < array_elements(t->c_cc); i++) {
|
|
fprintf(stderr, "%d - %d\n", i, t->c_cc[i]);
|
|
}
|
|
}
|
|
portable_sleep(10000);*/
|
|
}
|
|
|
|
static int ttcgetattr(int fd, struct termios *t)
|
|
{
|
|
int r;
|
|
block_signals(
|
|
#ifdef SIGTTOU
|
|
SIGTTOU
|
|
#else
|
|
0
|
|
#endif
|
|
,
|
|
#ifdef SIGTTIN
|
|
SIGTTIN
|
|
#else
|
|
0
|
|
#endif
|
|
);
|
|
#ifdef SIGTTOU
|
|
interruptible_signal(SIGTTOU, 1);
|
|
#endif
|
|
#ifdef SIGTTIN
|
|
interruptible_signal(SIGTTIN, 1);
|
|
#endif
|
|
r = tcgetattr(fd, t);
|
|
#ifdef SIGTTOU
|
|
interruptible_signal(SIGTTOU, 0);
|
|
#endif
|
|
#ifdef SIGTTIN
|
|
interruptible_signal(SIGTTIN, 0);
|
|
#endif
|
|
unblock_signals();
|
|
return r;
|
|
}
|
|
|
|
static int ttcsetattr(int fd, int a, struct termios *t)
|
|
{
|
|
int r;
|
|
block_signals(
|
|
#ifdef SIGTTOU
|
|
SIGTTOU
|
|
#else
|
|
0
|
|
#endif
|
|
,
|
|
#ifdef SIGTTIN
|
|
SIGTTIN
|
|
#else
|
|
0
|
|
#endif
|
|
);
|
|
#ifdef SIGTTOU
|
|
interruptible_signal(SIGTTOU, 1);
|
|
#endif
|
|
#ifdef SIGTTIN
|
|
interruptible_signal(SIGTTIN, 1);
|
|
#endif
|
|
r = tcsetattr(fd, a, t);
|
|
#ifdef SIGTTOU
|
|
interruptible_signal(SIGTTOU, 0);
|
|
#endif
|
|
#ifdef SIGTTIN
|
|
interruptible_signal(SIGTTIN, 0);
|
|
#endif
|
|
unblock_signals();
|
|
return r;
|
|
}
|
|
|
|
static struct termios saved_termios;
|
|
|
|
static int setraw(int ctl, int save)
|
|
{
|
|
struct termios t;
|
|
if (ctl < 0) return 0;
|
|
memset(&t, 0, sizeof(struct termios));
|
|
if (ttcgetattr(ctl, &t)) {
|
|
/*fprintf(stderr, "getattr result %s\n", strerror(errno));*/
|
|
/* If the terminal was destroyed (the user logged off),
|
|
* we fake success here so that we can destroy the terminal
|
|
* later.
|
|
*
|
|
* Linux returns EIO
|
|
* FreeBSD returns ENXIO
|
|
*/
|
|
if (errno == EIO || errno == ENXIO) return 0;
|
|
return -1;
|
|
}
|
|
if (save) memcpy(&saved_termios, &t, sizeof(struct termios));
|
|
os_cfmakeraw(&t);
|
|
t.c_lflag |= ISIG;
|
|
#ifdef TOSTOP
|
|
t.c_lflag |= TOSTOP;
|
|
#endif
|
|
t.c_oflag |= OPOST;
|
|
#ifdef DOS
|
|
t.c_lflag &= ~(ISIG | ECHO);
|
|
#endif
|
|
if (ttcsetattr(ctl, TCSANOW, &t)) {
|
|
/*fprintf(stderr, "setattr result %s\n", strerror(errno));*/
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void setcooked(int ctl)
|
|
{
|
|
if (ctl < 0) return;
|
|
ttcsetattr(ctl, TCSANOW, &saved_termios);
|
|
}
|
|
|
|
#elif defined(HAVE_SGTTY_H)
|
|
|
|
static struct sgttyb saved_sgtty;
|
|
|
|
static int setraw(int ctl, int save)
|
|
{
|
|
struct sgttyb sgtty;
|
|
if (ctl < 0) return 0;
|
|
if (gtty(ctl, &sgtty)) {
|
|
return -1;
|
|
}
|
|
if (save) memcpy(&saved_sgtty, &sgtty, sizeof(struct sgttyb));
|
|
sgtty.sg_flags |= CBREAK;
|
|
sgtty.sg_flags &= ~ECHO;
|
|
if (stty(ctl, &sgtty)) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void setcooked(int ctl)
|
|
{
|
|
if (ctl < 0) return;
|
|
stty(ctl, &saved_sgtty);
|
|
}
|
|
|
|
#else
|
|
|
|
static int setraw(int ctl, int save)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void setcooked(int ctl)
|
|
{
|
|
}
|
|
|
|
#endif
|
|
|
|
void handle_trm(int std_in, int std_out, int sock_in, int sock_out, int ctl_in, void *init_string, int init_len)
|
|
{
|
|
struct itrm *itrm;
|
|
struct links_event ev = { EV_INIT, 0, 0, 0 };
|
|
unsigned char *ts;
|
|
int xwin, def_charset;
|
|
itrm = mem_alloc(sizeof(struct itrm));
|
|
itrm->queue_event = queue_event;
|
|
itrm->free_trm = free_trm;
|
|
ditrm = itrm;
|
|
itrm->std_in = std_in;
|
|
itrm->std_out = std_out;
|
|
itrm->sock_in = sock_in;
|
|
itrm->sock_out = sock_out;
|
|
itrm->ctl_in = ctl_in;
|
|
itrm->blocked = 0;
|
|
itrm->qlen = 0;
|
|
itrm->tm = NULL;
|
|
itrm->ev_queue = DUMMY;
|
|
itrm->eqlen = 0;
|
|
setraw(itrm->ctl_in, 1);
|
|
set_handlers(std_in, in_kbd, NULL, itrm);
|
|
if (sock_in != std_out) set_handlers(sock_in, in_sock, NULL, itrm);
|
|
handle_terminal_resize(resize_terminal, &ev.x, &ev.y);
|
|
queue_event(itrm, (unsigned char *)&ev, sizeof(struct links_event));
|
|
xwin = is_xterm() * ENV_XWIN + is_twterm() * ENV_TWIN + is_screen() * ENV_SCREEN + get_system_env();
|
|
itrm->flags = 0;
|
|
if (!(ts = cast_uchar getenv("TERM"))) ts = cast_uchar "";
|
|
if ((xwin & ENV_TWIN) && !strcmp(cast_const_char ts, "linux")) itrm->flags |= USE_TWIN_MOUSE;
|
|
if (strlen(cast_const_char ts) >= MAX_TERM_LEN) queue_event(itrm, ts, MAX_TERM_LEN);
|
|
else {
|
|
unsigned char *mm;
|
|
int ll = MAX_TERM_LEN - (int)strlen(cast_const_char ts);
|
|
queue_event(itrm, ts, (int)strlen(cast_const_char ts));
|
|
mm = mem_calloc(ll);
|
|
queue_event(itrm, mm, ll);
|
|
mem_free(mm);
|
|
}
|
|
if (!(ts = get_cwd())) ts = stracpy(cast_uchar "");
|
|
if (strlen(cast_const_char ts) >= MAX_CWD_LEN) queue_event(itrm, ts, MAX_CWD_LEN);
|
|
else {
|
|
unsigned char *mm;
|
|
int ll = MAX_CWD_LEN - (int)strlen(cast_const_char ts);
|
|
queue_event(itrm, ts, (int)strlen(cast_const_char ts));
|
|
mm = mem_calloc(ll);
|
|
queue_event(itrm, mm, ll);
|
|
mem_free(mm);
|
|
}
|
|
mem_free(ts);
|
|
queue_event(itrm, (unsigned char *)&xwin, sizeof(int));
|
|
def_charset = get_default_charset();
|
|
queue_event(itrm, (unsigned char *)&def_charset, sizeof(int));
|
|
queue_event(itrm, (unsigned char *)&init_len, sizeof(int));
|
|
queue_event(itrm, (unsigned char *)init_string, init_len);
|
|
itrm->orig_title = get_window_title();
|
|
set_window_title(cast_uchar "Links");
|
|
itrm->mouse_h = handle_mouse(0, mouse_queue_event, itrm);
|
|
send_init_sequence(std_out, itrm->flags);
|
|
}
|
|
|
|
static void unblock_itrm_x(void *h)
|
|
{
|
|
NO_GFX;
|
|
close_handle(h);
|
|
if (!ditrm) return;
|
|
unblock_itrm(0);
|
|
}
|
|
|
|
int unblock_itrm(int fd)
|
|
{
|
|
struct itrm *itrm = ditrm;
|
|
int x, y;
|
|
if (!itrm) return -1;
|
|
if (setraw(itrm->ctl_in, 0)) return -1;
|
|
if (itrm->blocked != fd + 1) return -2;
|
|
itrm->blocked = 0;
|
|
set_handlers(itrm->std_in, in_kbd, NULL, itrm);
|
|
handle_terminal_resize(resize_terminal, &x, &y);
|
|
unblock_stdin();
|
|
itrm->mouse_h = handle_mouse(0, mouse_queue_event, itrm);
|
|
send_init_sequence(itrm->std_out, itrm->flags);
|
|
resize_terminal(x, y);
|
|
return 0;
|
|
}
|
|
|
|
void block_itrm(int fd)
|
|
{
|
|
struct itrm *itrm = ditrm;
|
|
NO_GFX;
|
|
if (!itrm) return;
|
|
if (itrm->blocked) return;
|
|
itrm->blocked = fd + 1;
|
|
block_stdin();
|
|
unhandle_terminal_resize();
|
|
if (itrm->mouse_h) unhandle_mouse(itrm->mouse_h), itrm->mouse_h = NULL;
|
|
send_term_sequence(itrm->std_out, itrm->flags);
|
|
setcooked(itrm->ctl_in);
|
|
set_handlers(itrm->std_in, NULL, NULL, itrm);
|
|
}
|
|
|
|
static void free_trm(struct itrm *itrm)
|
|
{
|
|
if (!itrm) return;
|
|
set_window_title(itrm->orig_title);
|
|
if (itrm->orig_title) mem_free(itrm->orig_title), itrm->orig_title = NULL;
|
|
unhandle_terminal_resize();
|
|
if (itrm->mouse_h) unhandle_mouse(itrm->mouse_h);
|
|
send_term_sequence(itrm->std_out, itrm->flags);
|
|
setcooked(itrm->ctl_in);
|
|
set_handlers(itrm->std_in, NULL, NULL, NULL);
|
|
set_handlers(itrm->sock_in, NULL, NULL, NULL);
|
|
set_handlers(itrm->std_out, NULL, NULL, NULL);
|
|
set_handlers(itrm->sock_out, NULL, NULL, NULL);
|
|
unregister_bottom_half(itrm_error, itrm);
|
|
if (itrm->tm != NULL) kill_timer(itrm->tm);
|
|
mem_free(itrm->ev_queue);
|
|
mem_free(itrm);
|
|
if (itrm == ditrm) ditrm = NULL;
|
|
}
|
|
|
|
void fatal_tty_exit(void)
|
|
{
|
|
#ifdef DOS
|
|
dos_mouse_terminate();
|
|
#endif
|
|
if (ditrm) setcooked(ditrm->ctl_in);
|
|
#ifdef G
|
|
if (drv && drv->emergency_shutdown) drv->emergency_shutdown();
|
|
#endif
|
|
restore_terminal();
|
|
}
|
|
|
|
static void refresh_terminal_size(void)
|
|
{
|
|
if (!ditrm->blocked) {
|
|
int new_x, new_y;
|
|
unhandle_terminal_resize();
|
|
handle_terminal_resize(resize_terminal, &new_x, &new_y);
|
|
resize_terminal(new_x, new_y);
|
|
}
|
|
}
|
|
|
|
static void resize_terminal_x(unsigned char *text)
|
|
{
|
|
int x, y;
|
|
unsigned char *p;
|
|
if (!(p = cast_uchar strchr(cast_const_char text, ','))) return;
|
|
*p++ = 0;
|
|
x = atoi(cast_const_char text);
|
|
y = atoi(cast_const_char p);
|
|
resize_window(x, y);
|
|
refresh_terminal_size();
|
|
}
|
|
|
|
void dispatch_special(unsigned char *text)
|
|
{
|
|
switch (text[0]) {
|
|
case TERM_FN_TITLE:
|
|
set_window_title(text + 1);
|
|
break;
|
|
case TERM_FN_RESIZE:
|
|
resize_terminal_x(text + 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define RD(xx) \
|
|
do { \
|
|
unsigned char cc; \
|
|
if (p < c) cc = buf[p++]; \
|
|
else if ((hard_read(itrm->sock_in, &cc, 1)) <= 0) { \
|
|
mem_free(path); \
|
|
mem_free(delet); \
|
|
goto fr; \
|
|
} \
|
|
xx = cc; \
|
|
} while (0)
|
|
|
|
static void in_sock(void *itrm_)
|
|
{
|
|
struct itrm *itrm = (struct itrm *)itrm_;
|
|
unsigned char buf[OUT_BUF_SIZE];
|
|
|
|
unsigned char *path, *delet;
|
|
int pl, dl;
|
|
unsigned char ch;
|
|
unsigned char fg;
|
|
int c, i, p;
|
|
int rs;
|
|
|
|
EINTRLOOP(c, (int)read(itrm->sock_in, buf, OUT_BUF_SIZE));
|
|
if (c <= 0) {
|
|
fr:
|
|
itrm_error(itrm);
|
|
goto ret;
|
|
}
|
|
|
|
qwerty:
|
|
for (i = 0; i < c; i++) if (!buf[i]) goto ex;
|
|
if (!is_blocked()) {
|
|
want_draw();
|
|
hard_write(itrm->std_out, buf, c);
|
|
done_draw();
|
|
}
|
|
goto ret;
|
|
ex:
|
|
if (!is_blocked()) {
|
|
want_draw();
|
|
hard_write(itrm->std_out, buf, i);
|
|
done_draw();
|
|
}
|
|
i++;
|
|
memmove(buf, buf + i, c - i);
|
|
c -= i;
|
|
p = 0;
|
|
path = init_str();
|
|
delet = init_str();
|
|
pl = dl = 0;
|
|
RD(fg);
|
|
while (1) {
|
|
RD(ch);
|
|
if (!ch) break;
|
|
add_chr_to_str(&path, &pl, ch);
|
|
}
|
|
while (1) {
|
|
RD(ch);
|
|
if (!ch) break;
|
|
add_chr_to_str(&delet, &dl, ch);
|
|
}
|
|
if (!*path) {
|
|
dispatch_special(delet);
|
|
} else {
|
|
int blockh;
|
|
unsigned char *param;
|
|
if (is_blocked() && fg) {
|
|
if (*delet)
|
|
EINTRLOOP(rs, unlink(cast_const_char delet));
|
|
goto to_je_ale_hnus;
|
|
}
|
|
param = mem_alloc(strlen(cast_const_char path) + strlen(cast_const_char delet) + 3);
|
|
param[0] = fg;
|
|
strcpy(cast_char(param + 1), cast_const_char path);
|
|
strcpy(cast_char(param + 1 + strlen(cast_const_char path) + 1), cast_const_char delet);
|
|
if (fg == 1) block_itrm(0);
|
|
if ((blockh = start_thread(exec_thread, param, (int)strlen(cast_const_char path) + (int)strlen(cast_const_char delet) + 3, *delet != 0)) == -1) {
|
|
if (fg == 1) unblock_itrm(0);
|
|
mem_free(param);
|
|
goto to_je_ale_hnus;
|
|
}
|
|
mem_free(param);
|
|
if (fg == 1) {
|
|
set_handlers(blockh, unblock_itrm_x, NULL, (void *)(my_intptr_t)blockh);
|
|
} else {
|
|
set_handlers(blockh, close_handle, NULL, (void *)(my_intptr_t)blockh);
|
|
}
|
|
}
|
|
to_je_ale_hnus:
|
|
mem_free(path);
|
|
mem_free(delet);
|
|
memmove(buf, buf + p, c - p);
|
|
c -= p;
|
|
goto qwerty;
|
|
|
|
ret:
|
|
return;
|
|
}
|
|
|
|
static int process_queue(struct itrm *);
|
|
static int get_esc_code(unsigned char *, int, unsigned char *, int *, int *);
|
|
|
|
static void kbd_timeout(void *itrm_)
|
|
{
|
|
struct itrm *itrm = (struct itrm *)itrm_;
|
|
struct links_event ev = { EV_KBD, KBD_ESC, 0, 0 };
|
|
unsigned char code;
|
|
int num;
|
|
int len = 0; /* against warning */
|
|
itrm->tm = NULL;
|
|
if (can_read(itrm->std_in)) {
|
|
in_kbd(itrm);
|
|
return;
|
|
}
|
|
if (!itrm->qlen) {
|
|
internal_error("timeout on empty queue");
|
|
return;
|
|
}
|
|
if (itrm->kqueue[0] != 27) {
|
|
len = 1;
|
|
goto skip_esc;
|
|
}
|
|
itrm->queue_event(itrm, (unsigned char *)&ev, sizeof(struct links_event));
|
|
if (get_esc_code(itrm->kqueue, itrm->qlen, &code, &num, &len)) len = 1;
|
|
skip_esc:
|
|
itrm->qlen -= len;
|
|
memmove(itrm->kqueue, itrm->kqueue + len, itrm->qlen);
|
|
while (process_queue(itrm))
|
|
;
|
|
}
|
|
|
|
static int get_esc_code(unsigned char *str, int len, unsigned char *code, int *num, int *el)
|
|
{
|
|
int pos;
|
|
*num = 0;
|
|
for (pos = 2; pos < len; pos++) {
|
|
if (str[pos] < '0' || str[pos] > '9' || pos > 7) {
|
|
*el = pos + 1;
|
|
*code = str[pos];
|
|
return 0;
|
|
}
|
|
*num = *num * 10 + str[pos] - '0';
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
struct os2_key {
|
|
int x, y;
|
|
};
|
|
*/
|
|
|
|
#if defined(OS2) || defined(DOS)
|
|
struct os2_key os2xtd[256] = {
|
|
/* 0 */
|
|
{0,0},
|
|
{0,0},
|
|
{' ',KBD_CTRL},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{KBD_BS,KBD_ALT},
|
|
{0,0},
|
|
/* 16 */
|
|
{'Q',KBD_ALT},
|
|
{'W',KBD_ALT},
|
|
{'E',KBD_ALT},
|
|
{'R',KBD_ALT},
|
|
{'T',KBD_ALT},
|
|
{'Y',KBD_ALT},
|
|
{'U',KBD_ALT},
|
|
{'I',KBD_ALT},
|
|
/* 24 */
|
|
{'O',KBD_ALT},
|
|
{'P',KBD_ALT},
|
|
{'[',KBD_ALT},
|
|
{']',KBD_ALT},
|
|
{KBD_ENTER,KBD_ALT},
|
|
{0,0},
|
|
{'A',KBD_ALT},
|
|
{'S',KBD_ALT},
|
|
/* 32 */
|
|
{'D',KBD_ALT},
|
|
{'F',KBD_ALT},
|
|
{'G',KBD_ALT},
|
|
{'H',KBD_ALT},
|
|
{'J',KBD_ALT},
|
|
{'K',KBD_ALT},
|
|
{'L',KBD_ALT},
|
|
{';',KBD_ALT},
|
|
/* 40 */
|
|
{'\'',KBD_ALT},
|
|
{'`',KBD_ALT},
|
|
{0,0},
|
|
{'\\',KBD_ALT},
|
|
{'Z',KBD_ALT},
|
|
{'X',KBD_ALT},
|
|
{'C',KBD_ALT},
|
|
{'V',KBD_ALT},
|
|
/* 48 */
|
|
{'B',KBD_ALT},
|
|
{'N',KBD_ALT},
|
|
{'M',KBD_ALT},
|
|
{',',KBD_ALT},
|
|
{'.',KBD_ALT},
|
|
{'/',KBD_ALT},
|
|
{0,0},
|
|
{'*',KBD_ALT},
|
|
/* 56 */
|
|
{0,0},
|
|
{' ',KBD_ALT},
|
|
{0,0},
|
|
{KBD_F1,0},
|
|
{KBD_F2,0},
|
|
{KBD_F3,0},
|
|
{KBD_F4,0},
|
|
{KBD_F5,0},
|
|
/* 64 */
|
|
{KBD_F6,0},
|
|
{KBD_F7,0},
|
|
{KBD_F8,0},
|
|
{KBD_F9,0},
|
|
{KBD_F10,0},
|
|
{0,0},
|
|
{0,0},
|
|
{KBD_HOME,0},
|
|
/* 72 */
|
|
{KBD_UP,0},
|
|
{KBD_PAGE_UP,0},
|
|
{'-',KBD_ALT},
|
|
{KBD_LEFT,0},
|
|
{'5',0},
|
|
{KBD_RIGHT,0},
|
|
{'+',KBD_ALT},
|
|
{KBD_END,0},
|
|
/* 80 */
|
|
{KBD_DOWN,0},
|
|
{KBD_PAGE_DOWN,0},
|
|
{KBD_INS,0},
|
|
{KBD_DEL,0},
|
|
{KBD_F1,KBD_SHIFT},
|
|
{KBD_F2,KBD_SHIFT},
|
|
{KBD_F3,KBD_SHIFT},
|
|
{KBD_F4,KBD_SHIFT},
|
|
/* 88 */
|
|
{KBD_F5,KBD_SHIFT},
|
|
{KBD_F6,KBD_SHIFT},
|
|
{KBD_F7,KBD_SHIFT},
|
|
{KBD_F8,KBD_SHIFT},
|
|
{KBD_F9,KBD_SHIFT},
|
|
{KBD_F10,KBD_SHIFT},
|
|
{KBD_F1,KBD_CTRL},
|
|
{KBD_F2,KBD_CTRL},
|
|
/* 96 */
|
|
{KBD_F3,KBD_CTRL},
|
|
{KBD_F4,KBD_CTRL},
|
|
{KBD_F5,KBD_CTRL},
|
|
{KBD_F6,KBD_CTRL},
|
|
{KBD_F7,KBD_CTRL},
|
|
{KBD_F8,KBD_CTRL},
|
|
{KBD_F9,KBD_CTRL},
|
|
{KBD_F10,KBD_CTRL},
|
|
/* 104 */
|
|
{KBD_F1,KBD_ALT},
|
|
{KBD_F2,KBD_ALT},
|
|
{KBD_F3,KBD_ALT},
|
|
{KBD_F4,KBD_ALT},
|
|
{KBD_F5,KBD_ALT},
|
|
{KBD_F6,KBD_ALT},
|
|
{KBD_F7,KBD_ALT},
|
|
{KBD_F8,KBD_ALT},
|
|
/* 112 */
|
|
{KBD_F9,KBD_ALT},
|
|
{KBD_F10,KBD_ALT},
|
|
{0,0},
|
|
{KBD_LEFT,KBD_CTRL},
|
|
{KBD_RIGHT,KBD_CTRL},
|
|
{KBD_END,KBD_CTRL},
|
|
{KBD_PAGE_DOWN,KBD_CTRL},
|
|
{KBD_HOME,KBD_CTRL},
|
|
/* 120 */
|
|
{'1',KBD_ALT},
|
|
{'2',KBD_ALT},
|
|
{'3',KBD_ALT},
|
|
{'4',KBD_ALT},
|
|
{'5',KBD_ALT},
|
|
{'6',KBD_ALT},
|
|
{'7',KBD_ALT},
|
|
{'8',KBD_ALT},
|
|
/* 128 */
|
|
{'9',KBD_ALT},
|
|
{'0',KBD_ALT},
|
|
{'-',KBD_ALT},
|
|
{'=',KBD_ALT},
|
|
{KBD_PAGE_UP,KBD_CTRL},
|
|
{KBD_F11,0},
|
|
{KBD_F12,0},
|
|
{KBD_F11,KBD_SHIFT},
|
|
/* 136 */
|
|
{KBD_F12,KBD_SHIFT},
|
|
{KBD_F11,KBD_CTRL},
|
|
{KBD_F12,KBD_CTRL},
|
|
{KBD_F11,KBD_ALT},
|
|
{KBD_F12,KBD_ALT},
|
|
{KBD_UP,KBD_CTRL},
|
|
{'-',KBD_CTRL},
|
|
{'5',KBD_CTRL},
|
|
/* 144 */
|
|
{'+',KBD_CTRL},
|
|
{KBD_DOWN,KBD_CTRL},
|
|
{KBD_INS,KBD_CTRL},
|
|
{KBD_DEL,KBD_CTRL},
|
|
{KBD_TAB,KBD_CTRL},
|
|
{0,0},
|
|
{0,0},
|
|
{KBD_HOME,KBD_ALT},
|
|
/* 152 */
|
|
{KBD_UP,KBD_ALT},
|
|
{KBD_PAGE_UP,KBD_ALT},
|
|
{0,0},
|
|
{KBD_LEFT,KBD_ALT},
|
|
{0,0},
|
|
{KBD_RIGHT,KBD_ALT},
|
|
{0,0},
|
|
{KBD_END,KBD_ALT},
|
|
/* 160 */
|
|
{KBD_DOWN,KBD_ALT},
|
|
{KBD_PAGE_DOWN,KBD_ALT},
|
|
{KBD_INS,KBD_ALT},
|
|
{KBD_DEL,KBD_ALT},
|
|
{0,0},
|
|
{KBD_TAB,KBD_ALT},
|
|
{KBD_ENTER,KBD_ALT},
|
|
{0,0},
|
|
/* 168 */
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
/* 176 */
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
/* 192 */
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
/* 208 */
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
/* 224 */
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
/* 240 */
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
{0,0},
|
|
/* 256 */
|
|
};
|
|
#endif
|
|
|
|
static int xterm_button = -1;
|
|
|
|
static int is_interix(void)
|
|
{
|
|
#ifdef INTERIX
|
|
return 1;
|
|
#else
|
|
unsigned char *term = cast_uchar getenv("TERM");
|
|
return term && !strncmp(cast_const_char term, "interix", 7);
|
|
#endif
|
|
}
|
|
|
|
static int is_uwin(void)
|
|
{
|
|
#ifdef _UWIN
|
|
return 1;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static int is_ibm(void)
|
|
{
|
|
unsigned char *term = cast_uchar getenv("TERM");
|
|
return term && !strncmp(cast_const_char term, "ibm", 3);
|
|
}
|
|
|
|
static int process_queue(struct itrm *itrm)
|
|
{
|
|
struct links_event ev = { EV_KBD, -1, 0, 0 };
|
|
int el = 0;
|
|
if (!itrm->qlen) goto end;
|
|
#if 0
|
|
{
|
|
int i;
|
|
fprintf(stderr, "queue(%d):", itrm->qlen);
|
|
for (i = 0; i < itrm->qlen; i++)
|
|
fprintf(stderr, " %02x", itrm->kqueue[i]);
|
|
fprintf(stderr, " \"");
|
|
for (i = 0; i < itrm->qlen; i++)
|
|
if (itrm->kqueue[i] >= 32) fprintf(stderr, "%c", itrm->kqueue[i]);
|
|
fprintf(stderr, "\"\n");
|
|
}
|
|
#endif
|
|
if (itrm->kqueue[0] == '\033') {
|
|
if (itrm->qlen < 2) goto ret;
|
|
if (itrm->kqueue[1] == '[' || itrm->kqueue[1] == 'O') {
|
|
unsigned char c = 0;
|
|
int v;
|
|
if (itrm->qlen >= 4 && itrm->kqueue[2] == '[') {
|
|
if (itrm->kqueue[3] < 'A' || itrm->kqueue[3] > 'L') goto ret;
|
|
ev.x = KBD_F1 - (itrm->kqueue[3] - 'A');
|
|
el = 4;
|
|
} else if (get_esc_code(itrm->kqueue, itrm->qlen, &c, &v, &el)) goto ret;
|
|
else switch (c) {
|
|
case 'L':
|
|
case '@': ev.x = KBD_INS; break;
|
|
case 'A': ev.x = KBD_UP; break;
|
|
case 'B': ev.x = KBD_DOWN; break;
|
|
case 'C': ev.x = KBD_RIGHT; break;
|
|
case 'D': ev.x = KBD_LEFT; break;
|
|
case 'F':
|
|
case 'K':
|
|
case 'e': ev.x = KBD_END; break;
|
|
case 'H':
|
|
case 0: ev.x = KBD_HOME; break;
|
|
case 'V':
|
|
case 'I': ev.x = KBD_PAGE_UP; break;
|
|
case 'U':
|
|
if (is_interix()) {
|
|
ev.x = KBD_END;
|
|
break;
|
|
}
|
|
/*-fallthrough*/
|
|
case 'G': ev.x = KBD_PAGE_DOWN; break;
|
|
case 'P':
|
|
if (is_ibm()) {
|
|
ev.x = KBD_DEL;
|
|
break;
|
|
}
|
|
ev.x = KBD_F1; break;
|
|
case 'Q': ev.x = KBD_F2; break;
|
|
case 'S':
|
|
if (is_interix()) {
|
|
ev.x = KBD_PAGE_UP;
|
|
break;
|
|
}
|
|
ev.x = KBD_F4; break;
|
|
case 'T':
|
|
if (is_interix()) {
|
|
ev.x = KBD_PAGE_DOWN;
|
|
break;
|
|
}
|
|
ev.x = KBD_F5; break;
|
|
case 'W': ev.x = KBD_F8; break;
|
|
case 'X': ev.x = KBD_F9; break;
|
|
case 'Y':
|
|
if (is_uwin())
|
|
ev.x = itrm->kqueue[1] == '[' ? KBD_END : KBD_F10;
|
|
else
|
|
ev.x = KBD_F11;
|
|
break;
|
|
|
|
case 'q': switch (v) {
|
|
case 139: ev.x = KBD_INS; break;
|
|
case 146: ev.x = KBD_END; break;
|
|
case 150: ev.x = KBD_PAGE_UP; break;
|
|
case 154: ev.x = KBD_PAGE_DOWN; break;
|
|
default: if (v >= 1 && v <= 48) {
|
|
int fn = (v - 1) % 12;
|
|
int mod = (v - 1) / 12;
|
|
ev.x = KBD_F1 - fn;
|
|
if (mod == 1)
|
|
ev.y |= KBD_SHIFT;
|
|
if (mod == 2)
|
|
ev.y |= KBD_CTRL;
|
|
if (mod == 3)
|
|
ev.y |= KBD_ALT;
|
|
} break;
|
|
} break;
|
|
case 'z': switch (v) {
|
|
case 247: ev.x = KBD_INS; break;
|
|
case 214: ev.x = KBD_HOME; break;
|
|
case 220: ev.x = KBD_END; break;
|
|
case 216: ev.x = KBD_PAGE_UP; break;
|
|
case 222: ev.x = KBD_PAGE_DOWN; break;
|
|
case 249: ev.x = KBD_DEL; break;
|
|
} break;
|
|
case '~': switch (v) {
|
|
case 1: ev.x = KBD_HOME; break;
|
|
case 2: ev.x = KBD_INS; break;
|
|
case 3: ev.x = KBD_DEL; break;
|
|
case 4: ev.x = KBD_END; break;
|
|
case 5: ev.x = KBD_PAGE_UP; break;
|
|
case 6: ev.x = KBD_PAGE_DOWN; break;
|
|
case 7: ev.x = KBD_HOME; break;
|
|
case 8: ev.x = KBD_END; break;
|
|
case 17: ev.x = KBD_F6; break;
|
|
case 18: ev.x = KBD_F7; break;
|
|
case 19: ev.x = KBD_F8; break;
|
|
case 20: ev.x = KBD_F9; break;
|
|
case 21: ev.x = KBD_F10; break;
|
|
case 23: ev.x = KBD_F11; break;
|
|
case 24: ev.x = KBD_F12; break;
|
|
case 200: itrm->flags |= BRACKETED_PASTE; break;
|
|
case 201: itrm->flags &= ~BRACKETED_PASTE; break;
|
|
} break;
|
|
case 'R':
|
|
refresh_terminal_size();
|
|
break;
|
|
case 'M':
|
|
case '<':
|
|
if (c == 'M' && v == 5) {
|
|
if (xterm_button == -1) xterm_button = 0; /* */
|
|
if (itrm->qlen - el < 5) goto ret;
|
|
ev.x = (unsigned char)(itrm->kqueue[el+1]) - ' ' - 1 + ((int)((unsigned char)(itrm->kqueue[el+2]) - ' ' - 1) << 7);
|
|
if ( ev.x & (1 << 13)) ev.x = 0; /* ev.x |= ~0 << 14; */
|
|
ev.y = (unsigned char)(itrm->kqueue[el+3]) - ' ' - 1 + ((int)((unsigned char)(itrm->kqueue[el+4]) - ' ' - 1) << 7);
|
|
if ( ev.y & (1 << 13)) ev.y = 0; /* ev.y |= ~0 << 14; */
|
|
switch ((itrm->kqueue[el] - ' ') ^ xterm_button) { /* Every event changhes only one bit */
|
|
case TW_BUTT_LEFT: ev.b = B_LEFT | ( (xterm_button & TW_BUTT_LEFT) ? B_UP : B_DOWN ); break;
|
|
case TW_BUTT_MIDDLE: ev.b = B_MIDDLE | ( (xterm_button & TW_BUTT_MIDDLE) ? B_UP : B_DOWN ); break;
|
|
case TW_BUTT_RIGHT: ev.b = B_RIGHT | ( (xterm_button & TW_BUTT_RIGHT) ? B_UP : B_DOWN ); break;
|
|
case 0: ev.b = B_DRAG;
|
|
/* default : Twin protocol error */
|
|
}
|
|
xterm_button = itrm->kqueue[el] - ' ';
|
|
el += 5;
|
|
} else {
|
|
int x = 0, y = 0, b = 0;
|
|
int button;
|
|
unsigned char ch = 0; /* against warning */
|
|
if (c == 'M') {
|
|
/* Legacy mouse protocol: \e[Mbxy whereas b, x and y are raw bytes, offset by 32. */
|
|
if (itrm->qlen - el < 3) goto ret;
|
|
b = itrm->kqueue[el++] - ' ';
|
|
x = itrm->kqueue[el++] - ' ';
|
|
y = itrm->kqueue[el++] - ' ';
|
|
/*fprintf(stderr, "b: %d\n", b);*/
|
|
} else if (c == '<') {
|
|
/* SGR 1006 mouse extension: \e[<b;x;yM where b, x and y are in decimal, no longer offset by 32,
|
|
and the trailing letter is 'm' instead of 'M' for mouse release so that the released button is reported. */
|
|
int eel;
|
|
eel = el;
|
|
while (1) {
|
|
if (el == itrm->qlen) goto ret;
|
|
if (el - eel >= 9) goto l1;
|
|
ch = itrm->kqueue[el++];
|
|
if (ch == ';') break;
|
|
if (ch < '0' || ch > '9') goto l1;
|
|
b = 10 * b + (ch - '0');
|
|
}
|
|
eel = el;
|
|
while (1) {
|
|
if (el == itrm->qlen) goto ret;
|
|
if (el - eel >= 9) goto l1;
|
|
ch = itrm->kqueue[el++];
|
|
if (ch == ';') break;
|
|
if (ch < '0' || ch > '9') goto l1;
|
|
x = 10 * x + (ch - '0');
|
|
}
|
|
eel = el;
|
|
while (1) {
|
|
if (el == itrm->qlen) goto ret;
|
|
if (el - eel >= 9) goto l1;
|
|
ch = itrm->kqueue[el++];
|
|
if (ch == 'M' || ch == 'm') break;
|
|
if (ch < '0' || ch > '9') goto l1;
|
|
y = 10 * y + (ch - '0');
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
x--;
|
|
y--;
|
|
if (x < 0 || y < 0 || b < 0)
|
|
break;
|
|
|
|
/*fprintf(stderr, "b: %d, c %c, ch %c, xterm_button %d\n", b, xterm_button, c, ch);*/
|
|
|
|
if (c == 'M' && b == 3) button = B_UP;
|
|
else if (c == '<' && ch == 'm') button = B_UP;
|
|
else if ((b & 0x20) == 0x20) button = B_DRAG, b &= ~0x20;
|
|
else button = B_DOWN;
|
|
|
|
if (b == 0) button |= B_LEFT;
|
|
else if (b == 1) button |= B_MIDDLE;
|
|
else if (b == 2) button |= B_RIGHT;
|
|
else if (b == 3 && xterm_button >= 0) button |= xterm_button;
|
|
else if (b == 0x40) button |= B_WHEELUP;
|
|
else if (b == 0x41) button |= B_WHEELDOWN;
|
|
else if (b == 0x42) button |= B_WHEELLEFT;
|
|
else if (b == 0x43) button |= B_WHEELRIGHT;
|
|
else if (b == 0x80) button |= B_FOURTH;
|
|
else if (b == 0x81) button |= B_FIFTH;
|
|
else if (b == 0x82) button |= B_SIXTH;
|
|
else break;
|
|
|
|
if ((b == 0x80 || b == 0x81 || b == 0x82) && (button & BM_ACT) == B_DOWN && xterm_button == (button & BM_BUTT)) {
|
|
/* xterm has a bug that it reports down events for both click and release */
|
|
button &= ~BM_ACT;
|
|
button |= B_UP;
|
|
}
|
|
|
|
if ((button & BM_ACT) == B_DOWN)
|
|
xterm_button = button & BM_BUTT;
|
|
if ((button & BM_ACT) == B_UP)
|
|
xterm_button = -1;
|
|
|
|
ev.b = button;
|
|
ev.x = x;
|
|
ev.y = y;
|
|
|
|
/*fprintf(stderr, "buttons: %02lx\n", ev.b);*/
|
|
}
|
|
/*{
|
|
int a;
|
|
for (a = 0; a < el; a++) {
|
|
fprintf(stderr, " %02x", itrm->kqueue[a]);
|
|
if (itrm->kqueue[a] >= ' ') fprintf(stderr, "(%c)", itrm->kqueue[a]);
|
|
}
|
|
fprintf(stderr, "\n");
|
|
fprintf(stderr, "%ld %ld %ld\n", ev.x, ev.y, ev.b);
|
|
}*/
|
|
ev.ev = EV_MOUSE;
|
|
break;
|
|
}
|
|
} else {
|
|
el = 2;
|
|
if (itrm->kqueue[1] == '\033') {
|
|
if (itrm->qlen >= 3 && (itrm->kqueue[2] == '[' || itrm->kqueue[2] == 'O')) el = 1;
|
|
ev.x = KBD_ESC;
|
|
goto l2;
|
|
} else if (itrm->kqueue[1] == 127) {
|
|
ev.x = KBD_DEL;
|
|
ev.y = 0;
|
|
goto l2;
|
|
} else if (itrm->kqueue[1] == 'F' && is_interix()) {
|
|
int num;
|
|
if (itrm->qlen < 3) goto ret;
|
|
if (itrm->kqueue[2] >= '1' && itrm->kqueue[2] <= '9') {
|
|
num = itrm->kqueue[2] - '1';
|
|
} else if (itrm->kqueue[2] >= 'A' && itrm->kqueue[2] <= 'Z') {
|
|
num = itrm->kqueue[2] - 'A' + 9;
|
|
} else if (itrm->kqueue[2] >= 'a' && itrm->kqueue[2] <= 'k') {
|
|
num = itrm->kqueue[2] - 'a' + 35;
|
|
} else if (itrm->kqueue[2] >= 'm' && itrm->kqueue[2] <= 'z') {
|
|
num = itrm->kqueue[2] - 'a' + 34;
|
|
} else goto do_alt;
|
|
if (num < 12) {
|
|
ev.x = KBD_F1 - num;
|
|
} else if (num < 24) {
|
|
ev.x = KBD_F1 - (num - 12);
|
|
ev.y |= KBD_SHIFT;
|
|
} else if (num < 36) {
|
|
ev.x = KBD_F1 - (num - 24);
|
|
ev.y |= KBD_ALT;
|
|
} else if (num < 48) {
|
|
ev.x = KBD_F1 - (num - 36);
|
|
ev.y |= KBD_CTRL;
|
|
} else {
|
|
ev.x = KBD_F1 - (num - 48);
|
|
ev.y |= KBD_SHIFT | KBD_CTRL;
|
|
}
|
|
el = 3;
|
|
goto l1;
|
|
} else {
|
|
do_alt:
|
|
ev.x = itrm->kqueue[1];
|
|
ev.y |= KBD_ALT;
|
|
goto l2;
|
|
}
|
|
}
|
|
goto l1;
|
|
} else if (itrm->kqueue[0] == 0) {
|
|
#if defined(OS2) || defined(DOS)
|
|
if (itrm->qlen < 2) goto ret;
|
|
if (!(ev.x = os2xtd[itrm->kqueue[1]].x)) ev.x = -1;
|
|
ev.y = os2xtd[itrm->kqueue[1]].y;
|
|
el = 2;
|
|
/*printf("%02x - %02x %02x\n", (int)itrm->kqueue[1], ev.x, ev.y);*/
|
|
goto l1;
|
|
#else
|
|
el = 1;
|
|
goto l1;
|
|
#endif
|
|
}
|
|
el = 1;
|
|
ev.x = itrm->kqueue[0];
|
|
l2:
|
|
/*if (ev.x == 1) ev.x = KBD_HOME;
|
|
if (ev.x == 2) ev.x = KBD_PAGE_UP;
|
|
if (ev.x == 4) ev.x = KBD_DEL;
|
|
if (ev.x == 5) ev.x = KBD_END;
|
|
if (ev.x == 6) ev.x = KBD_PAGE_DOWN;*/
|
|
if (ev.x == 3) ev.x = KBD_CTRL_C;
|
|
if (ev.x == 8) ev.x = KBD_BS;
|
|
if (ev.x == 9) ev.x = KBD_TAB;
|
|
if (ev.x == 10) ev.x = KBD_ENTER /*, ev.y = KBD_CTRL*/;
|
|
if (ev.x == 13) ev.x = KBD_ENTER;
|
|
if (ev.x == 127) {
|
|
if (is_interix()) ev.x = KBD_DEL;
|
|
else ev.x = KBD_BS;
|
|
}
|
|
if (ev.x >= 0 && ev.x < ' ') {
|
|
ev.x += 'A' - 1;
|
|
ev.y |= KBD_CTRL;
|
|
}
|
|
l1:
|
|
if (itrm->qlen < el) {
|
|
internal_error("event queue underflow");
|
|
itrm->qlen = el;
|
|
}
|
|
if (ev.x != -1) {
|
|
if (itrm->flags & BRACKETED_PASTE && ev.ev == EV_KBD)
|
|
ev.y |= KBD_PASTING;
|
|
itrm->queue_event(itrm, (unsigned char *)&ev, sizeof(struct links_event));
|
|
}
|
|
memmove(itrm->kqueue, itrm->kqueue + el, itrm->qlen -= el);
|
|
end:
|
|
if (itrm->qlen < IN_BUF_SIZE && !itrm->blocked) set_handlers(itrm->std_in, in_kbd, NULL, itrm);
|
|
return el;
|
|
ret:
|
|
itrm->tm = install_timer(ESC_TIMEOUT, kbd_timeout, itrm);
|
|
return 0;
|
|
}
|
|
|
|
static void in_kbd(void *itrm_)
|
|
{
|
|
struct itrm *itrm = (struct itrm *)itrm_;
|
|
int r;
|
|
if (!can_read(itrm->std_in)) return;
|
|
if (itrm->tm != NULL) kill_timer(itrm->tm), itrm->tm = NULL;
|
|
if (itrm->qlen >= IN_BUF_SIZE) {
|
|
set_handlers(itrm->std_in, NULL, NULL, itrm);
|
|
while (process_queue(itrm))
|
|
;
|
|
return;
|
|
}
|
|
EINTRLOOP(r, (int)read(itrm->std_in, itrm->kqueue + itrm->qlen, IN_BUF_SIZE - itrm->qlen));
|
|
if (r <= 0) {
|
|
struct links_event ev = { EV_ABORT, 0, 0, 0 };
|
|
set_handlers(itrm->std_in, NULL, NULL, itrm);
|
|
itrm->queue_event(itrm, (unsigned char *)&ev, sizeof(struct links_event));
|
|
return;
|
|
}
|
|
more_data:
|
|
if ((itrm->qlen += r) > IN_BUF_SIZE) {
|
|
error("ERROR: too many bytes read");
|
|
itrm->qlen = IN_BUF_SIZE;
|
|
}
|
|
if (itrm->qlen < IN_BUF_SIZE && can_read(itrm->std_in)) {
|
|
EINTRLOOP(r, (int)read(itrm->std_in, itrm->kqueue + itrm->qlen, IN_BUF_SIZE - itrm->qlen));
|
|
if (r > 0) goto more_data;
|
|
}
|
|
while (process_queue(itrm))
|
|
;
|
|
}
|
|
|
|
#ifdef GRDRV_VIRTUAL_DEVICES
|
|
|
|
int kbd_set_raw;
|
|
|
|
void svgalib_free_trm(struct itrm *itrm)
|
|
{
|
|
/*debug("svgalib_free: %p", itrm);*/
|
|
if (!itrm) return;
|
|
if (kbd_set_raw) setcooked(itrm->ctl_in);
|
|
set_handlers(itrm->std_in, NULL, NULL, NULL);
|
|
unregister_bottom_half(itrm_error, itrm);
|
|
if (itrm->tm != NULL) kill_timer(itrm->tm);
|
|
mem_free(itrm);
|
|
if (itrm == ditrm) ditrm = NULL;
|
|
}
|
|
|
|
struct itrm *handle_svgalib_keyboard(void (*queue_event)(struct itrm *, unsigned char *, int))
|
|
{
|
|
struct itrm *itrm;
|
|
itrm = mem_calloc(sizeof(struct itrm));
|
|
ditrm = itrm;
|
|
itrm->queue_event = queue_event;
|
|
itrm->free_trm = svgalib_free_trm;
|
|
itrm->std_in = 0;
|
|
itrm->ctl_in = 0;
|
|
itrm->tm = NULL;
|
|
if (kbd_set_raw) setraw(itrm->ctl_in, 1);
|
|
set_handlers(itrm->std_in, in_kbd, NULL, itrm);
|
|
/*debug("svgalib_handle: %p", itrm);*/
|
|
return itrm;
|
|
}
|
|
|
|
int svgalib_unblock_itrm(struct itrm *itrm)
|
|
{
|
|
/*debug("svgalib_unblock: %p", itrm);*/
|
|
if (!itrm) return -1;
|
|
if (kbd_set_raw) if (setraw(itrm->ctl_in, 0)) return -1;
|
|
itrm->blocked = 0;
|
|
set_handlers(itrm->std_in, in_kbd, NULL, itrm);
|
|
unblock_stdin();
|
|
return 0;
|
|
}
|
|
|
|
void svgalib_block_itrm(struct itrm *itrm)
|
|
{
|
|
/*debug("svgalib_block: %p", itrm);*/
|
|
if (!itrm) return;
|
|
itrm->blocked = 1;
|
|
block_stdin();
|
|
if (kbd_set_raw) setcooked(itrm->ctl_in);
|
|
set_handlers(itrm->std_in, NULL, NULL, itrm);
|
|
}
|
|
|
|
#endif
|
|
|