When we see an unknown sequence, it is not enough
[midnight-commander.git] / lib / tty / key.c
blobc58043e0bbf7e508cbe98eb9e6ff756929819128
1 /*
2 Keyboard support routines.
4 Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
5 2005, 2006, 2007, 2009, 2010, 2011, 2013
6 The Free Software Foundation, Inc.
8 Written by:
9 Miguel de Icaza, 1994, 1995
10 Janne Kukonlehto, 1994, 1995
11 Jakub Jelinek, 1995
12 Norbert Warmuth, 1997
13 Denys Vlasenko <vda.linux@googlemail.com>, 2013
14 Slava Zanko <slavazanko@gmail.com>, 2013
16 This file is part of the Midnight Commander.
18 The Midnight Commander is free software: you can redistribute it
19 and/or modify it under the terms of the GNU General Public License as
20 published by the Free Software Foundation, either version 3 of the License,
21 or (at your option) any later version.
23 The Midnight Commander is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 /** \file key.c
33 * \brief Source: keyboard support routines
36 #include <config.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/time.h>
44 #include <sys/types.h>
45 #include <unistd.h>
47 #include "lib/global.h"
49 #include "lib/vfs/vfs.h"
51 #include "tty.h"
52 #include "tty-internal.h" /* mouse_enabled */
53 #include "mouse.h"
54 #include "key.h"
56 #include "lib/widget.h" /* mc_refresh() */
58 #ifdef HAVE_TEXTMODE_X11_SUPPORT
59 #include "x11conn.h"
60 #endif
62 #ifdef __linux__
63 #if defined(__GLIBC__) && (__GLIBC__ < 2)
64 #include <linux/termios.h> /* TIOCLINUX */
65 #else
66 #include <termios.h>
67 #endif
68 #ifdef HAVE_SYS_IOCTL_H
69 #include <sys/ioctl.h>
70 #endif
71 #endif /* __linux__ */
73 #ifdef __CYGWIN__
74 #include <termios.h>
75 #ifdef HAVE_SYS_IOCTL_H
76 #include <sys/ioctl.h>
77 #endif
78 #endif /* __CYGWIN__ */
80 #ifdef __QNXNTO__
81 #include <dlfcn.h>
82 #include <Ph.h>
83 #include <sys/dcmd_chr.h>
84 #endif /* __QNXNTO__ */
86 /*** global variables ****************************************************************************/
88 int mou_auto_repeat = 100;
89 int double_click_speed = 250;
90 int old_esc_mode = 0;
91 /* timeout for old_esc_mode in usec */
92 int old_esc_mode_timeout = 1000000; /* settable via env */
93 int use_8th_bit_as_meta = 0;
95 /* This table is a mapping between names and the constants we use
96 * We use this to allow users to define alternate definitions for
97 * certain keys that may be missing from the terminal database
99 const key_code_name_t key_name_conv_tab[] = {
100 /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
101 to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
102 {KEY_F (1), "f1", N_("Function key 1"), "F1"},
103 {KEY_F (2), "f2", N_("Function key 2"), "F2"},
104 {KEY_F (3), "f3", N_("Function key 3"), "F3"},
105 {KEY_F (4), "f4", N_("Function key 4"), "F4"},
106 {KEY_F (5), "f5", N_("Function key 5"), "F5"},
107 {KEY_F (6), "f6", N_("Function key 6"), "F6"},
108 {KEY_F (7), "f7", N_("Function key 7"), "F7"},
109 {KEY_F (8), "f8", N_("Function key 8"), "F8"},
110 {KEY_F (9), "f9", N_("Function key 9"), "F9"},
111 {KEY_F (10), "f10", N_("Function key 10"), "F10"},
112 {KEY_F (11), "f11", N_("Function key 11"), "F11"},
113 {KEY_F (12), "f12", N_("Function key 12"), "F12"},
114 {KEY_F (13), "f13", N_("Function key 13"), "F13"},
115 {KEY_F (14), "f14", N_("Function key 14"), "F14"},
116 {KEY_F (15), "f15", N_("Function key 15"), "F15"},
117 {KEY_F (16), "f16", N_("Function key 16"), "F16"},
118 {KEY_F (17), "f17", N_("Function key 17"), "F17"},
119 {KEY_F (18), "f18", N_("Function key 18"), "F18"},
120 {KEY_F (19), "f19", N_("Function key 19"), "F19"},
121 {KEY_F (20), "f20", N_("Function key 20"), "F20"},
122 {KEY_BACKSPACE, "backspace", N_("Backspace key"), "Backspace"},
123 {KEY_END, "end", N_("End key"), "End"},
124 {KEY_UP, "up", N_("Up arrow key"), "Up"},
125 {KEY_DOWN, "down", N_("Down arrow key"), "Down"},
126 {KEY_LEFT, "left", N_("Left arrow key"), "Left"},
127 {KEY_RIGHT, "right", N_("Right arrow key"), "Right"},
128 {KEY_HOME, "home", N_("Home key"), "Home"},
129 {KEY_NPAGE, "pgdn", N_("Page Down key"), "PgDn"},
130 {KEY_PPAGE, "pgup", N_("Page Up key"), "PgUp"},
131 {KEY_IC, "insert", N_("Insert key"), "Ins"},
132 {KEY_DC, "delete", N_("Delete key"), "Del"},
133 {ALT ('\t'), "complete", N_("Completion/M-tab"), "Meta-Tab"},
134 {KEY_BTAB, "backtab", N_("Back Tabulation S-tab"), "Shift-Tab"},
135 {KEY_KP_ADD, "kpplus", N_("+ on keypad"), "+"},
136 {KEY_KP_SUBTRACT, "kpminus", N_("- on keypad"), "-"},
137 {(int) '/', "kpslash", N_("Slash on keypad"), "/"},
138 {KEY_KP_MULTIPLY, "kpasterisk", N_("* on keypad"), "*"},
140 /* From here on, these won't be shown in Learn keys (no space) */
141 {ESC_CHAR, "escape", N_("Escape key"), "Esc"},
142 {KEY_LEFT, "kpleft", N_("Left arrow keypad"), "Left"},
143 {KEY_RIGHT, "kpright", N_("Right arrow keypad"), "Right"},
144 {KEY_UP, "kpup", N_("Up arrow keypad"), "Up"},
145 {KEY_DOWN, "kpdown", N_("Down arrow keypad"), "Down"},
146 {KEY_HOME, "kphome", N_("Home on keypad"), "Home"},
147 {KEY_END, "kpend", N_("End on keypad"), "End"},
148 {KEY_NPAGE, "kpnpage", N_("Page Down keypad"), "PgDn"},
149 {KEY_PPAGE, "kpppage", N_("Page Up keypad"), "PgUp"},
150 {KEY_IC, "kpinsert", N_("Insert on keypad"), "Ins"},
151 {KEY_DC, "kpdelete", N_("Delete on keypad"), "Del"},
152 {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
153 {KEY_F (21), "f21", N_("Function key 21"), "F21"},
154 {KEY_F (22), "f22", N_("Function key 22"), "F22"},
155 {KEY_F (23), "f23", N_("Function key 23"), "F23"},
156 {KEY_F (24), "f24", N_("Function key 24"), "F24"},
157 {KEY_A1, "a1", N_("A1 key"), "A1"},
158 {KEY_C1, "c1", N_("C1 key"), "C1"},
160 /* Alternative label */
161 {ESC_CHAR, "esc", N_("Escape key"), "Esc"},
162 {KEY_BACKSPACE, "bs", N_("Backspace key"), "Bakspace"},
163 {KEY_IC, "ins", N_("Insert key"), "Ins"},
164 {KEY_DC, "del", N_("Delete key"), "Del"},
165 {(int) '+', "plus", N_("Plus"), "+"},
166 {(int) '-', "minus", N_("Minus"), "-"},
167 {(int) '*', "asterisk", N_("Asterisk"), "*"},
168 {(int) '.', "dot", N_("Dot"), "."},
169 {(int) '<', "lt", N_("Less than"), "<"},
170 {(int) '>', "gt", N_("Great than"), ">"},
171 {(int) '=', "equal", N_("Equal"), "="},
172 {(int) ',', "comma", N_("Comma"), ","},
173 {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
174 {(int) ':', "colon", N_("Colon"), ":"},
175 {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
176 {(int) '?', "question", N_("Question mark"), "?"},
177 {(int) '&', "ampersand", N_("Ampersand"), "&"},
178 {(int) '$', "dollar", N_("Dollar sign"), "$"},
179 {(int) '"', "quota", N_("Quotation mark"), "\""},
180 {(int) '%', "percent", N_("Percent sign"), "%"},
181 {(int) '^', "caret", N_("Caret"), "^"},
182 {(int) '~', "tilda", N_("Tilda"), "~"},
183 {(int) '`', "prime", N_("Prime"), "`"},
184 {(int) '_', "underline", N_("Underline"), "_"},
185 {(int) '_', "understrike", N_("Understrike"), "_"},
186 {(int) '|', "pipe", N_("Pipe"), "|"},
187 {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
188 {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
189 {(int) '[', "lbracket", N_("Left bracket"), "["},
190 {(int) ']', "rbracket", N_("Right bracket"), "]"},
191 {(int) '{', "lbrace", N_("Left brace"), "{"},
192 {(int) '}', "rbrace", N_("Right brace"), "}"},
193 {(int) '\n', "enter", N_("Enter"), "Enter"},
194 {(int) '\t', "tab", N_("Tab key"), "Tab"},
195 {(int) ' ', "space", N_("Space key"), "Space"},
196 {(int) '/', "slash", N_("Slash key"), "/"},
197 {(int) '\\', "backslash", N_("Backslash key"), "\\"},
198 {(int) '#', "number", N_("Number sign #"), "#"},
199 {(int) '#', "hash", N_("Number sign #"), "#"},
200 /* TRANSLATORS: Please translate as in "at sign" (@). */
201 {(int) '@', "at", N_("At sign"), "@"},
203 /* meta keys */
204 {KEY_M_CTRL, "control", N_("Ctrl"), "C"},
205 {KEY_M_CTRL, "ctrl", N_("Ctrl"), "C"},
206 {KEY_M_ALT, "meta", N_("Alt"), "M"},
207 {KEY_M_ALT, "alt", N_("Alt"), "M"},
208 {KEY_M_ALT, "ralt", N_("Alt"), "M"},
209 {KEY_M_SHIFT, "shift", N_("Shift"), "S"},
211 {0, NULL, NULL, NULL}
214 /*** file scope macro definitions ****************************************************************/
216 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *) NULL))
217 #define DIF_TIME(t1, t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000)
219 /* The maximum sequence length (32 + null terminator) */
220 #define SEQ_BUFFER_LEN 33
222 /*** file scope type declarations ****************************************************************/
224 /* Linux console keyboard modifiers */
225 typedef enum
227 SHIFT_PRESSED = (1 << 0),
228 ALTR_PRESSED = (1 << 1),
229 CONTROL_PRESSED = (1 << 2),
230 ALTL_PRESSED = (1 << 3)
231 } mod_pressed_t;
233 typedef struct key_def
235 char ch; /* Holds the matching char code */
236 int code; /* The code returned, valid if child == NULL */
237 struct key_def *next;
238 struct key_def *child; /* sequence continuation */
239 int action; /* optional action to be done. Now used only
240 to mark that we are just after the first
241 Escape */
242 } key_def;
244 typedef struct
246 int code;
247 const char *seq;
248 int action;
249 } key_define_t;
251 /* File descriptor monitoring add/remove routines */
252 typedef struct SelectList
254 int fd;
255 select_fn callback;
256 void *info;
257 struct SelectList *next;
258 } SelectList;
260 typedef enum KeySortType
262 KEY_NOSORT = 0,
263 KEY_SORTBYNAME,
264 KEY_SORTBYCODE
265 } KeySortType;
267 #ifdef __QNXNTO__
268 typedef int (*ph_dv_f) (void *, void *);
269 typedef int (*ph_ov_f) (void *);
270 typedef int (*ph_pqc_f) (unsigned short, PhCursorInfo_t *);
271 #endif
273 /*** file scope variables ************************************************************************/
275 static key_define_t mc_default_keys[] = {
276 {ESC_CHAR, ESC_STR, MCKEY_ESCAPE},
277 {ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION},
278 {0, NULL, MCKEY_NOACTION},
281 /* Broken terminfo and termcap databases on xterminals */
282 static key_define_t xterm_key_defines[] = {
283 {KEY_F (1), ESC_STR "OP", MCKEY_NOACTION},
284 {KEY_F (2), ESC_STR "OQ", MCKEY_NOACTION},
285 {KEY_F (3), ESC_STR "OR", MCKEY_NOACTION},
286 {KEY_F (4), ESC_STR "OS", MCKEY_NOACTION},
287 {KEY_F (1), ESC_STR "[11~", MCKEY_NOACTION},
288 {KEY_F (2), ESC_STR "[12~", MCKEY_NOACTION},
289 {KEY_F (3), ESC_STR "[13~", MCKEY_NOACTION},
290 {KEY_F (4), ESC_STR "[14~", MCKEY_NOACTION},
291 {KEY_F (5), ESC_STR "[15~", MCKEY_NOACTION},
292 {KEY_F (6), ESC_STR "[17~", MCKEY_NOACTION},
293 {KEY_F (7), ESC_STR "[18~", MCKEY_NOACTION},
294 {KEY_F (8), ESC_STR "[19~", MCKEY_NOACTION},
295 {KEY_F (9), ESC_STR "[20~", MCKEY_NOACTION},
296 {KEY_F (10), ESC_STR "[21~", MCKEY_NOACTION},
298 /* old xterm Shift-arrows */
299 {KEY_M_SHIFT | KEY_UP, ESC_STR "O2A", MCKEY_NOACTION},
300 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "O2B", MCKEY_NOACTION},
301 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "O2C", MCKEY_NOACTION},
302 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "O2D", MCKEY_NOACTION},
304 /* new xterm Shift-arrows */
305 {KEY_M_SHIFT | KEY_UP, ESC_STR "[1;2A", MCKEY_NOACTION},
306 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[1;2B", MCKEY_NOACTION},
307 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[1;2C", MCKEY_NOACTION},
308 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[1;2D", MCKEY_NOACTION},
310 /* more xterm keys with modifiers */
311 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5;5~", MCKEY_NOACTION},
312 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6;5~", MCKEY_NOACTION},
313 {KEY_M_CTRL | KEY_IC, ESC_STR "[2;5~", MCKEY_NOACTION},
314 {KEY_M_CTRL | KEY_DC, ESC_STR "[3;5~", MCKEY_NOACTION},
315 {KEY_M_CTRL | KEY_HOME, ESC_STR "[1;5H", MCKEY_NOACTION},
316 {KEY_M_CTRL | KEY_END, ESC_STR "[1;5F", MCKEY_NOACTION},
317 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[1;2H", MCKEY_NOACTION},
318 {KEY_M_SHIFT | KEY_END, ESC_STR "[1;2F", MCKEY_NOACTION},
319 {KEY_M_CTRL | KEY_UP, ESC_STR "[1;5A", MCKEY_NOACTION},
320 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;5B", MCKEY_NOACTION},
321 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;5C", MCKEY_NOACTION},
322 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;5D", MCKEY_NOACTION},
323 {KEY_M_SHIFT | KEY_IC, ESC_STR "[2;2~", MCKEY_NOACTION},
324 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3;2~", MCKEY_NOACTION},
325 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[1;6A", MCKEY_NOACTION},
326 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;6B", MCKEY_NOACTION},
327 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;6C", MCKEY_NOACTION},
328 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;6D", MCKEY_NOACTION},
330 /* putty */
331 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[[1;6A", MCKEY_NOACTION},
332 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[[1;6B", MCKEY_NOACTION},
333 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[[1;6C", MCKEY_NOACTION},
334 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[[1;6D", MCKEY_NOACTION},
336 /* putty alt-arrow keys */
337 /* removed as source esc esc esc trouble */
339 { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
340 { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
341 { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
342 { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
343 { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
344 { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
345 { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
346 { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
348 { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
349 { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
350 { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
351 { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
353 { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
354 { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
355 { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
356 { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
358 /* xterm alt-arrow keys */
359 {KEY_M_ALT | KEY_UP, ESC_STR "[1;3A", MCKEY_NOACTION},
360 {KEY_M_ALT | KEY_DOWN, ESC_STR "[1;3B", MCKEY_NOACTION},
361 {KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;3C", MCKEY_NOACTION},
362 {KEY_M_ALT | KEY_LEFT, ESC_STR "[1;3D", MCKEY_NOACTION},
363 {KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;3~", MCKEY_NOACTION},
364 {KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;3~", MCKEY_NOACTION},
365 {KEY_M_ALT | KEY_HOME, ESC_STR "[1~", MCKEY_NOACTION},
366 {KEY_M_ALT | KEY_END, ESC_STR "[4~", MCKEY_NOACTION},
367 {KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR "[1;7A", MCKEY_NOACTION},
368 {KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR "[1;7B", MCKEY_NOACTION},
369 {KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;7C", MCKEY_NOACTION},
370 {KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR "[1;7D", MCKEY_NOACTION},
371 {KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;7~", MCKEY_NOACTION},
372 {KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;7~", MCKEY_NOACTION},
373 {KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR "OH", MCKEY_NOACTION},
374 {KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR "OF", MCKEY_NOACTION},
376 /* rxvt keys with modifiers */
377 {KEY_M_SHIFT | KEY_UP, ESC_STR "[a", MCKEY_NOACTION},
378 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION},
379 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION},
380 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION},
381 {KEY_M_CTRL | KEY_UP, ESC_STR "Oa", MCKEY_NOACTION},
382 {KEY_M_CTRL | KEY_DOWN, ESC_STR "Ob", MCKEY_NOACTION},
383 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "Oc", MCKEY_NOACTION},
384 {KEY_M_CTRL | KEY_LEFT, ESC_STR "Od", MCKEY_NOACTION},
385 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5^", MCKEY_NOACTION},
386 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6^", MCKEY_NOACTION},
387 {KEY_M_CTRL | KEY_HOME, ESC_STR "[7^", MCKEY_NOACTION},
388 {KEY_M_CTRL | KEY_END, ESC_STR "[8^", MCKEY_NOACTION},
389 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[7$", MCKEY_NOACTION},
390 {KEY_M_SHIFT | KEY_END, ESC_STR "[8$", MCKEY_NOACTION},
391 {KEY_M_CTRL | KEY_IC, ESC_STR "[2^", MCKEY_NOACTION},
392 {KEY_M_CTRL | KEY_DC, ESC_STR "[3^", MCKEY_NOACTION},
393 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3$", MCKEY_NOACTION},
395 /* konsole keys with modifiers */
396 {KEY_M_SHIFT | KEY_HOME, ESC_STR "O2H", MCKEY_NOACTION},
397 {KEY_M_SHIFT | KEY_END, ESC_STR "O2F", MCKEY_NOACTION},
399 /* gnome-terminal */
400 {KEY_M_SHIFT | KEY_UP, ESC_STR "[2A", MCKEY_NOACTION},
401 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[2B", MCKEY_NOACTION},
402 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[2C", MCKEY_NOACTION},
403 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[2D", MCKEY_NOACTION},
404 {KEY_M_CTRL | KEY_UP, ESC_STR "[5A", MCKEY_NOACTION},
405 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[5B", MCKEY_NOACTION},
406 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[5C", MCKEY_NOACTION},
407 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[5D", MCKEY_NOACTION},
408 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[6A", MCKEY_NOACTION},
409 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[6B", MCKEY_NOACTION},
410 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[6C", MCKEY_NOACTION},
411 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[6D", MCKEY_NOACTION},
413 /* gnome-terminal - application mode */
414 {KEY_M_CTRL | KEY_UP, ESC_STR "O5A", MCKEY_NOACTION},
415 {KEY_M_CTRL | KEY_DOWN, ESC_STR "O5B", MCKEY_NOACTION},
416 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "O5C", MCKEY_NOACTION},
417 {KEY_M_CTRL | KEY_LEFT, ESC_STR "O5D", MCKEY_NOACTION},
418 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "O6A", MCKEY_NOACTION},
419 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "O6B", MCKEY_NOACTION},
420 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "O6C", MCKEY_NOACTION},
421 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "O6D", MCKEY_NOACTION},
423 /* iTerm */
424 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[5;2~", MCKEY_NOACTION},
425 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[6;2~", MCKEY_NOACTION},
427 /* putty */
428 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[[5;53~", MCKEY_NOACTION},
429 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[[6;53~", MCKEY_NOACTION},
431 /* keypad keys */
432 {KEY_IC, ESC_STR "Op", MCKEY_NOACTION},
433 {KEY_DC, ESC_STR "On", MCKEY_NOACTION},
434 {'/', ESC_STR "Oo", MCKEY_NOACTION},
435 {'\n', ESC_STR "OM", MCKEY_NOACTION},
437 {0, NULL, MCKEY_NOACTION},
440 /* qansi-m terminals have a much more key combinatios,
441 which are undefined in termcap/terminfo */
442 static key_define_t qansi_key_defines[] = {
443 /* qansi-m terminal */
444 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[u", MCKEY_NOACTION}, /* Ctrl-PgDown */
445 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[v", MCKEY_NOACTION}, /* Ctrl-PgUp */
446 {KEY_M_CTRL | KEY_HOME, ESC_STR "[h", MCKEY_NOACTION}, /* Ctrl-Home */
447 {KEY_M_CTRL | KEY_END, ESC_STR "[y", MCKEY_NOACTION}, /* Ctrl-End */
448 {KEY_M_CTRL | KEY_IC, ESC_STR "[`", MCKEY_NOACTION}, /* Ctrl-Insert */
449 {KEY_M_CTRL | KEY_DC, ESC_STR "[p", MCKEY_NOACTION}, /* Ctrl-Delete */
450 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION}, /* Ctrl-Left */
451 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION}, /* Ctrl-Right */
452 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION}, /* Ctrl-Down */
453 {KEY_M_CTRL | KEY_UP, ESC_STR "[a", MCKEY_NOACTION}, /* Ctrl-Up */
454 {KEY_M_CTRL | KEY_KP_ADD, ESC_STR "[s", MCKEY_NOACTION}, /* Ctrl-Gr-Plus */
455 {KEY_M_CTRL | KEY_KP_SUBTRACT, ESC_STR "[t", MCKEY_NOACTION}, /* Ctrl-Gr-Minus */
456 {KEY_M_CTRL | '\t', ESC_STR "[z", MCKEY_NOACTION}, /* Ctrl-Tab */
457 {KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION}, /* Shift-Tab */
458 {KEY_M_CTRL | KEY_F (1), ESC_STR "[1~", MCKEY_NOACTION}, /* Ctrl-F1 */
459 {KEY_M_CTRL | KEY_F (2), ESC_STR "[2~", MCKEY_NOACTION}, /* Ctrl-F2 */
460 {KEY_M_CTRL | KEY_F (3), ESC_STR "[3~", MCKEY_NOACTION}, /* Ctrl-F3 */
461 {KEY_M_CTRL | KEY_F (4), ESC_STR "[4~", MCKEY_NOACTION}, /* Ctrl-F4 */
462 {KEY_M_CTRL | KEY_F (5), ESC_STR "[5~", MCKEY_NOACTION}, /* Ctrl-F5 */
463 {KEY_M_CTRL | KEY_F (6), ESC_STR "[6~", MCKEY_NOACTION}, /* Ctrl-F6 */
464 {KEY_M_CTRL | KEY_F (7), ESC_STR "[7~", MCKEY_NOACTION}, /* Ctrl-F7 */
465 {KEY_M_CTRL | KEY_F (8), ESC_STR "[8~", MCKEY_NOACTION}, /* Ctrl-F8 */
466 {KEY_M_CTRL | KEY_F (9), ESC_STR "[9~", MCKEY_NOACTION}, /* Ctrl-F9 */
467 {KEY_M_CTRL | KEY_F (10), ESC_STR "[10~", MCKEY_NOACTION}, /* Ctrl-F10 */
468 {KEY_M_CTRL | KEY_F (11), ESC_STR "[11~", MCKEY_NOACTION}, /* Ctrl-F11 */
469 {KEY_M_CTRL | KEY_F (12), ESC_STR "[12~", MCKEY_NOACTION}, /* Ctrl-F12 */
470 {KEY_M_ALT | KEY_F (1), ESC_STR "[17~", MCKEY_NOACTION}, /* Alt-F1 */
471 {KEY_M_ALT | KEY_F (2), ESC_STR "[18~", MCKEY_NOACTION}, /* Alt-F2 */
472 {KEY_M_ALT | KEY_F (3), ESC_STR "[19~", MCKEY_NOACTION}, /* Alt-F3 */
473 {KEY_M_ALT | KEY_F (4), ESC_STR "[20~", MCKEY_NOACTION}, /* Alt-F4 */
474 {KEY_M_ALT | KEY_F (5), ESC_STR "[21~", MCKEY_NOACTION}, /* Alt-F5 */
475 {KEY_M_ALT | KEY_F (6), ESC_STR "[22~", MCKEY_NOACTION}, /* Alt-F6 */
476 {KEY_M_ALT | KEY_F (7), ESC_STR "[23~", MCKEY_NOACTION}, /* Alt-F7 */
477 {KEY_M_ALT | KEY_F (8), ESC_STR "[24~", MCKEY_NOACTION}, /* Alt-F8 */
478 {KEY_M_ALT | KEY_F (9), ESC_STR "[25~", MCKEY_NOACTION}, /* Alt-F9 */
479 {KEY_M_ALT | KEY_F (10), ESC_STR "[26~", MCKEY_NOACTION}, /* Alt-F10 */
480 {KEY_M_ALT | KEY_F (11), ESC_STR "[27~", MCKEY_NOACTION}, /* Alt-F11 */
481 {KEY_M_ALT | KEY_F (12), ESC_STR "[28~", MCKEY_NOACTION}, /* Alt-F12 */
482 {KEY_M_ALT | 'a', ESC_STR "Na", MCKEY_NOACTION}, /* Alt-a */
483 {KEY_M_ALT | 'b', ESC_STR "Nb", MCKEY_NOACTION}, /* Alt-b */
484 {KEY_M_ALT | 'c', ESC_STR "Nc", MCKEY_NOACTION}, /* Alt-c */
485 {KEY_M_ALT | 'd', ESC_STR "Nd", MCKEY_NOACTION}, /* Alt-d */
486 {KEY_M_ALT | 'e', ESC_STR "Ne", MCKEY_NOACTION}, /* Alt-e */
487 {KEY_M_ALT | 'f', ESC_STR "Nf", MCKEY_NOACTION}, /* Alt-f */
488 {KEY_M_ALT | 'g', ESC_STR "Ng", MCKEY_NOACTION}, /* Alt-g */
489 {KEY_M_ALT | 'h', ESC_STR "Nh", MCKEY_NOACTION}, /* Alt-h */
490 {KEY_M_ALT | 'i', ESC_STR "Ni", MCKEY_NOACTION}, /* Alt-i */
491 {KEY_M_ALT | 'j', ESC_STR "Nj", MCKEY_NOACTION}, /* Alt-j */
492 {KEY_M_ALT | 'k', ESC_STR "Nk", MCKEY_NOACTION}, /* Alt-k */
493 {KEY_M_ALT | 'l', ESC_STR "Nl", MCKEY_NOACTION}, /* Alt-l */
494 {KEY_M_ALT | 'm', ESC_STR "Nm", MCKEY_NOACTION}, /* Alt-m */
495 {KEY_M_ALT | 'n', ESC_STR "Nn", MCKEY_NOACTION}, /* Alt-n */
496 {KEY_M_ALT | 'o', ESC_STR "No", MCKEY_NOACTION}, /* Alt-o */
497 {KEY_M_ALT | 'p', ESC_STR "Np", MCKEY_NOACTION}, /* Alt-p */
498 {KEY_M_ALT | 'q', ESC_STR "Nq", MCKEY_NOACTION}, /* Alt-q */
499 {KEY_M_ALT | 'r', ESC_STR "Nr", MCKEY_NOACTION}, /* Alt-r */
500 {KEY_M_ALT | 's', ESC_STR "Ns", MCKEY_NOACTION}, /* Alt-s */
501 {KEY_M_ALT | 't', ESC_STR "Nt", MCKEY_NOACTION}, /* Alt-t */
502 {KEY_M_ALT | 'u', ESC_STR "Nu", MCKEY_NOACTION}, /* Alt-u */
503 {KEY_M_ALT | 'v', ESC_STR "Nv", MCKEY_NOACTION}, /* Alt-v */
504 {KEY_M_ALT | 'w', ESC_STR "Nw", MCKEY_NOACTION}, /* Alt-w */
505 {KEY_M_ALT | 'x', ESC_STR "Nx", MCKEY_NOACTION}, /* Alt-x */
506 {KEY_M_ALT | 'y', ESC_STR "Ny", MCKEY_NOACTION}, /* Alt-y */
507 {KEY_M_ALT | 'z', ESC_STR "Nz", MCKEY_NOACTION}, /* Alt-z */
508 {KEY_KP_SUBTRACT, ESC_STR "[S", MCKEY_NOACTION}, /* Gr-Minus */
509 {KEY_KP_ADD, ESC_STR "[T", MCKEY_NOACTION}, /* Gr-Plus */
510 {0, NULL, MCKEY_NOACTION},
513 /* This holds all the key definitions */
514 static key_def *keys = NULL;
516 static int input_fd;
517 static int disabled_channels = 0; /* Disable channels checking */
519 static SelectList *select_list = NULL;
521 static int seq_buffer[SEQ_BUFFER_LEN];
522 static int *seq_append = NULL;
524 static int *pending_keys = NULL;
526 #ifdef __QNXNTO__
527 ph_dv_f ph_attach;
528 ph_ov_f ph_input_group;
529 ph_pqc_f ph_query_cursor;
530 #endif
532 #ifdef HAVE_TEXTMODE_X11_SUPPORT
533 static Display *x11_display;
534 static Window x11_window;
535 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
537 static KeySortType has_been_sorted = KEY_NOSORT;
539 /* *INDENT-OFF* */
540 static const size_t key_conv_tab_size = G_N_ELEMENTS (key_name_conv_tab) - 1;
541 /* *INDENT-ON* */
543 static const key_code_name_t *key_conv_tab_sorted[G_N_ELEMENTS (key_name_conv_tab) - 1];
545 /*** file scope functions ************************************************************************/
546 /* --------------------------------------------------------------------------------------------- */
548 static int
549 add_selects (fd_set * select_set)
551 int top_fd = 0;
553 if (disabled_channels == 0)
555 SelectList *p;
557 for (p = select_list; p != NULL; p = p->next)
559 FD_SET (p->fd, select_set);
560 if (p->fd > top_fd)
561 top_fd = p->fd;
565 return top_fd;
568 /* --------------------------------------------------------------------------------------------- */
570 static void
571 check_selects (fd_set * select_set)
573 if (disabled_channels == 0)
575 gboolean retry;
579 SelectList *p;
581 retry = FALSE;
582 for (p = select_list; p; p = p->next)
583 if (FD_ISSET (p->fd, select_set))
585 FD_CLR (p->fd, select_set);
586 (*p->callback) (p->fd, p->info);
587 retry = TRUE;
588 break;
591 while (retry);
595 /* --------------------------------------------------------------------------------------------- */
596 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
598 static void
599 try_channels (int set_timeout)
601 struct timeval time_out;
602 static fd_set select_set;
603 struct timeval *timeptr;
604 int v;
605 int maxfdp;
607 while (1)
609 FD_ZERO (&select_set);
610 FD_SET (input_fd, &select_set); /* Add stdin */
611 maxfdp = max (add_selects (&select_set), input_fd);
613 timeptr = NULL;
614 if (set_timeout)
616 time_out.tv_sec = 0;
617 time_out.tv_usec = 100000;
618 timeptr = &time_out;
621 v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr);
622 if (v > 0)
624 check_selects (&select_set);
625 if (FD_ISSET (input_fd, &select_set))
626 break;
631 /* --------------------------------------------------------------------------------------------- */
633 static key_def *
634 create_sequence (const char *seq, int code, int action)
636 key_def *base, *p, *attach;
638 for (base = attach = NULL; *seq; seq++)
640 p = g_new (key_def, 1);
641 if (base == NULL)
642 base = p;
643 if (attach != NULL)
644 attach->child = p;
646 p->ch = *seq;
647 p->code = code;
648 p->child = p->next = NULL;
649 if (seq[1] == '\0')
650 p->action = action;
651 else
652 p->action = MCKEY_NOACTION;
653 attach = p;
655 return base;
658 /* --------------------------------------------------------------------------------------------- */
660 static void
661 define_sequences (const key_define_t * kd)
663 int i;
665 for (i = 0; kd[i].code != 0; i++)
666 define_sequence (kd[i].code, kd[i].seq, kd[i].action);
669 /* --------------------------------------------------------------------------------------------- */
671 #ifdef HAVE_TEXTMODE_X11_SUPPORT
672 static void
673 init_key_x11 (void)
675 if (getenv ("DISPLAY") != NULL && !mc_global.tty.disable_x11)
677 x11_display = mc_XOpenDisplay (0);
679 if (x11_display != NULL)
680 x11_window = DefaultRootWindow (x11_display);
683 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
685 /* --------------------------------------------------------------------------------------------- */
686 /* Workaround for System V Curses vt100 bug */
688 static int
689 getch_with_delay (void)
691 int c;
693 /* This routine could be used on systems without mouse support,
694 so we need to do the select check :-( */
695 while (1)
697 if (pending_keys == NULL)
698 try_channels (0);
700 /* Try to get a character */
701 c = get_key_code (0);
702 if (c != -1)
703 break;
704 /* Failed -> wait 0.1 secs and try again */
705 try_channels (1);
707 /* Success -> return the character */
708 return c;
711 /* --------------------------------------------------------------------------------------------- */
713 static void
714 xmouse_get_event (Gpm_Event * ev, gboolean extended)
716 static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
717 static struct timeval tv2;
718 static int clicks = 0;
719 static int last_btn = 0;
720 int btn;
722 /* Decode Xterm mouse information to a GPM style event */
724 if (!extended)
726 /* Variable btn has following meaning: */
727 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
728 btn = tty_lowlevel_getch () - 32;
729 /* Coordinates are 33-based */
730 /* Transform them to 1-based */
731 ev->x = tty_lowlevel_getch () - 32;
732 ev->y = tty_lowlevel_getch () - 32;
734 else
736 /* SGR 1006 extension (e.g. "\e[<0;12;300M"):
737 - Numbers are encoded in decimal to make it ASCII-safe
738 and to overcome the limit of 223 columns/rows.
739 - Mouse release is encoded by trailing 'm' rather than 'M'
740 so that the released button can be reported.
741 - Numbers are no longer offset by 32. */
742 char c;
743 btn = ev->x = ev->y = 0;
744 ev->type = 0; /* In case we return on an invalid sequence */
745 while ((c = tty_lowlevel_getch ()) != ';')
747 if (c < '0' || c > '9')
748 return;
749 btn = 10 * btn + (c - '0');
751 while ((c = tty_lowlevel_getch ()) != ';')
753 if (c < '0' || c > '9')
754 return;
755 ev->x = 10 * ev->x + (c - '0');
757 while ((c = tty_lowlevel_getch ()) != 'M' && c != 'm')
759 if (c < '0' || c > '9')
760 return;
761 ev->y = 10 * ev->y + (c - '0');
763 /* Legacy mouse protocol doesn't tell which button was released,
764 conveniently all of mc's widgets are written not to rely on this
765 information. With the SGR extension the released button becomes
766 known, but for the sake of simplicity we just ignore it. */
767 if (c == 'm')
768 btn = 3;
771 /* There seems to be no way of knowing which button was released */
772 /* So we assume all the buttons were released */
774 if (btn == 3)
776 if (last_btn != 0)
778 if ((last_btn & (GPM_B_UP | GPM_B_DOWN)) != 0)
780 /* FIXME: DIRTY HACK */
781 /* don't generate GPM_UP after mouse wheel */
782 /* need for menu event handling */
783 ev->type = 0;
784 tv1.tv_sec = 0;
785 tv1.tv_usec = 0;
787 else
789 ev->type = GPM_UP | (GPM_SINGLE << clicks);
790 GET_TIME (tv1);
792 ev->buttons = 0;
793 last_btn = 0;
794 clicks = 0;
796 else
798 /* Bogus event, maybe mouse wheel */
799 ev->type = 0;
802 else
804 if (btn >= 32 && btn <= 34)
806 btn -= 32;
807 ev->type = GPM_DRAG;
809 else
810 ev->type = GPM_DOWN;
812 GET_TIME (tv2);
813 if (tv1.tv_sec && (DIF_TIME (tv1, tv2) < double_click_speed))
815 clicks++;
816 clicks %= 3;
818 else
819 clicks = 0;
821 switch (btn)
823 case 0:
824 ev->buttons = GPM_B_LEFT;
825 break;
826 case 1:
827 ev->buttons = GPM_B_MIDDLE;
828 break;
829 case 2:
830 ev->buttons = GPM_B_RIGHT;
831 break;
832 case 64:
833 ev->buttons = GPM_B_UP;
834 clicks = 0;
835 break;
836 case 65:
837 ev->buttons = GPM_B_DOWN;
838 clicks = 0;
839 break;
840 default:
841 /* Nothing */
842 ev->type = 0;
843 ev->buttons = 0;
844 break;
846 last_btn = ev->buttons;
850 /* --------------------------------------------------------------------------------------------- */
852 * Get modifier state (shift, alt, ctrl) for the last key pressed.
853 * We are assuming that the state didn't change since the key press.
854 * This is only correct if get_modifier() is called very fast after
855 * the input was received, so that the user didn't release the
856 * modifier keys yet.
859 static int
860 get_modifier (void)
862 int result = 0;
863 #ifdef __QNXNTO__
864 int mod_status, shift_ext_status;
865 static int in_photon = 0;
866 static int ph_ig = 0;
867 PhCursorInfo_t cursor_info;
868 #endif /* __QNXNTO__ */
870 #ifdef HAVE_TEXTMODE_X11_SUPPORT
871 if (x11_window != 0)
873 Window root, child;
874 int root_x, root_y;
875 int win_x, win_y;
876 unsigned int mask;
878 mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x,
879 &root_y, &win_x, &win_y, &mask);
881 if (mask & ShiftMask)
882 result |= KEY_M_SHIFT;
883 if (mask & ControlMask)
884 result |= KEY_M_CTRL;
885 return result;
887 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
888 #ifdef __QNXNTO__
890 if (in_photon == 0)
892 /* First time here, let's load Photon library and attach
893 to Photon */
894 in_photon = -1;
895 if (getenv ("PHOTON2_PATH") != NULL)
897 /* QNX 6.x has no support for RTLD_LAZY */
898 void *ph_handle = dlopen ("/usr/lib/libph.so", RTLD_NOW);
899 if (ph_handle != NULL)
901 ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach");
902 ph_input_group = (ph_ov_f) dlsym (ph_handle, "PhInputGroup");
903 ph_query_cursor = (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor");
904 if ((ph_attach != NULL) && (ph_input_group != NULL) && (ph_query_cursor != NULL))
906 if ((*ph_attach) (0, 0))
907 { /* Attached */
908 ph_ig = (*ph_input_group) (0);
909 in_photon = 1;
915 /* We do not have Photon running. Assume we are in text
916 console or xterm */
917 if (in_photon == -1)
919 if (devctl (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status, sizeof (int), NULL) == -1)
920 return 0;
921 shift_ext_status = mod_status & 0xffffff00UL;
922 mod_status &= 0x7f;
923 if (mod_status & _LINESTATUS_CON_ALT)
924 result |= KEY_M_ALT;
925 if (mod_status & _LINESTATUS_CON_CTRL)
926 result |= KEY_M_CTRL;
927 if ((mod_status & _LINESTATUS_CON_SHIFT) || (shift_ext_status & 0x00000800UL))
928 result |= KEY_M_SHIFT;
930 else
932 (*ph_query_cursor) (ph_ig, &cursor_info);
933 if (cursor_info.key_mods & 0x04)
934 result |= KEY_M_ALT;
935 if (cursor_info.key_mods & 0x02)
936 result |= KEY_M_CTRL;
937 if (cursor_info.key_mods & 0x01)
938 result |= KEY_M_SHIFT;
940 #endif /* __QNXNTO__ */
942 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
944 unsigned char modifiers = 6;
946 if (ioctl (0, TIOCLINUX, &modifiers) < 0)
947 return 0;
949 /* Translate Linux modifiers into mc modifiers */
950 if (modifiers & SHIFT_PRESSED)
951 result |= KEY_M_SHIFT;
952 if (modifiers & (ALTL_PRESSED | ALTR_PRESSED))
953 result |= KEY_M_ALT;
954 if (modifiers & CONTROL_PRESSED)
955 result |= KEY_M_CTRL;
957 #endif /* !__linux__ */
958 return result;
961 /* --------------------------------------------------------------------------------------------- */
963 static gboolean
964 push_char (int c)
966 gboolean ret = FALSE;
968 if (seq_append == NULL)
969 seq_append = seq_buffer;
971 if (seq_append != &(seq_buffer[SEQ_BUFFER_LEN - 2]))
973 *(seq_append++) = c;
974 *seq_append = 0;
975 ret = TRUE;
978 return ret;
981 /* --------------------------------------------------------------------------------------------- */
982 /* Apply corrections for the keycode generated in get_key_code() */
984 static int
985 correct_key_code (int code)
987 unsigned int c = code & ~KEY_M_MASK; /* code without modifier */
988 unsigned int mod = code & KEY_M_MASK; /* modifier */
989 #ifdef __QNXNTO__
990 unsigned int qmod; /* bunch of the QNX console
991 modifiers needs unchanged */
992 #endif /* __QNXNTO__ */
995 * Add key modifiers directly from X11 or OS.
996 * Ordinary characters only get modifiers from sequences.
998 if (c < 32 || c >= 256)
1000 mod |= get_modifier ();
1003 /* This is needed if the newline is reported as carriage return */
1004 if (c == '\r')
1005 c = '\n';
1007 /* This is reported to be useful on AIX */
1008 if (c == KEY_SCANCEL)
1009 c = '\t';
1011 /* Convert Shift+Tab and Ctrl+Tab to Back Tab
1012 * only if modifiers directly from X11
1014 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1015 if (x11_window != 0)
1016 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
1018 if ((c == '\t') && (mod & (KEY_M_SHIFT | KEY_M_CTRL)))
1020 c = KEY_BTAB;
1021 mod = 0;
1025 /* F0 is the same as F10 for out purposes */
1026 if (c == KEY_F (0))
1027 c = KEY_F (10);
1030 * We are not interested if Ctrl was pressed when entering control
1031 * characters, so assume that it was. When checking for such keys,
1032 * XCTRL macro should be used. In some cases, we are interested,
1033 * e.g. to distinguish Ctrl-Enter from Enter.
1035 if (c == '\b')
1037 /* Special case for backspase ('\b' < 32) */
1038 c = KEY_BACKSPACE;
1039 mod &= ~KEY_M_CTRL;
1041 else if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n')
1043 mod |= KEY_M_CTRL;
1046 #ifdef __QNXNTO__
1047 qmod = get_modifier ();
1049 if ((c == 127) && (mod == 0))
1050 { /* Add Ctrl/Alt/Shift-BackSpace */
1051 mod |= get_modifier ();
1052 c = KEY_BACKSPACE;
1055 if ((c == '0') && (mod == 0))
1056 { /* Add Shift-Insert on key pad */
1057 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1059 mod = KEY_M_SHIFT;
1060 c = KEY_IC;
1064 if ((c == '.') && (mod == 0))
1065 { /* Add Shift-Del on key pad */
1066 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1068 mod = KEY_M_SHIFT;
1069 c = KEY_DC;
1072 #endif /* __QNXNTO__ */
1074 /* Unrecognized 0177 is delete (preserve Ctrl) */
1075 if (c == 0177)
1077 c = KEY_BACKSPACE;
1080 #if 0
1081 /* Unrecognized Ctrl-d is delete */
1082 if (c == (31 & 'd'))
1084 c = KEY_DC;
1085 mod &= ~KEY_M_CTRL;
1088 /* Unrecognized Ctrl-h is backspace */
1089 if (c == (31 & 'h'))
1091 c = KEY_BACKSPACE;
1092 mod &= ~KEY_M_CTRL;
1094 #endif
1096 /* Shift+BackSpace is backspace */
1097 if (c == KEY_BACKSPACE && (mod & KEY_M_SHIFT))
1099 mod &= ~KEY_M_SHIFT;
1102 /* Convert Shift+Fn to F(n+10) */
1103 if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT))
1105 c += 10;
1108 /* Remove Shift information from function keys */
1109 if (c >= KEY_F (1) && c <= KEY_F (20))
1111 mod &= ~KEY_M_SHIFT;
1114 if (!mc_global.tty.alternate_plus_minus)
1115 switch (c)
1117 case KEY_KP_ADD:
1118 c = '+';
1119 break;
1120 case KEY_KP_SUBTRACT:
1121 c = '-';
1122 break;
1123 case KEY_KP_MULTIPLY:
1124 c = '*';
1125 break;
1128 return (mod | c);
1131 /* --------------------------------------------------------------------------------------------- */
1133 static int
1134 getch_with_timeout (unsigned int delay_us)
1136 fd_set Read_FD_Set;
1137 int c;
1138 struct timeval time_out;
1140 time_out.tv_sec = delay_us / 1000000u;
1141 time_out.tv_usec = delay_us % 1000000u;
1142 tty_nodelay (TRUE);
1143 FD_ZERO (&Read_FD_Set);
1144 FD_SET (input_fd, &Read_FD_Set);
1145 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
1146 c = tty_lowlevel_getch ();
1147 tty_nodelay (FALSE);
1148 return c;
1151 /* --------------------------------------------------------------------------------------------- */
1153 static void
1154 learn_store_key (char *buffer, char **p, int c)
1156 if (*p - buffer > 253)
1157 return;
1158 if (c == ESC_CHAR)
1160 *(*p)++ = '\\';
1161 *(*p)++ = 'e';
1163 else if (c < ' ')
1165 *(*p)++ = '^';
1166 *(*p)++ = c + 'a' - 1;
1168 else if (c == '^')
1170 *(*p)++ = '^';
1171 *(*p)++ = '^';
1173 else
1174 *(*p)++ = (char) c;
1177 /* --------------------------------------------------------------------------------------------- */
1179 static void
1180 k_dispose (key_def * k)
1182 if (k != NULL)
1184 k_dispose (k->child);
1185 k_dispose (k->next);
1186 g_free (k);
1190 /* --------------------------------------------------------------------------------------------- */
1192 static void
1193 s_dispose (SelectList * sel)
1195 if (sel != NULL)
1197 s_dispose (sel->next);
1198 g_free (sel);
1202 /* --------------------------------------------------------------------------------------------- */
1204 static int
1205 key_code_comparator_by_name (const void *p1, const void *p2)
1207 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1208 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1210 return g_ascii_strcasecmp (n1->name, n2->name);
1213 /* --------------------------------------------------------------------------------------------- */
1215 static int
1216 key_code_comparator_by_code (const void *p1, const void *p2)
1218 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1219 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1221 return n1->code - n2->code;
1224 /* --------------------------------------------------------------------------------------------- */
1226 static inline void
1227 sort_key_conv_tab (enum KeySortType type_sort)
1229 if (has_been_sorted != type_sort)
1231 size_t i;
1232 for (i = 0; i < key_conv_tab_size; i++)
1233 key_conv_tab_sorted[i] = &key_name_conv_tab[i];
1235 if (type_sort == KEY_SORTBYNAME)
1237 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1238 &key_code_comparator_by_name);
1240 else if (type_sort == KEY_SORTBYCODE)
1242 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1243 &key_code_comparator_by_code);
1245 has_been_sorted = type_sort;
1249 /* --------------------------------------------------------------------------------------------- */
1251 static int
1252 lookup_keyname (const char *name, int *idx)
1254 if (name[0] != '\0')
1256 const key_code_name_t key = { 0, name, NULL, NULL };
1257 const key_code_name_t *keyp = &key;
1258 key_code_name_t **res;
1260 if (name[1] == '\0')
1262 *idx = -1;
1263 return (int) name[0];
1266 sort_key_conv_tab (KEY_SORTBYNAME);
1268 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1269 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_name);
1271 if (res != NULL)
1273 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1274 return (*res)->code;
1278 *idx = -1;
1279 return 0;
1282 /* --------------------------------------------------------------------------------------------- */
1284 static gboolean
1285 lookup_keycode (const long code, int *idx)
1287 if (code != 0)
1289 const key_code_name_t key = { code, NULL, NULL, NULL };
1290 const key_code_name_t *keyp = &key;
1291 key_code_name_t **res;
1293 sort_key_conv_tab (KEY_SORTBYCODE);
1295 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1296 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_code);
1298 if (res != NULL)
1300 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1301 return TRUE;
1305 *idx = -1;
1306 return FALSE;
1309 /* --------------------------------------------------------------------------------------------- */
1310 /*** public functions ****************************************************************************/
1311 /* --------------------------------------------------------------------------------------------- */
1312 /* This has to be called before init_slang or whatever routine
1313 calls any define_sequence */
1315 void
1316 init_key (void)
1318 const char *term = getenv ("TERM");
1320 /* This has to be the first define_sequence */
1321 /* So, we can assume that the first keys member has ESC */
1322 define_sequences (mc_default_keys);
1324 /* Terminfo on irix does not have some keys */
1325 if (mc_global.tty.xterm_flag
1326 || (term != NULL
1327 && (strncmp (term, "iris-ansi", 9) == 0
1328 || strncmp (term, "xterm", 5) == 0
1329 || strncmp (term, "rxvt", 4) == 0 || strcmp (term, "screen") == 0)))
1330 define_sequences (xterm_key_defines);
1332 /* load some additional keys (e.g. direct Alt-? support) */
1333 load_xtra_key_defines ();
1335 #ifdef __QNX__
1336 if ((term != NULL) && (strncmp (term, "qnx", 3) == 0))
1338 /* Modify the default value of use_8th_bit_as_meta: we would
1339 * like to provide a working mc for a newbie who knows nothing
1340 * about [Options|Display bits|Full 8 bits input]...
1342 * Don't use 'meta'-bit, when we are dealing with a
1343 * 'qnx*'-type terminal: clear the default value!
1344 * These terminal types use 0xFF as an escape character,
1345 * so use_8th_bit_as_meta==1 must not be enabled!
1347 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1348 * is not used now (doesn't even depend on use_8th_bit_as_meta
1349 * as in mc-3.1.2)...GREAT!...no additional code is required!]
1351 use_8th_bit_as_meta = 0;
1353 #endif /* __QNX__ */
1355 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1356 init_key_x11 ();
1357 #endif
1359 /* Load the qansi-m key definitions
1360 if we are running under the qansi-m terminal */
1361 if (term != NULL && (strncmp (term, "qansi-m", 7) == 0))
1362 define_sequences (qansi_key_defines);
1365 /* --------------------------------------------------------------------------------------------- */
1367 * This has to be called after SLang_init_tty/slint_init
1370 void
1371 init_key_input_fd (void)
1373 #ifdef HAVE_SLANG
1374 input_fd = SLang_TT_Read_FD;
1375 #endif
1378 /* --------------------------------------------------------------------------------------------- */
1380 void
1381 done_key (void)
1383 k_dispose (keys);
1384 s_dispose (select_list);
1386 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1387 if (x11_display)
1388 mc_XCloseDisplay (x11_display);
1389 #endif
1392 /* --------------------------------------------------------------------------------------------- */
1394 void
1395 add_select_channel (int fd, select_fn callback, void *info)
1397 SelectList *new;
1399 new = g_new (SelectList, 1);
1400 new->fd = fd;
1401 new->callback = callback;
1402 new->info = info;
1403 new->next = select_list;
1404 select_list = new;
1407 /* --------------------------------------------------------------------------------------------- */
1409 void
1410 delete_select_channel (int fd)
1412 SelectList *p = select_list;
1413 SelectList *p_prev = NULL;
1414 SelectList *p_next;
1416 while (p != NULL)
1417 if (p->fd == fd)
1419 p_next = p->next;
1421 if (p_prev != NULL)
1422 p_prev->next = p_next;
1423 else
1424 select_list = p_next;
1426 g_free (p);
1427 p = p_next;
1429 else
1431 p_prev = p;
1432 p = p->next;
1436 /* --------------------------------------------------------------------------------------------- */
1438 void
1439 channels_up (void)
1441 if (disabled_channels == 0)
1442 fputs ("Error: channels_up called with disabled_channels = 0\n", stderr);
1443 disabled_channels--;
1446 /* --------------------------------------------------------------------------------------------- */
1448 void
1449 channels_down (void)
1451 disabled_channels++;
1454 /* --------------------------------------------------------------------------------------------- */
1456 * Return the code associated with the symbolic name keyname
1459 long
1460 lookup_key (const char *name, char **label)
1462 char **lc_keys, **p;
1463 int k = -1;
1464 int key = 0;
1465 int lc_index = -1;
1467 int use_meta = -1;
1468 int use_ctrl = -1;
1469 int use_shift = -1;
1471 if (name == NULL)
1472 return 0;
1474 name = g_strstrip (g_strdup (name));
1475 p = lc_keys = g_strsplit_set (name, "-+ ", -1);
1476 g_free ((char *) name);
1478 while ((p != NULL) && (*p != NULL))
1480 if ((*p)[0] != '\0')
1482 int idx;
1484 key = lookup_keyname (g_strstrip (*p), &idx);
1486 if (key == KEY_M_ALT)
1487 use_meta = idx;
1488 else if (key == KEY_M_CTRL)
1489 use_ctrl = idx;
1490 else if (key == KEY_M_SHIFT)
1491 use_shift = idx;
1492 else
1494 k = key;
1495 lc_index = idx;
1496 break;
1500 p++;
1503 g_strfreev (lc_keys);
1505 /* output */
1506 if (k <= 0)
1507 return 0;
1510 if (label != NULL)
1512 GString *s;
1514 s = g_string_new ("");
1516 if (use_meta != -1)
1518 g_string_append (s, key_conv_tab_sorted[use_meta]->shortcut);
1519 g_string_append_c (s, '-');
1521 if (use_ctrl != -1)
1523 g_string_append (s, key_conv_tab_sorted[use_ctrl]->shortcut);
1524 g_string_append_c (s, '-');
1526 if (use_shift != -1)
1528 if (k < 127)
1529 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1530 else
1532 g_string_append (s, key_conv_tab_sorted[use_shift]->shortcut);
1533 g_string_append_c (s, '-');
1534 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1537 else if (k < 128)
1539 if ((k >= 'A') || (lc_index < 0) || (key_conv_tab_sorted[lc_index]->shortcut == NULL))
1540 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) k));
1541 else
1542 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1544 else if ((lc_index != -1) && (key_conv_tab_sorted[lc_index]->shortcut != NULL))
1545 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1546 else
1547 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) key));
1549 *label = g_string_free (s, FALSE);
1552 if (use_shift != -1)
1554 if (k < 127 && k > 31)
1555 k = g_ascii_toupper ((gchar) k);
1556 else
1557 k |= KEY_M_SHIFT;
1560 if (use_ctrl != -1)
1562 if (k < 256)
1563 k = XCTRL (k);
1564 else
1565 k |= KEY_M_CTRL;
1568 if (use_meta != -1)
1569 k = ALT (k);
1571 return (long) k;
1574 /* --------------------------------------------------------------------------------------------- */
1576 char *
1577 lookup_key_by_code (const int keycode)
1579 /* code without modifier */
1580 unsigned int k = keycode & ~KEY_M_MASK;
1581 /* modifier */
1582 unsigned int mod = keycode & KEY_M_MASK;
1584 int use_meta = -1;
1585 int use_ctrl = -1;
1586 int use_shift = -1;
1587 int key_idx = -1;
1589 GString *s;
1590 int idx;
1592 s = g_string_sized_new (8);
1594 if (lookup_keycode (k, &key_idx) || (k > 0 && k < 256))
1596 if (mod & KEY_M_ALT)
1598 if (lookup_keycode (KEY_M_ALT, &idx))
1600 use_meta = idx;
1601 g_string_append (s, key_conv_tab_sorted[use_meta]->name);
1602 g_string_append_c (s, '-');
1605 if (mod & KEY_M_CTRL)
1607 /* non printeble chars like a CTRL-[A..Z] */
1608 if (k < 32)
1609 k += 64;
1611 if (lookup_keycode (KEY_M_CTRL, &idx))
1613 use_ctrl = idx;
1614 g_string_append (s, key_conv_tab_sorted[use_ctrl]->name);
1615 g_string_append_c (s, '-');
1618 if (mod & KEY_M_SHIFT)
1620 if (lookup_keycode (KEY_M_ALT, &idx))
1622 use_shift = idx;
1623 if (k < 127)
1624 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1625 else
1627 g_string_append (s, key_conv_tab_sorted[use_shift]->name);
1628 g_string_append_c (s, '-');
1629 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1633 else if (k < 128)
1635 if ((k >= 'A') || (key_idx < 0) || (key_conv_tab_sorted[key_idx]->name == NULL))
1636 g_string_append_c (s, (gchar) k);
1637 else
1638 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1640 else if ((key_idx != -1) && (key_conv_tab_sorted[key_idx]->name != NULL))
1641 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1642 else
1643 g_string_append_c (s, (gchar) keycode);
1646 return g_string_free (s, s->len == 0);
1649 /* --------------------------------------------------------------------------------------------- */
1651 * Return TRUE on success, FALSE on error.
1652 * An error happens if SEQ is a beginning of an existing longer sequence.
1655 gboolean
1656 define_sequence (int code, const char *seq, int action)
1658 key_def *base;
1660 if (strlen (seq) > SEQ_BUFFER_LEN - 1)
1661 return FALSE;
1663 for (base = keys; (base != NULL) && (*seq != '\0');)
1664 if (*seq == base->ch)
1666 if (base->child == 0)
1668 if (*(seq + 1) != '\0')
1669 base->child = create_sequence (seq + 1, code, action);
1670 else
1672 /* The sequence matches an existing one. */
1673 base->code = code;
1674 base->action = action;
1676 return TRUE;
1679 base = base->child;
1680 seq++;
1682 else
1684 if (base->next)
1685 base = base->next;
1686 else
1688 base->next = create_sequence (seq, code, action);
1689 return TRUE;
1693 if (*seq == '\0')
1695 /* Attempt to redefine a sequence with a shorter sequence. */
1696 return FALSE;
1699 keys = create_sequence (seq, code, action);
1700 return TRUE;
1703 /* --------------------------------------------------------------------------------------------- */
1705 * Check if we are idle, i.e. there are no pending keyboard or mouse
1706 * events. Return 1 is idle, 0 is there are pending events.
1708 gboolean
1709 is_idle (void)
1711 int maxfdp;
1712 fd_set select_set;
1713 struct timeval time_out;
1715 FD_ZERO (&select_set);
1716 FD_SET (input_fd, &select_set);
1717 maxfdp = input_fd;
1718 #ifdef HAVE_LIBGPM
1719 if (mouse_enabled && (use_mouse_p == MOUSE_GPM) && (gpm_fd > 0))
1721 FD_SET (gpm_fd, &select_set);
1722 maxfdp = max (maxfdp, gpm_fd);
1724 #endif
1725 time_out.tv_sec = 0;
1726 time_out.tv_usec = 0;
1727 return (select (maxfdp + 1, &select_set, 0, 0, &time_out) <= 0);
1730 /* --------------------------------------------------------------------------------------------- */
1733 get_key_code (int no_delay)
1735 int c;
1736 static key_def *this = NULL, *parent;
1737 static struct timeval esctime = { -1, -1 };
1738 static int lastnodelay = -1;
1740 if (no_delay != lastnodelay)
1742 this = NULL;
1743 lastnodelay = no_delay;
1746 pend_send:
1747 if (pending_keys != NULL)
1749 int d;
1750 gboolean bad_seq;
1752 d = *pending_keys++;
1753 while (d == ESC_CHAR)
1754 d = ALT (*pending_keys++);
1756 bad_seq = (*pending_keys != ESC_CHAR && *pending_keys != 0);
1757 if (*pending_keys == '\0' || bad_seq)
1758 pending_keys = seq_append = NULL;
1760 if (bad_seq)
1762 /* This is an unknown ESC sequence.
1763 * To prevent interpreting its tail as a random garbage,
1764 * eat and discard all buffered and quickly following chars.
1765 * Small, but non-zero timeout is needed to reconnect
1766 * escape sequence split up by e.g. a serial line.
1768 int paranoia = 20;
1770 while (getch_with_timeout (old_esc_mode_timeout) >= 0 && --paranoia != 0)
1772 goto nodelay_try_again;
1775 if (d > 127 && d < 256 && use_8th_bit_as_meta)
1776 d = ALT (d & 0x7f);
1778 this = NULL;
1779 return correct_key_code (d);
1782 nodelay_try_again:
1783 if (no_delay)
1784 tty_nodelay (TRUE);
1786 c = tty_lowlevel_getch ();
1787 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1788 if (c == KEY_RESIZE)
1789 goto nodelay_try_again;
1790 #endif
1791 if (no_delay)
1793 tty_nodelay (FALSE);
1794 if (c == -1)
1796 if (this != NULL && parent != NULL && parent->action == MCKEY_ESCAPE && old_esc_mode)
1798 struct timeval current, time_out;
1800 if (esctime.tv_sec == -1)
1801 return -1;
1802 GET_TIME (current);
1803 time_out.tv_sec = old_esc_mode_timeout / 1000000 + esctime.tv_sec;
1804 time_out.tv_usec = old_esc_mode_timeout % 1000000 + esctime.tv_usec;
1805 if (time_out.tv_usec > 1000000)
1807 time_out.tv_usec -= 1000000;
1808 time_out.tv_sec++;
1810 if (current.tv_sec < time_out.tv_sec)
1811 return -1;
1812 if (current.tv_sec == time_out.tv_sec && current.tv_usec < time_out.tv_usec)
1813 return -1;
1814 this = NULL;
1815 pending_keys = seq_append = NULL;
1816 return ESC_CHAR;
1818 return -1;
1821 else if (c == -1)
1823 /* Maybe we got an incomplete match.
1824 This we do only in delay mode, since otherwise
1825 tty_lowlevel_getch can return -1 at any time. */
1826 if (seq_append != NULL)
1828 pending_keys = seq_buffer;
1829 goto pend_send;
1831 this = NULL;
1832 return -1;
1835 /* Search the key on the root */
1836 if (!no_delay || this == NULL)
1838 this = keys;
1839 parent = NULL;
1841 if ((c > 127 && c < 256) && use_8th_bit_as_meta)
1843 c &= 0x7f;
1845 /* The first sequence defined starts with esc */
1846 parent = keys;
1847 this = keys->child;
1851 while (this != NULL)
1853 if (c == this->ch)
1855 if (this->child == NULL)
1857 /* We got a complete match, return and reset search */
1858 int code;
1860 pending_keys = seq_append = NULL;
1861 code = this->code;
1862 this = NULL;
1863 return correct_key_code (code);
1865 /* No match yet, but it may be a prefix for a valid seq */
1866 if (!push_char (c))
1868 pending_keys = seq_buffer;
1869 goto pend_send;
1871 parent = this;
1872 this = this->child;
1873 if (parent->action == MCKEY_ESCAPE && old_esc_mode)
1875 if (no_delay)
1877 GET_TIME (esctime);
1878 goto nodelay_try_again;
1880 esctime.tv_sec = -1;
1881 c = getch_with_timeout (old_esc_mode_timeout);
1882 if (c == -1)
1884 pending_keys = seq_append = NULL;
1885 this = NULL;
1886 return ESC_CHAR;
1888 continue;
1890 if (no_delay)
1891 goto nodelay_try_again;
1892 c = tty_lowlevel_getch ();
1893 continue;
1896 /* c != this->ch. Try other keys with this prefix */
1897 if (this->next != NULL)
1899 this = this->next;
1900 continue;
1903 /* No match found. Is it one of our ESC <key> specials? */
1904 if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
1906 /* Convert escape-digits to F-keys */
1907 if (g_ascii_isdigit (c))
1908 c = KEY_F (c - '0');
1909 else if (c == ' ')
1910 c = ESC_CHAR;
1911 else
1912 c = ALT (c);
1914 pending_keys = seq_append = NULL;
1915 this = NULL;
1916 return correct_key_code (c);
1919 /* Unknown sequence. Maybe a prefix of a longer one. Save it. */
1920 push_char (c);
1921 pending_keys = seq_buffer;
1922 goto pend_send;
1924 } /* while (this != NULL) */
1926 this = NULL;
1927 return correct_key_code (c);
1930 /* --------------------------------------------------------------------------------------------- */
1931 /* Returns a character read from stdin with appropriate interpretation */
1932 /* Also takes care of generated mouse events */
1933 /* Returns EV_MOUSE if it is a mouse event */
1934 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
1937 tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block)
1939 int c;
1940 static int flag = 0; /* Return value from select */
1941 #ifdef HAVE_LIBGPM
1942 static struct Gpm_Event ev; /* Mouse event */
1943 #endif
1944 struct timeval time_out;
1945 struct timeval *time_addr = NULL;
1946 static int dirty = 3;
1948 if ((dirty == 3) || is_idle ())
1950 mc_refresh ();
1951 dirty = 1;
1953 else
1954 dirty++;
1956 vfs_timeout_handler ();
1958 /* Ok, we use (event->x < 0) to signal that the event does not contain
1959 a suitable position for the mouse, so we can't use show_mouse_pointer
1960 on it.
1962 if (event->x > 0)
1964 show_mouse_pointer (event->x, event->y);
1965 if (!redo_event)
1966 event->x = -1;
1969 /* Repeat if using mouse */
1970 while (pending_keys == NULL)
1972 int maxfdp;
1973 fd_set select_set;
1975 FD_ZERO (&select_set);
1976 FD_SET (input_fd, &select_set);
1977 maxfdp = max (add_selects (&select_set), input_fd);
1979 #ifdef HAVE_LIBGPM
1980 if (mouse_enabled && (use_mouse_p == MOUSE_GPM))
1982 if (gpm_fd < 0)
1984 /* Connection to gpm broken, possibly gpm has died */
1985 mouse_enabled = FALSE;
1986 use_mouse_p = MOUSE_NONE;
1987 break;
1990 FD_SET (gpm_fd, &select_set);
1991 maxfdp = max (maxfdp, gpm_fd);
1993 #endif
1995 if (redo_event)
1997 time_out.tv_usec = mou_auto_repeat * 1000;
1998 time_out.tv_sec = 0;
2000 time_addr = &time_out;
2002 else
2004 int seconds;
2006 seconds = vfs_timeouts ();
2007 time_addr = NULL;
2009 if (seconds != 0)
2011 /* the timeout could be improved and actually be
2012 * the number of seconds until the next vfs entry
2013 * timeouts in the stamp list.
2016 time_out.tv_sec = seconds;
2017 time_out.tv_usec = 0;
2018 time_addr = &time_out;
2022 if (!block || mc_global.tty.winch_flag != 0)
2024 time_addr = &time_out;
2025 time_out.tv_sec = 0;
2026 time_out.tv_usec = 0;
2029 tty_enable_interrupt_key ();
2030 flag = select (maxfdp + 1, &select_set, NULL, NULL, time_addr);
2031 tty_disable_interrupt_key ();
2033 /* select timed out: it could be for any of the following reasons:
2034 * redo_event -> it was because of the MOU_REPEAT handler
2035 * !block -> we did not block in the select call
2036 * else -> 10 second timeout to check the vfs status.
2038 if (flag == 0)
2040 if (redo_event)
2041 return EV_MOUSE;
2042 if (!block || mc_global.tty.winch_flag != 0)
2043 return EV_NONE;
2044 vfs_timeout_handler ();
2046 if (flag == -1 && errno == EINTR)
2047 return EV_NONE;
2049 check_selects (&select_set);
2051 if (FD_ISSET (input_fd, &select_set))
2052 break;
2053 #ifdef HAVE_LIBGPM
2054 if (mouse_enabled && use_mouse_p == MOUSE_GPM
2055 && gpm_fd > 0 && FD_ISSET (gpm_fd, &select_set))
2057 Gpm_GetEvent (&ev);
2058 Gpm_FitEvent (&ev);
2059 *event = ev;
2060 return EV_MOUSE;
2062 #endif /* !HAVE_LIBGPM */
2065 #ifndef HAVE_SLANG
2066 flag = is_wintouched (stdscr);
2067 untouchwin (stdscr);
2068 #endif /* !HAVE_SLANG */
2069 c = block ? getch_with_delay () : get_key_code (1);
2071 #ifndef HAVE_SLANG
2072 if (flag > 0)
2073 tty_touch_screen ();
2074 #endif /* !HAVE_SLANG */
2076 if (mouse_enabled && (c == MCKEY_MOUSE
2077 #ifdef KEY_MOUSE
2078 || c == KEY_MOUSE
2079 #endif /* KEY_MOUSE */
2080 || c == MCKEY_EXTENDED_MOUSE))
2082 /* Mouse event */
2083 xmouse_get_event (event, c == MCKEY_EXTENDED_MOUSE);
2084 return (event->type != 0) ? EV_MOUSE : EV_NONE;
2087 return c;
2090 /* --------------------------------------------------------------------------------------------- */
2091 /* Returns a key press, mouse events are discarded */
2094 tty_getch (void)
2096 Gpm_Event ev;
2097 int key;
2099 ev.x = -1;
2100 while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE);
2101 return key;
2104 /* --------------------------------------------------------------------------------------------- */
2106 char *
2107 learn_key (void)
2109 /* LEARN_TIMEOUT in usec */
2110 #define LEARN_TIMEOUT 200000
2112 fd_set Read_FD_Set;
2113 struct timeval endtime;
2114 struct timeval time_out;
2115 int c;
2116 char buffer[256];
2117 char *p = buffer;
2119 tty_keypad (FALSE); /* disable intepreting keys by ncurses */
2120 c = tty_lowlevel_getch ();
2121 while (c == -1)
2122 c = tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
2123 learn_store_key (buffer, &p, c);
2124 GET_TIME (endtime);
2125 endtime.tv_usec += LEARN_TIMEOUT;
2126 if (endtime.tv_usec > 1000000)
2128 endtime.tv_usec -= 1000000;
2129 endtime.tv_sec++;
2131 tty_nodelay (TRUE);
2132 while (TRUE)
2134 while ((c = tty_lowlevel_getch ()) == -1)
2136 GET_TIME (time_out);
2137 time_out.tv_usec = endtime.tv_usec - time_out.tv_usec;
2138 if (time_out.tv_usec < 0)
2139 time_out.tv_sec++;
2140 time_out.tv_sec = endtime.tv_sec - time_out.tv_sec;
2141 if (time_out.tv_sec >= 0 && time_out.tv_usec > 0)
2143 FD_ZERO (&Read_FD_Set);
2144 FD_SET (input_fd, &Read_FD_Set);
2145 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
2147 else
2148 break;
2150 if (c == -1)
2151 break;
2152 learn_store_key (buffer, &p, c);
2154 tty_keypad (TRUE);
2155 tty_nodelay (FALSE);
2156 *p = '\0';
2157 return g_strdup (buffer);
2158 #undef LEARN_TIMEOUT
2161 /* --------------------------------------------------------------------------------------------- */
2162 /* xterm and linux console only: set keypad to numeric or application
2163 mode. Only in application keypad mode it's possible to distinguish
2164 the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2166 void
2167 numeric_keypad_mode (void)
2169 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2171 fputs (ESC_STR ">", stdout);
2172 fflush (stdout);
2176 /* --------------------------------------------------------------------------------------------- */
2178 void
2179 application_keypad_mode (void)
2181 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2183 fputs (ESC_STR "=", stdout);
2184 fflush (stdout);
2188 /* --------------------------------------------------------------------------------------------- */