1 /* Support for keyboard interface */
17 #define HPUX_PIPE (len > PIPE_BUF || errno != EAGAIN)
24 #include "config/options.h"
25 #include "intl/gettext/libintl.h"
26 #include "main/select.h"
27 #include "main/timer.h"
28 #include "osdep/ascii.h"
29 #include "osdep/osdep.h"
30 #include "terminal/hardio.h"
31 #include "terminal/itrm.h"
32 #include "terminal/kbd.h"
33 #include "terminal/mouse.h"
34 #include "terminal/terminal.h"
35 #include "util/error.h"
36 #include "util/memory.h"
37 #include "util/string.h"
38 #include "util/time.h"
40 /* TODO: move stuff from here to itrm.{c,h} and mouse.{c,h} */
42 struct itrm
*ditrm
= NULL
;
44 static void free_itrm(struct itrm
*);
45 static void in_kbd(struct itrm
*);
46 static void in_sock(struct itrm
*);
47 static int process_queue(struct itrm
*);
48 static void handle_itrm_stdin(struct itrm
*);
49 static void unhandle_itrm_stdin(struct itrm
*);
52 /* This hack makes GCC put enum term_event_special_key in the debug
53 * information even though it is not otherwise used. The const
54 * prevents an unused-variable warning. */
55 static const enum term_event_special_key dummy_term_event_special_key
;
62 return ditrm
&& ditrm
->blocked
;
69 if (ditrm
) free_itrm(ditrm
);
73 /* A select_handler_T write_func for itrm->out.sock. This is called
74 * when there is data in itrm->out.queue and it is possible to write
75 * it to itrm->out.sock. When itrm->out.queue becomes empty, this
76 * handler is temporarily removed. */
78 itrm_queue_write(struct itrm
*itrm
)
81 int qlen
= int_min(itrm
->out
.queue
.len
, 128);
83 assertm(qlen
, "event queue empty");
84 if_assert_failed
return;
86 written
= safe_write(itrm
->out
.sock
, itrm
->out
.queue
.data
, qlen
);
88 if (written
< 0) free_itrm(itrm
); /* write error */
92 itrm
->out
.queue
.len
-= written
;
94 if (itrm
->out
.queue
.len
== 0) {
95 set_handlers(itrm
->out
.sock
,
96 get_handler(itrm
->out
.sock
, SELECT_HANDLER_READ
),
98 get_handler(itrm
->out
.sock
, SELECT_HANDLER_ERROR
),
99 get_handler(itrm
->out
.sock
, SELECT_HANDLER_DATA
));
101 assert(itrm
->out
.queue
.len
> 0);
102 memmove(itrm
->out
.queue
.data
, itrm
->out
.queue
.data
+ written
, itrm
->out
.queue
.len
);
108 itrm_queue_event(struct itrm
*itrm
, unsigned char *data
, int len
)
114 if (!itrm
->out
.queue
.len
&& can_write(itrm
->out
.sock
)) {
115 w
= safe_write(itrm
->out
.sock
, data
, len
);
116 if (w
<= 0 && HPUX_PIPE
) {
117 register_bottom_half(free_itrm
, itrm
);
124 unsigned char *c
= mem_realloc(itrm
->out
.queue
.data
,
125 itrm
->out
.queue
.len
+ left
);
132 itrm
->out
.queue
.data
= c
;
133 memcpy(itrm
->out
.queue
.data
+ itrm
->out
.queue
.len
, data
+ w
, left
);
134 itrm
->out
.queue
.len
+= left
;
135 set_handlers(itrm
->out
.sock
,
136 get_handler(itrm
->out
.sock
, SELECT_HANDLER_READ
),
137 (select_handler_T
) itrm_queue_write
,
138 (select_handler_T
) free_itrm
, itrm
);
146 struct interlink_event ev
;
149 set_kbd_interlink_event(&ev
, KBD_CTRL_C
, KBD_MOD_NONE
);
150 itrm_queue_event(ditrm
, (unsigned char *) &ev
, sizeof(ev
));
153 #define write_sequence(fd, seq) \
154 hard_write(fd, seq, sizeof(seq) - 1)
157 #define INIT_TERMINAL_SEQ "\033)0\0337" /* Special Character and Line Drawing Set, Save Cursor */
158 #define INIT_ALT_SCREEN_SEQ "\033[?47h" /* Use Alternate Screen Buffer */
161 send_init_sequence(int h
, int altscreen
)
163 write_sequence(h
, INIT_TERMINAL_SEQ
);
165 /* If alternate screen is supported switch to it. */
167 write_sequence(h
, INIT_ALT_SCREEN_SEQ
);
170 send_mouse_init_sequence(h
);
174 #define DONE_CLS_SEQ "\033[2J" /* Erase in Display, Clear All */
175 #define DONE_TERMINAL_SEQ "\0338\r \b" /* Restore Cursor (DECRC) + ??? */
176 #define DONE_ALT_SCREEN_SEQ "\033[?47l" /* Use Normal Screen Buffer */
179 send_done_sequence(int h
, int altscreen
)
181 write_sequence(h
, DONE_CLS_SEQ
);
184 send_mouse_done_sequence(h
);
187 /* Switch from alternate screen. */
189 write_sequence(h
, DONE_ALT_SCREEN_SEQ
);
192 write_sequence(h
, DONE_TERMINAL_SEQ
);
196 #undef write_sequence
199 resize_terminal(void)
201 struct interlink_event ev
;
204 get_terminal_size(ditrm
->out
.std
, &width
, &height
);
205 set_resize_interlink_event(&ev
, width
, height
);
206 itrm_queue_event(ditrm
, (char *) &ev
, sizeof(ev
));
210 get_terminal_name(unsigned char name
[MAX_TERM_LEN
])
212 unsigned char *term
= getenv("TERM");
215 memset(name
, 0, MAX_TERM_LEN
);
219 for (i
= 0; term
[i
] != 0 && i
< MAX_TERM_LEN
- 1; i
++)
220 name
[i
] = isident(term
[i
]) ? term
[i
] : '-';
225 setraw(int fd
, struct termios
*p
)
229 memset(&t
, 0, sizeof(t
));
230 if (tcgetattr(fd
, &t
)) return -1;
232 if (p
) copy_struct(p
, &t
);
234 elinks_cfmakeraw(&t
);
240 if (tcsetattr(fd
, TCSANOW
, &t
)) return -1;
245 /* Construct the struct itrm of this process, make ditrm point to it,
246 * set up select() handlers, and send the initial interlink packet.
248 * The first five parameters are file descriptors that this function
249 * saves in submembers of struct itrm, and for which this function may
250 * set select() handlers. Please see the definitions of struct
251 * itrm_in and struct itrm_out for further explanations.
253 * param member file if process is master file if process is slave
254 * ------ ------ ------------------------- ------------------------
255 * std_in in.std read tty device (or pipe) read tty device (or pipe)
256 * std_out out.std write tty device (or pipe) write tty device (or pipe)
257 * sock_in in.sock ==std_out (masterhood flag) read socket from master
258 * sock_out out.sock write pipe to same process write socket to master
259 * ctl_in in.ctl control tty device control tty device
261 * The remaining three parameters control the initial interlink packet.
263 * init_string = A string to be passed to the master process. Need
264 * not be null-terminated. If remote==0, this is a URI.
265 * Otherwise, this is a remote command.
266 * init_len = The length of init_string, in bytes.
267 * remote = 0 if asking the master to start a new session
268 * and display it via this process. Otherwise,
269 * enum remote_session_flags. */
271 handle_trm(int std_in
, int std_out
, int sock_in
, int sock_out
, int ctl_in
,
272 void *init_string
, int init_len
, int remote
)
275 struct terminal_info info
;
276 struct interlink_event_size
*size
= &info
.event
.info
.size
;
279 memset(&info
, 0, sizeof(info
));
281 get_terminal_size(ctl_in
, &size
->width
, &size
->height
);
282 info
.event
.ev
= EVENT_INIT
;
283 info
.system_env
= get_system_env();
284 info
.length
= init_len
;
287 info
.session_info
= remote
;
288 info
.magic
= INTERLINK_REMOTE_MAGIC
;
290 info
.session_info
= get_cmd_opt_int("base-session");
291 info
.magic
= INTERLINK_NORMAL_MAGIC
;
294 itrm
= mem_calloc(1, sizeof(*itrm
));
297 itrm
->in
.queue
.data
= mem_calloc(1, ITRM_IN_QUEUE_SIZE
);
298 if (!itrm
->in
.queue
.data
) {
304 itrm
->in
.std
= std_in
;
305 itrm
->out
.std
= std_out
;
306 itrm
->in
.sock
= sock_in
;
307 itrm
->out
.sock
= sock_out
;
308 itrm
->in
.ctl
= ctl_in
;
309 itrm
->timer
= TIMER_ID_UNDEF
;
310 itrm
->remote
= !!remote
;
312 /* FIXME: Combination altscreen + xwin does not work as it should,
313 * mouse clicks are reportedly partially ignored. */
314 if (info
.system_env
& (ENV_SCREEN
| ENV_XWIN
))
318 if (ctl_in
>= 0) setraw(ctl_in
, &itrm
->t
);
319 send_init_sequence(std_out
, itrm
->altscreen
);
320 handle_terminal_resize(ctl_in
, resize_terminal
);
326 handle_itrm_stdin(itrm
);
328 if (sock_in
!= std_out
)
329 set_handlers(sock_in
, (select_handler_T
) in_sock
,
330 NULL
, (select_handler_T
) free_itrm
, itrm
);
332 get_terminal_name(info
.name
);
336 memcpy(info
.cwd
, ts
, int_min(strlen(ts
), MAX_CWD_LEN
));
340 itrm_queue_event(itrm
, (char *) &info
, TERMINAL_INFO_SIZE
);
341 itrm_queue_event(itrm
, (char *) init_string
, init_len
);
345 /* A select_handler_T read_func and error_func for the pipe (long) h.
346 * This is called when the subprocess started on the terminal of this
347 * ELinks process exits. ELinks then resumes using the terminal. */
349 unblock_itrm_x(void *h
)
361 if (!ditrm
) return -1;
363 if (ditrm
->in
.ctl
>= 0 && setraw(ditrm
->in
.ctl
, NULL
)) return -1;
365 send_init_sequence(ditrm
->out
.std
, ditrm
->altscreen
);
367 handle_itrm_stdin(ditrm
);
368 resume_mouse(ditrm
->mouse_h
);
370 handle_terminal_resize(ditrm
->in
.ctl
, resize_terminal
);
384 kill_timer(&ditrm
->timer
);
385 ditrm
->in
.queue
.len
= 0;
386 unhandle_terminal_resize(ditrm
->in
.ctl
);
387 send_done_sequence(ditrm
->out
.std
, ditrm
->altscreen
);
388 tcsetattr(ditrm
->in
.ctl
, TCSANOW
, &ditrm
->t
);
389 unhandle_itrm_stdin(ditrm
);
390 suspend_mouse(ditrm
->mouse_h
);
395 free_itrm(struct itrm
*itrm
)
400 if (itrm
->orig_title
&& *itrm
->orig_title
) {
401 set_window_title(itrm
->orig_title
);
403 } else if (itrm
->touched_title
) {
404 /* Set the window title to the value of $TERM if X11
405 * wasn't compiled in. Should hopefully make at least
406 * half the users happy. (debian bug #312955) */
407 unsigned char title
[MAX_TERM_LEN
];
409 get_terminal_name(title
);
411 set_window_title(title
);
415 unhandle_terminal_resize(itrm
->in
.ctl
);
419 send_done_sequence(itrm
->out
.std
, itrm
->altscreen
);
420 tcsetattr(itrm
->in
.ctl
, TCSANOW
, &itrm
->t
);
423 mem_free_set(&itrm
->orig_title
, NULL
);
425 clear_handlers(itrm
->in
.std
);
426 clear_handlers(itrm
->in
.sock
);
427 clear_handlers(itrm
->out
.std
);
428 clear_handlers(itrm
->out
.sock
);
430 kill_timer(&itrm
->timer
);
432 if (itrm
== ditrm
) ditrm
= NULL
;
433 mem_free_if(itrm
->out
.queue
.data
);
434 mem_free_if(itrm
->in
.queue
.data
);
438 /* Resize terminal to dimensions specified by @text string.
439 * @text should look like "width,height,old-width,old-height" where width and
440 * height are integers. */
442 resize_terminal_from_str(unsigned char *text
)
444 enum { NEW_WIDTH
= 0, NEW_HEIGHT
, OLD_WIDTH
, OLD_HEIGHT
, NUMBERS
} i
;
445 int numbers
[NUMBERS
];
447 assert(text
&& *text
);
448 if_assert_failed
return;
450 for (i
= 0; i
< NUMBERS
; i
++) {
451 unsigned char *p
= strchr(text
, ',');
456 } else if (i
< OLD_HEIGHT
) {
460 numbers
[i
] = atoi(text
);
465 resize_window(numbers
[NEW_WIDTH
], numbers
[NEW_HEIGHT
],
466 numbers
[OLD_WIDTH
], numbers
[OLD_HEIGHT
]);
471 dispatch_special(unsigned char *text
)
479 if (!ditrm
->orig_title
)
480 ditrm
->orig_title
= get_window_title();
481 ditrm
->touched_title
= 1;
483 set_window_title(text
+ 1);
486 if (ditrm
&& ditrm
->remote
)
489 resize_terminal_from_str(text
+ 1);
495 safe_hard_write(int fd
, unsigned char *buf
, int len
)
497 if (is_blocked()) return;
500 hard_write(fd
, buf
, len
);
504 /* A select_handler_T read_func for itrm->in.sock. A slave process
505 * calls this when the master sends it data to be displayed. The
506 * master process never calls this. */
508 in_sock(struct itrm
*itrm
)
511 struct string
delete;
514 ssize_t bytes_read
, i
, p
;
515 unsigned char buf
[ITRM_OUT_QUEUE_SIZE
];
517 bytes_read
= safe_read(itrm
->in
.sock
, buf
, ITRM_OUT_QUEUE_SIZE
);
518 if (bytes_read
<= 0) goto free_and_return
;
521 for (i
= 0; i
< bytes_read
; i
++)
525 safe_hard_write(itrm
->out
.std
, buf
, bytes_read
);
529 if (i
) safe_hard_write(itrm
->out
.std
, buf
, i
);
532 assert(ITRM_OUT_QUEUE_SIZE
- i
> 0);
533 memmove(buf
, buf
+ i
, ITRM_OUT_QUEUE_SIZE
- i
);
540 if (p < bytes_read) \
542 else if ((hard_read(itrm->in.sock, &cc, 1)) <= 0) \
543 goto free_and_return; \
549 if (!init_string(&path
)) goto free_and_return
;
554 add_char_to_string(&path
, ch
);
557 if (!init_string(&delete)) {
559 goto free_and_return
;
565 add_char_to_string(&delete, ch
);
571 dispatch_special(delete.source
);
575 unsigned char *param
;
576 int path_len
, del_len
, param_len
;
578 if (is_blocked() && fg
) {
579 if (*delete.source
) unlink(delete.source
);
583 path_len
= path
.length
;
584 del_len
= delete.length
;
585 param_len
= path_len
+ del_len
+ 3;
587 param
= mem_alloc(param_len
);
588 if (!param
) goto nasty_thing
;
591 memcpy(param
+ 1, path
.source
, path_len
+ 1);
592 memcpy(param
+ 1 + path_len
+ 1, delete.source
, del_len
+ 1);
594 if (fg
== 1) block_itrm(itrm
->in
.ctl
);
596 blockh
= start_thread((void (*)(void *, int)) exec_thread
,
602 unblock_itrm(itrm
->in
.ctl
);
608 set_handlers(blockh
, (select_handler_T
) unblock_itrm_x
,
609 NULL
, (select_handler_T
) unblock_itrm_x
,
610 (void *) (long) blockh
);
613 set_handlers(blockh
, close_handle
, NULL
, close_handle
,
614 (void *) (long) blockh
);
620 done_string(&delete);
621 assert(ITRM_OUT_QUEUE_SIZE
- p
> 0);
622 memmove(buf
, buf
+ p
, ITRM_OUT_QUEUE_SIZE
- p
);
632 /* Returns the length of the escape sequence */
634 get_esc_code(unsigned char *str
, int len
, unsigned char *code
, int *num
)
641 for (pos
= 2; pos
< len
; pos
++) {
642 if (!isdigit(str
[pos
]) || pos
> 7) {
647 *num
= *num
* 10 + str
[pos
] - '0';
653 /* Define it to dump queue content in a readable form,
654 * it may help to determine terminal sequences, and see what goes on. --Zas */
655 /* #define DEBUG_ITRM_QUEUE */
657 #ifdef DEBUG_ITRM_QUEUE
659 #include <ctype.h> /* isprint() isspace() */
662 /* Returns length of the escape sequence or -1 if the caller needs to set up
663 * the ESC delay timer. */
665 decode_terminal_escape_sequence(struct itrm
*itrm
, struct interlink_event
*ev
)
667 struct term_event_keyboard kbd
= { KBD_UNDEF
, KBD_MOD_NONE
};
672 if (itrm
->in
.queue
.len
< 3) return -1;
674 if (itrm
->in
.queue
.data
[2] == '[') {
675 /* The terminfo entry for linux has "kf1=\E[[A", etc.
676 * These are not control sequences compliant with
677 * clause 5.4 of ECMA-48. */
678 if (itrm
->in
.queue
.len
>= 4
679 && itrm
->in
.queue
.data
[3] >= 'A'
680 && itrm
->in
.queue
.data
[3] <= 'L') {
681 kbd
.key
= number_to_kbd_fkey(itrm
->in
.queue
.data
[3] - 'A' + 1);
682 set_kbd_interlink_event(ev
, kbd
.key
, kbd
.modifier
);
689 el
= get_esc_code(itrm
->in
.queue
.data
, itrm
->in
.queue
.len
, &c
, &v
);
690 #ifdef DEBUG_ITRM_QUEUE
691 fprintf(stderr
, "esc code: %c v=%d c=%c el=%d\n", itrm
->in
.queue
.data
[1], v
, c
, el
);
695 switch (c
) { /* ECMA-48 Terminfo $TERM */
696 case 0: return -1; /* ------- -------- ----- */
697 case 'A': kbd
.key
= KBD_UP
; break; /* CUU kcuu1 vt200 */
698 case 'B': kbd
.key
= KBD_DOWN
; break; /* CUD kcud1 vt200 */
699 case 'C': kbd
.key
= KBD_RIGHT
; break; /* CUF kcuf1 vt200 */
700 case 'D': kbd
.key
= KBD_LEFT
; break; /* CUB kcub1 vt200 */
701 case 'F': /* (CPL) kend cons25 */
702 case 'e': kbd
.key
= KBD_END
; break; /* (VPR) kend */
703 case 'H': kbd
.key
= KBD_HOME
; break; /* CUP khome cons25 */
704 case 'I': kbd
.key
= KBD_PAGE_UP
; break; /* (CHT) kpp cons25 */
705 case 'G': kbd
.key
= KBD_PAGE_DOWN
; break; /* (CHA) knp cons25 */
706 /* Free BSD (TERM=cons25 etc.) */
707 /* case 'M': kbd.key = KBD_F1; break;*/ /* (DL) kf1 cons25 */
708 case 'N': kbd
.key
= KBD_F2
; break; /* (EF) kf2 cons25 */
709 case 'O': kbd
.key
= KBD_F3
; break; /* (EA) kf3 cons25 */
710 case 'P': kbd
.key
= KBD_F4
; break; /* (DCH) kf4 cons25 */
711 case 'Q': kbd
.key
= KBD_F5
; break; /* (SEE) kf5 cons25 */
712 /* case 'R': kbd.key = KBD_F6; break;*/ /* (CPR) kf6 cons25 */
713 case 'S': kbd
.key
= KBD_F7
; break; /* (SU) kf7 cons25 */
714 case 'T': kbd
.key
= KBD_F8
; break; /* (SD) kf8 cons25 */
715 case 'U': kbd
.key
= KBD_F9
; break; /* (NP) kf9 cons25 */
716 case 'V': kbd
.key
= KBD_F10
; break; /* (PP) kf10 cons25 */
717 case 'W': kbd
.key
= KBD_F11
; break; /* (CTC) kf11 cons25 */
718 case 'X': kbd
.key
= KBD_F12
; break; /* (ECH) kf12 cons25 */
720 case 'z': switch (v
) { /* private */
721 case 247: kbd
.key
= KBD_INS
; break; /* kich1 */
722 case 214: kbd
.key
= KBD_HOME
; break; /* khome sun */
723 case 220: kbd
.key
= KBD_END
; break; /* kend sun */
724 case 216: kbd
.key
= KBD_PAGE_UP
; break; /* kpp sun */
725 case 222: kbd
.key
= KBD_PAGE_DOWN
; break; /* knp sun */
726 case 249: kbd
.key
= KBD_DEL
; break; /* kdch1 */
729 case '~': switch (v
) { /* private */
730 case 1: kbd
.key
= KBD_HOME
; break; /* khome linux */
731 case 2: kbd
.key
= KBD_INS
; break; /* kich1 linux */
732 case 3: kbd
.key
= KBD_DEL
; break; /* kdch1 linux */
733 case 4: kbd
.key
= KBD_END
; break; /* kend linux */
734 case 5: kbd
.key
= KBD_PAGE_UP
; break; /* kpp linux */
735 case 6: kbd
.key
= KBD_PAGE_DOWN
; break; /* knp linux */
736 case 7: kbd
.key
= KBD_HOME
; break; /* khome rxvt */
737 case 8: kbd
.key
= KBD_END
; break; /* kend rxvt */
739 case 11: kbd
.key
= KBD_F1
; break; /* kf1 rxvt */
740 case 12: kbd
.key
= KBD_F2
; break; /* kf2 rxvt */
741 case 13: kbd
.key
= KBD_F3
; break; /* kf3 rxvt */
742 case 14: kbd
.key
= KBD_F4
; break; /* kf4 rxvt */
743 case 15: kbd
.key
= KBD_F5
; break; /* kf5 rxvt */
745 case 17: kbd
.key
= KBD_F6
; break; /* kf6 vt200 */
746 case 18: kbd
.key
= KBD_F7
; break; /* kf7 vt200 */
747 case 19: kbd
.key
= KBD_F8
; break; /* kf8 vt200 */
748 case 20: kbd
.key
= KBD_F9
; break; /* kf9 vt200 */
749 case 21: kbd
.key
= KBD_F10
; break; /* kf10 vt200 */
751 case 23: kbd
.key
= KBD_F11
; break; /* kf11 vt200 */
752 case 24: kbd
.key
= KBD_F12
; break; /* kf12 vt200 */
754 /* Give preference to F11 and F12 over shifted F1 and F2. */
756 case 23: kbd.key = KBD_F1; kbd.modifier = KBD_MOD_SHIFT; break;
757 case 24: kbd.key = KBD_F2; kbd.modifier = KBD_MOD_SHIFT; break;
760 case 25: kbd
.key
= KBD_F3
; kbd
.modifier
= KBD_MOD_SHIFT
; break;
761 case 26: kbd
.key
= KBD_F4
; kbd
.modifier
= KBD_MOD_SHIFT
; break;
763 case 28: kbd
.key
= KBD_F5
; kbd
.modifier
= KBD_MOD_SHIFT
; break;
764 case 29: kbd
.key
= KBD_F6
; kbd
.modifier
= KBD_MOD_SHIFT
; break;
766 case 31: kbd
.key
= KBD_F7
; kbd
.modifier
= KBD_MOD_SHIFT
; break;
767 case 32: kbd
.key
= KBD_F8
; kbd
.modifier
= KBD_MOD_SHIFT
; break;
768 case 33: kbd
.key
= KBD_F9
; kbd
.modifier
= KBD_MOD_SHIFT
; break;
769 case 34: kbd
.key
= KBD_F10
; kbd
.modifier
= KBD_MOD_SHIFT
; break;
773 case 'R': resize_terminal(); break; /* CPR u6 */
774 case 'M': /* (DL) kmous xterm */
776 el
= decode_terminal_mouse_escape_sequence(itrm
, ev
, el
, v
);
777 #endif /* CONFIG_MOUSE */
781 /* KBD_UNDEF here means it was unrecognized or a mouse event. */
782 if (kbd
.key
!= KBD_UNDEF
)
783 set_kbd_interlink_event(ev
, kbd
.key
, kbd
.modifier
);
788 /* Decode an escape sequence that begins with SS3 (SINGLE SHIFT 3).
789 * These are used for application cursor keys and the application keypad.
791 * -1 if the escape sequence is not yet complete; the caller sets a timer.
792 * 0 if the escape sequence should be parsed by some other function.
793 * The length of the escape sequence otherwise.
794 * Returning >0 does not imply this function has altered *ev. */
796 decode_terminal_application_key(struct itrm
*itrm
, struct interlink_event
*ev
)
799 struct interlink_event_keyboard kbd
= { KBD_UNDEF
, KBD_MOD_NONE
};
801 assert(itrm
->in
.queue
.len
>= 2);
802 assert(itrm
->in
.queue
.data
[0] == ASCII_ESC
);
803 assert(itrm
->in
.queue
.data
[1] == 0x4F); /* == 'O', incidentally */
804 if_assert_failed
return 0;
806 if (itrm
->in
.queue
.len
< 3) return -1;
807 /* According to ECMA-35 section 8.4, a single (possibly multibyte)
808 * character follows the SS3. We now assume the code identifies
809 * GL as the single-shift area and the designated set has 94
811 c
= itrm
->in
.queue
.data
[2];
812 if (c
< 0x21 || c
> 0x7E) return 0;
814 switch (c
) { /* Terminfo $TERM */
815 case ' ': kbd
.key
= ' '; break; /* xterm */
816 case 'A': kbd
.key
= KBD_UP
; break; /* kcuu1 vt100 */
817 case 'B': kbd
.key
= KBD_DOWN
; break; /* kcud1 vt100 */
818 case 'C': kbd
.key
= KBD_RIGHT
; break; /* kcuf1 vt100 */
819 case 'D': kbd
.key
= KBD_LEFT
; break; /* kcub1 vt100 */
820 case 'F': kbd
.key
= KBD_END
; break; /* kend xterm */
821 case 'H': kbd
.key
= KBD_HOME
; break; /* khome xterm */
822 case 'I': kbd
.key
= KBD_TAB
; break; /* xterm */
823 case 'M': kbd
.key
= KBD_ENTER
; break; /* kent vt100 */
824 /* FIXME: xterm generates ESC O 2 P for Shift-PF1 */
825 case 'P': kbd
.key
= KBD_F1
; break; /* kf1 vt100 */
826 case 'Q': kbd
.key
= KBD_F2
; break; /* kf2 vt100 */
827 case 'R': kbd
.key
= KBD_F3
; break; /* kf3 vt100 */
828 case 'S': kbd
.key
= KBD_F4
; break; /* kf4 vt100 */
829 case 'X': kbd
.key
= '='; break; /* xterm */
831 case 'j': case 'k': case 'l': case 'm': /* *+,- xterm */
832 case 'n': case 'o': case 'p': case 'q': /* ./01 xterm */
833 case 'r': case 's': case 't': case 'u': /* 2345 xterm */
834 case 'v': case 'w': case 'x': case 'y': /* 6789 xterm */
835 kbd
.key
= c
- 'p' + '0'; break;
837 if (kbd
.key
!= KBD_UNDEF
)
838 copy_struct(&ev
->info
.keyboard
, &kbd
);
840 return 3; /* even if we didn't recognize it */
845 set_kbd_event(struct interlink_event
*ev
, int key
, int modifier
)
851 #if defined(HAVE_SYS_CONSIO_H) || defined(HAVE_MACHINE_CONSOLE_H) /* BSD */
876 modifier
|= KBD_MOD_CTRL
;
880 set_kbd_interlink_event(ev
, key
, modifier
);
884 kbd_timeout(struct itrm
*itrm
)
886 struct interlink_event ev
;
889 itrm
->timer
= TIMER_ID_UNDEF
;
891 assertm(itrm
->in
.queue
.len
, "timeout on empty queue");
892 assert(!itrm
->blocked
); /* block_itrm should have killed itrm->timer */
893 if_assert_failed
return;
895 if (can_read(itrm
->in
.std
)) {
900 if (itrm
->in
.queue
.len
>= 2 && itrm
->in
.queue
.data
[0] == ASCII_ESC
) {
901 /* This is used for ESC [ and ESC O. */
902 set_kbd_event(&ev
, itrm
->in
.queue
.data
[1], KBD_MOD_ALT
);
905 set_kbd_event(&ev
, itrm
->in
.queue
.data
[0], KBD_MOD_NONE
);
908 itrm_queue_event(itrm
, (char *) &ev
, sizeof(ev
));
910 itrm
->in
.queue
.len
-= el
;
911 if (itrm
->in
.queue
.len
)
912 memmove(itrm
->in
.queue
.data
, itrm
->in
.queue
.data
+ el
, itrm
->in
.queue
.len
);
914 while (process_queue(itrm
));
917 /* Parse one event from itrm->in.queue and append to itrm->out.queue.
918 * Return the number of bytes removed from itrm->in.queue; at least 0.
919 * If this function leaves the queue not full, it also reenables reading
920 * from itrm->in.std. (Because it does not add to the queue, it never
921 * need disable reading.) On entry, the itrm must not be blocked. */
923 process_queue(struct itrm
*itrm
)
925 struct interlink_event ev
;
928 if (!itrm
->in
.queue
.len
) goto return_without_event
;
929 assert(!itrm
->blocked
);
930 if_assert_failed
return 0; /* unlike goto, don't enable reading */
932 set_kbd_interlink_event(&ev
, KBD_UNDEF
, KBD_MOD_NONE
);
934 #ifdef DEBUG_ITRM_QUEUE
938 /* Dump current queue in a readable form to stderr. */
939 for (i
= 0; i
< itrm
->in
.queue
.len
; i
++)
940 if (itrm
->in
.queue
.data
[i
] == ASCII_ESC
)
941 fprintf(stderr
, "ESC ");
942 else if (isprint(itrm
->in
.queue
.data
[i
]) && !isspace(itrm
->in
.queue
.data
[i
]))
943 fprintf(stderr
, "%c ", itrm
->in
.queue
.data
[i
]);
945 fprintf(stderr
, "0x%02x ", itrm
->in
.queue
.data
[i
]);
947 fprintf(stderr
, "\n");
950 #endif /* DEBUG_ITRM_QUEUE */
952 /* el == -1 means itrm->in.queue appears to be the beginning of an
953 * escape sequence but it is not yet complete. Set a timer;
954 * if it times out, then assume it wasn't an escape sequence
956 * el == 0 means this function has not yet figured out what the data
957 * in itrm->in.queue is, but some possibilities remain.
958 * One of them will be chosen before returning.
959 * el > 0 means some bytes were successfully parsed from the beginning
960 * of itrm->in.queue and should now be removed from there.
961 * However, this does not always imply an event will be queued.
964 /* ELinks should also recognize U+009B CONTROL SEQUENCE INTRODUCER
965 * as meaning the same as ESC 0x5B, and U+008F SINGLE SHIFT THREE as
966 * meaning the same as ESC 0x4F, but those cannot yet be implemented
967 * because of bug 777: the UTF-8 decoder is run too late. */
968 if (itrm
->in
.queue
.data
[0] == ASCII_ESC
) {
969 if (itrm
->in
.queue
.len
< 2) {
971 } else if (itrm
->in
.queue
.data
[1] == 0x5B /* CSI */) {
972 el
= decode_terminal_escape_sequence(itrm
, &ev
);
973 } else if (itrm
->in
.queue
.data
[1] == 0x4F /* SS3 */) {
974 el
= decode_terminal_application_key(itrm
, &ev
);
975 } else if (itrm
->in
.queue
.data
[1] == ASCII_ESC
) {
976 /* ESC ESC can be either Alt-Esc or the
977 * beginning of e.g. ESC ESC 0x5B 0x41,
978 * which we should parse as Esc Up. */
979 if (itrm
->in
.queue
.len
< 3) {
980 /* Need more data to figure it out. */
982 } else if (itrm
->in
.queue
.data
[2] == 0x5B
983 || itrm
->in
.queue
.data
[2] == 0x4F) {
984 /* The first ESC appears to be followed
985 * by an escape sequence. Treat it as
986 * a standalone Esc. */
988 set_kbd_event(&ev
, itrm
->in
.queue
.data
[0],
991 /* The second ESC of ESC ESC is not the
992 * beginning of any known escape sequence.
993 * This must be Alt-Esc, then. */
995 set_kbd_event(&ev
, itrm
->in
.queue
.data
[1],
998 } else { /* ESC followed by something else */
1000 set_kbd_event(&ev
, itrm
->in
.queue
.data
[1],
1004 } else if (itrm
->in
.queue
.data
[0] == 0) {
1005 static const struct term_event_keyboard os2xtd
[256] = {
1006 #include "terminal/key.inc"
1009 if (itrm
->in
.queue
.len
< 2)
1013 set_kbd_interlink_event(&ev
,
1014 os2xtd
[itrm
->in
.queue
.data
[1]].key
,
1015 os2xtd
[itrm
->in
.queue
.data
[1]].modifier
);
1021 set_kbd_event(&ev
, itrm
->in
.queue
.data
[0], KBD_MOD_NONE
);
1024 /* The call to decode_terminal_escape_sequence() might have changed the
1025 * keyboard event to a mouse event. */
1026 if (ev
.ev
== EVENT_MOUSE
|| ev
.info
.keyboard
.key
!= KBD_UNDEF
)
1027 itrm_queue_event(itrm
, (char *) &ev
, sizeof(ev
));
1029 return_without_event
:
1031 install_timer(&itrm
->timer
, ESC_TIMEOUT
, (void (*)(void *)) kbd_timeout
,
1035 assertm(itrm
->in
.queue
.len
>= el
, "event queue underflow");
1036 if_assert_failed
{ itrm
->in
.queue
.len
= el
; }
1038 itrm
->in
.queue
.len
-= el
;
1039 if (itrm
->in
.queue
.len
)
1040 memmove(itrm
->in
.queue
.data
, itrm
->in
.queue
.data
+ el
, itrm
->in
.queue
.len
);
1042 if (itrm
->in
.queue
.len
< ITRM_IN_QUEUE_SIZE
)
1043 handle_itrm_stdin(itrm
);
1050 /* A select_handler_T read_func for itrm->in.std. This is called when
1051 * characters typed by the user arrive from the terminal. */
1053 in_kbd(struct itrm
*itrm
)
1057 if (!can_read(itrm
->in
.std
)) return;
1059 kill_timer(&itrm
->timer
);
1061 if (itrm
->in
.queue
.len
>= ITRM_IN_QUEUE_SIZE
) {
1062 unhandle_itrm_stdin(itrm
);
1063 while (process_queue(itrm
));
1067 r
= safe_read(itrm
->in
.std
, itrm
->in
.queue
.data
+ itrm
->in
.queue
.len
,
1068 ITRM_IN_QUEUE_SIZE
- itrm
->in
.queue
.len
);
1074 itrm
->in
.queue
.len
+= r
;
1075 if (itrm
->in
.queue
.len
> ITRM_IN_QUEUE_SIZE
) {
1076 ERROR(gettext("Too many bytes read from the itrm!"));
1077 itrm
->in
.queue
.len
= ITRM_IN_QUEUE_SIZE
;
1080 while (process_queue(itrm
));
1083 /* Enable reading from itrm->in.std. ELinks will read any available
1084 * bytes from the tty into itrm->in.queue and then parse them.
1085 * Reading should be enabled whenever itrm->in.queue is not full and
1086 * itrm->blocked is 0. */
1088 handle_itrm_stdin(struct itrm
*itrm
)
1090 set_handlers(itrm
->in
.std
, (select_handler_T
) in_kbd
, NULL
,
1091 (select_handler_T
) free_itrm
, itrm
);
1094 /* Disable reading from itrm->in.std. Reading should be disabled
1095 * whenever itrm->in.queue is full (there is no room for the data)
1096 * or itrm->blocked is 1 (other processes may read the data). */
1098 unhandle_itrm_stdin(struct itrm
*itrm
)
1100 set_handlers(itrm
->in
.std
, (select_handler_T
) NULL
, NULL
,
1101 (select_handler_T
) free_itrm
, itrm
);