Merge branch '2206_jump_line'
[midnight-commander.git] / lib / tty / key.c
blob0d15a796079b8e88e2eb4e89b8510d0751875a89
1 /*
2 Keyboard support routines.
4 Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
5 2005, 2006, 2007, 2009, 2010, 2011
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
14 This file is part of the Midnight Commander.
16 The Midnight Commander is free software: you can redistribute it
17 and/or modify it under the terms of the GNU General Public License as
18 published by the Free Software Foundation, either version 3 of the License,
19 or (at your option) any later version.
21 The Midnight Commander is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU General Public License for more details.
26 You should have received a copy of the GNU General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
30 /** \file key.c
31 * \brief Source: keyboard support routines
34 #include <config.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/time.h>
42 #include <sys/types.h>
43 #include <unistd.h>
45 #include "lib/global.h"
47 #include "lib/vfs/vfs.h"
49 #include "tty.h"
50 #include "tty-internal.h" /* mouse_enabled */
51 #include "mouse.h"
52 #include "key.h"
54 #include "lib/widget.h" /* mc_refresh() */
56 #ifdef HAVE_TEXTMODE_X11_SUPPORT
57 #include "x11conn.h"
58 #endif
60 #ifdef __linux__
61 #if defined(__GLIBC__) && (__GLIBC__ < 2)
62 #include <linux/termios.h> /* TIOCLINUX */
63 #else
64 #include <termios.h>
65 #endif
66 #ifdef HAVE_SYS_IOCTL_H
67 #include <sys/ioctl.h>
68 #endif
69 #endif /* __linux__ */
71 #ifdef __CYGWIN__
72 #include <termios.h>
73 #ifdef HAVE_SYS_IOCTL_H
74 #include <sys/ioctl.h>
75 #endif
76 #endif /* __CYGWIN__ */
78 #ifdef __QNXNTO__
79 #include <dlfcn.h>
80 #include <Ph.h>
81 #include <sys/dcmd_chr.h>
82 #endif /* __QNXNTO__ */
84 /*** global variables ****************************************************************************/
86 int mou_auto_repeat = 100;
87 int double_click_speed = 250;
88 int old_esc_mode = 0;
89 /* timeout for old_esc_mode in usec */
90 int old_esc_mode_timeout = 1000000; /* settable via env */
91 int use_8th_bit_as_meta = 0;
93 /* This table is a mapping between names and the constants we use
94 * We use this to allow users to define alternate definitions for
95 * certain keys that may be missing from the terminal database
97 const key_code_name_t key_name_conv_tab[] = {
98 /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
99 to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
100 {KEY_F (1), "f1", N_("Function key 1"), "F1"},
101 {KEY_F (2), "f2", N_("Function key 2"), "F2"},
102 {KEY_F (3), "f3", N_("Function key 3"), "F3"},
103 {KEY_F (4), "f4", N_("Function key 4"), "F4"},
104 {KEY_F (5), "f5", N_("Function key 5"), "F5"},
105 {KEY_F (6), "f6", N_("Function key 6"), "F6"},
106 {KEY_F (7), "f7", N_("Function key 7"), "F7"},
107 {KEY_F (8), "f8", N_("Function key 8"), "F8"},
108 {KEY_F (9), "f9", N_("Function key 9"), "F9"},
109 {KEY_F (10), "f10", N_("Function key 10"), "F10"},
110 {KEY_F (11), "f11", N_("Function key 11"), "F11"},
111 {KEY_F (12), "f12", N_("Function key 12"), "F12"},
112 {KEY_F (13), "f13", N_("Function key 13"), "F13"},
113 {KEY_F (14), "f14", N_("Function key 14"), "F14"},
114 {KEY_F (15), "f15", N_("Function key 15"), "F15"},
115 {KEY_F (16), "f16", N_("Function key 16"), "F16"},
116 {KEY_F (17), "f17", N_("Function key 17"), "F17"},
117 {KEY_F (18), "f18", N_("Function key 18"), "F18"},
118 {KEY_F (19), "f19", N_("Function key 19"), "F19"},
119 {KEY_F (20), "f20", N_("Function key 20"), "F20"},
120 {KEY_BACKSPACE, "backspace", N_("Backspace key"), "Backspace"},
121 {KEY_END, "end", N_("End key"), "End"},
122 {KEY_UP, "up", N_("Up arrow key"), "Up"},
123 {KEY_DOWN, "down", N_("Down arrow key"), "Down"},
124 {KEY_LEFT, "left", N_("Left arrow key"), "Left"},
125 {KEY_RIGHT, "right", N_("Right arrow key"), "Right"},
126 {KEY_HOME, "home", N_("Home key"), "Home"},
127 {KEY_NPAGE, "pgdn", N_("Page Down key"), "PgDn"},
128 {KEY_PPAGE, "pgup", N_("Page Up key"), "PgUp"},
129 {KEY_IC, "insert", N_("Insert key"), "Ins"},
130 {KEY_DC, "delete", N_("Delete key"), "Del"},
131 {ALT ('\t'), "complete", N_("Completion/M-tab"), "Meta-Tab"},
132 {KEY_BTAB, "backtab", N_("Back Tabulation S-tab"), "Shift-Tab"},
133 {KEY_KP_ADD, "kpplus", N_("+ on keypad"), "+"},
134 {KEY_KP_SUBTRACT, "kpminus", N_("- on keypad"), "-"},
135 {(int) '/', "kpslash", N_("Slash on keypad"), "/"},
136 {KEY_KP_MULTIPLY, "kpasterisk", N_("* on keypad"), "*"},
138 /* From here on, these won't be shown in Learn keys (no space) */
139 {ESC_CHAR, "escape", N_("Escape key"), "Esc"},
140 {KEY_LEFT, "kpleft", N_("Left arrow keypad"), "Left"},
141 {KEY_RIGHT, "kpright", N_("Right arrow keypad"), "Right"},
142 {KEY_UP, "kpup", N_("Up arrow keypad"), "Up"},
143 {KEY_DOWN, "kpdown", N_("Down arrow keypad"), "Down"},
144 {KEY_HOME, "kphome", N_("Home on keypad"), "Home"},
145 {KEY_END, "kpend", N_("End on keypad"), "End"},
146 {KEY_NPAGE, "kpnpage", N_("Page Down keypad"), "PgDn"},
147 {KEY_PPAGE, "kpppage", N_("Page Up keypad"), "PgUp"},
148 {KEY_IC, "kpinsert", N_("Insert on keypad"), "Ins"},
149 {KEY_DC, "kpdelete", N_("Delete on keypad"), "Del"},
150 {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
151 {KEY_F (21), "f21", N_("Function key 21"), "F21"},
152 {KEY_F (22), "f22", N_("Function key 22"), "F22"},
153 {KEY_F (23), "f23", N_("Function key 23"), "F23"},
154 {KEY_F (24), "f24", N_("Function key 24"), "F24"},
155 {KEY_A1, "a1", N_("A1 key"), "A1"},
156 {KEY_C1, "c1", N_("C1 key"), "C1"},
158 /* Alternative label */
159 {ESC_CHAR, "esc", N_("Escape key"), "Esc"},
160 {KEY_BACKSPACE, "bs", N_("Backspace key"), "Bakspace"},
161 {KEY_IC, "ins", N_("Insert key"), "Ins"},
162 {KEY_DC, "del", N_("Delete key"), "Del"},
163 {(int) '+', "plus", N_("Plus"), "+"},
164 {(int) '-', "minus", N_("Minus"), "-"},
165 {(int) '*', "asterisk", N_("Asterisk"), "*"},
166 {(int) '.', "dot", N_("Dot"), "."},
167 {(int) '<', "lt", N_("Less than"), "<"},
168 {(int) '>', "gt", N_("Great than"), ">"},
169 {(int) '=', "equal", N_("Equal"), "="},
170 {(int) ',', "comma", N_("Comma"), ","},
171 {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
172 {(int) ':', "colon", N_("Colon"), ":"},
173 {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
174 {(int) '?', "question", N_("Question mark"), "?"},
175 {(int) '&', "ampersand", N_("Ampersand"), "&"},
176 {(int) '$', "dollar", N_("Dollar sign"), "$"},
177 {(int) '"', "quota", N_("Quotation mark"), "\""},
178 {(int) '%', "percent", N_("Percent sign"), "%"},
179 {(int) '^', "caret", N_("Caret"), "^"},
180 {(int) '~', "tilda", N_("Tilda"), "~"},
181 {(int) '`', "prime", N_("Prime"), "`"},
182 {(int) '_', "underline", N_("Underline"), "_"},
183 {(int) '_', "understrike", N_("Understrike"), "_"},
184 {(int) '|', "pipe", N_("Pipe"), "|"},
185 {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
186 {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
187 {(int) '[', "lbracket", N_("Left bracket"), "["},
188 {(int) ']', "rbracket", N_("Right bracket"), "]"},
189 {(int) '{', "lbrace", N_("Left brace"), "{"},
190 {(int) '}', "rbrace", N_("Right brace"), "}"},
191 {(int) '\n', "enter", N_("Enter"), "Enter"},
192 {(int) '\t', "tab", N_("Tab key"), "Tab"},
193 {(int) ' ', "space", N_("Space key"), "Space"},
194 {(int) '/', "slash", N_("Slash key"), "/"},
195 {(int) '\\', "backslash", N_("Backslash key"), "\\"},
196 {(int) '#', "number", N_("Number sign #"), "#"},
197 {(int) '#', "hash", N_("Number sign #"), "#"},
198 /* TRANSLATORS: Please translate as in "at sign" (@). */
199 {(int) '@', "at", N_("At sign"), "@"},
201 /* meta keys */
202 {KEY_M_CTRL, "control", N_("Ctrl"), "C"},
203 {KEY_M_CTRL, "ctrl", N_("Ctrl"), "C"},
204 {KEY_M_ALT, "meta", N_("Alt"), "M"},
205 {KEY_M_ALT, "alt", N_("Alt"), "M"},
206 {KEY_M_ALT, "ralt", N_("Alt"), "M"},
207 {KEY_M_SHIFT, "shift", N_("Shift"), "S"},
209 {0, NULL, NULL, NULL}
212 /*** file scope macro definitions ****************************************************************/
214 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *) NULL))
215 #define DIF_TIME(t1, t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000)
217 /* The maximum sequence length (32 + null terminator) */
218 #define SEQ_BUFFER_LEN 33
220 /*** file scope type declarations ****************************************************************/
222 /* Linux console keyboard modifiers */
223 typedef enum
225 SHIFT_PRESSED = (1 << 0),
226 ALTR_PRESSED = (1 << 1),
227 CONTROL_PRESSED = (1 << 2),
228 ALTL_PRESSED = (1 << 3)
229 } mod_pressed_t;
231 typedef struct key_def
233 char ch; /* Holds the matching char code */
234 int code; /* The code returned, valid if child == NULL */
235 struct key_def *next;
236 struct key_def *child; /* sequence continuation */
237 int action; /* optional action to be done. Now used only
238 to mark that we are just after the first
239 Escape */
240 } key_def;
242 typedef struct
244 int code;
245 const char *seq;
246 int action;
247 } key_define_t;
249 /* File descriptor monitoring add/remove routines */
250 typedef struct SelectList
252 int fd;
253 select_fn callback;
254 void *info;
255 struct SelectList *next;
256 } SelectList;
258 typedef enum KeySortType
260 KEY_NOSORT = 0,
261 KEY_SORTBYNAME,
262 KEY_SORTBYCODE
263 } KeySortType;
265 #ifdef __QNXNTO__
266 typedef int (*ph_dv_f) (void *, void *);
267 typedef int (*ph_ov_f) (void *);
268 typedef int (*ph_pqc_f) (unsigned short, PhCursorInfo_t *);
269 #endif
271 /*** file scope variables ************************************************************************/
273 static key_define_t mc_default_keys[] = {
274 {ESC_CHAR, ESC_STR, MCKEY_ESCAPE},
275 {ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION},
276 {0, NULL, MCKEY_NOACTION},
279 /* Broken terminfo and termcap databases on xterminals */
280 static key_define_t xterm_key_defines[] = {
281 {KEY_F (1), ESC_STR "OP", MCKEY_NOACTION},
282 {KEY_F (2), ESC_STR "OQ", MCKEY_NOACTION},
283 {KEY_F (3), ESC_STR "OR", MCKEY_NOACTION},
284 {KEY_F (4), ESC_STR "OS", MCKEY_NOACTION},
285 {KEY_F (1), ESC_STR "[11~", MCKEY_NOACTION},
286 {KEY_F (2), ESC_STR "[12~", MCKEY_NOACTION},
287 {KEY_F (3), ESC_STR "[13~", MCKEY_NOACTION},
288 {KEY_F (4), ESC_STR "[14~", MCKEY_NOACTION},
289 {KEY_F (5), ESC_STR "[15~", MCKEY_NOACTION},
290 {KEY_F (6), ESC_STR "[17~", MCKEY_NOACTION},
291 {KEY_F (7), ESC_STR "[18~", MCKEY_NOACTION},
292 {KEY_F (8), ESC_STR "[19~", MCKEY_NOACTION},
293 {KEY_F (9), ESC_STR "[20~", MCKEY_NOACTION},
294 {KEY_F (10), ESC_STR "[21~", MCKEY_NOACTION},
296 /* old xterm Shift-arrows */
297 {KEY_M_SHIFT | KEY_UP, ESC_STR "O2A", MCKEY_NOACTION},
298 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "O2B", MCKEY_NOACTION},
299 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "O2C", MCKEY_NOACTION},
300 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "O2D", MCKEY_NOACTION},
302 /* new xterm Shift-arrows */
303 {KEY_M_SHIFT | KEY_UP, ESC_STR "[1;2A", MCKEY_NOACTION},
304 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[1;2B", MCKEY_NOACTION},
305 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[1;2C", MCKEY_NOACTION},
306 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[1;2D", MCKEY_NOACTION},
308 /* more xterm keys with modifiers */
309 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5;5~", MCKEY_NOACTION},
310 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6;5~", MCKEY_NOACTION},
311 {KEY_M_CTRL | KEY_IC, ESC_STR "[2;5~", MCKEY_NOACTION},
312 {KEY_M_CTRL | KEY_DC, ESC_STR "[3;5~", MCKEY_NOACTION},
313 {KEY_M_CTRL | KEY_HOME, ESC_STR "[1;5H", MCKEY_NOACTION},
314 {KEY_M_CTRL | KEY_END, ESC_STR "[1;5F", MCKEY_NOACTION},
315 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[1;2H", MCKEY_NOACTION},
316 {KEY_M_SHIFT | KEY_END, ESC_STR "[1;2F", MCKEY_NOACTION},
317 {KEY_M_CTRL | KEY_UP, ESC_STR "[1;5A", MCKEY_NOACTION},
318 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;5B", MCKEY_NOACTION},
319 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;5C", MCKEY_NOACTION},
320 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;5D", MCKEY_NOACTION},
321 {KEY_M_SHIFT | KEY_IC, ESC_STR "[2;2~", MCKEY_NOACTION},
322 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3;2~", MCKEY_NOACTION},
323 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[1;6A", MCKEY_NOACTION},
324 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;6B", MCKEY_NOACTION},
325 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;6C", MCKEY_NOACTION},
326 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;6D", MCKEY_NOACTION},
328 /* putty */
329 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[[1;6A", MCKEY_NOACTION},
330 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[[1;6B", MCKEY_NOACTION},
331 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[[1;6C", MCKEY_NOACTION},
332 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[[1;6D", MCKEY_NOACTION},
334 /* putty alt-arrow keys */
335 /* removed as source esc esc esc trouble */
337 { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
338 { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
339 { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
340 { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
341 { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
342 { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
343 { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
344 { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
346 { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
347 { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
348 { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
349 { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
351 { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
352 { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
353 { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
354 { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
356 /* xterm alt-arrow keys */
357 {KEY_M_ALT | KEY_UP, ESC_STR "[1;3A", MCKEY_NOACTION},
358 {KEY_M_ALT | KEY_DOWN, ESC_STR "[1;3B", MCKEY_NOACTION},
359 {KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;3C", MCKEY_NOACTION},
360 {KEY_M_ALT | KEY_LEFT, ESC_STR "[1;3D", MCKEY_NOACTION},
361 {KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;3~", MCKEY_NOACTION},
362 {KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;3~", MCKEY_NOACTION},
363 {KEY_M_ALT | KEY_HOME, ESC_STR "[1~", MCKEY_NOACTION},
364 {KEY_M_ALT | KEY_END, ESC_STR "[4~", MCKEY_NOACTION},
365 {KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR "[1;7A", MCKEY_NOACTION},
366 {KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR "[1;7B", MCKEY_NOACTION},
367 {KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;7C", MCKEY_NOACTION},
368 {KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR "[1;7D", MCKEY_NOACTION},
369 {KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;7~", MCKEY_NOACTION},
370 {KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;7~", MCKEY_NOACTION},
371 {KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR "OH", MCKEY_NOACTION},
372 {KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR "OF", MCKEY_NOACTION},
374 /* rxvt keys with modifiers */
375 {KEY_M_SHIFT | KEY_UP, ESC_STR "[a", MCKEY_NOACTION},
376 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION},
377 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION},
378 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION},
379 {KEY_M_CTRL | KEY_UP, ESC_STR "Oa", MCKEY_NOACTION},
380 {KEY_M_CTRL | KEY_DOWN, ESC_STR "Ob", MCKEY_NOACTION},
381 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "Oc", MCKEY_NOACTION},
382 {KEY_M_CTRL | KEY_LEFT, ESC_STR "Od", MCKEY_NOACTION},
383 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5^", MCKEY_NOACTION},
384 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6^", MCKEY_NOACTION},
385 {KEY_M_CTRL | KEY_HOME, ESC_STR "[7^", MCKEY_NOACTION},
386 {KEY_M_CTRL | KEY_END, ESC_STR "[8^", MCKEY_NOACTION},
387 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[7$", MCKEY_NOACTION},
388 {KEY_M_SHIFT | KEY_END, ESC_STR "[8$", MCKEY_NOACTION},
389 {KEY_M_CTRL | KEY_IC, ESC_STR "[2^", MCKEY_NOACTION},
390 {KEY_M_CTRL | KEY_DC, ESC_STR "[3^", MCKEY_NOACTION},
391 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3$", MCKEY_NOACTION},
393 /* konsole keys with modifiers */
394 {KEY_M_SHIFT | KEY_HOME, ESC_STR "O2H", MCKEY_NOACTION},
395 {KEY_M_SHIFT | KEY_END, ESC_STR "O2F", MCKEY_NOACTION},
397 /* gnome-terminal */
398 {KEY_M_SHIFT | KEY_UP, ESC_STR "[2A", MCKEY_NOACTION},
399 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[2B", MCKEY_NOACTION},
400 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[2C", MCKEY_NOACTION},
401 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[2D", MCKEY_NOACTION},
402 {KEY_M_CTRL | KEY_UP, ESC_STR "[5A", MCKEY_NOACTION},
403 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[5B", MCKEY_NOACTION},
404 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[5C", MCKEY_NOACTION},
405 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[5D", MCKEY_NOACTION},
406 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[6A", MCKEY_NOACTION},
407 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[6B", MCKEY_NOACTION},
408 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[6C", MCKEY_NOACTION},
409 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[6D", MCKEY_NOACTION},
411 /* gnome-terminal - application mode */
412 {KEY_M_CTRL | KEY_UP, ESC_STR "O5A", MCKEY_NOACTION},
413 {KEY_M_CTRL | KEY_DOWN, ESC_STR "O5B", MCKEY_NOACTION},
414 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "O5C", MCKEY_NOACTION},
415 {KEY_M_CTRL | KEY_LEFT, ESC_STR "O5D", MCKEY_NOACTION},
416 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "O6A", MCKEY_NOACTION},
417 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "O6B", MCKEY_NOACTION},
418 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "O6C", MCKEY_NOACTION},
419 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "O6D", MCKEY_NOACTION},
421 /* iTerm */
422 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[5;2~", MCKEY_NOACTION},
423 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[6;2~", MCKEY_NOACTION},
425 /* putty */
426 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[[5;53~", MCKEY_NOACTION},
427 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[[6;53~", MCKEY_NOACTION},
429 /* keypad keys */
430 {KEY_IC, ESC_STR "Op", MCKEY_NOACTION},
431 {KEY_DC, ESC_STR "On", MCKEY_NOACTION},
432 {'/', ESC_STR "Oo", MCKEY_NOACTION},
433 {'\n', ESC_STR "OM", MCKEY_NOACTION},
435 {0, NULL, MCKEY_NOACTION},
438 /* qansi-m terminals have a much more key combinatios,
439 which are undefined in termcap/terminfo */
440 static key_define_t qansi_key_defines[] = {
441 /* qansi-m terminal */
442 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[u", MCKEY_NOACTION}, /* Ctrl-PgDown */
443 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[v", MCKEY_NOACTION}, /* Ctrl-PgUp */
444 {KEY_M_CTRL | KEY_HOME, ESC_STR "[h", MCKEY_NOACTION}, /* Ctrl-Home */
445 {KEY_M_CTRL | KEY_END, ESC_STR "[y", MCKEY_NOACTION}, /* Ctrl-End */
446 {KEY_M_CTRL | KEY_IC, ESC_STR "[`", MCKEY_NOACTION}, /* Ctrl-Insert */
447 {KEY_M_CTRL | KEY_DC, ESC_STR "[p", MCKEY_NOACTION}, /* Ctrl-Delete */
448 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION}, /* Ctrl-Left */
449 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION}, /* Ctrl-Right */
450 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION}, /* Ctrl-Down */
451 {KEY_M_CTRL | KEY_UP, ESC_STR "[a", MCKEY_NOACTION}, /* Ctrl-Up */
452 {KEY_M_CTRL | KEY_KP_ADD, ESC_STR "[s", MCKEY_NOACTION}, /* Ctrl-Gr-Plus */
453 {KEY_M_CTRL | KEY_KP_SUBTRACT, ESC_STR "[t", MCKEY_NOACTION}, /* Ctrl-Gr-Minus */
454 {KEY_M_CTRL | '\t', ESC_STR "[z", MCKEY_NOACTION}, /* Ctrl-Tab */
455 {KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION}, /* Shift-Tab */
456 {KEY_M_CTRL | KEY_F (1), ESC_STR "[1~", MCKEY_NOACTION}, /* Ctrl-F1 */
457 {KEY_M_CTRL | KEY_F (2), ESC_STR "[2~", MCKEY_NOACTION}, /* Ctrl-F2 */
458 {KEY_M_CTRL | KEY_F (3), ESC_STR "[3~", MCKEY_NOACTION}, /* Ctrl-F3 */
459 {KEY_M_CTRL | KEY_F (4), ESC_STR "[4~", MCKEY_NOACTION}, /* Ctrl-F4 */
460 {KEY_M_CTRL | KEY_F (5), ESC_STR "[5~", MCKEY_NOACTION}, /* Ctrl-F5 */
461 {KEY_M_CTRL | KEY_F (6), ESC_STR "[6~", MCKEY_NOACTION}, /* Ctrl-F6 */
462 {KEY_M_CTRL | KEY_F (7), ESC_STR "[7~", MCKEY_NOACTION}, /* Ctrl-F7 */
463 {KEY_M_CTRL | KEY_F (8), ESC_STR "[8~", MCKEY_NOACTION}, /* Ctrl-F8 */
464 {KEY_M_CTRL | KEY_F (9), ESC_STR "[9~", MCKEY_NOACTION}, /* Ctrl-F9 */
465 {KEY_M_CTRL | KEY_F (10), ESC_STR "[10~", MCKEY_NOACTION}, /* Ctrl-F10 */
466 {KEY_M_CTRL | KEY_F (11), ESC_STR "[11~", MCKEY_NOACTION}, /* Ctrl-F11 */
467 {KEY_M_CTRL | KEY_F (12), ESC_STR "[12~", MCKEY_NOACTION}, /* Ctrl-F12 */
468 {KEY_M_ALT | KEY_F (1), ESC_STR "[17~", MCKEY_NOACTION}, /* Alt-F1 */
469 {KEY_M_ALT | KEY_F (2), ESC_STR "[18~", MCKEY_NOACTION}, /* Alt-F2 */
470 {KEY_M_ALT | KEY_F (3), ESC_STR "[19~", MCKEY_NOACTION}, /* Alt-F3 */
471 {KEY_M_ALT | KEY_F (4), ESC_STR "[20~", MCKEY_NOACTION}, /* Alt-F4 */
472 {KEY_M_ALT | KEY_F (5), ESC_STR "[21~", MCKEY_NOACTION}, /* Alt-F5 */
473 {KEY_M_ALT | KEY_F (6), ESC_STR "[22~", MCKEY_NOACTION}, /* Alt-F6 */
474 {KEY_M_ALT | KEY_F (7), ESC_STR "[23~", MCKEY_NOACTION}, /* Alt-F7 */
475 {KEY_M_ALT | KEY_F (8), ESC_STR "[24~", MCKEY_NOACTION}, /* Alt-F8 */
476 {KEY_M_ALT | KEY_F (9), ESC_STR "[25~", MCKEY_NOACTION}, /* Alt-F9 */
477 {KEY_M_ALT | KEY_F (10), ESC_STR "[26~", MCKEY_NOACTION}, /* Alt-F10 */
478 {KEY_M_ALT | KEY_F (11), ESC_STR "[27~", MCKEY_NOACTION}, /* Alt-F11 */
479 {KEY_M_ALT | KEY_F (12), ESC_STR "[28~", MCKEY_NOACTION}, /* Alt-F12 */
480 {KEY_M_ALT | 'a', ESC_STR "Na", MCKEY_NOACTION}, /* Alt-a */
481 {KEY_M_ALT | 'b', ESC_STR "Nb", MCKEY_NOACTION}, /* Alt-b */
482 {KEY_M_ALT | 'c', ESC_STR "Nc", MCKEY_NOACTION}, /* Alt-c */
483 {KEY_M_ALT | 'd', ESC_STR "Nd", MCKEY_NOACTION}, /* Alt-d */
484 {KEY_M_ALT | 'e', ESC_STR "Ne", MCKEY_NOACTION}, /* Alt-e */
485 {KEY_M_ALT | 'f', ESC_STR "Nf", MCKEY_NOACTION}, /* Alt-f */
486 {KEY_M_ALT | 'g', ESC_STR "Ng", MCKEY_NOACTION}, /* Alt-g */
487 {KEY_M_ALT | 'h', ESC_STR "Nh", MCKEY_NOACTION}, /* Alt-h */
488 {KEY_M_ALT | 'i', ESC_STR "Ni", MCKEY_NOACTION}, /* Alt-i */
489 {KEY_M_ALT | 'j', ESC_STR "Nj", MCKEY_NOACTION}, /* Alt-j */
490 {KEY_M_ALT | 'k', ESC_STR "Nk", MCKEY_NOACTION}, /* Alt-k */
491 {KEY_M_ALT | 'l', ESC_STR "Nl", MCKEY_NOACTION}, /* Alt-l */
492 {KEY_M_ALT | 'm', ESC_STR "Nm", MCKEY_NOACTION}, /* Alt-m */
493 {KEY_M_ALT | 'n', ESC_STR "Nn", MCKEY_NOACTION}, /* Alt-n */
494 {KEY_M_ALT | 'o', ESC_STR "No", MCKEY_NOACTION}, /* Alt-o */
495 {KEY_M_ALT | 'p', ESC_STR "Np", MCKEY_NOACTION}, /* Alt-p */
496 {KEY_M_ALT | 'q', ESC_STR "Nq", MCKEY_NOACTION}, /* Alt-q */
497 {KEY_M_ALT | 'r', ESC_STR "Nr", MCKEY_NOACTION}, /* Alt-r */
498 {KEY_M_ALT | 's', ESC_STR "Ns", MCKEY_NOACTION}, /* Alt-s */
499 {KEY_M_ALT | 't', ESC_STR "Nt", MCKEY_NOACTION}, /* Alt-t */
500 {KEY_M_ALT | 'u', ESC_STR "Nu", MCKEY_NOACTION}, /* Alt-u */
501 {KEY_M_ALT | 'v', ESC_STR "Nv", MCKEY_NOACTION}, /* Alt-v */
502 {KEY_M_ALT | 'w', ESC_STR "Nw", MCKEY_NOACTION}, /* Alt-w */
503 {KEY_M_ALT | 'x', ESC_STR "Nx", MCKEY_NOACTION}, /* Alt-x */
504 {KEY_M_ALT | 'y', ESC_STR "Ny", MCKEY_NOACTION}, /* Alt-y */
505 {KEY_M_ALT | 'z', ESC_STR "Nz", MCKEY_NOACTION}, /* Alt-z */
506 {KEY_KP_SUBTRACT, ESC_STR "[S", MCKEY_NOACTION}, /* Gr-Minus */
507 {KEY_KP_ADD, ESC_STR "[T", MCKEY_NOACTION}, /* Gr-Plus */
508 {0, NULL, MCKEY_NOACTION},
511 /* This holds all the key definitions */
512 static key_def *keys = NULL;
514 static int input_fd;
515 static int disabled_channels = 0; /* Disable channels checking */
517 static SelectList *select_list = NULL;
519 static int seq_buffer[SEQ_BUFFER_LEN];
520 static int *seq_append = NULL;
522 static int *pending_keys = NULL;
524 #ifdef __QNXNTO__
525 ph_dv_f ph_attach;
526 ph_ov_f ph_input_group;
527 ph_pqc_f ph_query_cursor;
528 #endif
530 #ifdef HAVE_TEXTMODE_X11_SUPPORT
531 static Display *x11_display;
532 static Window x11_window;
533 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
535 static KeySortType has_been_sorted = KEY_NOSORT;
537 /* *INDENT-OFF* */
538 static const size_t key_conv_tab_size = G_N_ELEMENTS (key_name_conv_tab) - 1;
539 /* *INDENT-ON* */
541 static const key_code_name_t *key_conv_tab_sorted[G_N_ELEMENTS (key_name_conv_tab) - 1];
543 /*** file scope functions ************************************************************************/
544 /* --------------------------------------------------------------------------------------------- */
546 static int
547 add_selects (fd_set * select_set)
549 int top_fd = 0;
551 if (disabled_channels == 0)
553 SelectList *p;
555 for (p = select_list; p != NULL; p = p->next)
557 FD_SET (p->fd, select_set);
558 if (p->fd > top_fd)
559 top_fd = p->fd;
563 return top_fd;
566 /* --------------------------------------------------------------------------------------------- */
568 static void
569 check_selects (fd_set * select_set)
571 if (disabled_channels == 0)
573 gboolean retry;
577 SelectList *p;
579 retry = FALSE;
580 for (p = select_list; p; p = p->next)
581 if (FD_ISSET (p->fd, select_set))
583 FD_CLR (p->fd, select_set);
584 (*p->callback) (p->fd, p->info);
585 retry = TRUE;
586 break;
589 while (retry);
593 /* --------------------------------------------------------------------------------------------- */
594 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
596 static void
597 try_channels (int set_timeout)
599 struct timeval time_out;
600 static fd_set select_set;
601 struct timeval *timeptr;
602 int v;
603 int maxfdp;
605 while (1)
607 FD_ZERO (&select_set);
608 FD_SET (input_fd, &select_set); /* Add stdin */
609 maxfdp = max (add_selects (&select_set), input_fd);
611 timeptr = NULL;
612 if (set_timeout)
614 time_out.tv_sec = 0;
615 time_out.tv_usec = 100000;
616 timeptr = &time_out;
619 v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr);
620 if (v > 0)
622 check_selects (&select_set);
623 if (FD_ISSET (input_fd, &select_set))
624 break;
629 /* --------------------------------------------------------------------------------------------- */
631 static key_def *
632 create_sequence (const char *seq, int code, int action)
634 key_def *base, *p, *attach;
636 for (base = attach = NULL; *seq; seq++)
638 p = g_new (key_def, 1);
639 if (base == NULL)
640 base = p;
641 if (attach != NULL)
642 attach->child = p;
644 p->ch = *seq;
645 p->code = code;
646 p->child = p->next = NULL;
647 if (seq[1] == '\0')
648 p->action = action;
649 else
650 p->action = MCKEY_NOACTION;
651 attach = p;
653 return base;
656 /* --------------------------------------------------------------------------------------------- */
658 static void
659 define_sequences (const key_define_t * kd)
661 int i;
663 for (i = 0; kd[i].code != 0; i++)
664 define_sequence (kd[i].code, kd[i].seq, kd[i].action);
667 /* --------------------------------------------------------------------------------------------- */
669 #ifdef HAVE_TEXTMODE_X11_SUPPORT
670 static void
671 init_key_x11 (void)
673 if (getenv ("DISPLAY") != NULL && !mc_global.tty.disable_x11)
675 x11_display = mc_XOpenDisplay (0);
677 if (x11_display != NULL)
678 x11_window = DefaultRootWindow (x11_display);
681 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
683 /* --------------------------------------------------------------------------------------------- */
684 /* Workaround for System V Curses vt100 bug */
686 static int
687 getch_with_delay (void)
689 int c;
691 /* This routine could be used on systems without mouse support,
692 so we need to do the select check :-( */
693 while (1)
695 if (pending_keys == NULL)
696 try_channels (0);
698 /* Try to get a character */
699 c = get_key_code (0);
700 if (c != -1)
701 break;
702 /* Failed -> wait 0.1 secs and try again */
703 try_channels (1);
705 /* Success -> return the character */
706 return c;
709 /* --------------------------------------------------------------------------------------------- */
711 static void
712 xmouse_get_event (Gpm_Event * ev, gboolean extended)
714 static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
715 static struct timeval tv2;
716 static int clicks = 0;
717 static int last_btn = 0;
718 int btn;
720 /* Decode Xterm mouse information to a GPM style event */
722 if (!extended)
724 /* Variable btn has following meaning: */
725 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
726 btn = tty_lowlevel_getch () - 32;
727 /* Coordinates are 33-based */
728 /* Transform them to 1-based */
729 ev->x = tty_lowlevel_getch () - 32;
730 ev->y = tty_lowlevel_getch () - 32;
732 else
734 /* SGR 1006 extension (e.g. "\e[<0;12;300M"):
735 - Numbers are encoded in decimal to make it ASCII-safe
736 and to overcome the limit of 223 columns/rows.
737 - Mouse release is encoded by trailing 'm' rather than 'M'
738 so that the released button can be reported.
739 - Numbers are no longer offset by 32. */
740 char c;
741 btn = ev->x = ev->y = 0;
742 ev->type = 0; /* In case we return on an invalid sequence */
743 while ((c = tty_lowlevel_getch ()) != ';')
745 if (c < '0' || c > '9')
746 return;
747 btn = 10 * btn + (c - '0');
749 while ((c = tty_lowlevel_getch ()) != ';')
751 if (c < '0' || c > '9')
752 return;
753 ev->x = 10 * ev->x + (c - '0');
755 while ((c = tty_lowlevel_getch ()) != 'M' && c != 'm')
757 if (c < '0' || c > '9')
758 return;
759 ev->y = 10 * ev->y + (c - '0');
761 /* Legacy mouse protocol doesn't tell which button was released,
762 conveniently all of mc's widgets are written not to rely on this
763 information. With the SGR extension the released button becomes
764 known, but for the sake of simplicity we just ignore it. */
765 if (c == 'm')
766 btn = 3;
769 /* There seems to be no way of knowing which button was released */
770 /* So we assume all the buttons were released */
772 if (btn == 3)
774 if (last_btn != 0)
776 if ((last_btn & (GPM_B_UP | GPM_B_DOWN)) != 0)
778 /* FIXME: DIRTY HACK */
779 /* don't generate GPM_UP after mouse wheel */
780 /* need for menu event handling */
781 ev->type = 0;
782 tv1.tv_sec = 0;
783 tv1.tv_usec = 0;
785 else
787 ev->type = GPM_UP | (GPM_SINGLE << clicks);
788 GET_TIME (tv1);
790 ev->buttons = 0;
791 last_btn = 0;
792 clicks = 0;
794 else
796 /* Bogus event, maybe mouse wheel */
797 ev->type = 0;
800 else
802 if (btn >= 32 && btn <= 34)
804 btn -= 32;
805 ev->type = GPM_DRAG;
807 else
808 ev->type = GPM_DOWN;
810 GET_TIME (tv2);
811 if (tv1.tv_sec && (DIF_TIME (tv1, tv2) < double_click_speed))
813 clicks++;
814 clicks %= 3;
816 else
817 clicks = 0;
819 switch (btn)
821 case 0:
822 ev->buttons = GPM_B_LEFT;
823 break;
824 case 1:
825 ev->buttons = GPM_B_MIDDLE;
826 break;
827 case 2:
828 ev->buttons = GPM_B_RIGHT;
829 break;
830 case 64:
831 ev->buttons = GPM_B_UP;
832 clicks = 0;
833 break;
834 case 65:
835 ev->buttons = GPM_B_DOWN;
836 clicks = 0;
837 break;
838 default:
839 /* Nothing */
840 ev->type = 0;
841 ev->buttons = 0;
842 break;
844 last_btn = ev->buttons;
848 /* --------------------------------------------------------------------------------------------- */
850 * Get modifier state (shift, alt, ctrl) for the last key pressed.
851 * We are assuming that the state didn't change since the key press.
852 * This is only correct if get_modifier() is called very fast after
853 * the input was received, so that the user didn't release the
854 * modifier keys yet.
857 static int
858 get_modifier (void)
860 int result = 0;
861 #ifdef __QNXNTO__
862 int mod_status, shift_ext_status;
863 static int in_photon = 0;
864 static int ph_ig = 0;
865 PhCursorInfo_t cursor_info;
866 #endif /* __QNXNTO__ */
868 #ifdef HAVE_TEXTMODE_X11_SUPPORT
869 if (x11_window != 0)
871 Window root, child;
872 int root_x, root_y;
873 int win_x, win_y;
874 unsigned int mask;
876 mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x,
877 &root_y, &win_x, &win_y, &mask);
879 if (mask & ShiftMask)
880 result |= KEY_M_SHIFT;
881 if (mask & ControlMask)
882 result |= KEY_M_CTRL;
883 return result;
885 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
886 #ifdef __QNXNTO__
888 if (in_photon == 0)
890 /* First time here, let's load Photon library and attach
891 to Photon */
892 in_photon = -1;
893 if (getenv ("PHOTON2_PATH") != NULL)
895 /* QNX 6.x has no support for RTLD_LAZY */
896 void *ph_handle = dlopen ("/usr/lib/libph.so", RTLD_NOW);
897 if (ph_handle != NULL)
899 ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach");
900 ph_input_group = (ph_ov_f) dlsym (ph_handle, "PhInputGroup");
901 ph_query_cursor = (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor");
902 if ((ph_attach != NULL) && (ph_input_group != NULL) && (ph_query_cursor != NULL))
904 if ((*ph_attach) (0, 0))
905 { /* Attached */
906 ph_ig = (*ph_input_group) (0);
907 in_photon = 1;
913 /* We do not have Photon running. Assume we are in text
914 console or xterm */
915 if (in_photon == -1)
917 if (devctl (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status, sizeof (int), NULL) == -1)
918 return 0;
919 shift_ext_status = mod_status & 0xffffff00UL;
920 mod_status &= 0x7f;
921 if (mod_status & _LINESTATUS_CON_ALT)
922 result |= KEY_M_ALT;
923 if (mod_status & _LINESTATUS_CON_CTRL)
924 result |= KEY_M_CTRL;
925 if ((mod_status & _LINESTATUS_CON_SHIFT) || (shift_ext_status & 0x00000800UL))
926 result |= KEY_M_SHIFT;
928 else
930 (*ph_query_cursor) (ph_ig, &cursor_info);
931 if (cursor_info.key_mods & 0x04)
932 result |= KEY_M_ALT;
933 if (cursor_info.key_mods & 0x02)
934 result |= KEY_M_CTRL;
935 if (cursor_info.key_mods & 0x01)
936 result |= KEY_M_SHIFT;
938 #endif /* __QNXNTO__ */
940 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
942 unsigned char modifiers = 6;
944 if (ioctl (0, TIOCLINUX, &modifiers) < 0)
945 return 0;
947 /* Translate Linux modifiers into mc modifiers */
948 if (modifiers & SHIFT_PRESSED)
949 result |= KEY_M_SHIFT;
950 if (modifiers & (ALTL_PRESSED | ALTR_PRESSED))
951 result |= KEY_M_ALT;
952 if (modifiers & CONTROL_PRESSED)
953 result |= KEY_M_CTRL;
955 #endif /* !__linux__ */
956 return result;
959 /* --------------------------------------------------------------------------------------------- */
961 static gboolean
962 push_char (int c)
964 gboolean ret = FALSE;
966 if (seq_append == NULL)
967 seq_append = seq_buffer;
969 if (seq_append != &(seq_buffer[SEQ_BUFFER_LEN - 2]))
971 *(seq_append++) = c;
972 *seq_append = 0;
973 ret = TRUE;
976 return ret;
979 /* --------------------------------------------------------------------------------------------- */
980 /* Apply corrections for the keycode generated in get_key_code() */
982 static int
983 correct_key_code (int code)
985 unsigned int c = code & ~KEY_M_MASK; /* code without modifier */
986 unsigned int mod = code & KEY_M_MASK; /* modifier */
987 #ifdef __QNXNTO__
988 unsigned int qmod; /* bunch of the QNX console
989 modifiers needs unchanged */
990 #endif /* __QNXNTO__ */
993 * Add key modifiers directly from X11 or OS.
994 * Ordinary characters only get modifiers from sequences.
996 if (c < 32 || c >= 256)
998 mod |= get_modifier ();
1001 /* This is needed if the newline is reported as carriage return */
1002 if (c == '\r')
1003 c = '\n';
1005 /* This is reported to be useful on AIX */
1006 if (c == KEY_SCANCEL)
1007 c = '\t';
1009 /* Convert Shift+Tab and Ctrl+Tab to Back Tab
1010 * only if modifiers directly from X11
1012 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1013 if (x11_window != 0)
1014 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
1016 if ((c == '\t') && (mod & (KEY_M_SHIFT | KEY_M_CTRL)))
1018 c = KEY_BTAB;
1019 mod = 0;
1023 /* F0 is the same as F10 for out purposes */
1024 if (c == KEY_F (0))
1025 c = KEY_F (10);
1028 * We are not interested if Ctrl was pressed when entering control
1029 * characters, so assume that it was. When checking for such keys,
1030 * XCTRL macro should be used. In some cases, we are interested,
1031 * e.g. to distinguish Ctrl-Enter from Enter.
1033 if (c == '\b')
1035 /* Special case for backspase ('\b' < 32) */
1036 c = KEY_BACKSPACE;
1037 mod &= ~KEY_M_CTRL;
1039 else if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n')
1041 mod |= KEY_M_CTRL;
1044 #ifdef __QNXNTO__
1045 qmod = get_modifier ();
1047 if ((c == 127) && (mod == 0))
1048 { /* Add Ctrl/Alt/Shift-BackSpace */
1049 mod |= get_modifier ();
1050 c = KEY_BACKSPACE;
1053 if ((c == '0') && (mod == 0))
1054 { /* Add Shift-Insert on key pad */
1055 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1057 mod = KEY_M_SHIFT;
1058 c = KEY_IC;
1062 if ((c == '.') && (mod == 0))
1063 { /* Add Shift-Del on key pad */
1064 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1066 mod = KEY_M_SHIFT;
1067 c = KEY_DC;
1070 #endif /* __QNXNTO__ */
1072 /* Unrecognized 0177 is delete (preserve Ctrl) */
1073 if (c == 0177)
1075 c = KEY_BACKSPACE;
1078 #if 0
1079 /* Unrecognized Ctrl-d is delete */
1080 if (c == (31 & 'd'))
1082 c = KEY_DC;
1083 mod &= ~KEY_M_CTRL;
1086 /* Unrecognized Ctrl-h is backspace */
1087 if (c == (31 & 'h'))
1089 c = KEY_BACKSPACE;
1090 mod &= ~KEY_M_CTRL;
1092 #endif
1094 /* Shift+BackSpace is backspace */
1095 if (c == KEY_BACKSPACE && (mod & KEY_M_SHIFT))
1097 mod &= ~KEY_M_SHIFT;
1100 /* Convert Shift+Fn to F(n+10) */
1101 if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT))
1103 c += 10;
1106 /* Remove Shift information from function keys */
1107 if (c >= KEY_F (1) && c <= KEY_F (20))
1109 mod &= ~KEY_M_SHIFT;
1112 if (!mc_global.tty.alternate_plus_minus)
1113 switch (c)
1115 case KEY_KP_ADD:
1116 c = '+';
1117 break;
1118 case KEY_KP_SUBTRACT:
1119 c = '-';
1120 break;
1121 case KEY_KP_MULTIPLY:
1122 c = '*';
1123 break;
1126 return (mod | c);
1129 /* --------------------------------------------------------------------------------------------- */
1131 static int
1132 xgetch_second (void)
1134 fd_set Read_FD_Set;
1135 int c;
1136 struct timeval time_out;
1138 time_out.tv_sec = old_esc_mode_timeout / 1000000;
1139 time_out.tv_usec = old_esc_mode_timeout % 1000000;
1140 tty_nodelay (TRUE);
1141 FD_ZERO (&Read_FD_Set);
1142 FD_SET (input_fd, &Read_FD_Set);
1143 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
1144 c = tty_lowlevel_getch ();
1145 tty_nodelay (FALSE);
1146 return c;
1149 /* --------------------------------------------------------------------------------------------- */
1151 static void
1152 learn_store_key (char *buffer, char **p, int c)
1154 if (*p - buffer > 253)
1155 return;
1156 if (c == ESC_CHAR)
1158 *(*p)++ = '\\';
1159 *(*p)++ = 'e';
1161 else if (c < ' ')
1163 *(*p)++ = '^';
1164 *(*p)++ = c + 'a' - 1;
1166 else if (c == '^')
1168 *(*p)++ = '^';
1169 *(*p)++ = '^';
1171 else
1172 *(*p)++ = (char) c;
1175 /* --------------------------------------------------------------------------------------------- */
1177 static void
1178 k_dispose (key_def * k)
1180 if (k != NULL)
1182 k_dispose (k->child);
1183 k_dispose (k->next);
1184 g_free (k);
1188 /* --------------------------------------------------------------------------------------------- */
1190 static void
1191 s_dispose (SelectList * sel)
1193 if (sel != NULL)
1195 s_dispose (sel->next);
1196 g_free (sel);
1200 /* --------------------------------------------------------------------------------------------- */
1202 static int
1203 key_code_comparator_by_name (const void *p1, const void *p2)
1205 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1206 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1208 return g_ascii_strcasecmp (n1->name, n2->name);
1211 /* --------------------------------------------------------------------------------------------- */
1213 static int
1214 key_code_comparator_by_code (const void *p1, const void *p2)
1216 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1217 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1219 return n1->code - n2->code;
1222 /* --------------------------------------------------------------------------------------------- */
1224 static inline void
1225 sort_key_conv_tab (enum KeySortType type_sort)
1227 if (has_been_sorted != type_sort)
1229 size_t i;
1230 for (i = 0; i < key_conv_tab_size; i++)
1231 key_conv_tab_sorted[i] = &key_name_conv_tab[i];
1233 if (type_sort == KEY_SORTBYNAME)
1235 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1236 &key_code_comparator_by_name);
1238 else if (type_sort == KEY_SORTBYCODE)
1240 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1241 &key_code_comparator_by_code);
1243 has_been_sorted = type_sort;
1247 /* --------------------------------------------------------------------------------------------- */
1249 static int
1250 lookup_keyname (const char *name, int *idx)
1252 if (name[0] != '\0')
1254 const key_code_name_t key = { 0, name, NULL, NULL };
1255 const key_code_name_t *keyp = &key;
1256 key_code_name_t **res;
1258 if (name[1] == '\0')
1260 *idx = -1;
1261 return (int) name[0];
1264 sort_key_conv_tab (KEY_SORTBYNAME);
1266 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1267 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_name);
1269 if (res != NULL)
1271 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1272 return (*res)->code;
1276 *idx = -1;
1277 return 0;
1280 /* --------------------------------------------------------------------------------------------- */
1282 static gboolean
1283 lookup_keycode (const long code, int *idx)
1285 if (code != 0)
1287 const key_code_name_t key = { code, NULL, NULL, NULL };
1288 const key_code_name_t *keyp = &key;
1289 key_code_name_t **res;
1291 sort_key_conv_tab (KEY_SORTBYCODE);
1293 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1294 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_code);
1296 if (res != NULL)
1298 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1299 return TRUE;
1303 *idx = -1;
1304 return FALSE;
1307 /* --------------------------------------------------------------------------------------------- */
1308 /*** public functions ****************************************************************************/
1309 /* --------------------------------------------------------------------------------------------- */
1310 /* This has to be called before init_slang or whatever routine
1311 calls any define_sequence */
1313 void
1314 init_key (void)
1316 const char *term = getenv ("TERM");
1318 /* This has to be the first define_sequence */
1319 /* So, we can assume that the first keys member has ESC */
1320 define_sequences (mc_default_keys);
1322 /* Terminfo on irix does not have some keys */
1323 if (mc_global.tty.xterm_flag
1324 || (term != NULL
1325 && (strncmp (term, "iris-ansi", 9) == 0
1326 || strncmp (term, "xterm", 5) == 0
1327 || strncmp (term, "rxvt", 4) == 0 || strcmp (term, "screen") == 0)))
1328 define_sequences (xterm_key_defines);
1330 /* load some additional keys (e.g. direct Alt-? support) */
1331 load_xtra_key_defines ();
1333 #ifdef __QNX__
1334 if ((term != NULL) && (strncmp (term, "qnx", 3) == 0))
1336 /* Modify the default value of use_8th_bit_as_meta: we would
1337 * like to provide a working mc for a newbie who knows nothing
1338 * about [Options|Display bits|Full 8 bits input]...
1340 * Don't use 'meta'-bit, when we are dealing with a
1341 * 'qnx*'-type terminal: clear the default value!
1342 * These terminal types use 0xFF as an escape character,
1343 * so use_8th_bit_as_meta==1 must not be enabled!
1345 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1346 * is not used now (doesn't even depend on use_8th_bit_as_meta
1347 * as in mc-3.1.2)...GREAT!...no additional code is required!]
1349 use_8th_bit_as_meta = 0;
1351 #endif /* __QNX__ */
1353 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1354 init_key_x11 ();
1355 #endif
1357 /* Load the qansi-m key definitions
1358 if we are running under the qansi-m terminal */
1359 if (term != NULL && (strncmp (term, "qansi-m", 7) == 0))
1360 define_sequences (qansi_key_defines);
1363 /* --------------------------------------------------------------------------------------------- */
1365 * This has to be called after SLang_init_tty/slint_init
1368 void
1369 init_key_input_fd (void)
1371 #ifdef HAVE_SLANG
1372 input_fd = SLang_TT_Read_FD;
1373 #endif
1376 /* --------------------------------------------------------------------------------------------- */
1378 void
1379 done_key (void)
1381 k_dispose (keys);
1382 s_dispose (select_list);
1384 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1385 if (x11_display)
1386 mc_XCloseDisplay (x11_display);
1387 #endif
1390 /* --------------------------------------------------------------------------------------------- */
1392 void
1393 add_select_channel (int fd, select_fn callback, void *info)
1395 SelectList *new;
1397 new = g_new (SelectList, 1);
1398 new->fd = fd;
1399 new->callback = callback;
1400 new->info = info;
1401 new->next = select_list;
1402 select_list = new;
1405 /* --------------------------------------------------------------------------------------------- */
1407 void
1408 delete_select_channel (int fd)
1410 SelectList *p = select_list;
1411 SelectList *p_prev = NULL;
1412 SelectList *p_next;
1414 while (p != NULL)
1415 if (p->fd == fd)
1417 p_next = p->next;
1419 if (p_prev != NULL)
1420 p_prev->next = p_next;
1421 else
1422 select_list = p_next;
1424 g_free (p);
1425 p = p_next;
1427 else
1429 p_prev = p;
1430 p = p->next;
1434 /* --------------------------------------------------------------------------------------------- */
1436 void
1437 channels_up (void)
1439 if (disabled_channels == 0)
1440 fputs ("Error: channels_up called with disabled_channels = 0\n", stderr);
1441 disabled_channels--;
1444 /* --------------------------------------------------------------------------------------------- */
1446 void
1447 channels_down (void)
1449 disabled_channels++;
1452 /* --------------------------------------------------------------------------------------------- */
1454 * Return the code associated with the symbolic name keyname
1457 long
1458 lookup_key (const char *name, char **label)
1460 char **lc_keys, **p;
1461 int k = -1;
1462 int key = 0;
1463 int lc_index = -1;
1465 int use_meta = -1;
1466 int use_ctrl = -1;
1467 int use_shift = -1;
1469 if (name == NULL)
1470 return 0;
1472 name = g_strstrip (g_strdup (name));
1473 p = lc_keys = g_strsplit_set (name, "-+ ", -1);
1474 g_free ((char *) name);
1476 while ((p != NULL) && (*p != NULL))
1478 if ((*p)[0] != '\0')
1480 int idx;
1482 key = lookup_keyname (g_strstrip (*p), &idx);
1484 if (key == KEY_M_ALT)
1485 use_meta = idx;
1486 else if (key == KEY_M_CTRL)
1487 use_ctrl = idx;
1488 else if (key == KEY_M_SHIFT)
1489 use_shift = idx;
1490 else
1492 k = key;
1493 lc_index = idx;
1494 break;
1498 p++;
1501 g_strfreev (lc_keys);
1503 /* output */
1504 if (k <= 0)
1505 return 0;
1508 if (label != NULL)
1510 GString *s;
1512 s = g_string_new ("");
1514 if (use_meta != -1)
1516 g_string_append (s, key_conv_tab_sorted[use_meta]->shortcut);
1517 g_string_append_c (s, '-');
1519 if (use_ctrl != -1)
1521 g_string_append (s, key_conv_tab_sorted[use_ctrl]->shortcut);
1522 g_string_append_c (s, '-');
1524 if (use_shift != -1)
1526 if (k < 127)
1527 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1528 else
1530 g_string_append (s, key_conv_tab_sorted[use_shift]->shortcut);
1531 g_string_append_c (s, '-');
1532 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1535 else if (k < 128)
1537 if ((k >= 'A') || (lc_index < 0) || (key_conv_tab_sorted[lc_index]->shortcut == NULL))
1538 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) k));
1539 else
1540 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1542 else if ((lc_index != -1) && (key_conv_tab_sorted[lc_index]->shortcut != NULL))
1543 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1544 else
1545 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) key));
1547 *label = g_string_free (s, FALSE);
1550 if (use_shift != -1)
1552 if (k < 127 && k > 31)
1553 k = g_ascii_toupper ((gchar) k);
1554 else
1555 k |= KEY_M_SHIFT;
1558 if (use_ctrl != -1)
1560 if (k < 256)
1561 k = XCTRL (k);
1562 else
1563 k |= KEY_M_CTRL;
1566 if (use_meta != -1)
1567 k = ALT (k);
1569 return (long) k;
1572 /* --------------------------------------------------------------------------------------------- */
1574 char *
1575 lookup_key_by_code (const int keycode)
1577 /* code without modifier */
1578 unsigned int k = keycode & ~KEY_M_MASK;
1579 /* modifier */
1580 unsigned int mod = keycode & KEY_M_MASK;
1582 int use_meta = -1;
1583 int use_ctrl = -1;
1584 int use_shift = -1;
1585 int key_idx = -1;
1587 GString *s;
1588 int idx;
1590 s = g_string_sized_new (8);
1592 if (lookup_keycode (k, &key_idx) || (k > 0 && k < 256))
1594 if (mod & KEY_M_ALT)
1596 if (lookup_keycode (KEY_M_ALT, &idx))
1598 use_meta = idx;
1599 g_string_append (s, key_conv_tab_sorted[use_meta]->name);
1600 g_string_append_c (s, '-');
1603 if (mod & KEY_M_CTRL)
1605 /* non printeble chars like a CTRL-[A..Z] */
1606 if (k < 32)
1607 k += 64;
1609 if (lookup_keycode (KEY_M_CTRL, &idx))
1611 use_ctrl = idx;
1612 g_string_append (s, key_conv_tab_sorted[use_ctrl]->name);
1613 g_string_append_c (s, '-');
1616 if (mod & KEY_M_SHIFT)
1618 if (lookup_keycode (KEY_M_ALT, &idx))
1620 use_shift = idx;
1621 if (k < 127)
1622 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1623 else
1625 g_string_append (s, key_conv_tab_sorted[use_shift]->name);
1626 g_string_append_c (s, '-');
1627 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1631 else if (k < 128)
1633 if ((k >= 'A') || (key_idx < 0) || (key_conv_tab_sorted[key_idx]->name == NULL))
1634 g_string_append_c (s, (gchar) k);
1635 else
1636 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1638 else if ((key_idx != -1) && (key_conv_tab_sorted[key_idx]->name != NULL))
1639 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1640 else
1641 g_string_append_c (s, (gchar) keycode);
1644 return g_string_free (s, s->len == 0);
1647 /* --------------------------------------------------------------------------------------------- */
1649 * Return TRUE on success, FALSE on error.
1650 * An error happens if SEQ is a beginning of an existing longer sequence.
1653 gboolean
1654 define_sequence (int code, const char *seq, int action)
1656 key_def *base;
1658 if (strlen (seq) > SEQ_BUFFER_LEN - 1)
1659 return FALSE;
1661 for (base = keys; (base != NULL) && (*seq != '\0');)
1662 if (*seq == base->ch)
1664 if (base->child == 0)
1666 if (*(seq + 1) != '\0')
1667 base->child = create_sequence (seq + 1, code, action);
1668 else
1670 /* The sequence matches an existing one. */
1671 base->code = code;
1672 base->action = action;
1674 return TRUE;
1677 base = base->child;
1678 seq++;
1680 else
1682 if (base->next)
1683 base = base->next;
1684 else
1686 base->next = create_sequence (seq, code, action);
1687 return TRUE;
1691 if (*seq == '\0')
1693 /* Attempt to redefine a sequence with a shorter sequence. */
1694 return FALSE;
1697 keys = create_sequence (seq, code, action);
1698 return TRUE;
1701 /* --------------------------------------------------------------------------------------------- */
1703 * Check if we are idle, i.e. there are no pending keyboard or mouse
1704 * events. Return 1 is idle, 0 is there are pending events.
1706 gboolean
1707 is_idle (void)
1709 int maxfdp;
1710 fd_set select_set;
1711 struct timeval time_out;
1713 FD_ZERO (&select_set);
1714 FD_SET (input_fd, &select_set);
1715 maxfdp = input_fd;
1716 #ifdef HAVE_LIBGPM
1717 if (mouse_enabled && (use_mouse_p == MOUSE_GPM) && (gpm_fd > 0))
1719 FD_SET (gpm_fd, &select_set);
1720 maxfdp = max (maxfdp, gpm_fd);
1722 #endif
1723 time_out.tv_sec = 0;
1724 time_out.tv_usec = 0;
1725 return (select (maxfdp + 1, &select_set, 0, 0, &time_out) <= 0);
1728 /* --------------------------------------------------------------------------------------------- */
1731 get_key_code (int no_delay)
1733 int c;
1734 static key_def *this = NULL, *parent;
1735 static struct timeval esctime = { -1, -1 };
1736 static int lastnodelay = -1;
1738 if (no_delay != lastnodelay)
1740 this = NULL;
1741 lastnodelay = no_delay;
1744 pend_send:
1745 if (pending_keys != NULL)
1747 int d;
1749 d = *pending_keys++;
1750 while (d == ESC_CHAR && *pending_keys != '\0')
1751 d = ALT (*pending_keys++);
1753 if (*pending_keys == '\0')
1754 pending_keys = seq_append = NULL;
1756 if (d > 127 && d < 256 && use_8th_bit_as_meta)
1757 d = ALT (d & 0x7f);
1759 this = NULL;
1760 return correct_key_code (d);
1763 nodelay_try_again:
1764 if (no_delay)
1765 tty_nodelay (TRUE);
1767 c = tty_lowlevel_getch ();
1768 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1769 if (c == KEY_RESIZE)
1770 goto nodelay_try_again;
1771 #endif
1772 if (no_delay)
1774 tty_nodelay (FALSE);
1775 if (c == -1)
1777 if (this != NULL && parent != NULL && parent->action == MCKEY_ESCAPE && old_esc_mode)
1779 struct timeval current, time_out;
1781 if (esctime.tv_sec == -1)
1782 return -1;
1783 GET_TIME (current);
1784 time_out.tv_sec = old_esc_mode_timeout / 1000000 + esctime.tv_sec;
1785 time_out.tv_usec = old_esc_mode_timeout % 1000000 + esctime.tv_usec;
1786 if (time_out.tv_usec > 1000000)
1788 time_out.tv_usec -= 1000000;
1789 time_out.tv_sec++;
1791 if (current.tv_sec < time_out.tv_sec)
1792 return -1;
1793 if (current.tv_sec == time_out.tv_sec && current.tv_usec < time_out.tv_usec)
1794 return -1;
1795 this = NULL;
1796 pending_keys = seq_append = NULL;
1797 return ESC_CHAR;
1799 return -1;
1802 else if (c == -1)
1804 /* Maybe we got an incomplete match.
1805 This we do only in delay mode, since otherwise
1806 tty_lowlevel_getch can return -1 at any time. */
1807 if (seq_append != NULL)
1809 pending_keys = seq_buffer;
1810 goto pend_send;
1812 this = NULL;
1813 return -1;
1816 /* Search the key on the root */
1817 if (!no_delay || this == NULL)
1819 this = keys;
1820 parent = NULL;
1822 if ((c > 127 && c < 256) && use_8th_bit_as_meta)
1824 c &= 0x7f;
1826 /* The first sequence defined starts with esc */
1827 parent = keys;
1828 this = keys->child;
1831 while (this != NULL)
1833 if (c == this->ch)
1835 if (this->child)
1837 if (!push_char (c))
1839 pending_keys = seq_buffer;
1840 goto pend_send;
1842 parent = this;
1843 this = this->child;
1844 if (parent->action == MCKEY_ESCAPE && old_esc_mode)
1846 if (no_delay)
1848 GET_TIME (esctime);
1849 if (this == NULL)
1851 /* Shouldn't happen */
1852 fputs ("Internal error\n", stderr);
1853 exit (EXIT_FAILURE);
1855 goto nodelay_try_again;
1857 esctime.tv_sec = -1;
1858 c = xgetch_second ();
1859 if (c == -1)
1861 pending_keys = seq_append = NULL;
1862 this = NULL;
1863 return ESC_CHAR;
1866 else
1868 if (no_delay)
1869 goto nodelay_try_again;
1870 c = tty_lowlevel_getch ();
1873 else
1875 /* We got a complete match, return and reset search */
1876 int code;
1878 pending_keys = seq_append = NULL;
1879 code = this->code;
1880 this = NULL;
1881 return correct_key_code (code);
1884 else
1886 if (this->next != NULL)
1887 this = this->next;
1888 else
1890 if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
1892 /* Convert escape-digits to F-keys */
1893 if (g_ascii_isdigit (c))
1894 c = KEY_F (c - '0');
1895 else if (c == ' ')
1896 c = ESC_CHAR;
1897 else
1898 c = ALT (c);
1900 pending_keys = seq_append = NULL;
1901 this = NULL;
1902 return correct_key_code (c);
1904 /* Did not find a match or {c} was changed in the if above,
1905 so we have to return everything we had skipped
1907 push_char (c);
1908 pending_keys = seq_buffer;
1909 goto pend_send;
1913 this = NULL;
1914 return correct_key_code (c);
1917 /* --------------------------------------------------------------------------------------------- */
1918 /* Returns a character read from stdin with appropriate interpretation */
1919 /* Also takes care of generated mouse events */
1920 /* Returns EV_MOUSE if it is a mouse event */
1921 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
1924 tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block)
1926 int c;
1927 static int flag = 0; /* Return value from select */
1928 #ifdef HAVE_LIBGPM
1929 static struct Gpm_Event ev; /* Mouse event */
1930 #endif
1931 struct timeval time_out;
1932 struct timeval *time_addr = NULL;
1933 static int dirty = 3;
1935 if ((dirty == 3) || is_idle ())
1937 mc_refresh ();
1938 dirty = 1;
1940 else
1941 dirty++;
1943 vfs_timeout_handler ();
1945 /* Ok, we use (event->x < 0) to signal that the event does not contain
1946 a suitable position for the mouse, so we can't use show_mouse_pointer
1947 on it.
1949 if (event->x > 0)
1951 show_mouse_pointer (event->x, event->y);
1952 if (!redo_event)
1953 event->x = -1;
1956 /* Repeat if using mouse */
1957 while (pending_keys == NULL)
1959 int maxfdp;
1960 fd_set select_set;
1962 FD_ZERO (&select_set);
1963 FD_SET (input_fd, &select_set);
1964 maxfdp = max (add_selects (&select_set), input_fd);
1966 #ifdef HAVE_LIBGPM
1967 if (mouse_enabled && (use_mouse_p == MOUSE_GPM))
1969 if (gpm_fd < 0)
1971 /* Connection to gpm broken, possibly gpm has died */
1972 mouse_enabled = FALSE;
1973 use_mouse_p = MOUSE_NONE;
1974 break;
1977 FD_SET (gpm_fd, &select_set);
1978 maxfdp = max (maxfdp, gpm_fd);
1980 #endif
1982 if (redo_event)
1984 time_out.tv_usec = mou_auto_repeat * 1000;
1985 time_out.tv_sec = 0;
1987 time_addr = &time_out;
1989 else
1991 int seconds;
1993 seconds = vfs_timeouts ();
1994 time_addr = NULL;
1996 if (seconds != 0)
1998 /* the timeout could be improved and actually be
1999 * the number of seconds until the next vfs entry
2000 * timeouts in the stamp list.
2003 time_out.tv_sec = seconds;
2004 time_out.tv_usec = 0;
2005 time_addr = &time_out;
2009 if (!block || mc_global.tty.winch_flag != 0)
2011 time_addr = &time_out;
2012 time_out.tv_sec = 0;
2013 time_out.tv_usec = 0;
2016 tty_enable_interrupt_key ();
2017 flag = select (maxfdp + 1, &select_set, NULL, NULL, time_addr);
2018 tty_disable_interrupt_key ();
2020 /* select timed out: it could be for any of the following reasons:
2021 * redo_event -> it was because of the MOU_REPEAT handler
2022 * !block -> we did not block in the select call
2023 * else -> 10 second timeout to check the vfs status.
2025 if (flag == 0)
2027 if (redo_event)
2028 return EV_MOUSE;
2029 if (!block || mc_global.tty.winch_flag != 0)
2030 return EV_NONE;
2031 vfs_timeout_handler ();
2033 if (flag == -1 && errno == EINTR)
2034 return EV_NONE;
2036 check_selects (&select_set);
2038 if (FD_ISSET (input_fd, &select_set))
2039 break;
2040 #ifdef HAVE_LIBGPM
2041 if (mouse_enabled && use_mouse_p == MOUSE_GPM
2042 && gpm_fd > 0 && FD_ISSET (gpm_fd, &select_set))
2044 Gpm_GetEvent (&ev);
2045 Gpm_FitEvent (&ev);
2046 *event = ev;
2047 return EV_MOUSE;
2049 #endif /* !HAVE_LIBGPM */
2052 #ifndef HAVE_SLANG
2053 flag = is_wintouched (stdscr);
2054 untouchwin (stdscr);
2055 #endif /* !HAVE_SLANG */
2056 c = block ? getch_with_delay () : get_key_code (1);
2058 #ifndef HAVE_SLANG
2059 if (flag > 0)
2060 tty_touch_screen ();
2061 #endif /* !HAVE_SLANG */
2063 if (mouse_enabled && (c == MCKEY_MOUSE
2064 #ifdef KEY_MOUSE
2065 || c == KEY_MOUSE
2066 #endif /* KEY_MOUSE */
2067 || c == MCKEY_EXTENDED_MOUSE))
2069 /* Mouse event */
2070 xmouse_get_event (event, c == MCKEY_EXTENDED_MOUSE);
2071 return (event->type != 0) ? EV_MOUSE : EV_NONE;
2074 return c;
2077 /* --------------------------------------------------------------------------------------------- */
2078 /* Returns a key press, mouse events are discarded */
2081 tty_getch (void)
2083 Gpm_Event ev;
2084 int key;
2086 ev.x = -1;
2087 while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE);
2088 return key;
2091 /* --------------------------------------------------------------------------------------------- */
2093 char *
2094 learn_key (void)
2096 /* LEARN_TIMEOUT in usec */
2097 #define LEARN_TIMEOUT 200000
2099 fd_set Read_FD_Set;
2100 struct timeval endtime;
2101 struct timeval time_out;
2102 int c;
2103 char buffer[256];
2104 char *p = buffer;
2106 tty_keypad (FALSE); /* disable intepreting keys by ncurses */
2107 c = tty_lowlevel_getch ();
2108 while (c == -1)
2109 c = tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
2110 learn_store_key (buffer, &p, c);
2111 GET_TIME (endtime);
2112 endtime.tv_usec += LEARN_TIMEOUT;
2113 if (endtime.tv_usec > 1000000)
2115 endtime.tv_usec -= 1000000;
2116 endtime.tv_sec++;
2118 tty_nodelay (TRUE);
2119 while (TRUE)
2121 while ((c = tty_lowlevel_getch ()) == -1)
2123 GET_TIME (time_out);
2124 time_out.tv_usec = endtime.tv_usec - time_out.tv_usec;
2125 if (time_out.tv_usec < 0)
2126 time_out.tv_sec++;
2127 time_out.tv_sec = endtime.tv_sec - time_out.tv_sec;
2128 if (time_out.tv_sec >= 0 && time_out.tv_usec > 0)
2130 FD_ZERO (&Read_FD_Set);
2131 FD_SET (input_fd, &Read_FD_Set);
2132 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
2134 else
2135 break;
2137 if (c == -1)
2138 break;
2139 learn_store_key (buffer, &p, c);
2141 tty_keypad (TRUE);
2142 tty_nodelay (FALSE);
2143 *p = '\0';
2144 return g_strdup (buffer);
2145 #undef LEARN_TIMEOUT
2148 /* --------------------------------------------------------------------------------------------- */
2149 /* xterm and linux console only: set keypad to numeric or application
2150 mode. Only in application keypad mode it's possible to distinguish
2151 the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2153 void
2154 numeric_keypad_mode (void)
2156 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2158 fputs (ESC_STR ">", stdout);
2159 fflush (stdout);
2163 /* --------------------------------------------------------------------------------------------- */
2165 void
2166 application_keypad_mode (void)
2168 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2170 fputs (ESC_STR "=", stdout);
2171 fflush (stdout);
2175 /* --------------------------------------------------------------------------------------------- */