Ticket 1551: Update GPL version from 2 to 3
[midnight-commander.git] / lib / tty / key.c
blobea1386767f62eb5669e1aa9488a9fbfc102600e3
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"
46 #include "lib/strutil.h" /* str_casecmp */
48 #include "lib/vfs/vfs.h"
50 #include "tty.h"
51 #include "tty-internal.h" /* mouse_enabled */
52 #include "mouse.h"
53 #include "key.h"
55 #include "lib/widget.h" /* mc_refresh() */
57 #ifdef HAVE_TEXTMODE_X11_SUPPORT
58 #include "x11conn.h"
59 #endif
61 #ifdef __linux__
62 #if defined(__GLIBC__) && (__GLIBC__ < 2)
63 #include <linux/termios.h> /* TIOCLINUX */
64 #else
65 #include <termios.h>
66 #endif
67 #include <sys/ioctl.h>
68 #endif /* __linux__ */
70 #ifdef __CYGWIN__
71 #include <termios.h>
72 #include <sys/ioctl.h>
73 #endif /* __CYGWIN__ */
75 #ifdef __QNXNTO__
76 #include <dlfcn.h>
77 #include <Ph.h>
78 #include <sys/dcmd_chr.h>
79 #endif /* __QNXNTO__ */
81 /*** global variables ****************************************************************************/
83 int mou_auto_repeat = 100;
84 int double_click_speed = 250;
85 int old_esc_mode = 0;
86 int use_8th_bit_as_meta = 0;
88 /* This table is a mapping between names and the constants we use
89 * We use this to allow users to define alternate definitions for
90 * certain keys that may be missing from the terminal database
92 const key_code_name_t key_name_conv_tab[] = {
93 /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
94 to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
95 {KEY_F (1), "f1", N_("Function key 1"), "F1"},
96 {KEY_F (2), "f2", N_("Function key 2"), "F2"},
97 {KEY_F (3), "f3", N_("Function key 3"), "F3"},
98 {KEY_F (4), "f4", N_("Function key 4"), "F4"},
99 {KEY_F (5), "f5", N_("Function key 5"), "F5"},
100 {KEY_F (6), "f6", N_("Function key 6"), "F6"},
101 {KEY_F (7), "f7", N_("Function key 7"), "F7"},
102 {KEY_F (8), "f8", N_("Function key 8"), "F8"},
103 {KEY_F (9), "f9", N_("Function key 9"), "F9"},
104 {KEY_F (10), "f10", N_("Function key 10"), "F10"},
105 {KEY_F (11), "f11", N_("Function key 11"), "F11"},
106 {KEY_F (12), "f12", N_("Function key 12"), "F12"},
107 {KEY_F (13), "f13", N_("Function key 13"), "F13"},
108 {KEY_F (14), "f14", N_("Function key 14"), "F14"},
109 {KEY_F (15), "f15", N_("Function key 15"), "F15"},
110 {KEY_F (16), "f16", N_("Function key 16"), "F16"},
111 {KEY_F (17), "f17", N_("Function key 17"), "F17"},
112 {KEY_F (18), "f18", N_("Function key 18"), "F18"},
113 {KEY_F (19), "f19", N_("Function key 19"), "F19"},
114 {KEY_F (20), "f20", N_("Function key 20"), "F20"},
115 {KEY_BACKSPACE, "backspace", N_("Backspace key"), "Backspace"},
116 {KEY_END, "end", N_("End key"), "End"},
117 {KEY_UP, "up", N_("Up arrow key"), "Up"},
118 {KEY_DOWN, "down", N_("Down arrow key"), "Down"},
119 {KEY_LEFT, "left", N_("Left arrow key"), "Left"},
120 {KEY_RIGHT, "right", N_("Right arrow key"), "Right"},
121 {KEY_HOME, "home", N_("Home key"), "Home"},
122 {KEY_NPAGE, "pgdn", N_("Page Down key"), "PgDn"},
123 {KEY_PPAGE, "pgup", N_("Page Up key"), "PgUp"},
124 {KEY_IC, "insert", N_("Insert key"), "Ins"},
125 {KEY_DC, "delete", N_("Delete key"), "Del"},
126 {ALT ('\t'), "complete", N_("Completion/M-tab"), "Meta-Tab"},
127 {KEY_KP_ADD, "kpplus", N_("+ on keypad"), "+"},
128 {KEY_KP_SUBTRACT, "kpminus", N_("- on keypad"), "-"},
129 {(int) '/', "kpslash", N_("Slash on keypad"), "/"},
130 {KEY_KP_MULTIPLY, "kpasterisk", N_("* on keypad"), "*"},
132 /* From here on, these won't be shown in Learn keys (no space) */
133 {ESC_CHAR, "escape", N_("Escape key"), "Esc"},
134 {KEY_LEFT, "kpleft", N_("Left arrow keypad"), "Left"},
135 {KEY_RIGHT, "kpright", N_("Right arrow keypad"), "Right"},
136 {KEY_UP, "kpup", N_("Up arrow keypad"), "Up"},
137 {KEY_DOWN, "kpdown", N_("Down arrow keypad"), "Down"},
138 {KEY_HOME, "kphome", N_("Home on keypad"), "Home"},
139 {KEY_END, "kpend", N_("End on keypad"), "End"},
140 {KEY_NPAGE, "kpnpage", N_("Page Down keypad"), "PgDn"},
141 {KEY_PPAGE, "kpppage", N_("Page Up keypad"), "PgUp"},
142 {KEY_IC, "kpinsert", N_("Insert on keypad"), "Ins"},
143 {KEY_DC, "kpdelete", N_("Delete on keypad"), "Del"},
144 {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
145 {KEY_F (21), "f21", N_("Function key 21"), "F21"},
146 {KEY_F (22), "f22", N_("Function key 22"), "F22"},
147 {KEY_F (23), "f23", N_("Function key 23"), "F23"},
148 {KEY_F (24), "f24", N_("Function key 24"), "F24"},
149 {KEY_A1, "a1", N_("A1 key"), "A1"},
150 {KEY_C1, "c1", N_("C1 key"), "C1"},
152 /* Alternative label */
153 {ESC_CHAR, "esc", N_("Escape key"), "Esc"},
154 {KEY_BACKSPACE, "bs", N_("Backspace key"), "Bakspace"},
155 {KEY_IC, "ins", N_("Insert key"), "Ins"},
156 {KEY_DC, "del", N_("Delete key"), "Del"},
157 {(int) '+', "plus", N_("Plus"), "+"},
158 {(int) '-', "minus", N_("Minus"), "-"},
159 {(int) '*', "asterisk", N_("Asterisk"), "*"},
160 {(int) '.', "dot", N_("Dot"), "."},
161 {(int) '<', "lt", N_("Less than"), "<"},
162 {(int) '>', "gt", N_("Great than"), ">"},
163 {(int) '=', "equal", N_("Equal"), "="},
164 {(int) ',', "comma", N_("Comma"), ","},
165 {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
166 {(int) ':', "colon", N_("Colon"), ":"},
167 {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
168 {(int) '?', "question", N_("Question mark"), "?"},
169 {(int) '&', "ampersand", N_("Ampersand"), "&"},
170 {(int) '$', "dollar", N_("Dollar sign"), "$"},
171 {(int) '"', "quota", N_("Quotation mark"), "\""},
172 {(int) '%', "percent", N_("Percent sign"), "%"},
173 {(int) '^', "caret", N_("Caret"), "^"},
174 {(int) '~', "tilda", N_("Tilda"), "~"},
175 {(int) '`', "prime", N_("Prime"), "`"},
176 {(int) '_', "underline", N_("Underline"), "_"},
177 {(int) '_', "understrike", N_("Understrike"), "_"},
178 {(int) '|', "pipe", N_("Pipe"), "|"},
179 {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
180 {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
181 {(int) '[', "lbracket", N_("Left bracket"), "["},
182 {(int) ']', "rbracket", N_("Right bracket"), "]"},
183 {(int) '{', "lbrace", N_("Left brace"), "{"},
184 {(int) '}', "rbrace", N_("Right brace"), "}"},
185 {(int) '\n', "enter", N_("Enter"), "Enter"},
186 {(int) '\t', "tab", N_("Tab key"), "Tab"},
187 {(int) ' ', "space", N_("Space key"), "Space"},
188 {(int) '/', "slash", N_("Slash key"), "/"},
189 {(int) '\\', "backslash", N_("Backslash key"), "\\"},
190 {(int) '#', "number", N_("Number sign #"), "#"},
191 {(int) '#', "hash", N_("Number sign #"), "#"},
192 /* TRANSLATORS: Please translate as in "at sign" (@). */
193 {(int) '@', "at", N_("At sign"), "@"},
195 /* meta keys */
196 {KEY_M_CTRL, "control", N_("Ctrl"), "C"},
197 {KEY_M_CTRL, "ctrl", N_("Ctrl"), "C"},
198 {KEY_M_ALT, "meta", N_("Alt"), "M"},
199 {KEY_M_ALT, "alt", N_("Alt"), "M"},
200 {KEY_M_ALT, "ralt", N_("Alt"), "M"},
201 {KEY_M_SHIFT, "shift", N_("Shift"), "S"},
203 {0, NULL, NULL, NULL}
206 /*** file scope macro definitions ****************************************************************/
208 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *) NULL))
209 #define DIF_TIME(t1, t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000)
211 /* The maximum sequence length (32 + null terminator) */
212 #define SEQ_BUFFER_LEN 33
214 /*** file scope type declarations ****************************************************************/
216 /* Linux console keyboard modifiers */
217 typedef enum
219 SHIFT_PRESSED = (1 << 0),
220 ALTR_PRESSED = (1 << 1),
221 CONTROL_PRESSED = (1 << 2),
222 ALTL_PRESSED = (1 << 3)
223 } mod_pressed_t;
225 typedef struct key_def
227 char ch; /* Holds the matching char code */
228 int code; /* The code returned, valid if child == NULL */
229 struct key_def *next;
230 struct key_def *child; /* sequence continuation */
231 int action; /* optional action to be done. Now used only
232 to mark that we are just after the first
233 Escape */
234 } key_def;
236 typedef struct
238 int code;
239 const char *seq;
240 int action;
241 } key_define_t;
243 /* File descriptor monitoring add/remove routines */
244 typedef struct SelectList
246 int fd;
247 select_fn callback;
248 void *info;
249 struct SelectList *next;
250 } SelectList;
252 typedef enum KeySortType
254 KEY_NOSORT = 0,
255 KEY_SORTBYNAME,
256 KEY_SORTBYCODE
257 } KeySortType;
259 #ifdef __QNXNTO__
260 typedef int (*ph_dv_f) (void *, void *);
261 typedef int (*ph_ov_f) (void *);
262 typedef int (*ph_pqc_f) (unsigned short, PhCursorInfo_t *);
263 #endif
265 /*** file scope variables ************************************************************************/
267 static key_define_t mc_default_keys[] = {
268 {ESC_CHAR, ESC_STR, MCKEY_ESCAPE},
269 {ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION},
270 {0, NULL, MCKEY_NOACTION},
273 /* Broken terminfo and termcap databases on xterminals */
274 static key_define_t xterm_key_defines[] = {
275 {KEY_F (1), ESC_STR "OP", MCKEY_NOACTION},
276 {KEY_F (2), ESC_STR "OQ", MCKEY_NOACTION},
277 {KEY_F (3), ESC_STR "OR", MCKEY_NOACTION},
278 {KEY_F (4), ESC_STR "OS", MCKEY_NOACTION},
279 {KEY_F (1), ESC_STR "[11~", MCKEY_NOACTION},
280 {KEY_F (2), ESC_STR "[12~", MCKEY_NOACTION},
281 {KEY_F (3), ESC_STR "[13~", MCKEY_NOACTION},
282 {KEY_F (4), ESC_STR "[14~", MCKEY_NOACTION},
283 {KEY_F (5), ESC_STR "[15~", MCKEY_NOACTION},
284 {KEY_F (6), ESC_STR "[17~", MCKEY_NOACTION},
285 {KEY_F (7), ESC_STR "[18~", MCKEY_NOACTION},
286 {KEY_F (8), ESC_STR "[19~", MCKEY_NOACTION},
287 {KEY_F (9), ESC_STR "[20~", MCKEY_NOACTION},
288 {KEY_F (10), ESC_STR "[21~", MCKEY_NOACTION},
290 /* old xterm Shift-arrows */
291 {KEY_M_SHIFT | KEY_UP, ESC_STR "O2A", MCKEY_NOACTION},
292 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "O2B", MCKEY_NOACTION},
293 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "O2C", MCKEY_NOACTION},
294 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "O2D", MCKEY_NOACTION},
296 /* new xterm Shift-arrows */
297 {KEY_M_SHIFT | KEY_UP, ESC_STR "[1;2A", MCKEY_NOACTION},
298 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[1;2B", MCKEY_NOACTION},
299 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[1;2C", MCKEY_NOACTION},
300 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[1;2D", MCKEY_NOACTION},
302 /* more xterm keys with modifiers */
303 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5;5~", MCKEY_NOACTION},
304 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6;5~", MCKEY_NOACTION},
305 {KEY_M_CTRL | KEY_IC, ESC_STR "[2;5~", MCKEY_NOACTION},
306 {KEY_M_CTRL | KEY_DC, ESC_STR "[3;5~", MCKEY_NOACTION},
307 {KEY_M_CTRL | KEY_HOME, ESC_STR "[1;5H", MCKEY_NOACTION},
308 {KEY_M_CTRL | KEY_END, ESC_STR "[1;5F", MCKEY_NOACTION},
309 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[1;2H", MCKEY_NOACTION},
310 {KEY_M_SHIFT | KEY_END, ESC_STR "[1;2F", MCKEY_NOACTION},
311 {KEY_M_CTRL | KEY_UP, ESC_STR "[1;5A", MCKEY_NOACTION},
312 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;5B", MCKEY_NOACTION},
313 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;5C", MCKEY_NOACTION},
314 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;5D", MCKEY_NOACTION},
315 {KEY_M_SHIFT | KEY_IC, ESC_STR "[2;2~", MCKEY_NOACTION},
316 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3;2~", MCKEY_NOACTION},
317 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[1;6A", MCKEY_NOACTION},
318 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;6B", MCKEY_NOACTION},
319 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;6C", MCKEY_NOACTION},
320 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;6D", MCKEY_NOACTION},
322 /* putty */
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 alt-arrow keys */
329 /* removed as source esc esc esc trouble */
331 { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
332 { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
333 { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
334 { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
335 { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
336 { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
337 { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
338 { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
340 { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
341 { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
342 { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
343 { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
345 { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
346 { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
347 { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
348 { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
350 /* xterm alt-arrow keys */
351 {KEY_M_ALT | KEY_UP, ESC_STR "[1;3A", MCKEY_NOACTION},
352 {KEY_M_ALT | KEY_DOWN, ESC_STR "[1;3B", MCKEY_NOACTION},
353 {KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;3C", MCKEY_NOACTION},
354 {KEY_M_ALT | KEY_LEFT, ESC_STR "[1;3D", MCKEY_NOACTION},
355 {KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;3~", MCKEY_NOACTION},
356 {KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;3~", MCKEY_NOACTION},
357 {KEY_M_ALT | KEY_HOME, ESC_STR "[1~", MCKEY_NOACTION},
358 {KEY_M_ALT | KEY_END, ESC_STR "[4~", MCKEY_NOACTION},
359 {KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR "[1;7A", MCKEY_NOACTION},
360 {KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR "[1;7B", MCKEY_NOACTION},
361 {KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;7C", MCKEY_NOACTION},
362 {KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR "[1;7D", MCKEY_NOACTION},
363 {KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;7~", MCKEY_NOACTION},
364 {KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;7~", MCKEY_NOACTION},
365 {KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR "OH", MCKEY_NOACTION},
366 {KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR "OF", MCKEY_NOACTION},
368 /* rxvt keys with modifiers */
369 {KEY_M_SHIFT | KEY_UP, ESC_STR "[a", MCKEY_NOACTION},
370 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION},
371 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION},
372 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION},
373 {KEY_M_CTRL | KEY_UP, ESC_STR "Oa", MCKEY_NOACTION},
374 {KEY_M_CTRL | KEY_DOWN, ESC_STR "Ob", MCKEY_NOACTION},
375 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "Oc", MCKEY_NOACTION},
376 {KEY_M_CTRL | KEY_LEFT, ESC_STR "Od", MCKEY_NOACTION},
377 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5^", MCKEY_NOACTION},
378 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6^", MCKEY_NOACTION},
379 {KEY_M_CTRL | KEY_HOME, ESC_STR "[7^", MCKEY_NOACTION},
380 {KEY_M_CTRL | KEY_END, ESC_STR "[8^", MCKEY_NOACTION},
381 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[7$", MCKEY_NOACTION},
382 {KEY_M_SHIFT | KEY_END, ESC_STR "[8$", MCKEY_NOACTION},
383 {KEY_M_CTRL | KEY_IC, ESC_STR "[2^", MCKEY_NOACTION},
384 {KEY_M_CTRL | KEY_DC, ESC_STR "[3^", MCKEY_NOACTION},
385 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3$", MCKEY_NOACTION},
387 /* konsole keys with modifiers */
388 {KEY_M_SHIFT | KEY_HOME, ESC_STR "O2H", MCKEY_NOACTION},
389 {KEY_M_SHIFT | KEY_END, ESC_STR "O2F", MCKEY_NOACTION},
391 /* gnome-terminal */
392 {KEY_M_SHIFT | KEY_UP, ESC_STR "[2A", MCKEY_NOACTION},
393 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[2B", MCKEY_NOACTION},
394 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[2C", MCKEY_NOACTION},
395 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[2D", MCKEY_NOACTION},
396 {KEY_M_CTRL | KEY_UP, ESC_STR "[5A", MCKEY_NOACTION},
397 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[5B", MCKEY_NOACTION},
398 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[5C", MCKEY_NOACTION},
399 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[5D", MCKEY_NOACTION},
400 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[6A", MCKEY_NOACTION},
401 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[6B", MCKEY_NOACTION},
402 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[6C", MCKEY_NOACTION},
403 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[6D", MCKEY_NOACTION},
405 /* gnome-terminal - application mode */
406 {KEY_M_CTRL | KEY_UP, ESC_STR "O5A", MCKEY_NOACTION},
407 {KEY_M_CTRL | KEY_DOWN, ESC_STR "O5B", MCKEY_NOACTION},
408 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "O5C", MCKEY_NOACTION},
409 {KEY_M_CTRL | KEY_LEFT, ESC_STR "O5D", MCKEY_NOACTION},
410 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "O6A", MCKEY_NOACTION},
411 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "O6B", MCKEY_NOACTION},
412 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "O6C", MCKEY_NOACTION},
413 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "O6D", MCKEY_NOACTION},
415 /* iTerm */
416 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[5;2~", MCKEY_NOACTION},
417 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[6;2~", MCKEY_NOACTION},
419 /* putty */
420 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[[5;53~", MCKEY_NOACTION},
421 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[[6;53~", MCKEY_NOACTION},
423 /* keypad keys */
424 {KEY_IC, ESC_STR "Op", MCKEY_NOACTION},
425 {KEY_DC, ESC_STR "On", MCKEY_NOACTION},
426 {'/', ESC_STR "Oo", MCKEY_NOACTION},
427 {'\n', ESC_STR "OM", MCKEY_NOACTION},
429 {0, NULL, MCKEY_NOACTION},
432 /* qansi-m terminals have a much more key combinatios,
433 which are undefined in termcap/terminfo */
434 static key_define_t qansi_key_defines[] = {
435 /* qansi-m terminal */
436 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[u", MCKEY_NOACTION}, /* Ctrl-PgDown */
437 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[v", MCKEY_NOACTION}, /* Ctrl-PgUp */
438 {KEY_M_CTRL | KEY_HOME, ESC_STR "[h", MCKEY_NOACTION}, /* Ctrl-Home */
439 {KEY_M_CTRL | KEY_END, ESC_STR "[y", MCKEY_NOACTION}, /* Ctrl-End */
440 {KEY_M_CTRL | KEY_IC, ESC_STR "[`", MCKEY_NOACTION}, /* Ctrl-Insert */
441 {KEY_M_CTRL | KEY_DC, ESC_STR "[p", MCKEY_NOACTION}, /* Ctrl-Delete */
442 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION}, /* Ctrl-Left */
443 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION}, /* Ctrl-Right */
444 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION}, /* Ctrl-Down */
445 {KEY_M_CTRL | KEY_UP, ESC_STR "[a", MCKEY_NOACTION}, /* Ctrl-Up */
446 {KEY_M_CTRL | KEY_KP_ADD, ESC_STR "[s", MCKEY_NOACTION}, /* Ctrl-Gr-Plus */
447 {KEY_M_CTRL | KEY_KP_SUBTRACT, ESC_STR "[t", MCKEY_NOACTION}, /* Ctrl-Gr-Minus */
448 {KEY_M_CTRL | '\t', ESC_STR "[z", MCKEY_NOACTION}, /* Ctrl-Tab */
449 {KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION}, /* Shift-Tab */
450 {KEY_M_CTRL | KEY_F (1), ESC_STR "[1~", MCKEY_NOACTION}, /* Ctrl-F1 */
451 {KEY_M_CTRL | KEY_F (2), ESC_STR "[2~", MCKEY_NOACTION}, /* Ctrl-F2 */
452 {KEY_M_CTRL | KEY_F (3), ESC_STR "[3~", MCKEY_NOACTION}, /* Ctrl-F3 */
453 {KEY_M_CTRL | KEY_F (4), ESC_STR "[4~", MCKEY_NOACTION}, /* Ctrl-F4 */
454 {KEY_M_CTRL | KEY_F (5), ESC_STR "[5~", MCKEY_NOACTION}, /* Ctrl-F5 */
455 {KEY_M_CTRL | KEY_F (6), ESC_STR "[6~", MCKEY_NOACTION}, /* Ctrl-F6 */
456 {KEY_M_CTRL | KEY_F (7), ESC_STR "[7~", MCKEY_NOACTION}, /* Ctrl-F7 */
457 {KEY_M_CTRL | KEY_F (8), ESC_STR "[8~", MCKEY_NOACTION}, /* Ctrl-F8 */
458 {KEY_M_CTRL | KEY_F (9), ESC_STR "[9~", MCKEY_NOACTION}, /* Ctrl-F9 */
459 {KEY_M_CTRL | KEY_F (10), ESC_STR "[10~", MCKEY_NOACTION}, /* Ctrl-F10 */
460 {KEY_M_CTRL | KEY_F (11), ESC_STR "[11~", MCKEY_NOACTION}, /* Ctrl-F11 */
461 {KEY_M_CTRL | KEY_F (12), ESC_STR "[12~", MCKEY_NOACTION}, /* Ctrl-F12 */
462 {KEY_M_ALT | KEY_F (1), ESC_STR "[17~", MCKEY_NOACTION}, /* Alt-F1 */
463 {KEY_M_ALT | KEY_F (2), ESC_STR "[18~", MCKEY_NOACTION}, /* Alt-F2 */
464 {KEY_M_ALT | KEY_F (3), ESC_STR "[19~", MCKEY_NOACTION}, /* Alt-F3 */
465 {KEY_M_ALT | KEY_F (4), ESC_STR "[20~", MCKEY_NOACTION}, /* Alt-F4 */
466 {KEY_M_ALT | KEY_F (5), ESC_STR "[21~", MCKEY_NOACTION}, /* Alt-F5 */
467 {KEY_M_ALT | KEY_F (6), ESC_STR "[22~", MCKEY_NOACTION}, /* Alt-F6 */
468 {KEY_M_ALT | KEY_F (7), ESC_STR "[23~", MCKEY_NOACTION}, /* Alt-F7 */
469 {KEY_M_ALT | KEY_F (8), ESC_STR "[24~", MCKEY_NOACTION}, /* Alt-F8 */
470 {KEY_M_ALT | KEY_F (9), ESC_STR "[25~", MCKEY_NOACTION}, /* Alt-F9 */
471 {KEY_M_ALT | KEY_F (10), ESC_STR "[26~", MCKEY_NOACTION}, /* Alt-F10 */
472 {KEY_M_ALT | KEY_F (11), ESC_STR "[27~", MCKEY_NOACTION}, /* Alt-F11 */
473 {KEY_M_ALT | KEY_F (12), ESC_STR "[28~", MCKEY_NOACTION}, /* Alt-F12 */
474 {KEY_M_ALT | 'a', ESC_STR "Na", MCKEY_NOACTION}, /* Alt-a */
475 {KEY_M_ALT | 'b', ESC_STR "Nb", MCKEY_NOACTION}, /* Alt-b */
476 {KEY_M_ALT | 'c', ESC_STR "Nc", MCKEY_NOACTION}, /* Alt-c */
477 {KEY_M_ALT | 'd', ESC_STR "Nd", MCKEY_NOACTION}, /* Alt-d */
478 {KEY_M_ALT | 'e', ESC_STR "Ne", MCKEY_NOACTION}, /* Alt-e */
479 {KEY_M_ALT | 'f', ESC_STR "Nf", MCKEY_NOACTION}, /* Alt-f */
480 {KEY_M_ALT | 'g', ESC_STR "Ng", MCKEY_NOACTION}, /* Alt-g */
481 {KEY_M_ALT | 'h', ESC_STR "Nh", MCKEY_NOACTION}, /* Alt-h */
482 {KEY_M_ALT | 'i', ESC_STR "Ni", MCKEY_NOACTION}, /* Alt-i */
483 {KEY_M_ALT | 'j', ESC_STR "Nj", MCKEY_NOACTION}, /* Alt-j */
484 {KEY_M_ALT | 'k', ESC_STR "Nk", MCKEY_NOACTION}, /* Alt-k */
485 {KEY_M_ALT | 'l', ESC_STR "Nl", MCKEY_NOACTION}, /* Alt-l */
486 {KEY_M_ALT | 'm', ESC_STR "Nm", MCKEY_NOACTION}, /* Alt-m */
487 {KEY_M_ALT | 'n', ESC_STR "Nn", MCKEY_NOACTION}, /* Alt-n */
488 {KEY_M_ALT | 'o', ESC_STR "No", MCKEY_NOACTION}, /* Alt-o */
489 {KEY_M_ALT | 'p', ESC_STR "Np", MCKEY_NOACTION}, /* Alt-p */
490 {KEY_M_ALT | 'q', ESC_STR "Nq", MCKEY_NOACTION}, /* Alt-q */
491 {KEY_M_ALT | 'r', ESC_STR "Nr", MCKEY_NOACTION}, /* Alt-r */
492 {KEY_M_ALT | 's', ESC_STR "Ns", MCKEY_NOACTION}, /* Alt-s */
493 {KEY_M_ALT | 't', ESC_STR "Nt", MCKEY_NOACTION}, /* Alt-t */
494 {KEY_M_ALT | 'u', ESC_STR "Nu", MCKEY_NOACTION}, /* Alt-u */
495 {KEY_M_ALT | 'v', ESC_STR "Nv", MCKEY_NOACTION}, /* Alt-v */
496 {KEY_M_ALT | 'w', ESC_STR "Nw", MCKEY_NOACTION}, /* Alt-w */
497 {KEY_M_ALT | 'x', ESC_STR "Nx", MCKEY_NOACTION}, /* Alt-x */
498 {KEY_M_ALT | 'y', ESC_STR "Ny", MCKEY_NOACTION}, /* Alt-y */
499 {KEY_M_ALT | 'z', ESC_STR "Nz", MCKEY_NOACTION}, /* Alt-z */
500 {KEY_KP_SUBTRACT, ESC_STR "[S", MCKEY_NOACTION}, /* Gr-Minus */
501 {KEY_KP_ADD, ESC_STR "[T", MCKEY_NOACTION}, /* Gr-Plus */
502 {0, NULL, MCKEY_NOACTION},
505 /* timeout for old_esc_mode in usec */
506 int old_esc_mode_timeout = 1000000; /* settable via env */
508 /* This holds all the key definitions */
509 static key_def *keys = NULL;
511 static int input_fd;
512 static int disabled_channels = 0; /* Disable channels checking */
514 static SelectList *select_list = NULL;
516 static int seq_buffer[SEQ_BUFFER_LEN];
517 static int *seq_append = NULL;
519 static int *pending_keys = NULL;
521 #ifdef __QNXNTO__
522 ph_dv_f ph_attach;
523 ph_ov_f ph_input_group;
524 ph_pqc_f ph_query_cursor;
525 #endif
527 #ifdef HAVE_TEXTMODE_X11_SUPPORT
528 static Display *x11_display;
529 static Window x11_window;
530 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
532 static KeySortType has_been_sorted = KEY_NOSORT;
534 /* *INDENT-OFF* */
535 static const size_t key_conv_tab_size = G_N_ELEMENTS (key_name_conv_tab) - 1;
536 /* *INDENT-ON* */
538 static const key_code_name_t *key_conv_tab_sorted[G_N_ELEMENTS (key_name_conv_tab) - 1];
540 /*** file scope functions ************************************************************************/
541 /* --------------------------------------------------------------------------------------------- */
543 static int
544 add_selects (fd_set * select_set)
546 int top_fd = 0;
548 if (disabled_channels == 0)
550 SelectList *p;
552 for (p = select_list; p != NULL; p = p->next)
554 FD_SET (p->fd, select_set);
555 if (p->fd > top_fd)
556 top_fd = p->fd;
560 return top_fd;
563 /* --------------------------------------------------------------------------------------------- */
565 static void
566 check_selects (fd_set * select_set)
568 if (disabled_channels == 0)
570 gboolean retry;
574 SelectList *p;
576 retry = FALSE;
577 for (p = select_list; p; p = p->next)
578 if (FD_ISSET (p->fd, select_set))
580 FD_CLR (p->fd, select_set);
581 (*p->callback) (p->fd, p->info);
582 retry = TRUE;
583 break;
586 while (retry);
590 /* --------------------------------------------------------------------------------------------- */
591 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
593 static void
594 try_channels (int set_timeout)
596 struct timeval time_out;
597 static fd_set select_set;
598 struct timeval *timeptr;
599 int v;
600 int maxfdp;
602 while (1)
604 FD_ZERO (&select_set);
605 FD_SET (input_fd, &select_set); /* Add stdin */
606 maxfdp = max (add_selects (&select_set), input_fd);
608 timeptr = NULL;
609 if (set_timeout)
611 time_out.tv_sec = 0;
612 time_out.tv_usec = 100000;
613 timeptr = &time_out;
616 v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr);
617 if (v > 0)
619 check_selects (&select_set);
620 if (FD_ISSET (input_fd, &select_set))
621 break;
626 /* --------------------------------------------------------------------------------------------- */
628 static key_def *
629 create_sequence (const char *seq, int code, int action)
631 key_def *base, *p, *attach;
633 for (base = attach = NULL; *seq; seq++)
635 p = g_new (key_def, 1);
636 if (base == NULL)
637 base = p;
638 if (attach != NULL)
639 attach->child = p;
641 p->ch = *seq;
642 p->code = code;
643 p->child = p->next = NULL;
644 if (seq[1] == '\0')
645 p->action = action;
646 else
647 p->action = MCKEY_NOACTION;
648 attach = p;
650 return base;
653 /* --------------------------------------------------------------------------------------------- */
655 static void
656 define_sequences (const key_define_t * kd)
658 int i;
660 for (i = 0; kd[i].code != 0; i++)
661 define_sequence (kd[i].code, kd[i].seq, kd[i].action);
664 /* --------------------------------------------------------------------------------------------- */
666 static void
667 init_key_x11 (void)
669 #ifdef HAVE_TEXTMODE_X11_SUPPORT
670 if (getenv ("DISPLAY") != NULL)
672 x11_display = mc_XOpenDisplay (0);
674 if (x11_display != NULL)
675 x11_window = DefaultRootWindow (x11_display);
677 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
680 /* --------------------------------------------------------------------------------------------- */
681 /* Workaround for System V Curses vt100 bug */
683 static int
684 getch_with_delay (void)
686 int c;
688 /* This routine could be used on systems without mouse support,
689 so we need to do the select check :-( */
690 while (1)
692 if (pending_keys == NULL)
693 try_channels (0);
695 /* Try to get a character */
696 c = get_key_code (0);
697 if (c != -1)
698 break;
699 /* Failed -> wait 0.1 secs and try again */
700 try_channels (1);
702 /* Success -> return the character */
703 return c;
706 /* --------------------------------------------------------------------------------------------- */
708 static void
709 xmouse_get_event (Gpm_Event * ev)
711 int btn;
712 static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
713 static struct timeval tv2;
714 static int clicks = 0;
715 static int last_btn = 0;
717 /* Decode Xterm mouse information to a GPM style event */
719 /* Variable btn has following meaning: */
720 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
721 btn = tty_lowlevel_getch () - 32;
723 /* There seems to be no way of knowing which button was released */
724 /* So we assume all the buttons were released */
726 if (btn == 3)
728 if (last_btn != 0)
730 if ((last_btn & (GPM_B_UP | GPM_B_DOWN)) != 0)
732 /* FIXME: DIRTY HACK */
733 /* don't generate GPM_UP after mouse wheel */
734 /* need for menu event handling */
735 ev->type = 0;
736 tv1.tv_sec = 0;
737 tv1.tv_usec = 0;
739 else
741 ev->type = GPM_UP | (GPM_SINGLE << clicks);
742 GET_TIME (tv1);
744 ev->buttons = 0;
745 last_btn = 0;
746 clicks = 0;
748 else
750 /* Bogus event, maybe mouse wheel */
751 ev->type = 0;
754 else
756 if (btn >= 32 && btn <= 34)
758 btn -= 32;
759 ev->type = GPM_DRAG;
761 else
762 ev->type = GPM_DOWN;
764 GET_TIME (tv2);
765 if (tv1.tv_sec && (DIF_TIME (tv1, tv2) < double_click_speed))
767 clicks++;
768 clicks %= 3;
770 else
771 clicks = 0;
773 switch (btn)
775 case 0:
776 ev->buttons = GPM_B_LEFT;
777 break;
778 case 1:
779 ev->buttons = GPM_B_MIDDLE;
780 break;
781 case 2:
782 ev->buttons = GPM_B_RIGHT;
783 break;
784 case 64:
785 ev->buttons = GPM_B_UP;
786 clicks = 0;
787 break;
788 case 65:
789 ev->buttons = GPM_B_DOWN;
790 clicks = 0;
791 break;
792 default:
793 /* Nothing */
794 ev->type = 0;
795 ev->buttons = 0;
796 break;
798 last_btn = ev->buttons;
800 /* Coordinates are 33-based */
801 /* Transform them to 1-based */
802 ev->x = tty_lowlevel_getch () - 32;
803 ev->y = tty_lowlevel_getch () - 32;
806 /* --------------------------------------------------------------------------------------------- */
808 * Get modifier state (shift, alt, ctrl) for the last key pressed.
809 * We are assuming that the state didn't change since the key press.
810 * This is only correct if get_modifier() is called very fast after
811 * the input was received, so that the user didn't release the
812 * modifier keys yet.
815 static int
816 get_modifier (void)
818 int result = 0;
819 #ifdef __QNXNTO__
820 int mod_status, shift_ext_status;
821 static int in_photon = 0;
822 static int ph_ig = 0;
823 PhCursorInfo_t cursor_info;
824 #endif /* __QNXNTO__ */
826 #ifdef HAVE_TEXTMODE_X11_SUPPORT
827 if (x11_window != 0)
829 Window root, child;
830 int root_x, root_y;
831 int win_x, win_y;
832 unsigned int mask;
834 mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x,
835 &root_y, &win_x, &win_y, &mask);
837 if (mask & ShiftMask)
838 result |= KEY_M_SHIFT;
839 if (mask & ControlMask)
840 result |= KEY_M_CTRL;
841 return result;
843 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
844 #ifdef __QNXNTO__
846 if (in_photon == 0)
848 /* First time here, let's load Photon library and attach
849 to Photon */
850 in_photon = -1;
851 if (getenv ("PHOTON2_PATH") != NULL)
853 /* QNX 6.x has no support for RTLD_LAZY */
854 void *ph_handle = dlopen ("/usr/lib/libph.so", RTLD_NOW);
855 if (ph_handle != NULL)
857 ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach");
858 ph_input_group = (ph_ov_f) dlsym (ph_handle, "PhInputGroup");
859 ph_query_cursor = (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor");
860 if ((ph_attach != NULL) && (ph_input_group != NULL) && (ph_query_cursor != NULL))
862 if ((*ph_attach) (0, 0))
863 { /* Attached */
864 ph_ig = (*ph_input_group) (0);
865 in_photon = 1;
871 /* We do not have Photon running. Assume we are in text
872 console or xterm */
873 if (in_photon == -1)
875 if (devctl (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status, sizeof (int), NULL) == -1)
876 return 0;
877 shift_ext_status = mod_status & 0xffffff00UL;
878 mod_status &= 0x7f;
879 if (mod_status & _LINESTATUS_CON_ALT)
880 result |= KEY_M_ALT;
881 if (mod_status & _LINESTATUS_CON_CTRL)
882 result |= KEY_M_CTRL;
883 if ((mod_status & _LINESTATUS_CON_SHIFT) || (shift_ext_status & 0x00000800UL))
884 result |= KEY_M_SHIFT;
886 else
888 (*ph_query_cursor) (ph_ig, &cursor_info);
889 if (cursor_info.key_mods & 0x04)
890 result |= KEY_M_ALT;
891 if (cursor_info.key_mods & 0x02)
892 result |= KEY_M_CTRL;
893 if (cursor_info.key_mods & 0x01)
894 result |= KEY_M_SHIFT;
896 #endif /* __QNXNTO__ */
898 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
900 unsigned char modifiers = 6;
902 if (ioctl (0, TIOCLINUX, &modifiers) < 0)
903 return 0;
905 /* Translate Linux modifiers into mc modifiers */
906 if (modifiers & SHIFT_PRESSED)
907 result |= KEY_M_SHIFT;
908 if (modifiers & (ALTL_PRESSED | ALTR_PRESSED))
909 result |= KEY_M_ALT;
910 if (modifiers & CONTROL_PRESSED)
911 result |= KEY_M_CTRL;
913 #endif /* !__linux__ */
914 return result;
917 /* --------------------------------------------------------------------------------------------- */
919 static gboolean
920 push_char (int c)
922 gboolean ret = FALSE;
924 if (seq_append == NULL)
925 seq_append = seq_buffer;
927 if (seq_append != &(seq_buffer[SEQ_BUFFER_LEN - 2]))
929 *(seq_append++) = c;
930 *seq_append = 0;
931 ret = TRUE;
934 return ret;
937 /* --------------------------------------------------------------------------------------------- */
938 /* Apply corrections for the keycode generated in get_key_code() */
940 static int
941 correct_key_code (int code)
943 unsigned int c = code & ~KEY_M_MASK; /* code without modifier */
944 unsigned int mod = code & KEY_M_MASK; /* modifier */
945 #ifdef __QNXNTO__
946 unsigned int qmod; /* bunch of the QNX console
947 modifiers needs unchanged */
948 #endif /* __QNXNTO__ */
951 * Add key modifiers directly from X11 or OS.
952 * Ordinary characters only get modifiers from sequences.
954 if (c < 32 || c >= 256)
956 mod |= get_modifier ();
959 /* This is needed if the newline is reported as carriage return */
960 if (c == '\r')
961 c = '\n';
963 /* This is reported to be useful on AIX */
964 if (c == KEY_SCANCEL)
965 c = '\t';
967 /* Convert Shift+Tab and Ctrl+Tab to Back Tab */
968 if ((c == '\t') && (mod & (KEY_M_SHIFT | KEY_M_CTRL)))
970 c = KEY_BTAB;
971 mod = 0;
974 /* F0 is the same as F10 for out purposes */
975 if (c == KEY_F (0))
976 c = KEY_F (10);
979 * We are not interested if Ctrl was pressed when entering control
980 * characters, so assume that it was. When checking for such keys,
981 * XCTRL macro should be used. In some cases, we are interested,
982 * e.g. to distinguish Ctrl-Enter from Enter.
984 if (c == '\b')
986 /* Special case for backspase ('\b' < 32) */
987 c = KEY_BACKSPACE;
988 mod &= ~KEY_M_CTRL;
990 else if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n')
992 mod |= KEY_M_CTRL;
995 #ifdef __QNXNTO__
996 qmod = get_modifier ();
998 if ((c == 127) && (mod == 0))
999 { /* Add Ctrl/Alt/Shift-BackSpace */
1000 mod |= get_modifier ();
1001 c = KEY_BACKSPACE;
1004 if ((c == '0') && (mod == 0))
1005 { /* Add Shift-Insert on key pad */
1006 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1008 mod = KEY_M_SHIFT;
1009 c = KEY_IC;
1013 if ((c == '.') && (mod == 0))
1014 { /* Add Shift-Del on key pad */
1015 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1017 mod = KEY_M_SHIFT;
1018 c = KEY_DC;
1021 #endif /* __QNXNTO__ */
1023 /* Unrecognized 0177 is delete (preserve Ctrl) */
1024 if (c == 0177)
1026 c = KEY_BACKSPACE;
1029 #if 0
1030 /* Unrecognized Ctrl-d is delete */
1031 if (c == (31 & 'd'))
1033 c = KEY_DC;
1034 mod &= ~KEY_M_CTRL;
1037 /* Unrecognized Ctrl-h is backspace */
1038 if (c == (31 & 'h'))
1040 c = KEY_BACKSPACE;
1041 mod &= ~KEY_M_CTRL;
1043 #endif
1045 /* Shift+BackSpace is backspace */
1046 if (c == KEY_BACKSPACE && (mod & KEY_M_SHIFT))
1048 mod &= ~KEY_M_SHIFT;
1051 /* Convert Shift+Fn to F(n+10) */
1052 if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT))
1054 c += 10;
1057 /* Remove Shift information from function keys */
1058 if (c >= KEY_F (1) && c <= KEY_F (20))
1060 mod &= ~KEY_M_SHIFT;
1063 if (!mc_global.tty.alternate_plus_minus)
1064 switch (c)
1066 case KEY_KP_ADD:
1067 c = '+';
1068 break;
1069 case KEY_KP_SUBTRACT:
1070 c = '-';
1071 break;
1072 case KEY_KP_MULTIPLY:
1073 c = '*';
1074 break;
1077 return (mod | c);
1080 /* --------------------------------------------------------------------------------------------- */
1082 static int
1083 xgetch_second (void)
1085 fd_set Read_FD_Set;
1086 int c;
1087 struct timeval time_out;
1089 time_out.tv_sec = old_esc_mode_timeout / 1000000;
1090 time_out.tv_usec = old_esc_mode_timeout % 1000000;
1091 tty_nodelay (TRUE);
1092 FD_ZERO (&Read_FD_Set);
1093 FD_SET (input_fd, &Read_FD_Set);
1094 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
1095 c = tty_lowlevel_getch ();
1096 tty_nodelay (FALSE);
1097 return c;
1100 /* --------------------------------------------------------------------------------------------- */
1102 static void
1103 learn_store_key (char *buffer, char **p, int c)
1105 if (*p - buffer > 253)
1106 return;
1107 if (c == ESC_CHAR)
1109 *(*p)++ = '\\';
1110 *(*p)++ = 'e';
1112 else if (c < ' ')
1114 *(*p)++ = '^';
1115 *(*p)++ = c + 'a' - 1;
1117 else if (c == '^')
1119 *(*p)++ = '^';
1120 *(*p)++ = '^';
1122 else
1123 *(*p)++ = (char) c;
1126 /* --------------------------------------------------------------------------------------------- */
1128 static void
1129 k_dispose (key_def * k)
1131 if (k != NULL)
1133 k_dispose (k->child);
1134 k_dispose (k->next);
1135 g_free (k);
1139 /* --------------------------------------------------------------------------------------------- */
1141 static void
1142 s_dispose (SelectList * sel)
1144 if (sel != NULL)
1146 s_dispose (sel->next);
1147 g_free (sel);
1151 /* --------------------------------------------------------------------------------------------- */
1153 static int
1154 key_code_comparator_by_name (const void *p1, const void *p2)
1156 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1157 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1159 return str_casecmp (n1->name, n2->name);
1162 /* --------------------------------------------------------------------------------------------- */
1164 static int
1165 key_code_comparator_by_code (const void *p1, const void *p2)
1167 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1168 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1170 return n1->code - n2->code;
1173 /* --------------------------------------------------------------------------------------------- */
1175 static inline void
1176 sort_key_conv_tab (enum KeySortType type_sort)
1178 if (has_been_sorted != type_sort)
1180 size_t i;
1181 for (i = 0; i < key_conv_tab_size; i++)
1182 key_conv_tab_sorted[i] = &key_name_conv_tab[i];
1184 if (type_sort == KEY_SORTBYNAME)
1186 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1187 &key_code_comparator_by_name);
1189 else if (type_sort == KEY_SORTBYCODE)
1191 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1192 &key_code_comparator_by_code);
1194 has_been_sorted = type_sort;
1198 /* --------------------------------------------------------------------------------------------- */
1200 static int
1201 lookup_keyname (const char *name, int *idx)
1203 if (name[0] != '\0')
1205 const key_code_name_t key = { 0, name, NULL, NULL };
1206 const key_code_name_t *keyp = &key;
1207 key_code_name_t **res;
1209 if (name[1] == '\0')
1211 *idx = -1;
1212 return (int) name[0];
1215 sort_key_conv_tab (KEY_SORTBYNAME);
1217 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1218 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_name);
1220 if (res != NULL)
1222 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1223 return (*res)->code;
1227 *idx = -1;
1228 return 0;
1231 /* --------------------------------------------------------------------------------------------- */
1233 static gboolean
1234 lookup_keycode (const long code, int *idx)
1236 if (code != 0)
1238 const key_code_name_t key = { code, NULL, NULL, NULL };
1239 const key_code_name_t *keyp = &key;
1240 key_code_name_t **res;
1242 sort_key_conv_tab (KEY_SORTBYCODE);
1244 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1245 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_code);
1247 if (res != NULL)
1249 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1250 return TRUE;
1254 *idx = -1;
1255 return FALSE;
1258 /* --------------------------------------------------------------------------------------------- */
1259 /*** public functions ****************************************************************************/
1260 /* --------------------------------------------------------------------------------------------- */
1261 /* This has to be called before init_slang or whatever routine
1262 calls any define_sequence */
1264 void
1265 init_key (void)
1267 const char *term = getenv ("TERM");
1269 /* This has to be the first define_sequence */
1270 /* So, we can assume that the first keys member has ESC */
1271 define_sequences (mc_default_keys);
1273 /* Terminfo on irix does not have some keys */
1274 if (mc_global.tty.xterm_flag
1275 || (term != NULL
1276 && (strncmp (term, "iris-ansi", 9) == 0
1277 || strncmp (term, "xterm", 5) == 0
1278 || strncmp (term, "rxvt", 4) == 0 || strcmp (term, "screen") == 0)))
1279 define_sequences (xterm_key_defines);
1281 /* load some additional keys (e.g. direct Alt-? support) */
1282 load_xtra_key_defines ();
1284 #ifdef __QNX__
1285 if ((term != NULL) && (strncmp (term, "qnx", 3) == 0))
1287 /* Modify the default value of use_8th_bit_as_meta: we would
1288 * like to provide a working mc for a newbie who knows nothing
1289 * about [Options|Display bits|Full 8 bits input]...
1291 * Don't use 'meta'-bit, when we are dealing with a
1292 * 'qnx*'-type terminal: clear the default value!
1293 * These terminal types use 0xFF as an escape character,
1294 * so use_8th_bit_as_meta==1 must not be enabled!
1296 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1297 * is not used now (doesn't even depend on use_8th_bit_as_meta
1298 * as in mc-3.1.2)...GREAT!...no additional code is required!]
1300 use_8th_bit_as_meta = 0;
1302 #endif /* __QNX__ */
1304 init_key_x11 ();
1306 /* Load the qansi-m key definitions
1307 if we are running under the qansi-m terminal */
1308 if (term != NULL && (strncmp (term, "qansi-m", 7) == 0))
1309 define_sequences (qansi_key_defines);
1312 /* --------------------------------------------------------------------------------------------- */
1314 * This has to be called after SLang_init_tty/slint_init
1317 void
1318 init_key_input_fd (void)
1320 #ifdef HAVE_SLANG
1321 input_fd = SLang_TT_Read_FD;
1322 #endif
1325 /* --------------------------------------------------------------------------------------------- */
1327 void
1328 done_key (void)
1330 k_dispose (keys);
1331 s_dispose (select_list);
1333 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1334 if (x11_display)
1335 mc_XCloseDisplay (x11_display);
1336 #endif
1339 /* --------------------------------------------------------------------------------------------- */
1341 void
1342 add_select_channel (int fd, select_fn callback, void *info)
1344 SelectList *new;
1346 new = g_new (SelectList, 1);
1347 new->fd = fd;
1348 new->callback = callback;
1349 new->info = info;
1350 new->next = select_list;
1351 select_list = new;
1354 /* --------------------------------------------------------------------------------------------- */
1356 void
1357 delete_select_channel (int fd)
1359 SelectList *p = select_list;
1360 SelectList *p_prev = NULL;
1361 SelectList *p_next;
1363 while (p != NULL)
1364 if (p->fd == fd)
1366 p_next = p->next;
1368 if (p_prev != NULL)
1369 p_prev->next = p_next;
1370 else
1371 select_list = p_next;
1373 g_free (p);
1374 p = p_next;
1376 else
1378 p_prev = p;
1379 p = p->next;
1383 /* --------------------------------------------------------------------------------------------- */
1385 void
1386 channels_up (void)
1388 if (disabled_channels == 0)
1389 fputs ("Error: channels_up called with disabled_channels = 0\n", stderr);
1390 disabled_channels--;
1393 /* --------------------------------------------------------------------------------------------- */
1395 void
1396 channels_down (void)
1398 disabled_channels++;
1401 /* --------------------------------------------------------------------------------------------- */
1403 * Return the code associated with the symbolic name keyname
1406 long
1407 lookup_key (const char *name, char **label)
1409 char **lc_keys, **p;
1410 int k = -1;
1411 int key = 0;
1412 int lc_index = -1;
1414 int use_meta = -1;
1415 int use_ctrl = -1;
1416 int use_shift = -1;
1418 if (name == NULL)
1419 return 0;
1421 name = g_strstrip (g_strdup (name));
1422 p = lc_keys = g_strsplit_set (name, "-+ ", -1);
1423 g_free ((char *) name);
1425 while ((p != NULL) && (*p != NULL))
1427 if ((*p)[0] != '\0')
1429 int idx;
1431 key = lookup_keyname (g_strstrip (*p), &idx);
1433 if (key == KEY_M_ALT)
1434 use_meta = idx;
1435 else if (key == KEY_M_CTRL)
1436 use_ctrl = idx;
1437 else if (key == KEY_M_SHIFT)
1438 use_shift = idx;
1439 else
1441 k = key;
1442 lc_index = idx;
1443 break;
1447 p++;
1450 g_strfreev (lc_keys);
1452 /* output */
1453 if (k <= 0)
1454 return 0;
1457 if (label != NULL)
1459 GString *s;
1461 s = g_string_new ("");
1463 if (use_meta != -1)
1465 g_string_append (s, key_conv_tab_sorted[use_meta]->shortcut);
1466 g_string_append_c (s, '-');
1468 if (use_ctrl != -1)
1470 g_string_append (s, key_conv_tab_sorted[use_ctrl]->shortcut);
1471 g_string_append_c (s, '-');
1473 if (use_shift != -1)
1475 if (k < 127)
1476 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1477 else
1479 g_string_append (s, key_conv_tab_sorted[use_shift]->shortcut);
1480 g_string_append_c (s, '-');
1481 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1484 else if (k < 128)
1486 if ((k >= 'A') || (lc_index < 0) || (key_conv_tab_sorted[lc_index]->shortcut == NULL))
1487 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) k));
1488 else
1489 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1491 else if ((lc_index != -1) && (key_conv_tab_sorted[lc_index]->shortcut != NULL))
1492 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1493 else
1494 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) key));
1496 *label = g_string_free (s, FALSE);
1499 if (use_shift != -1)
1501 if (k < 127 && k > 31)
1502 k = g_ascii_toupper ((gchar) k);
1503 else
1504 k |= KEY_M_SHIFT;
1507 if (use_ctrl != -1)
1509 if (k < 256)
1510 k = XCTRL (k);
1511 else
1512 k |= KEY_M_CTRL;
1515 if (use_meta != -1)
1516 k = ALT (k);
1518 return (long) k;
1521 /* --------------------------------------------------------------------------------------------- */
1523 char *
1524 lookup_key_by_code (const int keycode)
1526 /* code without modifier */
1527 unsigned int k = keycode & ~KEY_M_MASK;
1528 /* modifier */
1529 unsigned int mod = keycode & KEY_M_MASK;
1531 int use_meta = -1;
1532 int use_ctrl = -1;
1533 int use_shift = -1;
1534 int key_idx = -1;
1536 GString *s;
1537 int idx;
1539 s = g_string_sized_new (8);
1541 if (lookup_keycode (k, &key_idx) || (k > 0 && k < 256))
1543 if (mod & KEY_M_ALT)
1545 if (lookup_keycode (KEY_M_ALT, &idx))
1547 use_meta = idx;
1548 g_string_append (s, key_conv_tab_sorted[use_meta]->name);
1549 g_string_append_c (s, '-');
1552 if (mod & KEY_M_CTRL)
1554 /* non printeble chars like a CTRL-[A..Z] */
1555 if (k < 32)
1556 k += 64;
1558 if (lookup_keycode (KEY_M_CTRL, &idx))
1560 use_ctrl = idx;
1561 g_string_append (s, key_conv_tab_sorted[use_ctrl]->name);
1562 g_string_append_c (s, '-');
1565 if (mod & KEY_M_SHIFT)
1567 if (lookup_keycode (KEY_M_ALT, &idx))
1569 use_shift = idx;
1570 if (k < 127)
1571 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1572 else
1574 g_string_append (s, key_conv_tab_sorted[use_shift]->name);
1575 g_string_append_c (s, '-');
1576 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1580 else if (k < 128)
1582 if ((k >= 'A') || (key_idx < 0) || (key_conv_tab_sorted[key_idx]->name == NULL))
1583 g_string_append_c (s, (gchar) k);
1584 else
1585 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1587 else if ((key_idx != -1) && (key_conv_tab_sorted[key_idx]->name != NULL))
1588 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1589 else
1590 g_string_append_c (s, (gchar) keycode);
1593 return g_string_free (s, s->len == 0);
1596 /* --------------------------------------------------------------------------------------------- */
1598 * Return TRUE on success, FALSE on error.
1599 * An error happens if SEQ is a beginning of an existing longer sequence.
1602 gboolean
1603 define_sequence (int code, const char *seq, int action)
1605 key_def *base;
1607 if (strlen (seq) > SEQ_BUFFER_LEN - 1)
1608 return FALSE;
1610 for (base = keys; (base != NULL) && (*seq != '\0');)
1611 if (*seq == base->ch)
1613 if (base->child == 0)
1615 if (*(seq + 1) != '\0')
1616 base->child = create_sequence (seq + 1, code, action);
1617 else
1619 /* The sequence matches an existing one. */
1620 base->code = code;
1621 base->action = action;
1623 return TRUE;
1626 base = base->child;
1627 seq++;
1629 else
1631 if (base->next)
1632 base = base->next;
1633 else
1635 base->next = create_sequence (seq, code, action);
1636 return TRUE;
1640 if (*seq == '\0')
1642 /* Attempt to redefine a sequence with a shorter sequence. */
1643 return FALSE;
1646 keys = create_sequence (seq, code, action);
1647 return TRUE;
1650 /* --------------------------------------------------------------------------------------------- */
1652 * Check if we are idle, i.e. there are no pending keyboard or mouse
1653 * events. Return 1 is idle, 0 is there are pending events.
1655 gboolean
1656 is_idle (void)
1658 int maxfdp;
1659 fd_set select_set;
1660 struct timeval time_out;
1662 FD_ZERO (&select_set);
1663 FD_SET (input_fd, &select_set);
1664 maxfdp = input_fd;
1665 #ifdef HAVE_LIBGPM
1666 if (mouse_enabled && (use_mouse_p == MOUSE_GPM) && (gpm_fd > 0))
1668 FD_SET (gpm_fd, &select_set);
1669 maxfdp = max (maxfdp, gpm_fd);
1671 #endif
1672 time_out.tv_sec = 0;
1673 time_out.tv_usec = 0;
1674 return (select (maxfdp + 1, &select_set, 0, 0, &time_out) <= 0);
1677 /* --------------------------------------------------------------------------------------------- */
1680 get_key_code (int no_delay)
1682 int c;
1683 static key_def *this = NULL, *parent;
1684 static struct timeval esctime = { -1, -1 };
1685 static int lastnodelay = -1;
1687 if (no_delay != lastnodelay)
1689 this = NULL;
1690 lastnodelay = no_delay;
1693 pend_send:
1694 if (pending_keys != NULL)
1696 int d = *pending_keys++;
1697 check_pend:
1698 if (*pending_keys == 0)
1700 pending_keys = NULL;
1701 seq_append = NULL;
1703 if ((d == ESC_CHAR) && (pending_keys != NULL))
1705 d = ALT (*pending_keys++);
1706 goto check_pend;
1708 if ((d > 127 && d < 256) && use_8th_bit_as_meta)
1709 d = ALT (d & 0x7f);
1710 this = NULL;
1711 return correct_key_code (d);
1714 nodelay_try_again:
1715 if (no_delay)
1716 tty_nodelay (TRUE);
1718 c = tty_lowlevel_getch ();
1719 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1720 if (c == KEY_RESIZE)
1721 goto nodelay_try_again;
1722 #endif
1723 if (no_delay)
1725 tty_nodelay (FALSE);
1726 if (c == -1)
1728 if (this != NULL && parent != NULL && parent->action == MCKEY_ESCAPE && old_esc_mode)
1730 struct timeval current, time_out;
1732 if (esctime.tv_sec == -1)
1733 return -1;
1734 GET_TIME (current);
1735 time_out.tv_sec = old_esc_mode_timeout / 1000000 + esctime.tv_sec;
1736 time_out.tv_usec = old_esc_mode_timeout % 1000000 + esctime.tv_usec;
1737 if (time_out.tv_usec > 1000000)
1739 time_out.tv_usec -= 1000000;
1740 time_out.tv_sec++;
1742 if (current.tv_sec < time_out.tv_sec)
1743 return -1;
1744 if (current.tv_sec == time_out.tv_sec && current.tv_usec < time_out.tv_usec)
1745 return -1;
1746 this = NULL;
1747 pending_keys = seq_append = NULL;
1748 return ESC_CHAR;
1750 return -1;
1753 else if (c == -1)
1755 /* Maybe we got an incomplete match.
1756 This we do only in delay mode, since otherwise
1757 tty_lowlevel_getch can return -1 at any time. */
1758 if (seq_append != NULL)
1760 pending_keys = seq_buffer;
1761 goto pend_send;
1763 this = NULL;
1764 return -1;
1767 /* Search the key on the root */
1768 if (!no_delay || this == NULL)
1770 this = keys;
1771 parent = NULL;
1773 if ((c > 127 && c < 256) && use_8th_bit_as_meta)
1775 c &= 0x7f;
1777 /* The first sequence defined starts with esc */
1778 parent = keys;
1779 this = keys->child;
1782 while (this != NULL)
1784 if (c == this->ch)
1786 if (this->child)
1788 if (!push_char (c))
1790 pending_keys = seq_buffer;
1791 goto pend_send;
1793 parent = this;
1794 this = this->child;
1795 if (parent->action == MCKEY_ESCAPE && old_esc_mode)
1797 if (no_delay)
1799 GET_TIME (esctime);
1800 if (this == NULL)
1802 /* Shouldn't happen */
1803 fputs ("Internal error\n", stderr);
1804 exit (EXIT_FAILURE);
1806 goto nodelay_try_again;
1808 esctime.tv_sec = -1;
1809 c = xgetch_second ();
1810 if (c == -1)
1812 pending_keys = seq_append = NULL;
1813 this = NULL;
1814 return ESC_CHAR;
1817 else
1819 if (no_delay)
1820 goto nodelay_try_again;
1821 c = tty_lowlevel_getch ();
1824 else
1826 /* We got a complete match, return and reset search */
1827 int code;
1829 pending_keys = seq_append = NULL;
1830 code = this->code;
1831 this = NULL;
1832 return correct_key_code (code);
1835 else
1837 if (this->next != NULL)
1838 this = this->next;
1839 else
1841 if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
1843 /* Convert escape-digits to F-keys */
1844 if (g_ascii_isdigit (c))
1845 c = KEY_F (c - '0');
1846 else if (c == ' ')
1847 c = ESC_CHAR;
1848 else
1849 c = ALT (c);
1851 pending_keys = seq_append = NULL;
1852 this = NULL;
1853 return correct_key_code (c);
1855 /* Did not find a match or {c} was changed in the if above,
1856 so we have to return everything we had skipped
1858 push_char (c);
1859 pending_keys = seq_buffer;
1860 goto pend_send;
1864 this = NULL;
1865 return correct_key_code (c);
1868 /* --------------------------------------------------------------------------------------------- */
1869 /* Returns a character read from stdin with appropriate interpretation */
1870 /* Also takes care of generated mouse events */
1871 /* Returns EV_MOUSE if it is a mouse event */
1872 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
1875 tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block)
1877 int c;
1878 static int flag = 0; /* Return value from select */
1879 #ifdef HAVE_LIBGPM
1880 static struct Gpm_Event ev; /* Mouse event */
1881 #endif
1882 struct timeval time_out;
1883 struct timeval *time_addr = NULL;
1884 static int dirty = 3;
1886 if ((dirty == 3) || is_idle ())
1888 mc_refresh ();
1889 dirty = 1;
1891 else
1892 dirty++;
1894 vfs_timeout_handler ();
1896 /* Ok, we use (event->x < 0) to signal that the event does not contain
1897 a suitable position for the mouse, so we can't use show_mouse_pointer
1898 on it.
1900 if (event->x > 0)
1902 show_mouse_pointer (event->x, event->y);
1903 if (!redo_event)
1904 event->x = -1;
1907 /* Repeat if using mouse */
1908 while (pending_keys == NULL)
1910 int maxfdp;
1911 fd_set select_set;
1913 FD_ZERO (&select_set);
1914 FD_SET (input_fd, &select_set);
1915 maxfdp = max (add_selects (&select_set), input_fd);
1917 #ifdef HAVE_LIBGPM
1918 if (mouse_enabled && (use_mouse_p == MOUSE_GPM))
1920 if (gpm_fd < 0)
1922 /* Connection to gpm broken, possibly gpm has died */
1923 mouse_enabled = FALSE;
1924 use_mouse_p = MOUSE_NONE;
1925 break;
1928 FD_SET (gpm_fd, &select_set);
1929 maxfdp = max (maxfdp, gpm_fd);
1931 #endif
1933 if (redo_event)
1935 time_out.tv_usec = mou_auto_repeat * 1000;
1936 time_out.tv_sec = 0;
1938 time_addr = &time_out;
1940 else
1942 int seconds;
1944 seconds = vfs_timeouts ();
1945 time_addr = NULL;
1947 if (seconds != 0)
1949 /* the timeout could be improved and actually be
1950 * the number of seconds until the next vfs entry
1951 * timeouts in the stamp list.
1954 time_out.tv_sec = seconds;
1955 time_out.tv_usec = 0;
1956 time_addr = &time_out;
1960 if (!block || mc_global.tty.winch_flag)
1962 time_addr = &time_out;
1963 time_out.tv_sec = 0;
1964 time_out.tv_usec = 0;
1967 tty_enable_interrupt_key ();
1968 flag = select (maxfdp + 1, &select_set, NULL, NULL, time_addr);
1969 tty_disable_interrupt_key ();
1971 /* select timed out: it could be for any of the following reasons:
1972 * redo_event -> it was because of the MOU_REPEAT handler
1973 * !block -> we did not block in the select call
1974 * else -> 10 second timeout to check the vfs status.
1976 if (flag == 0)
1978 if (redo_event)
1979 return EV_MOUSE;
1980 if (!block || mc_global.tty.winch_flag)
1981 return EV_NONE;
1982 vfs_timeout_handler ();
1984 if (flag == -1 && errno == EINTR)
1985 return EV_NONE;
1987 check_selects (&select_set);
1989 if (FD_ISSET (input_fd, &select_set))
1990 break;
1991 #ifdef HAVE_LIBGPM
1992 if (mouse_enabled && use_mouse_p == MOUSE_GPM
1993 && gpm_fd > 0 && FD_ISSET (gpm_fd, &select_set))
1995 Gpm_GetEvent (&ev);
1996 Gpm_FitEvent (&ev);
1997 *event = ev;
1998 return EV_MOUSE;
2000 #endif /* !HAVE_LIBGPM */
2003 #ifndef HAVE_SLANG
2004 flag = is_wintouched (stdscr);
2005 untouchwin (stdscr);
2006 #endif /* !HAVE_SLANG */
2007 c = block ? getch_with_delay () : get_key_code (1);
2009 #ifndef HAVE_SLANG
2010 if (flag > 0)
2011 tty_touch_screen ();
2012 #endif /* !HAVE_SLANG */
2014 if (mouse_enabled && (c == MCKEY_MOUSE
2015 #ifdef KEY_MOUSE
2016 || c == KEY_MOUSE
2017 #endif /* KEY_MOUSE */
2020 /* Mouse event */
2021 xmouse_get_event (event);
2022 return (event->type != 0) ? EV_MOUSE : EV_NONE;
2025 return c;
2028 /* --------------------------------------------------------------------------------------------- */
2029 /* Returns a key press, mouse events are discarded */
2032 tty_getch (void)
2034 Gpm_Event ev;
2035 int key;
2037 ev.x = -1;
2038 while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE);
2039 return key;
2042 /* --------------------------------------------------------------------------------------------- */
2044 char *
2045 learn_key (void)
2047 /* LEARN_TIMEOUT in usec */
2048 #define LEARN_TIMEOUT 200000
2050 fd_set Read_FD_Set;
2051 struct timeval endtime;
2052 struct timeval time_out;
2053 int c;
2054 char buffer[256];
2055 char *p = buffer;
2057 tty_keypad (FALSE); /* disable intepreting keys by ncurses */
2058 c = tty_lowlevel_getch ();
2059 while (c == -1)
2060 c = tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
2061 learn_store_key (buffer, &p, c);
2062 GET_TIME (endtime);
2063 endtime.tv_usec += LEARN_TIMEOUT;
2064 if (endtime.tv_usec > 1000000)
2066 endtime.tv_usec -= 1000000;
2067 endtime.tv_sec++;
2069 tty_nodelay (TRUE);
2070 for (;;)
2072 while ((c = tty_lowlevel_getch ()) == -1)
2074 GET_TIME (time_out);
2075 time_out.tv_usec = endtime.tv_usec - time_out.tv_usec;
2076 if (time_out.tv_usec < 0)
2077 time_out.tv_sec++;
2078 time_out.tv_sec = endtime.tv_sec - time_out.tv_sec;
2079 if (time_out.tv_sec >= 0 && time_out.tv_usec > 0)
2081 FD_ZERO (&Read_FD_Set);
2082 FD_SET (input_fd, &Read_FD_Set);
2083 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
2085 else
2086 break;
2088 if (c == -1)
2089 break;
2090 learn_store_key (buffer, &p, c);
2092 tty_keypad (TRUE);
2093 tty_nodelay (FALSE);
2094 *p = '\0';
2095 return g_strdup (buffer);
2096 #undef LEARN_TIMEOUT
2099 /* --------------------------------------------------------------------------------------------- */
2100 /* xterm and linux console only: set keypad to numeric or application
2101 mode. Only in application keypad mode it's possible to distinguish
2102 the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2104 void
2105 numeric_keypad_mode (void)
2107 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2109 fputs (ESC_STR ">", stdout);
2110 fflush (stdout);
2114 /* --------------------------------------------------------------------------------------------- */
2116 void
2117 application_keypad_mode (void)
2119 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2121 fputs (ESC_STR "=", stdout);
2122 fflush (stdout);
2126 /* --------------------------------------------------------------------------------------------- */