1 /* Keyboard support routines.
3 Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4 2005, 2006, 2007 Free Software Foundation, Inc.
6 Written by: 1994, 1995 Miguel de Icaza.
7 1994, 1995 Janne Kukonlehto.
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
26 * \brief Source: keyboard support routines
37 #include <sys/types.h>
40 #include "../../src/global.h"
42 #include "../../src/tty/tty.h"
43 #include "../../src/tty/mouse.h"
44 #include "../../src/tty/key.h"
45 #include "../../src/tty/win.h" /* xterm_flag */
47 #include "../../src/main.h"
48 #include "../../src/layout.h" /* winch_flag */
49 #include "../../src/cons.saver.h"
50 #include "../../src/strutil.h" /* str_casecmp */
53 #include "../../vfs/gc.h"
56 #ifdef HAVE_TEXTMODE_X11_SUPPORT
57 # include "../src/x11conn.h"
61 # if defined(__GLIBC__) && (__GLIBC__ < 2)
62 # include <linux/termios.h> /* TIOCLINUX */
63 # elif defined HAVE_TERMIOS_H
66 # include <sys/ioctl.h>
67 #endif /* __linux__ */
71 # include <sys/ioctl.h>
72 #endif /* __CYGWIN__ */
77 # include <sys/dcmd_chr.h>
80 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL))
81 #define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \
82 (t2.tv_usec-t1.tv_usec)/1000)
84 /* Linux console keyboard modifiers */
85 #define SHIFT_PRESSED (1 << 0)
86 #define ALTR_PRESSED (1 << 1)
87 #define CONTROL_PRESSED (1 << 2)
88 #define ALTL_PRESSED (1 << 3)
90 int mou_auto_repeat
= 100;
91 int double_click_speed
= 250;
93 /* timeout for old_esc_mode in usec */
94 static int keyboard_key_timeout
= 1000000; /* settable via env */
96 int use_8th_bit_as_meta
= 0;
98 typedef struct key_def
{
99 char ch
; /* Holds the matching char code */
100 int code
; /* The code returned, valid if child == NULL */
101 struct key_def
*next
;
102 struct key_def
*child
; /* sequence continuation */
103 int action
; /* optional action to be done. Now used only
104 to mark that we are just after the first
108 /* This holds all the key definitions */
109 static key_def
*keys
= NULL
;
112 static int disabled_channels
= 0; /* Disable channels checking */
113 static int xgetch_second (void);
114 static int get_modifier (void);
116 /* File descriptor monitoring add/remove routines */
117 typedef struct SelectList
{
121 struct SelectList
*next
;
125 typedef int (*ph_dv_f
) (void *, void *);
126 typedef int (*ph_ov_f
) (void *);
127 typedef int (*ph_pqc_f
) (unsigned short, PhCursorInfo_t
*);
129 ph_ov_f ph_input_group
;
130 ph_pqc_f ph_query_cursor
;
133 static SelectList
*select_list
= NULL
;
135 void add_select_channel (int fd
, select_fn callback
, void *info
)
139 new = g_new (SelectList
, 1);
141 new->callback
= callback
;
143 new->next
= select_list
;
147 void delete_select_channel (int fd
)
149 SelectList
*p
= select_list
;
150 SelectList
*p_prev
= NULL
;
158 p_prev
->next
= p_next
;
160 select_list
= p_next
;
172 inline static int add_selects (fd_set
*select_set
)
177 if (disabled_channels
)
180 for (p
= select_list
; p
; p
= p
->next
) {
181 FD_SET (p
->fd
, select_set
);
188 static void check_selects (fd_set
*select_set
)
193 if (disabled_channels
)
198 for (p
= select_list
; p
; p
= p
->next
)
199 if (FD_ISSET (p
->fd
, select_set
)) {
200 FD_CLR (p
->fd
, select_set
);
201 (*p
->callback
)(p
->fd
, p
->info
);
208 void channels_up (void)
210 if (!disabled_channels
)
211 fputs ("Error: channels_up called with disabled_channels = 0\n",
216 void channels_down (void)
222 is_abort_char (int c
)
224 return (c
== XCTRL('c') || c
== XCTRL('g') || c
== ESC_CHAR
||
229 * Common handler for standard movement keys in a text area. Provided
230 * functions are called with the "data" argument. backfn and forfn also
231 * get an argument indicating how many lines to scroll. Return MSG_HANDLED
232 * if the key was handled, MSG_NOT_HANDLED otherwise.
235 check_movement_keys (int key
, int page_size
, void *data
, move_fn backfn
,
236 move_fn forfn
, move_fn topfn
, move_fn bottomfn
)
251 (*backfn
) (data
, page_size
- 1);
256 (*forfn
) (data
, page_size
- 1);
260 case KEY_M_CTRL
| KEY_HOME
:
261 case KEY_M_CTRL
| KEY_PPAGE
:
268 case KEY_M_CTRL
| KEY_END
:
269 case KEY_M_CTRL
| KEY_NPAGE
:
272 (*bottomfn
) (data
, 0);
277 (*backfn
) (data
, page_size
- 1);
281 (*forfn
) (data
, page_size
- 1);
285 (*backfn
) (data
, page_size
/ 2);
289 (*forfn
) (data
, page_size
/ 2);
297 (*bottomfn
) (data
, 0);
301 return MSG_NOT_HANDLED
;
306 typedef const struct {
312 /* Broken terminfo and termcap databases on xterminals */
313 static key_define_t xterm_key_defines
[] = {
314 { KEY_F(1), ESC_STR
"OP", MCKEY_NOACTION
},
315 { KEY_F(2), ESC_STR
"OQ", MCKEY_NOACTION
},
316 { KEY_F(3), ESC_STR
"OR", MCKEY_NOACTION
},
317 { KEY_F(4), ESC_STR
"OS", MCKEY_NOACTION
},
318 { KEY_F(1), ESC_STR
"[11~", MCKEY_NOACTION
},
319 { KEY_F(2), ESC_STR
"[12~", MCKEY_NOACTION
},
320 { KEY_F(3), ESC_STR
"[13~", MCKEY_NOACTION
},
321 { KEY_F(4), ESC_STR
"[14~", MCKEY_NOACTION
},
322 { KEY_F(5), ESC_STR
"[15~", MCKEY_NOACTION
},
323 { KEY_F(6), ESC_STR
"[17~", MCKEY_NOACTION
},
324 { KEY_F(7), ESC_STR
"[18~", MCKEY_NOACTION
},
325 { KEY_F(8), ESC_STR
"[19~", MCKEY_NOACTION
},
326 { KEY_F(9), ESC_STR
"[20~", MCKEY_NOACTION
},
327 { KEY_F(10), ESC_STR
"[21~", MCKEY_NOACTION
},
329 /* old xterm Shift-arrows */
330 { KEY_M_SHIFT
| KEY_UP
, ESC_STR
"O2A", MCKEY_NOACTION
},
331 { KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"O2B", MCKEY_NOACTION
},
332 { KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"O2C", MCKEY_NOACTION
},
333 { KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"O2D", MCKEY_NOACTION
},
335 /* new xterm Shift-arrows */
336 { KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[1;2A", MCKEY_NOACTION
},
337 { KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[1;2B", MCKEY_NOACTION
},
338 { KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[1;2C", MCKEY_NOACTION
},
339 { KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[1;2D", MCKEY_NOACTION
},
341 /* more xterm keys with modifiers */
342 { KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[5;5~", MCKEY_NOACTION
},
343 { KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[6;5~", MCKEY_NOACTION
},
344 { KEY_M_CTRL
| KEY_IC
, ESC_STR
"[2;5~", MCKEY_NOACTION
},
345 { KEY_M_CTRL
| KEY_DC
, ESC_STR
"[3;5~", MCKEY_NOACTION
},
346 { KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[1;5H", MCKEY_NOACTION
},
347 { KEY_M_CTRL
| KEY_END
, ESC_STR
"[1;5F", MCKEY_NOACTION
},
348 { KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"[1;2H", MCKEY_NOACTION
},
349 { KEY_M_SHIFT
| KEY_END
, ESC_STR
"[1;2F", MCKEY_NOACTION
},
350 { KEY_M_CTRL
| KEY_UP
, ESC_STR
"[1;5A", MCKEY_NOACTION
},
351 { KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[1;5B", MCKEY_NOACTION
},
352 { KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[1;5C", MCKEY_NOACTION
},
353 { KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[1;5D", MCKEY_NOACTION
},
354 { KEY_M_SHIFT
| KEY_IC
, ESC_STR
"[2;2~", MCKEY_NOACTION
},
355 { KEY_M_SHIFT
| KEY_DC
, ESC_STR
"[3;2~", MCKEY_NOACTION
},
356 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[1;6A", MCKEY_NOACTION
},
357 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[1;6B", MCKEY_NOACTION
},
358 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[1;6C", MCKEY_NOACTION
},
359 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[1;6D", MCKEY_NOACTION
},
362 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[[1;6A", MCKEY_NOACTION
},
363 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[[1;6B", MCKEY_NOACTION
},
364 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[[1;6C", MCKEY_NOACTION
},
365 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[[1;6D", MCKEY_NOACTION
},
367 /* putty alt-arrow keys */
368 /* removed as source esc esc esc trouble */
370 { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
371 { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
372 { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
373 { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
374 { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
375 { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
376 { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
377 { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
379 { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
380 { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
381 { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
382 { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
384 { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
385 { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
386 { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
387 { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
389 /* xterm alt-arrow keys */
390 { KEY_M_ALT
| KEY_UP
, ESC_STR
"[1;3A", MCKEY_NOACTION
},
391 { KEY_M_ALT
| KEY_DOWN
, ESC_STR
"[1;3B", MCKEY_NOACTION
},
392 { KEY_M_ALT
| KEY_RIGHT
, ESC_STR
"[1;3C", MCKEY_NOACTION
},
393 { KEY_M_ALT
| KEY_LEFT
, ESC_STR
"[1;3D", MCKEY_NOACTION
},
394 { KEY_M_ALT
| KEY_PPAGE
, ESC_STR
"[5;3~", MCKEY_NOACTION
},
395 { KEY_M_ALT
| KEY_NPAGE
, ESC_STR
"[6;3~", MCKEY_NOACTION
},
396 { KEY_M_ALT
| KEY_HOME
, ESC_STR
"[1~", MCKEY_NOACTION
},
397 { KEY_M_ALT
| KEY_END
, ESC_STR
"[4~", MCKEY_NOACTION
},
398 { KEY_M_CTRL
| KEY_M_ALT
| KEY_UP
, ESC_STR
"[1;7A", MCKEY_NOACTION
},
399 { KEY_M_CTRL
| KEY_M_ALT
| KEY_DOWN
, ESC_STR
"[1;7B", MCKEY_NOACTION
},
400 { KEY_M_CTRL
| KEY_M_ALT
| KEY_RIGHT
, ESC_STR
"[1;7C", MCKEY_NOACTION
},
401 { KEY_M_CTRL
| KEY_M_ALT
| KEY_LEFT
, ESC_STR
"[1;7D", MCKEY_NOACTION
},
402 { KEY_M_CTRL
| KEY_M_ALT
| KEY_PPAGE
, ESC_STR
"[5;7~", MCKEY_NOACTION
},
403 { KEY_M_CTRL
| KEY_M_ALT
| KEY_NPAGE
, ESC_STR
"[6;7~", MCKEY_NOACTION
},
404 { KEY_M_CTRL
| KEY_M_ALT
| KEY_HOME
, ESC_STR
"OH", MCKEY_NOACTION
},
405 { KEY_M_CTRL
| KEY_M_ALT
| KEY_END
, ESC_STR
"OF", MCKEY_NOACTION
},
407 /* rxvt keys with modifiers */
408 { KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[a", MCKEY_NOACTION
},
409 { KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[b", MCKEY_NOACTION
},
410 { KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[c", MCKEY_NOACTION
},
411 { KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[d", MCKEY_NOACTION
},
412 { KEY_M_CTRL
| KEY_UP
, ESC_STR
"Oa", MCKEY_NOACTION
},
413 { KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"Ob", MCKEY_NOACTION
},
414 { KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"Oc", MCKEY_NOACTION
},
415 { KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"Od", MCKEY_NOACTION
},
416 { KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[5^", MCKEY_NOACTION
},
417 { KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[6^", MCKEY_NOACTION
},
418 { KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[7^", MCKEY_NOACTION
},
419 { KEY_M_CTRL
| KEY_END
, ESC_STR
"[8^", MCKEY_NOACTION
},
420 { KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"[7$", MCKEY_NOACTION
},
421 { KEY_M_SHIFT
| KEY_END
, ESC_STR
"[8$", MCKEY_NOACTION
},
422 { KEY_M_CTRL
| KEY_IC
, ESC_STR
"[2^", MCKEY_NOACTION
},
423 { KEY_M_CTRL
| KEY_DC
, ESC_STR
"[3^", MCKEY_NOACTION
},
424 { KEY_M_SHIFT
| KEY_DC
, ESC_STR
"[3$", MCKEY_NOACTION
},
426 /* konsole keys with modifiers */
427 { KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"O2H", MCKEY_NOACTION
},
428 { KEY_M_SHIFT
| KEY_END
, ESC_STR
"O2F", MCKEY_NOACTION
},
431 { KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[2A", MCKEY_NOACTION
},
432 { KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[2B", MCKEY_NOACTION
},
433 { KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[2C", MCKEY_NOACTION
},
434 { KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[2D", MCKEY_NOACTION
},
435 { KEY_M_CTRL
| KEY_UP
, ESC_STR
"[5A", MCKEY_NOACTION
},
436 { KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[5B", MCKEY_NOACTION
},
437 { KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[5C", MCKEY_NOACTION
},
438 { KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[5D", MCKEY_NOACTION
},
439 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[6A", MCKEY_NOACTION
},
440 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[6B", MCKEY_NOACTION
},
441 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[6C", MCKEY_NOACTION
},
442 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[6D", MCKEY_NOACTION
},
444 /* gnome-terminal - application mode */
445 { KEY_M_CTRL
| KEY_UP
, ESC_STR
"O5A", MCKEY_NOACTION
},
446 { KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"O5B", MCKEY_NOACTION
},
447 { KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"O5C", MCKEY_NOACTION
},
448 { KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"O5D", MCKEY_NOACTION
},
449 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"O6A", MCKEY_NOACTION
},
450 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"O6B", MCKEY_NOACTION
},
451 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"O6C", MCKEY_NOACTION
},
452 { KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"O6D", MCKEY_NOACTION
},
455 { KEY_M_SHIFT
| KEY_PPAGE
, ESC_STR
"[5;2~", MCKEY_NOACTION
},
456 { KEY_M_SHIFT
| KEY_NPAGE
, ESC_STR
"[6;2~", MCKEY_NOACTION
},
459 { KEY_M_SHIFT
| KEY_PPAGE
, ESC_STR
"[[5;53~", MCKEY_NOACTION
},
460 { KEY_M_SHIFT
| KEY_NPAGE
, ESC_STR
"[[6;53~", MCKEY_NOACTION
},
463 { KEY_IC
, ESC_STR
"Op", MCKEY_NOACTION
},
464 { KEY_DC
, ESC_STR
"On", MCKEY_NOACTION
},
465 { '/', ESC_STR
"Oo", MCKEY_NOACTION
},
466 { '\n', ESC_STR
"OM", MCKEY_NOACTION
},
468 { 0, 0, MCKEY_NOACTION
},
471 /* qansi-m terminals have a much more key combinatios,
472 which are undefined in termcap/terminfo */
473 static key_define_t qansi_key_defines
[] =
475 /* qansi-m terminal */
476 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[u", MCKEY_NOACTION
}, /* Ctrl-PgDown */
477 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[v", MCKEY_NOACTION
}, /* Ctrl-PgUp */
478 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[h", MCKEY_NOACTION
}, /* Ctrl-Home */
479 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[y", MCKEY_NOACTION
}, /* Ctrl-End */
480 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[`", MCKEY_NOACTION
}, /* Ctrl-Insert */
481 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[p", MCKEY_NOACTION
}, /* Ctrl-Delete */
482 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[d", MCKEY_NOACTION
}, /* Ctrl-Left */
483 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[c", MCKEY_NOACTION
}, /* Ctrl-Right */
484 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[b", MCKEY_NOACTION
}, /* Ctrl-Down */
485 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[a", MCKEY_NOACTION
}, /* Ctrl-Up */
486 {KEY_M_CTRL
| KEY_KP_ADD
, ESC_STR
"[s", MCKEY_NOACTION
}, /* Ctrl-Gr-Plus */
487 {KEY_M_CTRL
| KEY_KP_SUBTRACT
, ESC_STR
"[t", MCKEY_NOACTION
}, /* Ctrl-Gr-Minus */
488 {KEY_M_CTRL
| '\t', ESC_STR
"[z", MCKEY_NOACTION
}, /* Ctrl-Tab */
489 {KEY_M_SHIFT
| '\t', ESC_STR
"[Z", MCKEY_NOACTION
}, /* Shift-Tab */
490 {KEY_M_CTRL
| KEY_F(1), ESC_STR
"[1~", MCKEY_NOACTION
}, /* Ctrl-F1 */
491 {KEY_M_CTRL
| KEY_F(2), ESC_STR
"[2~", MCKEY_NOACTION
}, /* Ctrl-F2 */
492 {KEY_M_CTRL
| KEY_F(3), ESC_STR
"[3~", MCKEY_NOACTION
}, /* Ctrl-F3 */
493 {KEY_M_CTRL
| KEY_F(4), ESC_STR
"[4~", MCKEY_NOACTION
}, /* Ctrl-F4 */
494 {KEY_M_CTRL
| KEY_F(5), ESC_STR
"[5~", MCKEY_NOACTION
}, /* Ctrl-F5 */
495 {KEY_M_CTRL
| KEY_F(6), ESC_STR
"[6~", MCKEY_NOACTION
}, /* Ctrl-F6 */
496 {KEY_M_CTRL
| KEY_F(7), ESC_STR
"[7~", MCKEY_NOACTION
}, /* Ctrl-F7 */
497 {KEY_M_CTRL
| KEY_F(8), ESC_STR
"[8~", MCKEY_NOACTION
}, /* Ctrl-F8 */
498 {KEY_M_CTRL
| KEY_F(9), ESC_STR
"[9~", MCKEY_NOACTION
}, /* Ctrl-F9 */
499 {KEY_M_CTRL
| KEY_F(10), ESC_STR
"[10~", MCKEY_NOACTION
}, /* Ctrl-F10 */
500 {KEY_M_CTRL
| KEY_F(11), ESC_STR
"[11~", MCKEY_NOACTION
}, /* Ctrl-F11 */
501 {KEY_M_CTRL
| KEY_F(12), ESC_STR
"[12~", MCKEY_NOACTION
}, /* Ctrl-F12 */
502 {KEY_M_ALT
| KEY_F(1), ESC_STR
"[17~", MCKEY_NOACTION
}, /* Alt-F1 */
503 {KEY_M_ALT
| KEY_F(2), ESC_STR
"[18~", MCKEY_NOACTION
}, /* Alt-F2 */
504 {KEY_M_ALT
| KEY_F(3), ESC_STR
"[19~", MCKEY_NOACTION
}, /* Alt-F3 */
505 {KEY_M_ALT
| KEY_F(4), ESC_STR
"[20~", MCKEY_NOACTION
}, /* Alt-F4 */
506 {KEY_M_ALT
| KEY_F(5), ESC_STR
"[21~", MCKEY_NOACTION
}, /* Alt-F5 */
507 {KEY_M_ALT
| KEY_F(6), ESC_STR
"[22~", MCKEY_NOACTION
}, /* Alt-F6 */
508 {KEY_M_ALT
| KEY_F(7), ESC_STR
"[23~", MCKEY_NOACTION
}, /* Alt-F7 */
509 {KEY_M_ALT
| KEY_F(8), ESC_STR
"[24~", MCKEY_NOACTION
}, /* Alt-F8 */
510 {KEY_M_ALT
| KEY_F(9), ESC_STR
"[25~", MCKEY_NOACTION
}, /* Alt-F9 */
511 {KEY_M_ALT
| KEY_F(10), ESC_STR
"[26~", MCKEY_NOACTION
}, /* Alt-F10 */
512 {KEY_M_ALT
| KEY_F(11), ESC_STR
"[27~", MCKEY_NOACTION
}, /* Alt-F11 */
513 {KEY_M_ALT
| KEY_F(12), ESC_STR
"[28~", MCKEY_NOACTION
}, /* Alt-F12 */
514 {KEY_M_ALT
| 'a', ESC_STR
"Na", MCKEY_NOACTION
}, /* Alt-a */
515 {KEY_M_ALT
| 'b', ESC_STR
"Nb", MCKEY_NOACTION
}, /* Alt-b */
516 {KEY_M_ALT
| 'c', ESC_STR
"Nc", MCKEY_NOACTION
}, /* Alt-c */
517 {KEY_M_ALT
| 'd', ESC_STR
"Nd", MCKEY_NOACTION
}, /* Alt-d */
518 {KEY_M_ALT
| 'e', ESC_STR
"Ne", MCKEY_NOACTION
}, /* Alt-e */
519 {KEY_M_ALT
| 'f', ESC_STR
"Nf", MCKEY_NOACTION
}, /* Alt-f */
520 {KEY_M_ALT
| 'g', ESC_STR
"Ng", MCKEY_NOACTION
}, /* Alt-g */
521 {KEY_M_ALT
| 'i', ESC_STR
"Ni", MCKEY_NOACTION
}, /* Alt-i */
522 {KEY_M_ALT
| 'j', ESC_STR
"Nj", MCKEY_NOACTION
}, /* Alt-j */
523 {KEY_M_ALT
| 'k', ESC_STR
"Nk", MCKEY_NOACTION
}, /* Alt-k */
524 {KEY_M_ALT
| 'l', ESC_STR
"Nl", MCKEY_NOACTION
}, /* Alt-l */
525 {KEY_M_ALT
| 'm', ESC_STR
"Nm", MCKEY_NOACTION
}, /* Alt-m */
526 {KEY_M_ALT
| 'n', ESC_STR
"Nn", MCKEY_NOACTION
}, /* Alt-n */
527 {KEY_M_ALT
| 'o', ESC_STR
"No", MCKEY_NOACTION
}, /* Alt-o */
528 {KEY_M_ALT
| 'p', ESC_STR
"Np", MCKEY_NOACTION
}, /* Alt-p */
529 {KEY_M_ALT
| 'q', ESC_STR
"Nq", MCKEY_NOACTION
}, /* Alt-r */
530 {KEY_M_ALT
| 's', ESC_STR
"Ns", MCKEY_NOACTION
}, /* Alt-s */
531 {KEY_M_ALT
| 't', ESC_STR
"Nt", MCKEY_NOACTION
}, /* Alt-t */
532 {KEY_M_ALT
| 'u', ESC_STR
"Nu", MCKEY_NOACTION
}, /* Alt-u */
533 {KEY_M_ALT
| 'v', ESC_STR
"Nv", MCKEY_NOACTION
}, /* Alt-v */
534 {KEY_M_ALT
| 'w', ESC_STR
"Nw", MCKEY_NOACTION
}, /* Alt-w */
535 {KEY_M_ALT
| 'x', ESC_STR
"Nx", MCKEY_NOACTION
}, /* Alt-x */
536 {KEY_M_ALT
| 'y', ESC_STR
"Ny", MCKEY_NOACTION
}, /* Alt-y */
537 {KEY_M_ALT
| 'z', ESC_STR
"Nz", MCKEY_NOACTION
}, /* Alt-z */
538 {KEY_KP_SUBTRACT
, ESC_STR
"[S", MCKEY_NOACTION
}, /* Gr-Minus */
539 {KEY_KP_ADD
, ESC_STR
"[T", MCKEY_NOACTION
}, /* Gr-Plus */
540 {0, NULL
, MCKEY_NOACTION
},
543 static key_define_t mc_default_keys
[] = {
544 { ESC_CHAR
, ESC_STR
, MCKEY_ESCAPE
},
545 { ESC_CHAR
, ESC_STR ESC_STR
, MCKEY_NOACTION
},
546 { 0, NULL
, MCKEY_NOACTION
},
550 /* This table is a mapping between names and the constants we use
551 * We use this to allow users to define alternate definitions for
552 * certain keys that may be missing from the terminal database
554 key_code_name_t key_name_conv_tab
[] = {
555 /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
556 to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
557 { KEY_F(1), "f1", N_("Function key 1") },
558 { KEY_F(2), "f2", N_("Function key 2") },
559 { KEY_F(3), "f3", N_("Function key 3") },
560 { KEY_F(4), "f4", N_("Function key 4") },
561 { KEY_F(5), "f5", N_("Function key 5") },
562 { KEY_F(6), "f6", N_("Function key 6") },
563 { KEY_F(7), "f7", N_("Function key 7") },
564 { KEY_F(8), "f8", N_("Function key 8") },
565 { KEY_F(9), "f9", N_("Function key 9") },
566 { KEY_F(10), "f10", N_("Function key 10") },
567 { KEY_F(11), "f11", N_("Function key 11") },
568 { KEY_F(12), "f12", N_("Function key 12") },
569 { KEY_F(13), "f13", N_("Function key 13") },
570 { KEY_F(14), "f14", N_("Function key 14") },
571 { KEY_F(15), "f15", N_("Function key 15") },
572 { KEY_F(16), "f16", N_("Function key 16") },
573 { KEY_F(17), "f17", N_("Function key 17") },
574 { KEY_F(18), "f18", N_("Function key 18") },
575 { KEY_F(19), "f19", N_("Function key 19") },
576 { KEY_F(20), "f20", N_("Function key 20") },
577 { KEY_BACKSPACE
, "bs", N_("Backspace key") },
578 { KEY_END
, "end", N_("End key") },
579 { KEY_UP
, "up", N_("Up arrow key") },
580 { KEY_DOWN
, "down", N_("Down arrow key") },
581 { KEY_LEFT
, "left", N_("Left arrow key") },
582 { KEY_RIGHT
, "right", N_("Right arrow key") },
583 { KEY_HOME
, "home", N_("Home key") },
584 { KEY_NPAGE
, "pgdn", N_("Page Down key") },
585 { KEY_PPAGE
, "pgup", N_("Page Up key") },
586 { KEY_IC
, "ins", N_("Insert key") },
587 { KEY_DC
, "delete", N_("Delete key") },
588 { ALT('\t'), "complete", N_("Completion/M-tab") },
589 { KEY_KP_ADD
, "kpplus", N_("+ on keypad") },
590 { KEY_KP_SUBTRACT
,"kpminus", N_("- on keypad") },
591 { KEY_KP_MULTIPLY
,"kpasterix", N_("* on keypad") },
593 /* From here on, these won't be shown in Learn keys (no space) */
594 { KEY_LEFT
, "kpleft", N_("Left arrow keypad") },
595 { KEY_RIGHT
, "kpright", N_("Right arrow keypad") },
596 { KEY_UP
, "kpup", N_("Up arrow keypad") },
597 { KEY_DOWN
, "kpdown", N_("Down arrow keypad") },
598 { KEY_HOME
, "kphome", N_("Home on keypad") },
599 { KEY_END
, "kpend", N_("End on keypad") },
600 { KEY_NPAGE
, "kpnpage", N_("Page Down keypad") },
601 { KEY_PPAGE
, "kpppage", N_("Page Up keypad") },
602 { KEY_IC
, "kpinsert", N_("Insert on keypad") },
603 { KEY_DC
, "kpdelete", N_("Delete on keypad") },
604 { (int) '\n', "kpenter", N_("Enter on keypad") },
605 { (int) '\n', "enter", N_("Enter on keypad") },
606 { (int) '\t', "tab", N_("Tab on keypad") },
607 { (int) ' ', "space", N_("Space on keypad") },
608 { (int) '/', "kpslash", N_("Slash on keypad") },
609 { (int) '#', "kpnumlock", N_("NumLock on keypad") },
611 /* Alternative label */
612 { KEY_BACKSPACE
, "backspace", N_("Backspace key") },
613 { KEY_IC
, "insert", N_("Insert key") },
614 { KEY_KP_ADD
, "plus", N_("+ on keypad") },
615 { KEY_KP_SUBTRACT
,"minus", N_("- on keypad") },
616 { KEY_KP_MULTIPLY
,"asterix", N_("* on keypad") },
619 { KEY_M_CTRL
, "control", N_("Ctrl") },
620 { KEY_M_CTRL
, "ctrl", N_("Ctrl") },
621 { KEY_M_ALT
, "alt", N_("Alt") },
622 { KEY_M_ALT
, "ralt", N_("Alt") },
623 { KEY_M_ALT
, "meta", N_("Alt") },
624 { KEY_M_SHIFT
, "shift", N_("Shift") },
630 lookup_keyname (char *keyname
)
634 if (keyname
[0] == '\0')
636 if (keyname
[1] == '\0')
637 return (int) keyname
[0];
639 for (i
= 0; key_name_conv_tab
[i
].code
; i
++)
640 if (str_casecmp (key_name_conv_tab
[i
].name
, keyname
) == 0)
641 return key_name_conv_tab
[i
].code
;
647 /* Return the code associated with the symbolic name keyname */
649 lookup_key (char *keyname
)
653 guint keys_count
= -1;
660 keys
= g_strsplit (keyname
, " ", -1);
661 keys_count
= g_strv_length (keys
);
662 for (i
= keys_count
- 1; i
>= 0; i
--) {
663 if (keys
[i
] !=NULL
&& keys
[i
][0] != 0) {
664 key
= lookup_keyname (keys
[i
]);
665 if (key
& KEY_M_CTRL
) {
686 define_sequences (key_define_t
*kd
)
690 for (i
= 0; kd
[i
].code
!= 0; i
++)
691 define_sequence(kd
[i
].code
, kd
[i
].seq
, kd
[i
].action
);
694 #ifdef HAVE_TEXTMODE_X11_SUPPORT
696 static Display
*x11_display
;
697 static Window x11_window
;
702 if (!getenv ("DISPLAY"))
705 x11_display
= mc_XOpenDisplay (0);
708 x11_window
= DefaultRootWindow (x11_display
);
710 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
713 /* This has to be called before init_slang or whatever routine
714 calls any define_sequence */
718 const char *term
= getenv ("TERM");
719 char *kt
= getenv ("KEYBOARD_KEY_TIMEOUT_US");
721 keyboard_key_timeout
= atoi (kt
);
723 /* This has to be the first define_sequence */
724 /* So, we can assume that the first keys member has ESC */
725 define_sequences (mc_default_keys
);
727 /* Terminfo on irix does not have some keys */
730 && (strncmp (term
, "iris-ansi", 9) == 0
731 || strncmp (term
, "xterm", 5) == 0
732 || strncmp (term
, "rxvt", 4) == 0
733 || strcmp (term
, "screen") == 0)))
734 define_sequences (xterm_key_defines
);
736 /* load some additional keys (e.g. direct Alt-? support) */
737 load_xtra_key_defines ();
740 if (term
&& strncmp (term
, "qnx", 3) == 0) {
741 /* Modify the default value of use_8th_bit_as_meta: we would
742 * like to provide a working mc for a newbie who knows nothing
743 * about [Options|Display bits|Full 8 bits input]...
745 * Don't use 'meta'-bit, when we are dealing with a
746 * 'qnx*'-type terminal: clear the default value!
747 * These terminal types use 0xFF as an escape character,
748 * so use_8th_bit_as_meta==1 must not be enabled!
750 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
751 * is not used now (doesn't even depend on use_8th_bit_as_meta
752 * as in mc-3.1.2)...GREAT!...no additional code is required!]
754 use_8th_bit_as_meta
= 0;
758 #ifdef HAVE_TEXTMODE_X11_SUPPORT
760 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
762 /* Load the qansi-m key definitions
763 if we are running under the qansi-m terminal */
764 if (term
!= NULL
&& (strncmp (term
, "qansi-m", 7) == 0)) {
765 define_sequences (qansi_key_defines
);
769 /* This has to be called after SLang_init_tty/slint_init */
770 void init_key_input_fd (void)
773 input_fd
= SLang_TT_Read_FD
;
779 xmouse_get_event (Gpm_Event
*ev
)
782 static struct timeval tv1
= { 0, 0 }; /* Force first click as single */
783 static struct timeval tv2
;
785 static int last_btn
= 0;
787 /* Decode Xterm mouse information to a GPM style event */
789 /* Variable btn has following meaning: */
790 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
793 /* There seems to be no way of knowing which button was released */
794 /* So we assume all the buttons were released */
798 ev
->type
= GPM_UP
| (GPM_SINGLE
<< clicks
);
804 /* Bogus event, maybe mouse wheel */
808 if (btn
>= 32 && btn
<= 34) {
815 if (tv1
.tv_sec
&& (DIF_TIME (tv1
,tv2
) < double_click_speed
)) {
823 ev
->buttons
= GPM_B_LEFT
;
826 ev
->buttons
= GPM_B_MIDDLE
;
829 ev
->buttons
= GPM_B_RIGHT
;
832 ev
->buttons
= GPM_B_UP
;
836 ev
->buttons
= GPM_B_DOWN
;
845 last_btn
= ev
->buttons
;
847 /* Coordinates are 33-based */
848 /* Transform them to 1-based */
849 ev
->x
= getch () - 32;
850 ev
->y
= getch () - 32;
853 static key_def
*create_sequence (const char *seq
, int code
, int action
)
855 key_def
*base
, *p
, *attach
;
857 for (base
= attach
= NULL
; *seq
; seq
++) {
858 p
= g_new (key_def
, 1);
860 if (attach
) attach
->child
= p
;
864 p
->child
= p
->next
= NULL
;
868 p
->action
= MCKEY_NOACTION
;
874 /* The maximum sequence length (32 + null terminator) */
875 #define SEQ_BUFFER_LEN 33
876 static int seq_buffer
[SEQ_BUFFER_LEN
];
877 static int *seq_append
= 0;
879 static int push_char (int c
)
882 seq_append
= seq_buffer
;
884 if (seq_append
== &(seq_buffer
[SEQ_BUFFER_LEN
-2]))
892 * Return 1 on success, 0 on error.
893 * An error happens if SEQ is a beginning of an existing longer sequence.
895 int define_sequence (int code
, const char *seq
, int action
)
899 if (strlen (seq
) > SEQ_BUFFER_LEN
-1)
902 for (base
= keys
; (base
!= 0) && *seq
; ) {
903 if (*seq
== base
->ch
) {
904 if (base
->child
== 0) {
906 base
->child
= create_sequence (seq
+1, code
, action
);
909 /* The sequence matches an existing one. */
911 base
->action
= action
;
922 base
->next
= create_sequence (seq
, code
, action
);
929 /* Attempt to redefine a sequence with a shorter sequence. */
933 keys
= create_sequence (seq
, code
, action
);
937 static int *pending_keys
;
939 /* Apply corrections for the keycode generated in get_key_code() */
941 correct_key_code (int code
)
943 unsigned int c
= code
& ~KEY_M_MASK
; /* code without modifier */
944 unsigned int mod
= code
& KEY_M_MASK
; /* modifier */
946 unsigned int qmod
; /* bunch of the QNX console
947 modifiers needs unchanged */
948 #endif /* __QNXNTO__ */
951 * Add key modifiers directly from X11 or OS.
952 * Ordinary characters only get modifiers from sequences.
954 if (c
< 32 || c
>= 256) {
955 mod
|= get_modifier ();
958 /* This is needed if the newline is reported as carriage return */
962 /* This is reported to be useful on AIX */
963 if (c
== KEY_SCANCEL
)
966 /* Convert Shift+Tab and Ctrl+Tab to Back Tab */
967 if ((c
== '\t') && (mod
& (KEY_M_SHIFT
| KEY_M_CTRL
))) {
972 /* F0 is the same as F10 for out purposes */
977 * We are not interested if Ctrl was pressed when entering control
978 * characters, so assume that it was. When checking for such keys,
979 * XCTRL macro should be used. In some cases, we are interested,
980 * e.g. to distinguish Ctrl-Enter from Enter.
982 if (c
< 32 && c
!= ESC_CHAR
&& c
!= '\t' && c
!= '\n') {
989 if ((c
== 127) && (mod
==0)) /* Add Ctrl/Alt/Shift-BackSpace */
991 mod
|= get_modifier();
995 if ((c
=='0') && (mod
==0)) /* Add Shift-Insert on key pad */
997 if ((qmod
& KEY_M_SHIFT
) == KEY_M_SHIFT
)
1004 if ((c
=='.') && (mod
==0)) /* Add Shift-Del on key pad */
1006 if ((qmod
& KEY_M_SHIFT
) == KEY_M_SHIFT
)
1012 #endif /* __QNXNTO__ */
1014 /* Unrecognized 0177 is delete (preserve Ctrl) */
1019 /* Unrecognized Ctrl-d is delete */
1020 if (c
== (31 & 'd')) {
1025 /* Unrecognized Ctrl-h is backspace */
1026 if (c
== (31 & 'h')) {
1031 /* Shift+BackSpace is backspace */
1032 if (c
== KEY_BACKSPACE
&& (mod
& KEY_M_SHIFT
)) {
1033 mod
&= ~KEY_M_SHIFT
;
1036 /* Convert Shift+Fn to F(n+10) */
1037 if (c
>= KEY_F (1) && c
<= KEY_F (10) && (mod
& KEY_M_SHIFT
)) {
1041 /* Remove Shift information from function keys */
1042 if (c
>= KEY_F (1) && c
<= KEY_F (20)) {
1043 mod
&= ~KEY_M_SHIFT
;
1046 if (!alternate_plus_minus
)
1051 case KEY_KP_SUBTRACT
:
1054 case KEY_KP_MULTIPLY
:
1062 int get_key_code (int no_delay
)
1065 static key_def
*this = NULL
, *parent
;
1066 static struct timeval esctime
= { -1, -1 };
1067 static int lastnodelay
= -1;
1069 if (no_delay
!= lastnodelay
) {
1071 lastnodelay
= no_delay
;
1076 int d
= *pending_keys
++;
1078 if (!*pending_keys
) {
1082 if (d
== ESC_CHAR
&& pending_keys
) {
1083 d
= ALT(*pending_keys
++);
1086 if ((d
> 127 && d
< 256) && use_8th_bit_as_meta
)
1089 return correct_key_code (d
);
1097 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1098 if (c
== KEY_RESIZE
)
1099 goto nodelay_try_again
;
1102 tty_nodelay (FALSE
);
1104 if (this != NULL
&& parent
!= NULL
&&
1105 parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
) {
1106 struct timeval current
, timeout
;
1108 if (esctime
.tv_sec
== -1)
1111 timeout
.tv_sec
= keyboard_key_timeout
/ 1000000 + esctime
.tv_sec
;
1112 timeout
.tv_usec
= keyboard_key_timeout
% 1000000 + esctime
.tv_usec
;
1113 if (timeout
.tv_usec
> 1000000) {
1114 timeout
.tv_usec
-= 1000000;
1117 if (current
.tv_sec
< timeout
.tv_sec
)
1119 if (current
.tv_sec
== timeout
.tv_sec
&&
1120 current
.tv_usec
< timeout
.tv_usec
)
1123 pending_keys
= seq_append
= NULL
;
1128 } else if (c
== -1) {
1129 /* Maybe we got an incomplete match.
1130 This we do only in delay mode, since otherwise
1131 getch can return -1 at any time. */
1133 pending_keys
= seq_buffer
;
1140 /* Search the key on the root */
1141 if (!no_delay
|| this == NULL
) {
1145 if ((c
> 127 && c
< 256) && use_8th_bit_as_meta
) {
1148 /* The first sequence defined starts with esc */
1154 if (c
== this->ch
) {
1156 if (!push_char (c
)) {
1157 pending_keys
= seq_buffer
;
1162 if (parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
) {
1166 /* Shouldn't happen */
1167 fputs ("Internal error\n", stderr
);
1170 goto nodelay_try_again
;
1172 esctime
.tv_sec
= -1;
1173 c
= xgetch_second ();
1175 pending_keys
= seq_append
= NULL
;
1181 goto nodelay_try_again
;
1185 /* We got a complete match, return and reset search */
1188 pending_keys
= seq_append
= NULL
;
1191 return correct_key_code (code
);
1197 if (parent
!= NULL
&& parent
->action
== MCKEY_ESCAPE
) {
1199 /* Convert escape-digits to F-keys */
1200 if (g_ascii_isdigit(c
))
1201 c
= KEY_F (c
- '0');
1207 pending_keys
= seq_append
= NULL
;
1209 return correct_key_code (c
);
1211 /* Did not find a match or {c} was changed in the if above,
1212 so we have to return everything we had skipped
1215 pending_keys
= seq_buffer
;
1221 return correct_key_code (c
);
1224 /* Return the code associated with the symbolic name keyname */
1225 int lookup_key (char *keyname
)
1229 for (i
= 0; key_name_conv_tab
[i
].code
; i
++){
1230 if (str_casecmp (key_name_conv_tab
[i
].name
, keyname
))
1232 return key_name_conv_tab
[i
].code
;
1236 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
1238 try_channels (int set_timeout
)
1240 struct timeval timeout
;
1241 static fd_set select_set
;
1242 struct timeval
*timeptr
;
1247 FD_ZERO (&select_set
);
1248 FD_SET (input_fd
, &select_set
); /* Add stdin */
1249 maxfdp
= max (add_selects (&select_set
), input_fd
);
1253 timeout
.tv_usec
= 100000;
1258 v
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, timeptr
);
1260 check_selects (&select_set
);
1261 if (FD_ISSET (input_fd
, &select_set
))
1267 /* Workaround for System V Curses vt100 bug */
1268 static int getch_with_delay (void)
1272 /* This routine could be used on systems without mouse support,
1273 so we need to do the select check :-( */
1278 /* Try to get a character */
1279 c
= get_key_code (0);
1282 /* Failed -> wait 0.1 secs and try again */
1285 /* Success -> return the character */
1289 /* Returns a character read from stdin with appropriate interpretation */
1290 /* Also takes care of generated mouse events */
1291 /* Returns EV_MOUSE if it is a mouse event */
1292 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
1294 get_event (struct Gpm_Event
*event
, int redo_event
, int block
)
1297 static int flag
; /* Return value from select */
1299 static struct Gpm_Event ev
; /* Mouse event */
1301 struct timeval timeout
;
1302 struct timeval
*time_addr
= NULL
;
1303 static int dirty
= 3;
1305 if ((dirty
== 3) || is_idle ()) {
1312 vfs_timeout_handler ();
1314 /* Ok, we use (event->x < 0) to signal that the event does not contain
1315 a suitable position for the mouse, so we can't use show_mouse_pointer
1319 show_mouse_pointer (event
->x
, event
->y
);
1324 /* Repeat if using mouse */
1325 while (mouse_enabled
&& !pending_keys
) {
1329 FD_ZERO (&select_set
);
1330 FD_SET (input_fd
, &select_set
);
1331 maxfdp
= max (add_selects (&select_set
), input_fd
);
1334 if (use_mouse_p
== MOUSE_GPM
) {
1336 /* Connection to gpm broken, possibly gpm has died */
1338 use_mouse_p
= MOUSE_NONE
;
1341 FD_SET (gpm_fd
, &select_set
);
1342 maxfdp
= max (maxfdp
, gpm_fd
);
1348 timeout
.tv_usec
= mou_auto_repeat
* 1000;
1351 time_addr
= &timeout
;
1355 if ((seconds
= vfs_timeouts ())) {
1356 /* the timeout could be improved and actually be
1357 * the number of seconds until the next vfs entry
1358 * timeouts in the stamp list.
1361 timeout
.tv_sec
= seconds
;
1362 timeout
.tv_usec
= 0;
1363 time_addr
= &timeout
;
1368 if (!block
|| winch_flag
) {
1369 time_addr
= &timeout
;
1371 timeout
.tv_usec
= 0;
1373 tty_enable_interrupt_key ();
1374 flag
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, time_addr
);
1375 tty_disable_interrupt_key ();
1377 /* select timed out: it could be for any of the following reasons:
1378 * redo_event -> it was because of the MOU_REPEAT handler
1379 * !block -> we did not block in the select call
1380 * else -> 10 second timeout to check the vfs status.
1385 if (!block
|| winch_flag
)
1387 vfs_timeout_handler ();
1389 if (flag
== -1 && errno
== EINTR
)
1392 check_selects (&select_set
);
1394 if (FD_ISSET (input_fd
, &select_set
))
1397 if (use_mouse_p
== MOUSE_GPM
&& gpm_fd
> 0
1398 && FD_ISSET (gpm_fd
, &select_set
)) {
1404 #endif /* !HAVE_LIBGPM */
1407 flag
= is_wintouched (stdscr
);
1408 untouchwin (stdscr
);
1409 #endif /* !HAVE_SLANG */
1410 c
= block
? getch_with_delay () : get_key_code (1);
1414 tty_touch_screen ();
1415 #endif /* !HAVE_SLANG */
1417 if (c
== MCKEY_MOUSE
1420 #endif /* KEY_MOUSE */
1423 xmouse_get_event (event
);
1433 /* Returns a key press, mouse events are discarded */
1440 while ((key
= get_event (&ev
, 0, 1)) == EV_NONE
)
1445 static int xgetch_second (void)
1449 struct timeval timeout
;
1451 timeout
.tv_sec
= keyboard_key_timeout
/ 1000000;
1452 timeout
.tv_usec
= keyboard_key_timeout
% 1000000;
1454 FD_ZERO (&Read_FD_Set
);
1455 FD_SET (input_fd
, &Read_FD_Set
);
1456 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &timeout
);
1458 tty_nodelay (FALSE
);
1463 learn_store_key (char *buffer
, char **p
, int c
)
1465 if (*p
- buffer
> 253)
1467 if (c
== ESC_CHAR
) {
1470 } else if (c
< ' ') {
1472 *(*p
)++ = c
+ 'a' - 1;
1473 } else if (c
== '^') {
1480 char *learn_key (void)
1482 /* LEARN_TIMEOUT in usec */
1483 #define LEARN_TIMEOUT 200000
1486 struct timeval endtime
;
1487 struct timeval timeout
;
1492 tty_keypad (FALSE
); /* disable intepreting keys by ncurses */
1495 c
= getch (); /* Sanity check, should be unnecessary */
1496 learn_store_key (buffer
, &p
, c
);
1498 endtime
.tv_usec
+= LEARN_TIMEOUT
;
1499 if (endtime
.tv_usec
> 1000000) {
1500 endtime
.tv_usec
-= 1000000;
1505 while ((c
= getch ()) == -1) {
1507 timeout
.tv_usec
= endtime
.tv_usec
- timeout
.tv_usec
;
1508 if (timeout
.tv_usec
< 0)
1510 timeout
.tv_sec
= endtime
.tv_sec
- timeout
.tv_sec
;
1511 if (timeout
.tv_sec
>= 0 && timeout
.tv_usec
> 0) {
1512 FD_ZERO (&Read_FD_Set
);
1513 FD_SET (input_fd
, &Read_FD_Set
);
1514 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &timeout
);
1520 learn_store_key (buffer
, &p
, c
);
1523 tty_nodelay (FALSE
);
1525 return g_strdup (buffer
);
1528 /* xterm and linux console only: set keypad to numeric or application
1529 mode. Only in application keypad mode it's possible to distinguish
1530 the '+' key and the '+' on the keypad ('*' and '-' ditto)*/
1532 numeric_keypad_mode (void)
1534 if (console_flag
|| xterm_flag
) {
1535 fputs ("\033>", stdout
);
1541 application_keypad_mode (void)
1543 if (console_flag
|| xterm_flag
) {
1544 fputs ("\033=", stdout
);
1551 * Check if we are idle, i.e. there are no pending keyboard or mouse
1552 * events. Return 1 is idle, 0 is there are pending events.
1559 struct timeval timeout
;
1561 FD_ZERO (&select_set
);
1562 FD_SET (input_fd
, &select_set
);
1565 if (use_mouse_p
== MOUSE_GPM
&& mouse_enabled
&& gpm_fd
> 0) {
1566 FD_SET (gpm_fd
, &select_set
);
1567 maxfdp
= max (maxfdp
, gpm_fd
);
1571 timeout
.tv_usec
= 0;
1572 return (select (maxfdp
+ 1, &select_set
, 0, 0, &timeout
) <= 0);
1577 * Get modifier state (shift, alt, ctrl) for the last key pressed.
1578 * We are assuming that the state didn't change since the key press.
1579 * This is only correct if get_modifier() is called very fast after
1580 * the input was received, so that the user didn't release the
1581 * modifier keys yet.
1588 int mod_status
, shift_ext_status
;
1589 static int in_photon
= 0;
1590 static int ph_ig
= 0;
1591 PhCursorInfo_t cursor_info
;
1592 #endif /* __QNXNTO__ */
1594 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1601 mc_XQueryPointer (x11_display
, x11_window
, &root
, &child
, &root_x
,
1602 &root_y
, &win_x
, &win_y
, &mask
);
1604 if (mask
& ShiftMask
)
1605 result
|= KEY_M_SHIFT
;
1606 if (mask
& ControlMask
)
1607 result
|= KEY_M_CTRL
;
1610 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
1613 if (in_photon
== 0) {
1614 /* First time here, let's load Photon library and attach
1617 if (getenv ("PHOTON2_PATH") != NULL
) {
1618 /* QNX 6.x has no support for RTLD_LAZY */
1619 void *ph_handle
= dlopen ("/usr/lib/libph.so", RTLD_NOW
);
1620 if (ph_handle
!= NULL
) {
1621 ph_attach
= (ph_dv_f
) dlsym (ph_handle
, "PhAttach");
1623 (ph_ov_f
) dlsym (ph_handle
, "PhInputGroup");
1625 (ph_pqc_f
) dlsym (ph_handle
, "PhQueryCursor");
1626 if ((ph_attach
!= NULL
) && (ph_input_group
!= NULL
)
1627 && (ph_query_cursor
!= NULL
)) {
1628 if ((*ph_attach
) (0, 0)) { /* Attached */
1629 ph_ig
= (*ph_input_group
) (0);
1636 /* We do not have Photon running. Assume we are in text
1638 if (in_photon
== -1) {
1640 (fileno (stdin
), DCMD_CHR_LINESTATUS
, &mod_status
,
1641 sizeof (int), NULL
) == -1)
1643 shift_ext_status
= mod_status
& 0xffffff00UL
;
1645 if (mod_status
& _LINESTATUS_CON_ALT
)
1646 result
|= KEY_M_ALT
;
1647 if (mod_status
& _LINESTATUS_CON_CTRL
)
1648 result
|= KEY_M_CTRL
;
1649 if ((mod_status
& _LINESTATUS_CON_SHIFT
)
1650 || (shift_ext_status
& 0x00000800UL
))
1651 result
|= KEY_M_SHIFT
;
1653 (*ph_query_cursor
) (ph_ig
, &cursor_info
);
1654 if (cursor_info
.key_mods
& 0x04)
1655 result
|= KEY_M_ALT
;
1656 if (cursor_info
.key_mods
& 0x02)
1657 result
|= KEY_M_CTRL
;
1658 if (cursor_info
.key_mods
& 0x01)
1659 result
|= KEY_M_SHIFT
;
1661 #endif /* __QNXNTO__ */
1663 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
1665 unsigned char modifiers
= 6;
1667 if (ioctl (0, TIOCLINUX
, &modifiers
) < 0)
1670 /* Translate Linux modifiers into mc modifiers */
1671 if (modifiers
& SHIFT_PRESSED
)
1672 result
|= KEY_M_SHIFT
;
1673 if (modifiers
& (ALTL_PRESSED
| ALTR_PRESSED
))
1674 result
|= KEY_M_ALT
;
1675 if (modifiers
& CONTROL_PRESSED
)
1676 result
|= KEY_M_CTRL
;
1678 #endif /* !__linux__ */
1682 static void k_dispose (key_def
*k
)
1686 k_dispose (k
->child
);
1687 k_dispose (k
->next
);
1691 static void s_dispose (SelectList
*sel
)
1696 s_dispose (sel
->next
);
1703 s_dispose (select_list
);
1705 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1707 mc_XCloseDisplay (x11_display
);