Define winch_flag as volatile sig_atomic_t.
[midnight-commander.git] / lib / tty / key.c
blob63d181056159a9fbe24a8381421f7295ef7e9427
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 static int mouse_btn, mouse_x, mouse_y;
526 #ifdef __QNXNTO__
527 ph_dv_f ph_attach;
528 ph_ov_f ph_input_group;
529 ph_pqc_f ph_query_cursor;
530 #endif
532 #ifdef HAVE_TEXTMODE_X11_SUPPORT
533 static Display *x11_display;
534 static Window x11_window;
535 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
537 static KeySortType has_been_sorted = KEY_NOSORT;
539 /* *INDENT-OFF* */
540 static const size_t key_conv_tab_size = G_N_ELEMENTS (key_name_conv_tab) - 1;
541 /* *INDENT-ON* */
543 static const key_code_name_t *key_conv_tab_sorted[G_N_ELEMENTS (key_name_conv_tab) - 1];
545 /*** file scope functions ************************************************************************/
546 /* --------------------------------------------------------------------------------------------- */
548 static int
549 add_selects (fd_set * select_set)
551 int top_fd = 0;
553 if (disabled_channels == 0)
555 SelectList *p;
557 for (p = select_list; p != NULL; p = p->next)
559 FD_SET (p->fd, select_set);
560 if (p->fd > top_fd)
561 top_fd = p->fd;
565 return top_fd;
568 /* --------------------------------------------------------------------------------------------- */
570 static void
571 check_selects (fd_set * select_set)
573 if (disabled_channels == 0)
575 gboolean retry;
579 SelectList *p;
581 retry = FALSE;
582 for (p = select_list; p; p = p->next)
583 if (FD_ISSET (p->fd, select_set))
585 FD_CLR (p->fd, select_set);
586 (*p->callback) (p->fd, p->info);
587 retry = TRUE;
588 break;
591 while (retry);
595 /* --------------------------------------------------------------------------------------------- */
596 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
598 static void
599 try_channels (int set_timeout)
601 struct timeval time_out;
602 static fd_set select_set;
603 struct timeval *timeptr;
604 int v;
605 int maxfdp;
607 while (1)
609 FD_ZERO (&select_set);
610 FD_SET (input_fd, &select_set); /* Add stdin */
611 maxfdp = max (add_selects (&select_set), input_fd);
613 timeptr = NULL;
614 if (set_timeout)
616 time_out.tv_sec = 0;
617 time_out.tv_usec = 100000;
618 timeptr = &time_out;
621 v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr);
622 if (v > 0)
624 check_selects (&select_set);
625 if (FD_ISSET (input_fd, &select_set))
626 break;
631 /* --------------------------------------------------------------------------------------------- */
633 static key_def *
634 create_sequence (const char *seq, int code, int action)
636 key_def *base, *p, *attach;
638 for (base = attach = NULL; *seq; seq++)
640 p = g_new (key_def, 1);
641 if (base == NULL)
642 base = p;
643 if (attach != NULL)
644 attach->child = p;
646 p->ch = *seq;
647 p->code = code;
648 p->child = p->next = NULL;
649 if (seq[1] == '\0')
650 p->action = action;
651 else
652 p->action = MCKEY_NOACTION;
653 attach = p;
655 return base;
658 /* --------------------------------------------------------------------------------------------- */
660 static void
661 define_sequences (const key_define_t * kd)
663 int i;
665 for (i = 0; kd[i].code != 0; i++)
666 define_sequence (kd[i].code, kd[i].seq, kd[i].action);
669 /* --------------------------------------------------------------------------------------------- */
671 #ifdef HAVE_TEXTMODE_X11_SUPPORT
672 static void
673 init_key_x11 (void)
675 if (getenv ("DISPLAY") != NULL && !mc_global.tty.disable_x11)
677 x11_display = mc_XOpenDisplay (0);
679 if (x11_display != NULL)
680 x11_window = DefaultRootWindow (x11_display);
683 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
685 /* --------------------------------------------------------------------------------------------- */
686 /* Workaround for System V Curses vt100 bug */
688 static int
689 getch_with_delay (void)
691 int c;
693 /* This routine could be used on systems without mouse support,
694 so we need to do the select check :-( */
695 while (1)
697 if (pending_keys == NULL)
698 try_channels (0);
700 /* Try to get a character */
701 c = get_key_code (0);
702 if (c != -1)
703 break;
704 /* Failed -> wait 0.1 secs and try again */
705 try_channels (1);
707 /* Success -> return the character */
708 return c;
711 /* --------------------------------------------------------------------------------------------- */
713 static void
714 xmouse_get_event (Gpm_Event * ev)
716 static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
717 static struct timeval tv2;
718 static int clicks = 0;
719 static int last_btn = 0;
720 int btn = mouse_btn;
722 /* Decode Xterm mouse information to a GPM style event */
724 /* There seems to be no way of knowing which button was released */
725 /* So we assume all the buttons were released */
727 if (btn == 3)
729 if (last_btn != 0)
731 if ((last_btn & (GPM_B_UP | GPM_B_DOWN)) != 0)
733 /* FIXME: DIRTY HACK */
734 /* don't generate GPM_UP after mouse wheel */
735 /* need for menu event handling */
736 ev->type = 0;
737 tv1.tv_sec = 0;
738 tv1.tv_usec = 0;
740 else
742 ev->type = GPM_UP | (GPM_SINGLE << clicks);
743 GET_TIME (tv1);
745 ev->buttons = 0;
746 last_btn = 0;
747 clicks = 0;
749 else
751 /* Bogus event, maybe mouse wheel */
752 ev->type = 0;
755 else
757 if (btn >= 32 && btn <= 34)
759 btn -= 32;
760 ev->type = GPM_DRAG;
762 else
763 ev->type = GPM_DOWN;
765 GET_TIME (tv2);
766 if (tv1.tv_sec && (DIF_TIME (tv1, tv2) < double_click_speed))
768 clicks++;
769 clicks %= 3;
771 else
772 clicks = 0;
774 switch (btn)
776 case 0:
777 ev->buttons = GPM_B_LEFT;
778 break;
779 case 1:
780 ev->buttons = GPM_B_MIDDLE;
781 break;
782 case 2:
783 ev->buttons = GPM_B_RIGHT;
784 break;
785 case 64:
786 ev->buttons = GPM_B_UP;
787 clicks = 0;
788 break;
789 case 65:
790 ev->buttons = GPM_B_DOWN;
791 clicks = 0;
792 break;
793 default:
794 /* Nothing */
795 ev->type = 0;
796 ev->buttons = 0;
797 break;
799 last_btn = ev->buttons;
801 ev->x = mouse_x;
802 ev->y = mouse_y;
805 /* --------------------------------------------------------------------------------------------- */
807 * Get modifier state (shift, alt, ctrl) for the last key pressed.
808 * We are assuming that the state didn't change since the key press.
809 * This is only correct if get_modifier() is called very fast after
810 * the input was received, so that the user didn't release the
811 * modifier keys yet.
814 static int
815 get_modifier (void)
817 int result = 0;
818 #ifdef __QNXNTO__
819 int mod_status, shift_ext_status;
820 static int in_photon = 0;
821 static int ph_ig = 0;
822 PhCursorInfo_t cursor_info;
823 #endif /* __QNXNTO__ */
825 #ifdef HAVE_TEXTMODE_X11_SUPPORT
826 if (x11_window != 0)
828 Window root, child;
829 int root_x, root_y;
830 int win_x, win_y;
831 unsigned int mask;
833 mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x,
834 &root_y, &win_x, &win_y, &mask);
836 if (mask & ShiftMask)
837 result |= KEY_M_SHIFT;
838 if (mask & ControlMask)
839 result |= KEY_M_CTRL;
840 return result;
842 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
843 #ifdef __QNXNTO__
845 if (in_photon == 0)
847 /* First time here, let's load Photon library and attach
848 to Photon */
849 in_photon = -1;
850 if (getenv ("PHOTON2_PATH") != NULL)
852 /* QNX 6.x has no support for RTLD_LAZY */
853 void *ph_handle = dlopen ("/usr/lib/libph.so", RTLD_NOW);
854 if (ph_handle != NULL)
856 ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach");
857 ph_input_group = (ph_ov_f) dlsym (ph_handle, "PhInputGroup");
858 ph_query_cursor = (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor");
859 if ((ph_attach != NULL) && (ph_input_group != NULL) && (ph_query_cursor != NULL))
861 if ((*ph_attach) (0, 0))
862 { /* Attached */
863 ph_ig = (*ph_input_group) (0);
864 in_photon = 1;
870 /* We do not have Photon running. Assume we are in text
871 console or xterm */
872 if (in_photon == -1)
874 if (devctl (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status, sizeof (int), NULL) == -1)
875 return 0;
876 shift_ext_status = mod_status & 0xffffff00UL;
877 mod_status &= 0x7f;
878 if (mod_status & _LINESTATUS_CON_ALT)
879 result |= KEY_M_ALT;
880 if (mod_status & _LINESTATUS_CON_CTRL)
881 result |= KEY_M_CTRL;
882 if ((mod_status & _LINESTATUS_CON_SHIFT) || (shift_ext_status & 0x00000800UL))
883 result |= KEY_M_SHIFT;
885 else
887 (*ph_query_cursor) (ph_ig, &cursor_info);
888 if (cursor_info.key_mods & 0x04)
889 result |= KEY_M_ALT;
890 if (cursor_info.key_mods & 0x02)
891 result |= KEY_M_CTRL;
892 if (cursor_info.key_mods & 0x01)
893 result |= KEY_M_SHIFT;
895 #endif /* __QNXNTO__ */
897 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
899 unsigned char modifiers = 6;
901 if (ioctl (0, TIOCLINUX, &modifiers) < 0)
902 return 0;
904 /* Translate Linux modifiers into mc modifiers */
905 if (modifiers & SHIFT_PRESSED)
906 result |= KEY_M_SHIFT;
907 if (modifiers & (ALTL_PRESSED | ALTR_PRESSED))
908 result |= KEY_M_ALT;
909 if (modifiers & CONTROL_PRESSED)
910 result |= KEY_M_CTRL;
912 #endif /* !__linux__ */
913 return result;
916 /* --------------------------------------------------------------------------------------------- */
918 static gboolean
919 push_char (int c)
921 gboolean ret = FALSE;
923 if (seq_append == NULL)
924 seq_append = seq_buffer;
926 if (seq_append != &(seq_buffer[SEQ_BUFFER_LEN - 2]))
928 *(seq_append++) = c;
929 *seq_append = 0;
930 ret = TRUE;
933 return ret;
936 /* --------------------------------------------------------------------------------------------- */
937 /* Parse extended mouse coordinates.
938 Returns -1 if pending_keys (up to seq_append) cannot be a prefix of extended mouse coordinates.
939 Returns 0 if pending_keys (up to seq_append) is a valid (but still incomplete) prefix for
940 extended mouse coordinates, e.g. "^[[32;4".
941 Returns 1 and fills the mouse_btn, mouse_x, mouse_y values if pending_keys (up to seq_append) is
942 a complete extended mouse sequence, e.g. "^[[32;42;5M"
945 /* Technical info (Egmont Koblinger <egmont@gmail.com>):
947 The ancient way of reporting mouse coordinates only supports coordinates up to 223,
948 so if your terminal is wider (or taller, but that's unlikely), you cannot use your mouse
949 in the rightmost columns.
951 * The old way of reporting mouse coordinates is the following:
952 + Output DECSET 1000 to enable mouse
953 + Expect escape sequences in the format \e[M<action+32><x+32><y+32> whereas <action+32>,
954 <x+32> and <y+32> are single bytes. (Action is 0 for left click, 1 for middle click,
955 2 for right click, 3 for release, or something like this.)
956 + Disadvantages of this format:
957 + x and y can only go up to 223.
958 + Coordinates above 95 are not ascii-compatible, so any character set converting
959 layer (e.g. luit) messes them up.
960 + The stream is not valid UTF-8, even if everything else is.
962 * The first new extension, introduced by xterm-262, is the following:
963 + Output DECSET 1000 to enable mouse, followed by DECSET 1005 to activate extended mode.
964 + Expect escape sequences in the format \e[M<action+32><<x+32>><<y+32>> whereas <<x+32>>
965 and <<y+32>> each can be up to two bytes long: coordinate+32 is encoded in UTF-8.
966 + Disadvantates of this format:
967 + There's still a limit of 2015 rows/columns (okay, it's not a real life problem).
968 + Doesn't solve the luit issue.
969 + It is "horribly broken" (quoting urxvt's changelog) in terms of compatibility
970 with the previous standard. There is no way for an application to tell whether
971 the underlying terminal supports this new mode (whether DECSET 1005 did actually change
972 the behavior or not), but depending on this a completely different user action might
973 generate the same input. Example:
974 + If the terminal doesn't support this extension, then clicking at (162, 129)
975 generates \e[M<32><194><161>.
976 + If the terminal supports this extension, then clicking at (129, 1) [bit of math:
977 129+32 = 161, U+0161 in UTF-8 is 194 161] generates \e[M<32><194><161><33>.
978 + so there's no way to tell whether the terminal ignored the 1005 escape sequence,
979 the user clicked on (162, 129) and then typed an exclamation mark; or whether
980 the terminal recognized the escape, and the user clicked on (129, 1).
981 + Due to this horrible brokenness, there's no way to implement support it without
982 explicitly asking the user (via a setting) if the terminal can speak this extension.
984 * The second new extension, introduced by rxvt-unicode-9.10, is the following:
985 + Output DECSET 1000 to enable mouse, followed by DECSET 1015 to activate this extended mode.
986 + Expect escape sequences in the format \e[{action+32};{x};{y}M where this time I used
987 the braces to denote spelling out the numbers in decimal, rather than using raw bytes.
988 + The only thing I don't understand is why they kept the offset of 32 at action, but other
989 than that, this format is totally okay, and solves all the weaknesses of the previous ones.
991 Currently, at least the following terminal emulators have support for these:
992 * xterm supports the xterm extension
993 * rxvt-unicode >= 9.10 supports both extensions
994 * iterm2 supports both extensions
995 * vte >= 0.31 supports the urxvt extension
998 static int
999 parse_extended_mouse_coordinates (void)
1001 int c, btn = 0, x = 0, y = 0;
1002 const int *p = pending_keys;
1003 const int *endp = seq_append;
1005 if (p == endp)
1006 return 0;
1007 c = *p++;
1008 if (c != ESC_CHAR)
1009 return -1;
1011 if (p == endp)
1012 return 0;
1013 c = *p++;
1014 if (c != '[')
1015 return -1;
1017 while (TRUE)
1019 if (p == endp)
1020 return 0;
1021 c = *p++;
1022 if (c == ';')
1023 break;
1024 if (c < '0' || c > '9')
1025 return -1;
1026 btn = 10 * btn + c - '0';
1028 if (btn < 32)
1029 return -1;
1030 btn -= 32;
1032 while (TRUE)
1034 if (p == endp)
1035 return 0;
1036 c = *p++;
1037 if (c == ';')
1038 break;
1039 if (c < '0' || c > '9')
1040 return -1;
1041 x = 10 * x + c - '0';
1043 if (x < 1)
1044 return -1;
1046 while (TRUE)
1048 if (p == endp)
1049 return 0;
1050 c = *p++;
1051 if (c == 'M')
1052 break;
1053 if (c < '0' || c > '9')
1054 return -1;
1055 y = 10 * y + c - '0';
1057 if (y < 1)
1058 return -1;
1060 mouse_btn = btn;
1061 mouse_x = x;
1062 mouse_y = y;
1063 return 1;
1066 /* --------------------------------------------------------------------------------------------- */
1067 /* Apply corrections for the keycode generated in get_key_code() */
1069 static int
1070 correct_key_code (int code)
1072 unsigned int c = code & ~KEY_M_MASK; /* code without modifier */
1073 unsigned int mod = code & KEY_M_MASK; /* modifier */
1074 #ifdef __QNXNTO__
1075 unsigned int qmod; /* bunch of the QNX console
1076 modifiers needs unchanged */
1077 #endif /* __QNXNTO__ */
1080 * Add key modifiers directly from X11 or OS.
1081 * Ordinary characters only get modifiers from sequences.
1083 if (c < 32 || c >= 256)
1085 mod |= get_modifier ();
1088 /* This is needed if the newline is reported as carriage return */
1089 if (c == '\r')
1090 c = '\n';
1092 /* This is reported to be useful on AIX */
1093 if (c == KEY_SCANCEL)
1094 c = '\t';
1096 /* Convert Shift+Tab and Ctrl+Tab to Back Tab
1097 * only if modifiers directly from X11
1099 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1100 if (x11_window != 0)
1101 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
1103 if ((c == '\t') && (mod & (KEY_M_SHIFT | KEY_M_CTRL)))
1105 c = KEY_BTAB;
1106 mod = 0;
1110 /* F0 is the same as F10 for out purposes */
1111 if (c == KEY_F (0))
1112 c = KEY_F (10);
1115 * We are not interested if Ctrl was pressed when entering control
1116 * characters, so assume that it was. When checking for such keys,
1117 * XCTRL macro should be used. In some cases, we are interested,
1118 * e.g. to distinguish Ctrl-Enter from Enter.
1120 if (c == '\b')
1122 /* Special case for backspase ('\b' < 32) */
1123 c = KEY_BACKSPACE;
1124 mod &= ~KEY_M_CTRL;
1126 else if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n')
1128 mod |= KEY_M_CTRL;
1131 #ifdef __QNXNTO__
1132 qmod = get_modifier ();
1134 if ((c == 127) && (mod == 0))
1135 { /* Add Ctrl/Alt/Shift-BackSpace */
1136 mod |= get_modifier ();
1137 c = KEY_BACKSPACE;
1140 if ((c == '0') && (mod == 0))
1141 { /* Add Shift-Insert on key pad */
1142 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1144 mod = KEY_M_SHIFT;
1145 c = KEY_IC;
1149 if ((c == '.') && (mod == 0))
1150 { /* Add Shift-Del on key pad */
1151 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1153 mod = KEY_M_SHIFT;
1154 c = KEY_DC;
1157 #endif /* __QNXNTO__ */
1159 /* Unrecognized 0177 is delete (preserve Ctrl) */
1160 if (c == 0177)
1162 c = KEY_BACKSPACE;
1165 #if 0
1166 /* Unrecognized Ctrl-d is delete */
1167 if (c == (31 & 'd'))
1169 c = KEY_DC;
1170 mod &= ~KEY_M_CTRL;
1173 /* Unrecognized Ctrl-h is backspace */
1174 if (c == (31 & 'h'))
1176 c = KEY_BACKSPACE;
1177 mod &= ~KEY_M_CTRL;
1179 #endif
1181 /* Shift+BackSpace is backspace */
1182 if (c == KEY_BACKSPACE && (mod & KEY_M_SHIFT))
1184 mod &= ~KEY_M_SHIFT;
1187 /* Convert Shift+Fn to F(n+10) */
1188 if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT))
1190 c += 10;
1193 /* Remove Shift information from function keys */
1194 if (c >= KEY_F (1) && c <= KEY_F (20))
1196 mod &= ~KEY_M_SHIFT;
1199 if (!mc_global.tty.alternate_plus_minus)
1200 switch (c)
1202 case KEY_KP_ADD:
1203 c = '+';
1204 break;
1205 case KEY_KP_SUBTRACT:
1206 c = '-';
1207 break;
1208 case KEY_KP_MULTIPLY:
1209 c = '*';
1210 break;
1213 return (mod | c);
1216 /* --------------------------------------------------------------------------------------------- */
1218 static int
1219 xgetch_second (void)
1221 fd_set Read_FD_Set;
1222 int c;
1223 struct timeval time_out;
1225 time_out.tv_sec = old_esc_mode_timeout / 1000000;
1226 time_out.tv_usec = old_esc_mode_timeout % 1000000;
1227 tty_nodelay (TRUE);
1228 FD_ZERO (&Read_FD_Set);
1229 FD_SET (input_fd, &Read_FD_Set);
1230 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
1231 c = tty_lowlevel_getch ();
1232 tty_nodelay (FALSE);
1233 return c;
1236 /* --------------------------------------------------------------------------------------------- */
1238 static void
1239 learn_store_key (char *buffer, char **p, int c)
1241 if (*p - buffer > 253)
1242 return;
1243 if (c == ESC_CHAR)
1245 *(*p)++ = '\\';
1246 *(*p)++ = 'e';
1248 else if (c < ' ')
1250 *(*p)++ = '^';
1251 *(*p)++ = c + 'a' - 1;
1253 else if (c == '^')
1255 *(*p)++ = '^';
1256 *(*p)++ = '^';
1258 else
1259 *(*p)++ = (char) c;
1262 /* --------------------------------------------------------------------------------------------- */
1264 static void
1265 k_dispose (key_def * k)
1267 if (k != NULL)
1269 k_dispose (k->child);
1270 k_dispose (k->next);
1271 g_free (k);
1275 /* --------------------------------------------------------------------------------------------- */
1277 static void
1278 s_dispose (SelectList * sel)
1280 if (sel != NULL)
1282 s_dispose (sel->next);
1283 g_free (sel);
1287 /* --------------------------------------------------------------------------------------------- */
1289 static int
1290 key_code_comparator_by_name (const void *p1, const void *p2)
1292 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1293 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1295 return g_ascii_strcasecmp (n1->name, n2->name);
1298 /* --------------------------------------------------------------------------------------------- */
1300 static int
1301 key_code_comparator_by_code (const void *p1, const void *p2)
1303 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1304 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1306 return n1->code - n2->code;
1309 /* --------------------------------------------------------------------------------------------- */
1311 static inline void
1312 sort_key_conv_tab (enum KeySortType type_sort)
1314 if (has_been_sorted != type_sort)
1316 size_t i;
1317 for (i = 0; i < key_conv_tab_size; i++)
1318 key_conv_tab_sorted[i] = &key_name_conv_tab[i];
1320 if (type_sort == KEY_SORTBYNAME)
1322 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1323 &key_code_comparator_by_name);
1325 else if (type_sort == KEY_SORTBYCODE)
1327 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1328 &key_code_comparator_by_code);
1330 has_been_sorted = type_sort;
1334 /* --------------------------------------------------------------------------------------------- */
1336 static int
1337 lookup_keyname (const char *name, int *idx)
1339 if (name[0] != '\0')
1341 const key_code_name_t key = { 0, name, NULL, NULL };
1342 const key_code_name_t *keyp = &key;
1343 key_code_name_t **res;
1345 if (name[1] == '\0')
1347 *idx = -1;
1348 return (int) name[0];
1351 sort_key_conv_tab (KEY_SORTBYNAME);
1353 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1354 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_name);
1356 if (res != NULL)
1358 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1359 return (*res)->code;
1363 *idx = -1;
1364 return 0;
1367 /* --------------------------------------------------------------------------------------------- */
1369 static gboolean
1370 lookup_keycode (const long code, int *idx)
1372 if (code != 0)
1374 const key_code_name_t key = { code, NULL, NULL, NULL };
1375 const key_code_name_t *keyp = &key;
1376 key_code_name_t **res;
1378 sort_key_conv_tab (KEY_SORTBYCODE);
1380 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1381 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_code);
1383 if (res != NULL)
1385 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1386 return TRUE;
1390 *idx = -1;
1391 return FALSE;
1394 /* --------------------------------------------------------------------------------------------- */
1395 /*** public functions ****************************************************************************/
1396 /* --------------------------------------------------------------------------------------------- */
1397 /* This has to be called before init_slang or whatever routine
1398 calls any define_sequence */
1400 void
1401 init_key (void)
1403 const char *term = getenv ("TERM");
1405 /* This has to be the first define_sequence */
1406 /* So, we can assume that the first keys member has ESC */
1407 define_sequences (mc_default_keys);
1409 /* Terminfo on irix does not have some keys */
1410 if (mc_global.tty.xterm_flag
1411 || (term != NULL
1412 && (strncmp (term, "iris-ansi", 9) == 0
1413 || strncmp (term, "xterm", 5) == 0
1414 || strncmp (term, "rxvt", 4) == 0 || strcmp (term, "screen") == 0)))
1415 define_sequences (xterm_key_defines);
1417 /* load some additional keys (e.g. direct Alt-? support) */
1418 load_xtra_key_defines ();
1420 #ifdef __QNX__
1421 if ((term != NULL) && (strncmp (term, "qnx", 3) == 0))
1423 /* Modify the default value of use_8th_bit_as_meta: we would
1424 * like to provide a working mc for a newbie who knows nothing
1425 * about [Options|Display bits|Full 8 bits input]...
1427 * Don't use 'meta'-bit, when we are dealing with a
1428 * 'qnx*'-type terminal: clear the default value!
1429 * These terminal types use 0xFF as an escape character,
1430 * so use_8th_bit_as_meta==1 must not be enabled!
1432 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1433 * is not used now (doesn't even depend on use_8th_bit_as_meta
1434 * as in mc-3.1.2)...GREAT!...no additional code is required!]
1436 use_8th_bit_as_meta = 0;
1438 #endif /* __QNX__ */
1440 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1441 init_key_x11 ();
1442 #endif
1444 /* Load the qansi-m key definitions
1445 if we are running under the qansi-m terminal */
1446 if (term != NULL && (strncmp (term, "qansi-m", 7) == 0))
1447 define_sequences (qansi_key_defines);
1450 /* --------------------------------------------------------------------------------------------- */
1452 * This has to be called after SLang_init_tty/slint_init
1455 void
1456 init_key_input_fd (void)
1458 #ifdef HAVE_SLANG
1459 input_fd = SLang_TT_Read_FD;
1460 #endif
1463 /* --------------------------------------------------------------------------------------------- */
1465 void
1466 done_key (void)
1468 k_dispose (keys);
1469 s_dispose (select_list);
1471 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1472 if (x11_display)
1473 mc_XCloseDisplay (x11_display);
1474 #endif
1477 /* --------------------------------------------------------------------------------------------- */
1479 void
1480 add_select_channel (int fd, select_fn callback, void *info)
1482 SelectList *new;
1484 new = g_new (SelectList, 1);
1485 new->fd = fd;
1486 new->callback = callback;
1487 new->info = info;
1488 new->next = select_list;
1489 select_list = new;
1492 /* --------------------------------------------------------------------------------------------- */
1494 void
1495 delete_select_channel (int fd)
1497 SelectList *p = select_list;
1498 SelectList *p_prev = NULL;
1499 SelectList *p_next;
1501 while (p != NULL)
1502 if (p->fd == fd)
1504 p_next = p->next;
1506 if (p_prev != NULL)
1507 p_prev->next = p_next;
1508 else
1509 select_list = p_next;
1511 g_free (p);
1512 p = p_next;
1514 else
1516 p_prev = p;
1517 p = p->next;
1521 /* --------------------------------------------------------------------------------------------- */
1523 void
1524 channels_up (void)
1526 if (disabled_channels == 0)
1527 fputs ("Error: channels_up called with disabled_channels = 0\n", stderr);
1528 disabled_channels--;
1531 /* --------------------------------------------------------------------------------------------- */
1533 void
1534 channels_down (void)
1536 disabled_channels++;
1539 /* --------------------------------------------------------------------------------------------- */
1541 * Return the code associated with the symbolic name keyname
1544 long
1545 lookup_key (const char *name, char **label)
1547 char **lc_keys, **p;
1548 int k = -1;
1549 int key = 0;
1550 int lc_index = -1;
1552 int use_meta = -1;
1553 int use_ctrl = -1;
1554 int use_shift = -1;
1556 if (name == NULL)
1557 return 0;
1559 name = g_strstrip (g_strdup (name));
1560 p = lc_keys = g_strsplit_set (name, "-+ ", -1);
1561 g_free ((char *) name);
1563 while ((p != NULL) && (*p != NULL))
1565 if ((*p)[0] != '\0')
1567 int idx;
1569 key = lookup_keyname (g_strstrip (*p), &idx);
1571 if (key == KEY_M_ALT)
1572 use_meta = idx;
1573 else if (key == KEY_M_CTRL)
1574 use_ctrl = idx;
1575 else if (key == KEY_M_SHIFT)
1576 use_shift = idx;
1577 else
1579 k = key;
1580 lc_index = idx;
1581 break;
1585 p++;
1588 g_strfreev (lc_keys);
1590 /* output */
1591 if (k <= 0)
1592 return 0;
1595 if (label != NULL)
1597 GString *s;
1599 s = g_string_new ("");
1601 if (use_meta != -1)
1603 g_string_append (s, key_conv_tab_sorted[use_meta]->shortcut);
1604 g_string_append_c (s, '-');
1606 if (use_ctrl != -1)
1608 g_string_append (s, key_conv_tab_sorted[use_ctrl]->shortcut);
1609 g_string_append_c (s, '-');
1611 if (use_shift != -1)
1613 if (k < 127)
1614 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1615 else
1617 g_string_append (s, key_conv_tab_sorted[use_shift]->shortcut);
1618 g_string_append_c (s, '-');
1619 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1622 else if (k < 128)
1624 if ((k >= 'A') || (lc_index < 0) || (key_conv_tab_sorted[lc_index]->shortcut == NULL))
1625 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) k));
1626 else
1627 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1629 else if ((lc_index != -1) && (key_conv_tab_sorted[lc_index]->shortcut != NULL))
1630 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1631 else
1632 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) key));
1634 *label = g_string_free (s, FALSE);
1637 if (use_shift != -1)
1639 if (k < 127 && k > 31)
1640 k = g_ascii_toupper ((gchar) k);
1641 else
1642 k |= KEY_M_SHIFT;
1645 if (use_ctrl != -1)
1647 if (k < 256)
1648 k = XCTRL (k);
1649 else
1650 k |= KEY_M_CTRL;
1653 if (use_meta != -1)
1654 k = ALT (k);
1656 return (long) k;
1659 /* --------------------------------------------------------------------------------------------- */
1661 char *
1662 lookup_key_by_code (const int keycode)
1664 /* code without modifier */
1665 unsigned int k = keycode & ~KEY_M_MASK;
1666 /* modifier */
1667 unsigned int mod = keycode & KEY_M_MASK;
1669 int use_meta = -1;
1670 int use_ctrl = -1;
1671 int use_shift = -1;
1672 int key_idx = -1;
1674 GString *s;
1675 int idx;
1677 s = g_string_sized_new (8);
1679 if (lookup_keycode (k, &key_idx) || (k > 0 && k < 256))
1681 if (mod & KEY_M_ALT)
1683 if (lookup_keycode (KEY_M_ALT, &idx))
1685 use_meta = idx;
1686 g_string_append (s, key_conv_tab_sorted[use_meta]->name);
1687 g_string_append_c (s, '-');
1690 if (mod & KEY_M_CTRL)
1692 /* non printeble chars like a CTRL-[A..Z] */
1693 if (k < 32)
1694 k += 64;
1696 if (lookup_keycode (KEY_M_CTRL, &idx))
1698 use_ctrl = idx;
1699 g_string_append (s, key_conv_tab_sorted[use_ctrl]->name);
1700 g_string_append_c (s, '-');
1703 if (mod & KEY_M_SHIFT)
1705 if (lookup_keycode (KEY_M_ALT, &idx))
1707 use_shift = idx;
1708 if (k < 127)
1709 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1710 else
1712 g_string_append (s, key_conv_tab_sorted[use_shift]->name);
1713 g_string_append_c (s, '-');
1714 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1718 else if (k < 128)
1720 if ((k >= 'A') || (key_idx < 0) || (key_conv_tab_sorted[key_idx]->name == NULL))
1721 g_string_append_c (s, (gchar) k);
1722 else
1723 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1725 else if ((key_idx != -1) && (key_conv_tab_sorted[key_idx]->name != NULL))
1726 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1727 else
1728 g_string_append_c (s, (gchar) keycode);
1731 return g_string_free (s, s->len == 0);
1734 /* --------------------------------------------------------------------------------------------- */
1736 * Return TRUE on success, FALSE on error.
1737 * An error happens if SEQ is a beginning of an existing longer sequence.
1740 gboolean
1741 define_sequence (int code, const char *seq, int action)
1743 key_def *base;
1745 if (strlen (seq) > SEQ_BUFFER_LEN - 1)
1746 return FALSE;
1748 for (base = keys; (base != NULL) && (*seq != '\0');)
1749 if (*seq == base->ch)
1751 if (base->child == 0)
1753 if (*(seq + 1) != '\0')
1754 base->child = create_sequence (seq + 1, code, action);
1755 else
1757 /* The sequence matches an existing one. */
1758 base->code = code;
1759 base->action = action;
1761 return TRUE;
1764 base = base->child;
1765 seq++;
1767 else
1769 if (base->next)
1770 base = base->next;
1771 else
1773 base->next = create_sequence (seq, code, action);
1774 return TRUE;
1778 if (*seq == '\0')
1780 /* Attempt to redefine a sequence with a shorter sequence. */
1781 return FALSE;
1784 keys = create_sequence (seq, code, action);
1785 return TRUE;
1788 /* --------------------------------------------------------------------------------------------- */
1790 * Check if we are idle, i.e. there are no pending keyboard or mouse
1791 * events. Return 1 is idle, 0 is there are pending events.
1793 gboolean
1794 is_idle (void)
1796 int maxfdp;
1797 fd_set select_set;
1798 struct timeval time_out;
1800 FD_ZERO (&select_set);
1801 FD_SET (input_fd, &select_set);
1802 maxfdp = input_fd;
1803 #ifdef HAVE_LIBGPM
1804 if (mouse_enabled && (use_mouse_p == MOUSE_GPM) && (gpm_fd > 0))
1806 FD_SET (gpm_fd, &select_set);
1807 maxfdp = max (maxfdp, gpm_fd);
1809 #endif
1810 time_out.tv_sec = 0;
1811 time_out.tv_usec = 0;
1812 return (select (maxfdp + 1, &select_set, 0, 0, &time_out) <= 0);
1815 /* --------------------------------------------------------------------------------------------- */
1818 get_key_code (int no_delay)
1820 int c;
1821 static key_def *this = NULL, *parent;
1822 static struct timeval esctime = { -1, -1 };
1823 static int lastnodelay = -1;
1825 if (no_delay != lastnodelay)
1827 this = NULL;
1828 lastnodelay = no_delay;
1831 pend_send:
1832 if (pending_keys != NULL)
1834 int m;
1836 m = parse_extended_mouse_coordinates ();
1837 if (m == 1)
1839 pending_keys = seq_append = NULL;
1840 this = NULL;
1841 return MCKEY_EXTENDED_MOUSE;
1843 if (m == -1)
1845 int d = *pending_keys++;
1846 check_pend:
1847 if (*pending_keys == 0)
1849 pending_keys = NULL;
1850 seq_append = NULL;
1852 if ((d == ESC_CHAR) && (pending_keys != NULL))
1854 d = ALT (*pending_keys++);
1855 goto check_pend;
1857 if ((d > 127 && d < 256) && use_8th_bit_as_meta)
1858 d = ALT (d & 0x7f);
1859 this = NULL;
1860 return correct_key_code (d);
1862 /* else if (m == 0), just let it continue */
1865 nodelay_try_again:
1866 if (no_delay)
1867 tty_nodelay (TRUE);
1869 c = tty_lowlevel_getch ();
1870 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1871 if (c == KEY_RESIZE)
1872 goto nodelay_try_again;
1873 #endif
1874 if (no_delay)
1876 tty_nodelay (FALSE);
1877 if (c == -1)
1879 if (this != NULL && parent != NULL && parent->action == MCKEY_ESCAPE && old_esc_mode)
1881 struct timeval current, time_out;
1883 if (esctime.tv_sec == -1)
1884 return -1;
1885 GET_TIME (current);
1886 time_out.tv_sec = old_esc_mode_timeout / 1000000 + esctime.tv_sec;
1887 time_out.tv_usec = old_esc_mode_timeout % 1000000 + esctime.tv_usec;
1888 if (time_out.tv_usec > 1000000)
1890 time_out.tv_usec -= 1000000;
1891 time_out.tv_sec++;
1893 if (current.tv_sec < time_out.tv_sec)
1894 return -1;
1895 if (current.tv_sec == time_out.tv_sec && current.tv_usec < time_out.tv_usec)
1896 return -1;
1897 this = NULL;
1898 pending_keys = seq_append = NULL;
1899 return ESC_CHAR;
1901 return -1;
1904 else if (c == -1)
1906 /* Maybe we got an incomplete match.
1907 This we do only in delay mode, since otherwise
1908 tty_lowlevel_getch can return -1 at any time. */
1909 if (seq_append != NULL)
1911 pending_keys = seq_buffer;
1912 goto pend_send;
1914 this = NULL;
1915 return -1;
1918 /* Search the key on the root */
1919 if (!no_delay || this == NULL)
1921 this = keys;
1922 parent = NULL;
1924 if ((c > 127 && c < 256) && use_8th_bit_as_meta)
1926 c &= 0x7f;
1928 /* The first sequence defined starts with esc */
1929 parent = keys;
1930 this = keys->child;
1933 while (this != NULL)
1935 if (c == this->ch)
1937 if (this->child)
1939 if (!push_char (c))
1941 pending_keys = seq_buffer;
1942 goto pend_send;
1944 parent = this;
1945 this = this->child;
1946 if (parent->action == MCKEY_ESCAPE && old_esc_mode)
1948 if (no_delay)
1950 GET_TIME (esctime);
1951 if (this == NULL)
1953 /* Shouldn't happen */
1954 fputs ("Internal error\n", stderr);
1955 exit (EXIT_FAILURE);
1957 goto nodelay_try_again;
1959 esctime.tv_sec = -1;
1960 c = xgetch_second ();
1961 if (c == -1)
1963 pending_keys = seq_append = NULL;
1964 this = NULL;
1965 return ESC_CHAR;
1968 else
1970 if (no_delay)
1971 goto nodelay_try_again;
1972 c = tty_lowlevel_getch ();
1975 else
1977 /* We got a complete match, return and reset search */
1978 int code;
1980 pending_keys = seq_append = NULL;
1981 code = this->code;
1982 this = NULL;
1983 return correct_key_code (code);
1986 else
1988 if (this->next != NULL)
1989 this = this->next;
1990 else
1992 if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
1994 /* Convert escape-digits to F-keys */
1995 if (g_ascii_isdigit (c))
1996 c = KEY_F (c - '0');
1997 else if (c == ' ')
1998 c = ESC_CHAR;
1999 else
2000 c = ALT (c);
2002 pending_keys = seq_append = NULL;
2003 this = NULL;
2004 return correct_key_code (c);
2006 /* Did not find a match or {c} was changed in the if above,
2007 so we have to return everything we had skipped
2009 push_char (c);
2010 pending_keys = seq_buffer;
2011 goto pend_send;
2015 this = NULL;
2016 return correct_key_code (c);
2019 /* --------------------------------------------------------------------------------------------- */
2020 /* Returns a character read from stdin with appropriate interpretation */
2021 /* Also takes care of generated mouse events */
2022 /* Returns EV_MOUSE if it is a mouse event */
2023 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
2026 tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block)
2028 int c;
2029 static int flag = 0; /* Return value from select */
2030 #ifdef HAVE_LIBGPM
2031 static struct Gpm_Event ev; /* Mouse event */
2032 #endif
2033 struct timeval time_out;
2034 struct timeval *time_addr = NULL;
2035 static int dirty = 3;
2037 if ((dirty == 3) || is_idle ())
2039 mc_refresh ();
2040 dirty = 1;
2042 else
2043 dirty++;
2045 vfs_timeout_handler ();
2047 /* Ok, we use (event->x < 0) to signal that the event does not contain
2048 a suitable position for the mouse, so we can't use show_mouse_pointer
2049 on it.
2051 if (event->x > 0)
2053 show_mouse_pointer (event->x, event->y);
2054 if (!redo_event)
2055 event->x = -1;
2058 /* Repeat if using mouse */
2059 while (pending_keys == NULL)
2061 int maxfdp;
2062 fd_set select_set;
2064 FD_ZERO (&select_set);
2065 FD_SET (input_fd, &select_set);
2066 maxfdp = max (add_selects (&select_set), input_fd);
2068 #ifdef HAVE_LIBGPM
2069 if (mouse_enabled && (use_mouse_p == MOUSE_GPM))
2071 if (gpm_fd < 0)
2073 /* Connection to gpm broken, possibly gpm has died */
2074 mouse_enabled = FALSE;
2075 use_mouse_p = MOUSE_NONE;
2076 break;
2079 FD_SET (gpm_fd, &select_set);
2080 maxfdp = max (maxfdp, gpm_fd);
2082 #endif
2084 if (redo_event)
2086 time_out.tv_usec = mou_auto_repeat * 1000;
2087 time_out.tv_sec = 0;
2089 time_addr = &time_out;
2091 else
2093 int seconds;
2095 seconds = vfs_timeouts ();
2096 time_addr = NULL;
2098 if (seconds != 0)
2100 /* the timeout could be improved and actually be
2101 * the number of seconds until the next vfs entry
2102 * timeouts in the stamp list.
2105 time_out.tv_sec = seconds;
2106 time_out.tv_usec = 0;
2107 time_addr = &time_out;
2111 if (!block || mc_global.tty.winch_flag != 0)
2113 time_addr = &time_out;
2114 time_out.tv_sec = 0;
2115 time_out.tv_usec = 0;
2118 tty_enable_interrupt_key ();
2119 flag = select (maxfdp + 1, &select_set, NULL, NULL, time_addr);
2120 tty_disable_interrupt_key ();
2122 /* select timed out: it could be for any of the following reasons:
2123 * redo_event -> it was because of the MOU_REPEAT handler
2124 * !block -> we did not block in the select call
2125 * else -> 10 second timeout to check the vfs status.
2127 if (flag == 0)
2129 if (redo_event)
2130 return EV_MOUSE;
2131 if (!block || mc_global.tty.winch_flag != 0)
2132 return EV_NONE;
2133 vfs_timeout_handler ();
2135 if (flag == -1 && errno == EINTR)
2136 return EV_NONE;
2138 check_selects (&select_set);
2140 if (FD_ISSET (input_fd, &select_set))
2141 break;
2142 #ifdef HAVE_LIBGPM
2143 if (mouse_enabled && use_mouse_p == MOUSE_GPM
2144 && gpm_fd > 0 && FD_ISSET (gpm_fd, &select_set))
2146 Gpm_GetEvent (&ev);
2147 Gpm_FitEvent (&ev);
2148 *event = ev;
2149 return EV_MOUSE;
2151 #endif /* !HAVE_LIBGPM */
2154 #ifndef HAVE_SLANG
2155 flag = is_wintouched (stdscr);
2156 untouchwin (stdscr);
2157 #endif /* !HAVE_SLANG */
2158 c = block ? getch_with_delay () : get_key_code (1);
2160 #ifndef HAVE_SLANG
2161 if (flag > 0)
2162 tty_touch_screen ();
2163 #endif /* !HAVE_SLANG */
2165 if (mouse_enabled && (c == MCKEY_MOUSE
2166 #ifdef KEY_MOUSE
2167 || c == KEY_MOUSE
2168 #endif /* KEY_MOUSE */
2169 || c == MCKEY_EXTENDED_MOUSE))
2171 /* Mouse event */
2172 /* In case of extended coordinates, mouse_btn, mouse_x and mouse_y are already filled in. */
2173 if (c != MCKEY_EXTENDED_MOUSE)
2175 /* Variable btn has following meaning: */
2176 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
2177 mouse_btn = tty_lowlevel_getch () - 32;
2178 /* Coordinates are 33-based */
2179 /* Transform them to 1-based */
2180 mouse_x = tty_lowlevel_getch () - 32;
2181 mouse_y = tty_lowlevel_getch () - 32;
2183 xmouse_get_event (event);
2184 return (event->type != 0) ? EV_MOUSE : EV_NONE;
2187 return c;
2190 /* --------------------------------------------------------------------------------------------- */
2191 /* Returns a key press, mouse events are discarded */
2194 tty_getch (void)
2196 Gpm_Event ev;
2197 int key;
2199 ev.x = -1;
2200 while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE);
2201 return key;
2204 /* --------------------------------------------------------------------------------------------- */
2206 char *
2207 learn_key (void)
2209 /* LEARN_TIMEOUT in usec */
2210 #define LEARN_TIMEOUT 200000
2212 fd_set Read_FD_Set;
2213 struct timeval endtime;
2214 struct timeval time_out;
2215 int c;
2216 char buffer[256];
2217 char *p = buffer;
2219 tty_keypad (FALSE); /* disable intepreting keys by ncurses */
2220 c = tty_lowlevel_getch ();
2221 while (c == -1)
2222 c = tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
2223 learn_store_key (buffer, &p, c);
2224 GET_TIME (endtime);
2225 endtime.tv_usec += LEARN_TIMEOUT;
2226 if (endtime.tv_usec > 1000000)
2228 endtime.tv_usec -= 1000000;
2229 endtime.tv_sec++;
2231 tty_nodelay (TRUE);
2232 while (TRUE)
2234 while ((c = tty_lowlevel_getch ()) == -1)
2236 GET_TIME (time_out);
2237 time_out.tv_usec = endtime.tv_usec - time_out.tv_usec;
2238 if (time_out.tv_usec < 0)
2239 time_out.tv_sec++;
2240 time_out.tv_sec = endtime.tv_sec - time_out.tv_sec;
2241 if (time_out.tv_sec >= 0 && time_out.tv_usec > 0)
2243 FD_ZERO (&Read_FD_Set);
2244 FD_SET (input_fd, &Read_FD_Set);
2245 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
2247 else
2248 break;
2250 if (c == -1)
2251 break;
2252 learn_store_key (buffer, &p, c);
2254 tty_keypad (TRUE);
2255 tty_nodelay (FALSE);
2256 *p = '\0';
2257 return g_strdup (buffer);
2258 #undef LEARN_TIMEOUT
2261 /* --------------------------------------------------------------------------------------------- */
2262 /* xterm and linux console only: set keypad to numeric or application
2263 mode. Only in application keypad mode it's possible to distinguish
2264 the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2266 void
2267 numeric_keypad_mode (void)
2269 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2271 fputs (ESC_STR ">", stdout);
2272 fflush (stdout);
2276 /* --------------------------------------------------------------------------------------------- */
2278 void
2279 application_keypad_mode (void)
2281 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2283 fputs (ESC_STR "=", stdout);
2284 fflush (stdout);
2288 /* --------------------------------------------------------------------------------------------- */