links

lynx-like text mode web browser
git clone anongit@rnpnr.xyz:links.git
Log | Files | Refs | Feed | README | LICENSE

kbd.c (22003B)


      1 /* kbd.c
      2  * (c) 2002 Mikulas Patocka
      3  * This file is a part of the Links program, released under GPL.
      4  */
      5 
      6 #include <limits.h>
      7 
      8 #include "links.h"
      9 
     10 #define OUT_BUF_SIZE 10240
     11 #define IN_BUF_SIZE  64
     12 
     13 #define USE_TWIN_MOUSE  1
     14 #define BRACKETED_PASTE 2
     15 
     16 #define TW_BUTT_LEFT   1
     17 #define TW_BUTT_MIDDLE 2
     18 #define TW_BUTT_RIGHT  4
     19 
     20 struct itrm {
     21 	int std_in;
     22 	int std_out;
     23 	int sock_in;
     24 	int sock_out;
     25 	int ctl_in;
     26 	int blocked;
     27 	int flags;
     28 	unsigned char kqueue[IN_BUF_SIZE];
     29 	int qlen;
     30 	struct timer *tm;
     31 	void (*queue_event)(struct itrm *, unsigned char *, int);
     32 	unsigned char *ev_queue;
     33 	int eqlen;
     34 	void *mouse_h;
     35 	unsigned char *orig_title;
     36 	void (*free_trm)(struct itrm *);
     37 };
     38 
     39 static void free_trm(struct itrm *);
     40 static void in_kbd(void *);
     41 
     42 static struct itrm *ditrm = NULL;
     43 
     44 int
     45 is_blocked(void)
     46 {
     47 	return ditrm && ditrm->blocked;
     48 }
     49 
     50 void
     51 free_all_itrms(void)
     52 {
     53 	if (ditrm)
     54 		ditrm->free_trm(ditrm);
     55 }
     56 
     57 static void
     58 itrm_error(void *itrm_)
     59 {
     60 	struct itrm *itrm = (struct itrm *)itrm_;
     61 	itrm->free_trm(itrm);
     62 	terminate_loop = 1;
     63 }
     64 
     65 static void
     66 write_ev_queue(void *itrm_)
     67 {
     68 	struct itrm *itrm = (struct itrm *)itrm_;
     69 	int l, to_write;
     70 	if (!itrm->eqlen)
     71 		internal("event queue empty");
     72 	to_write = itrm->eqlen;
     73 retry:
     74 	EINTRLOOP(l, (int)write(itrm->sock_out, itrm->ev_queue, to_write));
     75 	if (l <= 0) {
     76 		if (to_write > 1) {
     77 			to_write >>= 1;
     78 			goto retry;
     79 		}
     80 		itrm_error(itrm);
     81 	}
     82 	memmove(itrm->ev_queue, itrm->ev_queue + l, itrm->eqlen -= l);
     83 	if (!itrm->eqlen)
     84 		set_handlers(itrm->sock_out,
     85 		             get_handler(itrm->sock_out, H_READ), NULL,
     86 		             get_handler_data(itrm->sock_out));
     87 }
     88 
     89 static void
     90 queue_event(struct itrm *itrm, unsigned char *data, int len)
     91 {
     92 	int w = 0;
     93 	if (!len)
     94 		return;
     95 	if (!itrm->eqlen && can_write(itrm->sock_out)) {
     96 		int to_write = len;
     97 retry:
     98 		EINTRLOOP(w, (int)write(itrm->sock_out, data, to_write));
     99 		if (w <= 0) {
    100 			if (to_write > 1) {
    101 				to_write >>= 1;
    102 				goto retry;
    103 			}
    104 			register_bottom_half(itrm_error, itrm);
    105 			return;
    106 		}
    107 	}
    108 	if (w < len) {
    109 		if ((unsigned)itrm->eqlen + (unsigned)(len - w) > INT_MAX)
    110 			overalloc();
    111 		itrm->ev_queue =
    112 		    xrealloc(itrm->ev_queue, itrm->eqlen + len - w);
    113 		memcpy(itrm->ev_queue + itrm->eqlen, data + w, len - w);
    114 		itrm->eqlen += len - w;
    115 		set_handlers(itrm->sock_out,
    116 		             get_handler(itrm->sock_out, H_READ),
    117 		             write_ev_queue, itrm);
    118 	}
    119 }
    120 
    121 void
    122 kbd_ctrl_c(void)
    123 {
    124 	struct links_event ev = { EV_KBD, KBD_CTRL_C, 0, 0 };
    125 	if (ditrm)
    126 		ditrm->queue_event(ditrm, (unsigned char *)&ev,
    127 		                   sizeof(struct links_event));
    128 }
    129 
    130 unsigned char init_seq[] = "\033)0\0337";
    131 unsigned char init_seq_x_mouse[] =
    132     "\033[?1000h\033[?1002h\033[?1005l\033[?1015l\033[?1006h\033[?2004h";
    133 unsigned char init_seq_tw_mouse[] = "\033[?9h";
    134 unsigned char term_seq[] = "\033[2J\0338\r \b";
    135 unsigned char term_seq_x_mouse[] =
    136     "\033[?1000l\r       \r\033[?1002l\r       \r\033[?1006l\r       "
    137     "\r\033[?2004l\r       \r";
    138 unsigned char term_seq_tw_mouse[] = "\033[?9l";
    139 
    140 static void
    141 send_init_sequence(int h, int flags)
    142 {
    143 	hard_write(h, init_seq, (int)strlen(cast_const_char init_seq));
    144 	if (flags & USE_TWIN_MOUSE)
    145 		hard_write(h, init_seq_tw_mouse,
    146 		           (int)strlen(cast_const_char init_seq_tw_mouse));
    147 	else
    148 		hard_write(h, init_seq_x_mouse,
    149 		           (int)strlen(cast_const_char init_seq_x_mouse));
    150 }
    151 
    152 static void
    153 send_term_sequence(int h, int flags)
    154 {
    155 	hard_write(h, term_seq, (int)strlen(cast_const_char term_seq));
    156 	if (flags & USE_TWIN_MOUSE)
    157 		hard_write(h, term_seq_tw_mouse,
    158 		           (int)strlen(cast_const_char term_seq_tw_mouse));
    159 	else
    160 		hard_write(h, term_seq_x_mouse,
    161 		           (int)strlen(cast_const_char term_seq_x_mouse));
    162 }
    163 
    164 static void
    165 resize_terminal(int x, int y)
    166 {
    167 	struct links_event ev = { EV_RESIZE, 0, 0, 0 };
    168 	ev.x = x;
    169 	ev.y = y;
    170 	queue_event(ditrm, (unsigned char *)&ev, sizeof(struct links_event));
    171 }
    172 
    173 static void
    174 os_cfmakeraw(struct termios *t)
    175 {
    176 	cfmakeraw(t);
    177 #ifdef VMIN
    178 	t->c_cc[VMIN] = 1;
    179 #endif
    180 #if defined(NO_CTRL_Z) && defined(VSUSP)
    181 	t->c_cc[VSUSP] = 0;
    182 #endif
    183 }
    184 
    185 static int
    186 ttcgetattr(int fd, struct termios *t)
    187 {
    188 	int r;
    189 	block_signals(
    190 #ifdef SIGTTOU
    191 	    SIGTTOU
    192 #else
    193 	    0
    194 #endif
    195 	    ,
    196 #ifdef SIGTTIN
    197 	    SIGTTIN
    198 #else
    199 	    0
    200 #endif
    201 	);
    202 #ifdef SIGTTOU
    203 	interruptible_signal(SIGTTOU, 1);
    204 #endif
    205 #ifdef SIGTTIN
    206 	interruptible_signal(SIGTTIN, 1);
    207 #endif
    208 	r = tcgetattr(fd, t);
    209 #ifdef SIGTTOU
    210 	interruptible_signal(SIGTTOU, 0);
    211 #endif
    212 #ifdef SIGTTIN
    213 	interruptible_signal(SIGTTIN, 0);
    214 #endif
    215 	unblock_signals();
    216 	return r;
    217 }
    218 
    219 static int
    220 ttcsetattr(int fd, int a, struct termios *t)
    221 {
    222 	int r;
    223 	block_signals(
    224 #ifdef SIGTTOU
    225 	    SIGTTOU
    226 #else
    227 	    0
    228 #endif
    229 	    ,
    230 #ifdef SIGTTIN
    231 	    SIGTTIN
    232 #else
    233 	    0
    234 #endif
    235 	);
    236 #ifdef SIGTTOU
    237 	interruptible_signal(SIGTTOU, 1);
    238 #endif
    239 #ifdef SIGTTIN
    240 	interruptible_signal(SIGTTIN, 1);
    241 #endif
    242 	r = tcsetattr(fd, a, t);
    243 #ifdef SIGTTOU
    244 	interruptible_signal(SIGTTOU, 0);
    245 #endif
    246 #ifdef SIGTTIN
    247 	interruptible_signal(SIGTTIN, 0);
    248 #endif
    249 	unblock_signals();
    250 	return r;
    251 }
    252 
    253 static struct termios saved_termios;
    254 
    255 static int
    256 setraw(int ctl, int save)
    257 {
    258 	struct termios t;
    259 	if (ctl < 0)
    260 		return 0;
    261 	memset(&t, 0, sizeof(struct termios));
    262 	if (ttcgetattr(ctl, &t)) {
    263 		/*fprintf(stderr, "getattr result %s\n", strerror(errno));*/
    264 		/* If the terminal was destroyed (the user logged off),
    265 		 * we fake success here so that we can destroy the terminal
    266 		 * later.
    267 		 *
    268 		 * Linux returns EIO
    269 		 * FreeBSD returns ENXIO
    270 		 */
    271 		if (errno == EIO || errno == ENXIO)
    272 			return 0;
    273 		return -1;
    274 	}
    275 	if (save)
    276 		memcpy(&saved_termios, &t, sizeof(struct termios));
    277 	os_cfmakeraw(&t);
    278 	t.c_lflag |= ISIG;
    279 #ifdef TOSTOP
    280 	t.c_lflag |= TOSTOP;
    281 #endif
    282 	t.c_oflag |= OPOST;
    283 	if (ttcsetattr(ctl, TCSANOW, &t)) {
    284 		return -1;
    285 	}
    286 	return 0;
    287 }
    288 
    289 static void
    290 setcooked(int ctl)
    291 {
    292 	if (ctl < 0)
    293 		return;
    294 	ttcsetattr(ctl, TCSANOW, &saved_termios);
    295 }
    296 
    297 void
    298 handle_trm(int sock_out, void *init_string, int init_len)
    299 {
    300 	struct itrm *itrm;
    301 	struct links_event ev = { EV_INIT, 0, 0, 0 };
    302 	unsigned char *ts;
    303 	int xwin, def_charset;
    304 	itrm = xmalloc(sizeof(struct itrm));
    305 	itrm->queue_event = queue_event;
    306 	itrm->free_trm = free_trm;
    307 	ditrm = itrm;
    308 	itrm->std_in = 0;
    309 	itrm->std_out = 1;
    310 	itrm->sock_in = 1;
    311 	itrm->sock_out = sock_out;
    312 	itrm->ctl_in = 0;
    313 	itrm->blocked = 0;
    314 	itrm->qlen = 0;
    315 	itrm->tm = NULL;
    316 	itrm->ev_queue = NULL;
    317 	itrm->eqlen = 0;
    318 	setraw(itrm->ctl_in, 1);
    319 	set_handlers(0, in_kbd, NULL, itrm);
    320 	handle_terminal_resize(resize_terminal, &ev.x, &ev.y);
    321 	queue_event(itrm, (unsigned char *)&ev, sizeof(struct links_event));
    322 	xwin = is_xterm() * ENV_XWIN + is_screen() * ENV_SCREEN;
    323 	itrm->flags = 0;
    324 	if (!(ts = cast_uchar getenv("TERM")))
    325 		ts = cast_uchar "";
    326 	if (strlen(cast_const_char ts) >= MAX_TERM_LEN)
    327 		queue_event(itrm, ts, MAX_TERM_LEN);
    328 	else {
    329 		unsigned char *mm;
    330 		int ll = MAX_TERM_LEN - (int)strlen(cast_const_char ts);
    331 		queue_event(itrm, ts, (int)strlen(cast_const_char ts));
    332 		mm = mem_calloc(ll);
    333 		queue_event(itrm, mm, ll);
    334 		free(mm);
    335 	}
    336 	if (!(ts = get_cwd()))
    337 		ts = stracpy(cast_uchar "");
    338 	if (strlen(cast_const_char ts) >= MAX_CWD_LEN)
    339 		queue_event(itrm, ts, MAX_CWD_LEN);
    340 	else {
    341 		unsigned char *mm;
    342 		int ll = MAX_CWD_LEN - (int)strlen(cast_const_char ts);
    343 		queue_event(itrm, ts, (int)strlen(cast_const_char ts));
    344 		mm = mem_calloc(ll);
    345 		queue_event(itrm, mm, ll);
    346 		free(mm);
    347 	}
    348 	free(ts);
    349 	queue_event(itrm, (unsigned char *)&xwin, sizeof(int));
    350 	def_charset = 0;
    351 	queue_event(itrm, (unsigned char *)&def_charset, sizeof(int));
    352 	queue_event(itrm, (unsigned char *)&init_len, sizeof(int));
    353 	queue_event(itrm, (unsigned char *)init_string, init_len);
    354 	itrm->orig_title = get_window_title();
    355 	set_window_title(cast_uchar "Links");
    356 	itrm->mouse_h = NULL;
    357 	send_init_sequence(1, itrm->flags);
    358 }
    359 
    360 int
    361 unblock_itrm(int fd)
    362 {
    363 	struct itrm *itrm = ditrm;
    364 	int x, y;
    365 	if (!itrm)
    366 		return -1;
    367 	if (setraw(itrm->ctl_in, 0))
    368 		return -1;
    369 	if (itrm->blocked != fd + 1)
    370 		return -2;
    371 	itrm->blocked = 0;
    372 	send_init_sequence(itrm->std_out, itrm->flags);
    373 	set_handlers(itrm->std_in, in_kbd, NULL, itrm);
    374 	handle_terminal_resize(resize_terminal, &x, &y);
    375 	itrm->mouse_h = NULL;
    376 	resize_terminal(x, y);
    377 	return 0;
    378 }
    379 
    380 void
    381 block_itrm(int fd)
    382 {
    383 	struct itrm *itrm = ditrm;
    384 	if (!itrm)
    385 		return;
    386 	if (itrm->blocked)
    387 		return;
    388 	itrm->blocked = fd + 1;
    389 	unhandle_terminal_resize();
    390 	itrm->mouse_h = NULL;
    391 	send_term_sequence(itrm->std_out, itrm->flags);
    392 	setcooked(itrm->ctl_in);
    393 	set_handlers(itrm->std_in, NULL, NULL, itrm);
    394 }
    395 
    396 static void
    397 free_trm(struct itrm *itrm)
    398 {
    399 	if (!itrm)
    400 		return;
    401 	set_window_title(itrm->orig_title);
    402 	free(itrm->orig_title);
    403 	itrm->orig_title = NULL;
    404 	unhandle_terminal_resize();
    405 	send_term_sequence(itrm->std_out, itrm->flags);
    406 	setcooked(itrm->ctl_in);
    407 	set_handlers(itrm->std_in, NULL, NULL, NULL);
    408 	set_handlers(itrm->sock_in, NULL, NULL, NULL);
    409 	set_handlers(itrm->std_out, NULL, NULL, NULL);
    410 	set_handlers(itrm->sock_out, NULL, NULL, NULL);
    411 	unregister_bottom_half(itrm_error, itrm);
    412 	if (itrm->tm != NULL)
    413 		kill_timer(itrm->tm);
    414 	free(itrm->ev_queue);
    415 	free(itrm);
    416 	if (itrm == ditrm)
    417 		ditrm = NULL;
    418 }
    419 
    420 static void
    421 refresh_terminal_size(void)
    422 {
    423 	int new_x, new_y;
    424 	if (!ditrm->blocked) {
    425 		unhandle_terminal_resize();
    426 		handle_terminal_resize(resize_terminal, &new_x, &new_y);
    427 		resize_terminal(new_x, new_y);
    428 	}
    429 }
    430 
    431 static void
    432 resize_terminal_x(unsigned char *text)
    433 {
    434 	unsigned char *p;
    435 	if (!(p = cast_uchar strchr(cast_const_char text, ',')))
    436 		return;
    437 	*p++ = 0;
    438 	refresh_terminal_size();
    439 }
    440 
    441 void
    442 dispatch_special(unsigned char *text)
    443 {
    444 	switch (text[0]) {
    445 	case TERM_FN_TITLE:
    446 		set_window_title(text + 1);
    447 		break;
    448 	case TERM_FN_RESIZE:
    449 		resize_terminal_x(text + 1);
    450 		break;
    451 	}
    452 }
    453 
    454 static int process_queue(struct itrm *);
    455 static int get_esc_code(unsigned char *, int, unsigned char *, int *, int *);
    456 
    457 static void
    458 kbd_timeout(void *itrm_)
    459 {
    460 	struct itrm *itrm = (struct itrm *)itrm_;
    461 	struct links_event ev = { EV_KBD, KBD_ESC, 0, 0 };
    462 	unsigned char code;
    463 	int num;
    464 	int len = 0; /* against warning */
    465 	itrm->tm = NULL;
    466 	if (can_read(itrm->std_in)) {
    467 		in_kbd(itrm);
    468 		return;
    469 	}
    470 	if (!itrm->qlen) {
    471 		internal("timeout on empty queue");
    472 		return;
    473 	}
    474 	if (itrm->kqueue[0] != 27) {
    475 		len = 1;
    476 		goto skip_esc;
    477 	}
    478 	itrm->queue_event(itrm, (unsigned char *)&ev,
    479 	                  sizeof(struct links_event));
    480 	if (get_esc_code(itrm->kqueue, itrm->qlen, &code, &num, &len))
    481 		len = 1;
    482 skip_esc:
    483 	itrm->qlen -= len;
    484 	memmove(itrm->kqueue, itrm->kqueue + len, itrm->qlen);
    485 	while (process_queue(itrm))
    486 		;
    487 }
    488 
    489 static int
    490 get_esc_code(unsigned char *str, int len, unsigned char *code, int *num,
    491              int *el)
    492 {
    493 	int pos;
    494 	*num = 0;
    495 	for (pos = 2; pos < len; pos++) {
    496 		if (str[pos] < '0' || str[pos] > '9' || pos > 7) {
    497 			*el = pos + 1;
    498 			*code = str[pos];
    499 			return 0;
    500 		}
    501 		*num = *num * 10 + str[pos] - '0';
    502 	}
    503 	return -1;
    504 }
    505 
    506 static int xterm_button = -1;
    507 
    508 static int
    509 process_queue(struct itrm *itrm)
    510 {
    511 	struct links_event ev = { EV_KBD, -1, 0, 0 };
    512 	int el = 0;
    513 	if (!itrm->qlen)
    514 		goto end;
    515 	if (itrm->kqueue[0] == '\033') {
    516 		if (itrm->qlen < 2)
    517 			goto ret;
    518 		if (itrm->kqueue[1] == '[' || itrm->kqueue[1] == 'O') {
    519 			unsigned char c = 0;
    520 			int v;
    521 			if (itrm->qlen >= 4 && itrm->kqueue[2] == '[') {
    522 				if (itrm->kqueue[3] < 'A'
    523 				    || itrm->kqueue[3] > 'L')
    524 					goto ret;
    525 				ev.x = KBD_F1 - (itrm->kqueue[3] - 'A');
    526 				el = 4;
    527 			} else if (get_esc_code(itrm->kqueue, itrm->qlen, &c,
    528 			                        &v, &el))
    529 				goto ret;
    530 			else
    531 				switch (c) {
    532 				case 'L':
    533 				case '@':
    534 					ev.x = KBD_INS;
    535 					break;
    536 				case 'A':
    537 					ev.x = KBD_UP;
    538 					break;
    539 				case 'B':
    540 					ev.x = KBD_DOWN;
    541 					break;
    542 				case 'C':
    543 					ev.x = KBD_RIGHT;
    544 					break;
    545 				case 'D':
    546 					ev.x = KBD_LEFT;
    547 					break;
    548 				case 'F':
    549 				case 'K':
    550 				case 'e':
    551 					ev.x = KBD_END;
    552 					break;
    553 				case 'H':
    554 				case 0:
    555 					ev.x = KBD_HOME;
    556 					break;
    557 				case 'V':
    558 				case 'I':
    559 					ev.x = KBD_PAGE_UP;
    560 					break;
    561 				case 'U':
    562 				case 'G':
    563 					ev.x = KBD_PAGE_DOWN;
    564 					break;
    565 				case 'P':
    566 					ev.x = KBD_F1;
    567 					break;
    568 				case 'Q':
    569 					ev.x = KBD_F2;
    570 					break;
    571 				case 'S':
    572 					ev.x = KBD_F4;
    573 					break;
    574 				case 'T':
    575 					ev.x = KBD_F5;
    576 					break;
    577 				case 'W':
    578 					ev.x = KBD_F8;
    579 					break;
    580 				case 'X':
    581 					ev.x = KBD_F9;
    582 					break;
    583 				case 'Y':
    584 					ev.x = KBD_F11;
    585 					break;
    586 
    587 				case 'q':
    588 					switch (v) {
    589 					case 139:
    590 						ev.x = KBD_INS;
    591 						break;
    592 					case 146:
    593 						ev.x = KBD_END;
    594 						break;
    595 					case 150:
    596 						ev.x = KBD_PAGE_UP;
    597 						break;
    598 					case 154:
    599 						ev.x = KBD_PAGE_DOWN;
    600 						break;
    601 					default:
    602 						if (v >= 1 && v <= 48) {
    603 							int fn = (v - 1) % 12;
    604 							int mod = (v - 1) / 12;
    605 							ev.x = KBD_F1 - fn;
    606 							if (mod == 1)
    607 								ev.y |=
    608 								    KBD_SHIFT;
    609 							if (mod == 2)
    610 								ev.y |=
    611 								    KBD_CTRL;
    612 							if (mod == 3)
    613 								ev.y |= KBD_ALT;
    614 						}
    615 						break;
    616 					}
    617 					break;
    618 				case 'z':
    619 					switch (v) {
    620 					case 247:
    621 						ev.x = KBD_INS;
    622 						break;
    623 					case 214:
    624 						ev.x = KBD_HOME;
    625 						break;
    626 					case 220:
    627 						ev.x = KBD_END;
    628 						break;
    629 					case 216:
    630 						ev.x = KBD_PAGE_UP;
    631 						break;
    632 					case 222:
    633 						ev.x = KBD_PAGE_DOWN;
    634 						break;
    635 					case 249:
    636 						ev.x = KBD_DEL;
    637 						break;
    638 					}
    639 					break;
    640 				case '~':
    641 					switch (v) {
    642 					case 1:
    643 						ev.x = KBD_HOME;
    644 						break;
    645 					case 2:
    646 						ev.x = KBD_INS;
    647 						break;
    648 					case 3:
    649 						ev.x = KBD_DEL;
    650 						break;
    651 					case 4:
    652 						ev.x = KBD_END;
    653 						break;
    654 					case 5:
    655 						ev.x = KBD_PAGE_UP;
    656 						break;
    657 					case 6:
    658 						ev.x = KBD_PAGE_DOWN;
    659 						break;
    660 					case 7:
    661 						ev.x = KBD_HOME;
    662 						break;
    663 					case 8:
    664 						ev.x = KBD_END;
    665 						break;
    666 					case 17:
    667 						ev.x = KBD_F6;
    668 						break;
    669 					case 18:
    670 						ev.x = KBD_F7;
    671 						break;
    672 					case 19:
    673 						ev.x = KBD_F8;
    674 						break;
    675 					case 20:
    676 						ev.x = KBD_F9;
    677 						break;
    678 					case 21:
    679 						ev.x = KBD_F10;
    680 						break;
    681 					case 23:
    682 						ev.x = KBD_F11;
    683 						break;
    684 					case 24:
    685 						ev.x = KBD_F12;
    686 						break;
    687 					case 200:
    688 						itrm->flags |= BRACKETED_PASTE;
    689 						break;
    690 					case 201:
    691 						itrm->flags &= ~BRACKETED_PASTE;
    692 						break;
    693 					}
    694 					break;
    695 				case 'R':
    696 					refresh_terminal_size();
    697 					break;
    698 				case 'M':
    699 				case '<':
    700 					if (c == 'M' && v == 5) {
    701 						if (xterm_button == -1)
    702 							xterm_button = 0;
    703 						if (itrm->qlen - el < 5)
    704 							goto ret;
    705 						ev.x =
    706 						    (unsigned char)(itrm->kqueue
    707 						                        [el
    708 						                         + 1])
    709 						    - ' ' - 1
    710 						    + ((int)((unsigned char)(itrm->kqueue
    711 						                                 [el
    712 						                                  + 2])
    713 						             - ' ' - 1)
    714 						       << 7);
    715 						if (ev.x & (1 << 13))
    716 							ev.x = 0;
    717 						ev.y =
    718 						    (unsigned char)(itrm->kqueue
    719 						                        [el
    720 						                         + 3])
    721 						    - ' ' - 1
    722 						    + ((int)((unsigned char)(itrm->kqueue
    723 						                                 [el
    724 						                                  + 4])
    725 						             - ' ' - 1)
    726 						       << 7);
    727 						if (ev.y & (1 << 13))
    728 							ev.y = 0;
    729 						switch (
    730 						    (itrm->kqueue[el] - ' ')
    731 						    ^ xterm_button) { /* Every
    732 							                 event
    733 							                 changhes
    734 							                 only
    735 							                 one bit
    736 							               */
    737 						case TW_BUTT_LEFT:
    738 							ev.b =
    739 							    B_LEFT
    740 							    | ((xterm_button
    741 							        & TW_BUTT_LEFT)
    742 							           ? B_UP
    743 							           : B_DOWN);
    744 							break;
    745 						case TW_BUTT_MIDDLE:
    746 							ev.b =
    747 							    B_MIDDLE
    748 							    | ((xterm_button
    749 							        & TW_BUTT_MIDDLE)
    750 							           ? B_UP
    751 							           : B_DOWN);
    752 							break;
    753 						case TW_BUTT_RIGHT:
    754 							ev.b =
    755 							    B_RIGHT
    756 							    | ((xterm_button
    757 							        & TW_BUTT_RIGHT)
    758 							           ? B_UP
    759 							           : B_DOWN);
    760 							break;
    761 						case 0:
    762 							ev.b = B_DRAG;
    763 							/* default : Twin
    764 							 * protocol error */
    765 						}
    766 						xterm_button =
    767 						    itrm->kqueue[el] - ' ';
    768 						el += 5;
    769 					} else {
    770 						int x = 0, y = 0, b = 0;
    771 						int button;
    772 						unsigned char ch;
    773 						if (c == 'M') {
    774 							/* Legacy mouse
    775 							 * protocol: \e[Mbxy
    776 							 * whereas b, x and y
    777 							 * are raw bytes, offset
    778 							 * by 32. */
    779 							if (itrm->qlen - el < 3)
    780 								goto ret;
    781 							b = itrm->kqueue[el++]
    782 							    - ' ';
    783 							x = itrm->kqueue[el++]
    784 							    - ' ';
    785 							y = itrm->kqueue[el++]
    786 							    - ' ';
    787 						} else if (c == '<') {
    788 							/* SGR 1006 mouse
    789 							   extension: \e[<b;x;yM
    790 							   where b, x and y are
    791 							   in decimal, no longer
    792 							   offset by 32, and the
    793 							   trailing letter is
    794 							   'm' instead of 'M'
    795 							   for mouse release so
    796 							   that the released
    797 							   button is reported.
    798 							 */
    799 							int eel;
    800 							eel = el;
    801 							while (1) {
    802 								if (el
    803 								    == itrm->qlen)
    804 									goto ret;
    805 								if (el - eel
    806 								    >= 9)
    807 									goto l1;
    808 								ch =
    809 								    itrm->kqueue
    810 									[el++];
    811 								if (ch == ';')
    812 									break;
    813 								if (ch < '0'
    814 								    || ch > '9')
    815 									goto l1;
    816 								b = 10 * b
    817 								    + (ch
    818 								       - '0');
    819 							}
    820 							eel = el;
    821 							while (1) {
    822 								if (el
    823 								    == itrm->qlen)
    824 									goto ret;
    825 								if (el - eel
    826 								    >= 9)
    827 									goto l1;
    828 								ch =
    829 								    itrm->kqueue
    830 									[el++];
    831 								if (ch == ';')
    832 									break;
    833 								if (ch < '0'
    834 								    || ch > '9')
    835 									goto l1;
    836 								x = 10 * x
    837 								    + (ch
    838 								       - '0');
    839 							}
    840 							eel = el;
    841 							while (1) {
    842 								if (el
    843 								    == itrm->qlen)
    844 									goto ret;
    845 								if (el - eel
    846 								    >= 9)
    847 									goto l1;
    848 								ch =
    849 								    itrm->kqueue
    850 									[el++];
    851 								if (ch == 'M'
    852 								    || ch == 'm')
    853 									break;
    854 								if (ch < '0'
    855 								    || ch > '9')
    856 									goto l1;
    857 								y = 10 * y
    858 								    + (ch
    859 								       - '0');
    860 							}
    861 						} else {
    862 							break;
    863 						}
    864 						x--;
    865 						y--;
    866 						if (x < 0 || y < 0 || b < 0)
    867 							break;
    868 						if (c == 'M' && b == 3)
    869 							button = B_UP;
    870 						else if (c == '<' && ch == 'm')
    871 							button = B_UP;
    872 						else if ((b & 0x20) == 0x20)
    873 							button = B_DRAG,
    874 							b &= ~0x20;
    875 						else
    876 							button = B_DOWN;
    877 						if (b == 0)
    878 							button |= B_LEFT;
    879 						else if (b == 1)
    880 							button |= B_MIDDLE;
    881 						else if (b == 2)
    882 							button |= B_RIGHT;
    883 						else if (b == 3
    884 						         && xterm_button >= 0)
    885 							button |= xterm_button;
    886 						else if (b == 0x40)
    887 							button |= B_WHEELUP;
    888 						else if (b == 0x41)
    889 							button |= B_WHEELDOWN;
    890 						else if (b == 0x42)
    891 							button |= B_WHEELLEFT;
    892 						else if (b == 0x43)
    893 							button |= B_WHEELRIGHT;
    894 						else if (b == 0x80)
    895 							button |= B_FOURTH;
    896 						else if (b == 0x81)
    897 							button |= B_FIFTH;
    898 						else if (b == 0x82)
    899 							button |= B_SIXTH;
    900 						else
    901 							break;
    902 						if ((b == 0x80 || b == 0x81
    903 						     || b == 0x82)
    904 						    && (button & BM_ACT)
    905 						           == B_DOWN
    906 						    && xterm_button
    907 						           == (button
    908 						               & BM_BUTT)) {
    909 							/* xterm has a bug that
    910 							 * it reports down
    911 							 * events for both click
    912 							 * and release */
    913 							button &= ~BM_ACT;
    914 							button |= B_UP;
    915 						}
    916 						if ((button & BM_ACT) == B_DOWN)
    917 							xterm_button =
    918 							    button & BM_BUTT;
    919 						if ((button & BM_ACT) == B_UP)
    920 							xterm_button = -1;
    921 						ev.b = button;
    922 						ev.x = x;
    923 						ev.y = y;
    924 					}
    925 					ev.ev = EV_MOUSE;
    926 					break;
    927 				}
    928 		} else {
    929 			el = 2;
    930 			if (itrm->kqueue[1] == '\033') {
    931 				if (itrm->qlen >= 3
    932 				    && (itrm->kqueue[2] == '['
    933 				        || itrm->kqueue[2] == 'O'))
    934 					el = 1;
    935 				ev.x = KBD_ESC;
    936 				goto l2;
    937 			} else if (itrm->kqueue[1] == 127) {
    938 				ev.x = KBD_DEL;
    939 				ev.y = 0;
    940 				goto l2;
    941 			} else {
    942 				ev.x = itrm->kqueue[1];
    943 				ev.y |= KBD_ALT;
    944 				goto l2;
    945 			}
    946 		}
    947 		goto l1;
    948 	} else if (itrm->kqueue[0] == 0) {
    949 		el = 1;
    950 		goto l1;
    951 	}
    952 	el = 1;
    953 	ev.x = itrm->kqueue[0];
    954 l2:
    955 	if (ev.x == 3)
    956 		ev.x = KBD_CTRL_C;
    957 	if (ev.x == 8)
    958 		ev.x = KBD_BS;
    959 	if (ev.x == 9)
    960 		ev.x = KBD_TAB;
    961 	if (ev.x == 10)
    962 		ev.x = KBD_ENTER;
    963 	if (ev.x == 13)
    964 		ev.x = KBD_ENTER;
    965 	if (ev.x == 127)
    966 		ev.x = KBD_BS;
    967 	if (ev.x >= 0 && ev.x < ' ') {
    968 		ev.x += 'A' - 1;
    969 		ev.y |= KBD_CTRL;
    970 	}
    971 l1:
    972 	if (itrm->qlen < el) {
    973 		internal("event queue underflow");
    974 		itrm->qlen = el;
    975 	}
    976 	if (ev.x != -1) {
    977 		if (itrm->flags & BRACKETED_PASTE && ev.ev == EV_KBD)
    978 			ev.y |= KBD_PASTING;
    979 		itrm->queue_event(itrm, (unsigned char *)&ev,
    980 		                  sizeof(struct links_event));
    981 	}
    982 	memmove(itrm->kqueue, itrm->kqueue + el, itrm->qlen -= el);
    983 end:
    984 	if (itrm->qlen < IN_BUF_SIZE && !itrm->blocked)
    985 		set_handlers(itrm->std_in, in_kbd, NULL, itrm);
    986 	return el;
    987 ret:
    988 	itrm->tm = install_timer(ESC_TIMEOUT, kbd_timeout, itrm);
    989 	return 0;
    990 }
    991 
    992 static void
    993 in_kbd(void *itrm_)
    994 {
    995 	struct itrm *itrm = (struct itrm *)itrm_;
    996 	int r;
    997 	if (!can_read(itrm->std_in))
    998 		return;
    999 	if (itrm->tm != NULL) {
   1000 		kill_timer(itrm->tm);
   1001 		itrm->tm = NULL;
   1002 	}
   1003 	if (itrm->qlen >= IN_BUF_SIZE) {
   1004 		set_handlers(itrm->std_in, NULL, NULL, itrm);
   1005 		while (process_queue(itrm))
   1006 			;
   1007 		return;
   1008 	}
   1009 	EINTRLOOP(r, (int)read(itrm->std_in, itrm->kqueue + itrm->qlen,
   1010 	                       IN_BUF_SIZE - itrm->qlen));
   1011 	if (r <= 0) {
   1012 		struct links_event ev = { EV_ABORT, 0, 0, 0 };
   1013 		set_handlers(itrm->std_in, NULL, NULL, itrm);
   1014 		itrm->queue_event(itrm, (unsigned char *)&ev,
   1015 		                  sizeof(struct links_event));
   1016 		return;
   1017 	}
   1018 more_data:
   1019 	if ((itrm->qlen += r) > IN_BUF_SIZE) {
   1020 		error("ERROR: too many bytes read");
   1021 		itrm->qlen = IN_BUF_SIZE;
   1022 	}
   1023 	if (itrm->qlen < IN_BUF_SIZE && can_read(itrm->std_in)) {
   1024 		EINTRLOOP(r, (int)read(itrm->std_in, itrm->kqueue + itrm->qlen,
   1025 		                       IN_BUF_SIZE - itrm->qlen));
   1026 		if (r > 0)
   1027 			goto more_data;
   1028 	}
   1029 	while (process_queue(itrm))
   1030 		;
   1031 }