Moved declaration of old_esc_mode_timeout variable to the proper file section.
[midnight-commander.git] / lib / tty / key.c
blob952539498ff881e881fa1cefe19e7a6631de2a2d
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 #include <sys/ioctl.h>
67 #endif /* __linux__ */
69 #ifdef __CYGWIN__
70 #include <termios.h>
71 #include <sys/ioctl.h>
72 #endif /* __CYGWIN__ */
74 #ifdef __QNXNTO__
75 #include <dlfcn.h>
76 #include <Ph.h>
77 #include <sys/dcmd_chr.h>
78 #endif /* __QNXNTO__ */
80 /*** global variables ****************************************************************************/
82 int mou_auto_repeat = 100;
83 int double_click_speed = 250;
84 int old_esc_mode = 0;
85 /* timeout for old_esc_mode in usec */
86 int old_esc_mode_timeout = 1000000; /* settable via env */
87 int use_8th_bit_as_meta = 0;
89 /* This table is a mapping between names and the constants we use
90 * We use this to allow users to define alternate definitions for
91 * certain keys that may be missing from the terminal database
93 const key_code_name_t key_name_conv_tab[] = {
94 /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
95 to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
96 {KEY_F (1), "f1", N_("Function key 1"), "F1"},
97 {KEY_F (2), "f2", N_("Function key 2"), "F2"},
98 {KEY_F (3), "f3", N_("Function key 3"), "F3"},
99 {KEY_F (4), "f4", N_("Function key 4"), "F4"},
100 {KEY_F (5), "f5", N_("Function key 5"), "F5"},
101 {KEY_F (6), "f6", N_("Function key 6"), "F6"},
102 {KEY_F (7), "f7", N_("Function key 7"), "F7"},
103 {KEY_F (8), "f8", N_("Function key 8"), "F8"},
104 {KEY_F (9), "f9", N_("Function key 9"), "F9"},
105 {KEY_F (10), "f10", N_("Function key 10"), "F10"},
106 {KEY_F (11), "f11", N_("Function key 11"), "F11"},
107 {KEY_F (12), "f12", N_("Function key 12"), "F12"},
108 {KEY_F (13), "f13", N_("Function key 13"), "F13"},
109 {KEY_F (14), "f14", N_("Function key 14"), "F14"},
110 {KEY_F (15), "f15", N_("Function key 15"), "F15"},
111 {KEY_F (16), "f16", N_("Function key 16"), "F16"},
112 {KEY_F (17), "f17", N_("Function key 17"), "F17"},
113 {KEY_F (18), "f18", N_("Function key 18"), "F18"},
114 {KEY_F (19), "f19", N_("Function key 19"), "F19"},
115 {KEY_F (20), "f20", N_("Function key 20"), "F20"},
116 {KEY_BACKSPACE, "backspace", N_("Backspace key"), "Backspace"},
117 {KEY_END, "end", N_("End key"), "End"},
118 {KEY_UP, "up", N_("Up arrow key"), "Up"},
119 {KEY_DOWN, "down", N_("Down arrow key"), "Down"},
120 {KEY_LEFT, "left", N_("Left arrow key"), "Left"},
121 {KEY_RIGHT, "right", N_("Right arrow key"), "Right"},
122 {KEY_HOME, "home", N_("Home key"), "Home"},
123 {KEY_NPAGE, "pgdn", N_("Page Down key"), "PgDn"},
124 {KEY_PPAGE, "pgup", N_("Page Up key"), "PgUp"},
125 {KEY_IC, "insert", N_("Insert key"), "Ins"},
126 {KEY_DC, "delete", N_("Delete key"), "Del"},
127 {ALT ('\t'), "complete", N_("Completion/M-tab"), "Meta-Tab"},
128 {KEY_KP_ADD, "kpplus", N_("+ on keypad"), "+"},
129 {KEY_KP_SUBTRACT, "kpminus", N_("- on keypad"), "-"},
130 {(int) '/', "kpslash", N_("Slash on keypad"), "/"},
131 {KEY_KP_MULTIPLY, "kpasterisk", N_("* on keypad"), "*"},
133 /* From here on, these won't be shown in Learn keys (no space) */
134 {ESC_CHAR, "escape", N_("Escape key"), "Esc"},
135 {KEY_LEFT, "kpleft", N_("Left arrow keypad"), "Left"},
136 {KEY_RIGHT, "kpright", N_("Right arrow keypad"), "Right"},
137 {KEY_UP, "kpup", N_("Up arrow keypad"), "Up"},
138 {KEY_DOWN, "kpdown", N_("Down arrow keypad"), "Down"},
139 {KEY_HOME, "kphome", N_("Home on keypad"), "Home"},
140 {KEY_END, "kpend", N_("End on keypad"), "End"},
141 {KEY_NPAGE, "kpnpage", N_("Page Down keypad"), "PgDn"},
142 {KEY_PPAGE, "kpppage", N_("Page Up keypad"), "PgUp"},
143 {KEY_IC, "kpinsert", N_("Insert on keypad"), "Ins"},
144 {KEY_DC, "kpdelete", N_("Delete on keypad"), "Del"},
145 {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
146 {KEY_F (21), "f21", N_("Function key 21"), "F21"},
147 {KEY_F (22), "f22", N_("Function key 22"), "F22"},
148 {KEY_F (23), "f23", N_("Function key 23"), "F23"},
149 {KEY_F (24), "f24", N_("Function key 24"), "F24"},
150 {KEY_A1, "a1", N_("A1 key"), "A1"},
151 {KEY_C1, "c1", N_("C1 key"), "C1"},
153 /* Alternative label */
154 {ESC_CHAR, "esc", N_("Escape key"), "Esc"},
155 {KEY_BACKSPACE, "bs", N_("Backspace key"), "Bakspace"},
156 {KEY_IC, "ins", N_("Insert key"), "Ins"},
157 {KEY_DC, "del", N_("Delete key"), "Del"},
158 {(int) '+', "plus", N_("Plus"), "+"},
159 {(int) '-', "minus", N_("Minus"), "-"},
160 {(int) '*', "asterisk", N_("Asterisk"), "*"},
161 {(int) '.', "dot", N_("Dot"), "."},
162 {(int) '<', "lt", N_("Less than"), "<"},
163 {(int) '>', "gt", N_("Great than"), ">"},
164 {(int) '=', "equal", N_("Equal"), "="},
165 {(int) ',', "comma", N_("Comma"), ","},
166 {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
167 {(int) ':', "colon", N_("Colon"), ":"},
168 {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
169 {(int) '?', "question", N_("Question mark"), "?"},
170 {(int) '&', "ampersand", N_("Ampersand"), "&"},
171 {(int) '$', "dollar", N_("Dollar sign"), "$"},
172 {(int) '"', "quota", N_("Quotation mark"), "\""},
173 {(int) '%', "percent", N_("Percent sign"), "%"},
174 {(int) '^', "caret", N_("Caret"), "^"},
175 {(int) '~', "tilda", N_("Tilda"), "~"},
176 {(int) '`', "prime", N_("Prime"), "`"},
177 {(int) '_', "underline", N_("Underline"), "_"},
178 {(int) '_', "understrike", N_("Understrike"), "_"},
179 {(int) '|', "pipe", N_("Pipe"), "|"},
180 {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
181 {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
182 {(int) '[', "lbracket", N_("Left bracket"), "["},
183 {(int) ']', "rbracket", N_("Right bracket"), "]"},
184 {(int) '{', "lbrace", N_("Left brace"), "{"},
185 {(int) '}', "rbrace", N_("Right brace"), "}"},
186 {(int) '\n', "enter", N_("Enter"), "Enter"},
187 {(int) '\t', "tab", N_("Tab key"), "Tab"},
188 {(int) ' ', "space", N_("Space key"), "Space"},
189 {(int) '/', "slash", N_("Slash key"), "/"},
190 {(int) '\\', "backslash", N_("Backslash key"), "\\"},
191 {(int) '#', "number", N_("Number sign #"), "#"},
192 {(int) '#', "hash", N_("Number sign #"), "#"},
193 /* TRANSLATORS: Please translate as in "at sign" (@). */
194 {(int) '@', "at", N_("At sign"), "@"},
196 /* meta keys */
197 {KEY_M_CTRL, "control", N_("Ctrl"), "C"},
198 {KEY_M_CTRL, "ctrl", N_("Ctrl"), "C"},
199 {KEY_M_ALT, "meta", N_("Alt"), "M"},
200 {KEY_M_ALT, "alt", N_("Alt"), "M"},
201 {KEY_M_ALT, "ralt", N_("Alt"), "M"},
202 {KEY_M_SHIFT, "shift", N_("Shift"), "S"},
204 {0, NULL, NULL, NULL}
207 /*** file scope macro definitions ****************************************************************/
209 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *) NULL))
210 #define DIF_TIME(t1, t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000)
212 /* The maximum sequence length (32 + null terminator) */
213 #define SEQ_BUFFER_LEN 33
215 /*** file scope type declarations ****************************************************************/
217 /* Linux console keyboard modifiers */
218 typedef enum
220 SHIFT_PRESSED = (1 << 0),
221 ALTR_PRESSED = (1 << 1),
222 CONTROL_PRESSED = (1 << 2),
223 ALTL_PRESSED = (1 << 3)
224 } mod_pressed_t;
226 typedef struct key_def
228 char ch; /* Holds the matching char code */
229 int code; /* The code returned, valid if child == NULL */
230 struct key_def *next;
231 struct key_def *child; /* sequence continuation */
232 int action; /* optional action to be done. Now used only
233 to mark that we are just after the first
234 Escape */
235 } key_def;
237 typedef struct
239 int code;
240 const char *seq;
241 int action;
242 } key_define_t;
244 /* File descriptor monitoring add/remove routines */
245 typedef struct SelectList
247 int fd;
248 select_fn callback;
249 void *info;
250 struct SelectList *next;
251 } SelectList;
253 typedef enum KeySortType
255 KEY_NOSORT = 0,
256 KEY_SORTBYNAME,
257 KEY_SORTBYCODE
258 } KeySortType;
260 #ifdef __QNXNTO__
261 typedef int (*ph_dv_f) (void *, void *);
262 typedef int (*ph_ov_f) (void *);
263 typedef int (*ph_pqc_f) (unsigned short, PhCursorInfo_t *);
264 #endif
266 /*** file scope variables ************************************************************************/
268 static key_define_t mc_default_keys[] = {
269 {ESC_CHAR, ESC_STR, MCKEY_ESCAPE},
270 {ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION},
271 {0, NULL, MCKEY_NOACTION},
274 /* Broken terminfo and termcap databases on xterminals */
275 static key_define_t xterm_key_defines[] = {
276 {KEY_F (1), ESC_STR "OP", MCKEY_NOACTION},
277 {KEY_F (2), ESC_STR "OQ", MCKEY_NOACTION},
278 {KEY_F (3), ESC_STR "OR", MCKEY_NOACTION},
279 {KEY_F (4), ESC_STR "OS", MCKEY_NOACTION},
280 {KEY_F (1), ESC_STR "[11~", MCKEY_NOACTION},
281 {KEY_F (2), ESC_STR "[12~", MCKEY_NOACTION},
282 {KEY_F (3), ESC_STR "[13~", MCKEY_NOACTION},
283 {KEY_F (4), ESC_STR "[14~", MCKEY_NOACTION},
284 {KEY_F (5), ESC_STR "[15~", MCKEY_NOACTION},
285 {KEY_F (6), ESC_STR "[17~", MCKEY_NOACTION},
286 {KEY_F (7), ESC_STR "[18~", MCKEY_NOACTION},
287 {KEY_F (8), ESC_STR "[19~", MCKEY_NOACTION},
288 {KEY_F (9), ESC_STR "[20~", MCKEY_NOACTION},
289 {KEY_F (10), ESC_STR "[21~", MCKEY_NOACTION},
291 /* old xterm Shift-arrows */
292 {KEY_M_SHIFT | KEY_UP, ESC_STR "O2A", MCKEY_NOACTION},
293 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "O2B", MCKEY_NOACTION},
294 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "O2C", MCKEY_NOACTION},
295 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "O2D", MCKEY_NOACTION},
297 /* new xterm Shift-arrows */
298 {KEY_M_SHIFT | KEY_UP, ESC_STR "[1;2A", MCKEY_NOACTION},
299 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[1;2B", MCKEY_NOACTION},
300 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[1;2C", MCKEY_NOACTION},
301 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[1;2D", MCKEY_NOACTION},
303 /* more xterm keys with modifiers */
304 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5;5~", MCKEY_NOACTION},
305 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6;5~", MCKEY_NOACTION},
306 {KEY_M_CTRL | KEY_IC, ESC_STR "[2;5~", MCKEY_NOACTION},
307 {KEY_M_CTRL | KEY_DC, ESC_STR "[3;5~", MCKEY_NOACTION},
308 {KEY_M_CTRL | KEY_HOME, ESC_STR "[1;5H", MCKEY_NOACTION},
309 {KEY_M_CTRL | KEY_END, ESC_STR "[1;5F", MCKEY_NOACTION},
310 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[1;2H", MCKEY_NOACTION},
311 {KEY_M_SHIFT | KEY_END, ESC_STR "[1;2F", MCKEY_NOACTION},
312 {KEY_M_CTRL | KEY_UP, ESC_STR "[1;5A", MCKEY_NOACTION},
313 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;5B", MCKEY_NOACTION},
314 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;5C", MCKEY_NOACTION},
315 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;5D", MCKEY_NOACTION},
316 {KEY_M_SHIFT | KEY_IC, ESC_STR "[2;2~", MCKEY_NOACTION},
317 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3;2~", MCKEY_NOACTION},
318 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[1;6A", MCKEY_NOACTION},
319 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;6B", MCKEY_NOACTION},
320 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;6C", MCKEY_NOACTION},
321 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;6D", MCKEY_NOACTION},
323 /* putty */
324 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[[1;6A", MCKEY_NOACTION},
325 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[[1;6B", MCKEY_NOACTION},
326 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[[1;6C", MCKEY_NOACTION},
327 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[[1;6D", MCKEY_NOACTION},
329 /* putty alt-arrow keys */
330 /* removed as source esc esc esc trouble */
332 { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
333 { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
334 { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
335 { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
336 { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
337 { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
338 { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
339 { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
341 { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
342 { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
343 { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
344 { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
346 { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
347 { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
348 { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
349 { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
351 /* xterm alt-arrow keys */
352 {KEY_M_ALT | KEY_UP, ESC_STR "[1;3A", MCKEY_NOACTION},
353 {KEY_M_ALT | KEY_DOWN, ESC_STR "[1;3B", MCKEY_NOACTION},
354 {KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;3C", MCKEY_NOACTION},
355 {KEY_M_ALT | KEY_LEFT, ESC_STR "[1;3D", MCKEY_NOACTION},
356 {KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;3~", MCKEY_NOACTION},
357 {KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;3~", MCKEY_NOACTION},
358 {KEY_M_ALT | KEY_HOME, ESC_STR "[1~", MCKEY_NOACTION},
359 {KEY_M_ALT | KEY_END, ESC_STR "[4~", MCKEY_NOACTION},
360 {KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR "[1;7A", MCKEY_NOACTION},
361 {KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR "[1;7B", MCKEY_NOACTION},
362 {KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;7C", MCKEY_NOACTION},
363 {KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR "[1;7D", MCKEY_NOACTION},
364 {KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;7~", MCKEY_NOACTION},
365 {KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;7~", MCKEY_NOACTION},
366 {KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR "OH", MCKEY_NOACTION},
367 {KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR "OF", MCKEY_NOACTION},
369 /* rxvt keys with modifiers */
370 {KEY_M_SHIFT | KEY_UP, ESC_STR "[a", MCKEY_NOACTION},
371 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION},
372 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION},
373 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION},
374 {KEY_M_CTRL | KEY_UP, ESC_STR "Oa", MCKEY_NOACTION},
375 {KEY_M_CTRL | KEY_DOWN, ESC_STR "Ob", MCKEY_NOACTION},
376 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "Oc", MCKEY_NOACTION},
377 {KEY_M_CTRL | KEY_LEFT, ESC_STR "Od", MCKEY_NOACTION},
378 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5^", MCKEY_NOACTION},
379 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6^", MCKEY_NOACTION},
380 {KEY_M_CTRL | KEY_HOME, ESC_STR "[7^", MCKEY_NOACTION},
381 {KEY_M_CTRL | KEY_END, ESC_STR "[8^", MCKEY_NOACTION},
382 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[7$", MCKEY_NOACTION},
383 {KEY_M_SHIFT | KEY_END, ESC_STR "[8$", MCKEY_NOACTION},
384 {KEY_M_CTRL | KEY_IC, ESC_STR "[2^", MCKEY_NOACTION},
385 {KEY_M_CTRL | KEY_DC, ESC_STR "[3^", MCKEY_NOACTION},
386 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3$", MCKEY_NOACTION},
388 /* konsole keys with modifiers */
389 {KEY_M_SHIFT | KEY_HOME, ESC_STR "O2H", MCKEY_NOACTION},
390 {KEY_M_SHIFT | KEY_END, ESC_STR "O2F", MCKEY_NOACTION},
392 /* gnome-terminal */
393 {KEY_M_SHIFT | KEY_UP, ESC_STR "[2A", MCKEY_NOACTION},
394 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[2B", MCKEY_NOACTION},
395 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[2C", MCKEY_NOACTION},
396 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[2D", MCKEY_NOACTION},
397 {KEY_M_CTRL | KEY_UP, ESC_STR "[5A", MCKEY_NOACTION},
398 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[5B", MCKEY_NOACTION},
399 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[5C", MCKEY_NOACTION},
400 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[5D", MCKEY_NOACTION},
401 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[6A", MCKEY_NOACTION},
402 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[6B", MCKEY_NOACTION},
403 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[6C", MCKEY_NOACTION},
404 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[6D", MCKEY_NOACTION},
406 /* gnome-terminal - application mode */
407 {KEY_M_CTRL | KEY_UP, ESC_STR "O5A", MCKEY_NOACTION},
408 {KEY_M_CTRL | KEY_DOWN, ESC_STR "O5B", MCKEY_NOACTION},
409 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "O5C", MCKEY_NOACTION},
410 {KEY_M_CTRL | KEY_LEFT, ESC_STR "O5D", MCKEY_NOACTION},
411 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "O6A", MCKEY_NOACTION},
412 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "O6B", MCKEY_NOACTION},
413 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "O6C", MCKEY_NOACTION},
414 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "O6D", MCKEY_NOACTION},
416 /* iTerm */
417 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[5;2~", MCKEY_NOACTION},
418 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[6;2~", MCKEY_NOACTION},
420 /* putty */
421 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[[5;53~", MCKEY_NOACTION},
422 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[[6;53~", MCKEY_NOACTION},
424 /* keypad keys */
425 {KEY_IC, ESC_STR "Op", MCKEY_NOACTION},
426 {KEY_DC, ESC_STR "On", MCKEY_NOACTION},
427 {'/', ESC_STR "Oo", MCKEY_NOACTION},
428 {'\n', ESC_STR "OM", MCKEY_NOACTION},
430 {0, NULL, MCKEY_NOACTION},
433 /* qansi-m terminals have a much more key combinatios,
434 which are undefined in termcap/terminfo */
435 static key_define_t qansi_key_defines[] = {
436 /* qansi-m terminal */
437 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[u", MCKEY_NOACTION}, /* Ctrl-PgDown */
438 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[v", MCKEY_NOACTION}, /* Ctrl-PgUp */
439 {KEY_M_CTRL | KEY_HOME, ESC_STR "[h", MCKEY_NOACTION}, /* Ctrl-Home */
440 {KEY_M_CTRL | KEY_END, ESC_STR "[y", MCKEY_NOACTION}, /* Ctrl-End */
441 {KEY_M_CTRL | KEY_IC, ESC_STR "[`", MCKEY_NOACTION}, /* Ctrl-Insert */
442 {KEY_M_CTRL | KEY_DC, ESC_STR "[p", MCKEY_NOACTION}, /* Ctrl-Delete */
443 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION}, /* Ctrl-Left */
444 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION}, /* Ctrl-Right */
445 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION}, /* Ctrl-Down */
446 {KEY_M_CTRL | KEY_UP, ESC_STR "[a", MCKEY_NOACTION}, /* Ctrl-Up */
447 {KEY_M_CTRL | KEY_KP_ADD, ESC_STR "[s", MCKEY_NOACTION}, /* Ctrl-Gr-Plus */
448 {KEY_M_CTRL | KEY_KP_SUBTRACT, ESC_STR "[t", MCKEY_NOACTION}, /* Ctrl-Gr-Minus */
449 {KEY_M_CTRL | '\t', ESC_STR "[z", MCKEY_NOACTION}, /* Ctrl-Tab */
450 {KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION}, /* Shift-Tab */
451 {KEY_M_CTRL | KEY_F (1), ESC_STR "[1~", MCKEY_NOACTION}, /* Ctrl-F1 */
452 {KEY_M_CTRL | KEY_F (2), ESC_STR "[2~", MCKEY_NOACTION}, /* Ctrl-F2 */
453 {KEY_M_CTRL | KEY_F (3), ESC_STR "[3~", MCKEY_NOACTION}, /* Ctrl-F3 */
454 {KEY_M_CTRL | KEY_F (4), ESC_STR "[4~", MCKEY_NOACTION}, /* Ctrl-F4 */
455 {KEY_M_CTRL | KEY_F (5), ESC_STR "[5~", MCKEY_NOACTION}, /* Ctrl-F5 */
456 {KEY_M_CTRL | KEY_F (6), ESC_STR "[6~", MCKEY_NOACTION}, /* Ctrl-F6 */
457 {KEY_M_CTRL | KEY_F (7), ESC_STR "[7~", MCKEY_NOACTION}, /* Ctrl-F7 */
458 {KEY_M_CTRL | KEY_F (8), ESC_STR "[8~", MCKEY_NOACTION}, /* Ctrl-F8 */
459 {KEY_M_CTRL | KEY_F (9), ESC_STR "[9~", MCKEY_NOACTION}, /* Ctrl-F9 */
460 {KEY_M_CTRL | KEY_F (10), ESC_STR "[10~", MCKEY_NOACTION}, /* Ctrl-F10 */
461 {KEY_M_CTRL | KEY_F (11), ESC_STR "[11~", MCKEY_NOACTION}, /* Ctrl-F11 */
462 {KEY_M_CTRL | KEY_F (12), ESC_STR "[12~", MCKEY_NOACTION}, /* Ctrl-F12 */
463 {KEY_M_ALT | KEY_F (1), ESC_STR "[17~", MCKEY_NOACTION}, /* Alt-F1 */
464 {KEY_M_ALT | KEY_F (2), ESC_STR "[18~", MCKEY_NOACTION}, /* Alt-F2 */
465 {KEY_M_ALT | KEY_F (3), ESC_STR "[19~", MCKEY_NOACTION}, /* Alt-F3 */
466 {KEY_M_ALT | KEY_F (4), ESC_STR "[20~", MCKEY_NOACTION}, /* Alt-F4 */
467 {KEY_M_ALT | KEY_F (5), ESC_STR "[21~", MCKEY_NOACTION}, /* Alt-F5 */
468 {KEY_M_ALT | KEY_F (6), ESC_STR "[22~", MCKEY_NOACTION}, /* Alt-F6 */
469 {KEY_M_ALT | KEY_F (7), ESC_STR "[23~", MCKEY_NOACTION}, /* Alt-F7 */
470 {KEY_M_ALT | KEY_F (8), ESC_STR "[24~", MCKEY_NOACTION}, /* Alt-F8 */
471 {KEY_M_ALT | KEY_F (9), ESC_STR "[25~", MCKEY_NOACTION}, /* Alt-F9 */
472 {KEY_M_ALT | KEY_F (10), ESC_STR "[26~", MCKEY_NOACTION}, /* Alt-F10 */
473 {KEY_M_ALT | KEY_F (11), ESC_STR "[27~", MCKEY_NOACTION}, /* Alt-F11 */
474 {KEY_M_ALT | KEY_F (12), ESC_STR "[28~", MCKEY_NOACTION}, /* Alt-F12 */
475 {KEY_M_ALT | 'a', ESC_STR "Na", MCKEY_NOACTION}, /* Alt-a */
476 {KEY_M_ALT | 'b', ESC_STR "Nb", MCKEY_NOACTION}, /* Alt-b */
477 {KEY_M_ALT | 'c', ESC_STR "Nc", MCKEY_NOACTION}, /* Alt-c */
478 {KEY_M_ALT | 'd', ESC_STR "Nd", MCKEY_NOACTION}, /* Alt-d */
479 {KEY_M_ALT | 'e', ESC_STR "Ne", MCKEY_NOACTION}, /* Alt-e */
480 {KEY_M_ALT | 'f', ESC_STR "Nf", MCKEY_NOACTION}, /* Alt-f */
481 {KEY_M_ALT | 'g', ESC_STR "Ng", MCKEY_NOACTION}, /* Alt-g */
482 {KEY_M_ALT | 'h', ESC_STR "Nh", MCKEY_NOACTION}, /* Alt-h */
483 {KEY_M_ALT | 'i', ESC_STR "Ni", MCKEY_NOACTION}, /* Alt-i */
484 {KEY_M_ALT | 'j', ESC_STR "Nj", MCKEY_NOACTION}, /* Alt-j */
485 {KEY_M_ALT | 'k', ESC_STR "Nk", MCKEY_NOACTION}, /* Alt-k */
486 {KEY_M_ALT | 'l', ESC_STR "Nl", MCKEY_NOACTION}, /* Alt-l */
487 {KEY_M_ALT | 'm', ESC_STR "Nm", MCKEY_NOACTION}, /* Alt-m */
488 {KEY_M_ALT | 'n', ESC_STR "Nn", MCKEY_NOACTION}, /* Alt-n */
489 {KEY_M_ALT | 'o', ESC_STR "No", MCKEY_NOACTION}, /* Alt-o */
490 {KEY_M_ALT | 'p', ESC_STR "Np", MCKEY_NOACTION}, /* Alt-p */
491 {KEY_M_ALT | 'q', ESC_STR "Nq", MCKEY_NOACTION}, /* Alt-q */
492 {KEY_M_ALT | 'r', ESC_STR "Nr", MCKEY_NOACTION}, /* Alt-r */
493 {KEY_M_ALT | 's', ESC_STR "Ns", MCKEY_NOACTION}, /* Alt-s */
494 {KEY_M_ALT | 't', ESC_STR "Nt", MCKEY_NOACTION}, /* Alt-t */
495 {KEY_M_ALT | 'u', ESC_STR "Nu", MCKEY_NOACTION}, /* Alt-u */
496 {KEY_M_ALT | 'v', ESC_STR "Nv", MCKEY_NOACTION}, /* Alt-v */
497 {KEY_M_ALT | 'w', ESC_STR "Nw", MCKEY_NOACTION}, /* Alt-w */
498 {KEY_M_ALT | 'x', ESC_STR "Nx", MCKEY_NOACTION}, /* Alt-x */
499 {KEY_M_ALT | 'y', ESC_STR "Ny", MCKEY_NOACTION}, /* Alt-y */
500 {KEY_M_ALT | 'z', ESC_STR "Nz", MCKEY_NOACTION}, /* Alt-z */
501 {KEY_KP_SUBTRACT, ESC_STR "[S", MCKEY_NOACTION}, /* Gr-Minus */
502 {KEY_KP_ADD, ESC_STR "[T", MCKEY_NOACTION}, /* Gr-Plus */
503 {0, NULL, MCKEY_NOACTION},
506 /* This holds all the key definitions */
507 static key_def *keys = NULL;
509 static int input_fd;
510 static int disabled_channels = 0; /* Disable channels checking */
512 static SelectList *select_list = NULL;
514 static int seq_buffer[SEQ_BUFFER_LEN];
515 static int *seq_append = NULL;
517 static int *pending_keys = NULL;
519 static int mouse_btn, mouse_x, mouse_y;
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 static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
712 static struct timeval tv2;
713 static int clicks = 0;
714 static int last_btn = 0;
715 int btn = mouse_btn;
717 /* Decode Xterm mouse information to a GPM style event */
719 /* There seems to be no way of knowing which button was released */
720 /* So we assume all the buttons were released */
722 if (btn == 3)
724 if (last_btn != 0)
726 if ((last_btn & (GPM_B_UP | GPM_B_DOWN)) != 0)
728 /* FIXME: DIRTY HACK */
729 /* don't generate GPM_UP after mouse wheel */
730 /* need for menu event handling */
731 ev->type = 0;
732 tv1.tv_sec = 0;
733 tv1.tv_usec = 0;
735 else
737 ev->type = GPM_UP | (GPM_SINGLE << clicks);
738 GET_TIME (tv1);
740 ev->buttons = 0;
741 last_btn = 0;
742 clicks = 0;
744 else
746 /* Bogus event, maybe mouse wheel */
747 ev->type = 0;
750 else
752 if (btn >= 32 && btn <= 34)
754 btn -= 32;
755 ev->type = GPM_DRAG;
757 else
758 ev->type = GPM_DOWN;
760 GET_TIME (tv2);
761 if (tv1.tv_sec && (DIF_TIME (tv1, tv2) < double_click_speed))
763 clicks++;
764 clicks %= 3;
766 else
767 clicks = 0;
769 switch (btn)
771 case 0:
772 ev->buttons = GPM_B_LEFT;
773 break;
774 case 1:
775 ev->buttons = GPM_B_MIDDLE;
776 break;
777 case 2:
778 ev->buttons = GPM_B_RIGHT;
779 break;
780 case 64:
781 ev->buttons = GPM_B_UP;
782 clicks = 0;
783 break;
784 case 65:
785 ev->buttons = GPM_B_DOWN;
786 clicks = 0;
787 break;
788 default:
789 /* Nothing */
790 ev->type = 0;
791 ev->buttons = 0;
792 break;
794 last_btn = ev->buttons;
796 ev->x = mouse_x;
797 ev->y = mouse_y;
800 /* --------------------------------------------------------------------------------------------- */
802 * Get modifier state (shift, alt, ctrl) for the last key pressed.
803 * We are assuming that the state didn't change since the key press.
804 * This is only correct if get_modifier() is called very fast after
805 * the input was received, so that the user didn't release the
806 * modifier keys yet.
809 static int
810 get_modifier (void)
812 int result = 0;
813 #ifdef __QNXNTO__
814 int mod_status, shift_ext_status;
815 static int in_photon = 0;
816 static int ph_ig = 0;
817 PhCursorInfo_t cursor_info;
818 #endif /* __QNXNTO__ */
820 #ifdef HAVE_TEXTMODE_X11_SUPPORT
821 if (x11_window != 0)
823 Window root, child;
824 int root_x, root_y;
825 int win_x, win_y;
826 unsigned int mask;
828 mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x,
829 &root_y, &win_x, &win_y, &mask);
831 if (mask & ShiftMask)
832 result |= KEY_M_SHIFT;
833 if (mask & ControlMask)
834 result |= KEY_M_CTRL;
835 return result;
837 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
838 #ifdef __QNXNTO__
840 if (in_photon == 0)
842 /* First time here, let's load Photon library and attach
843 to Photon */
844 in_photon = -1;
845 if (getenv ("PHOTON2_PATH") != NULL)
847 /* QNX 6.x has no support for RTLD_LAZY */
848 void *ph_handle = dlopen ("/usr/lib/libph.so", RTLD_NOW);
849 if (ph_handle != NULL)
851 ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach");
852 ph_input_group = (ph_ov_f) dlsym (ph_handle, "PhInputGroup");
853 ph_query_cursor = (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor");
854 if ((ph_attach != NULL) && (ph_input_group != NULL) && (ph_query_cursor != NULL))
856 if ((*ph_attach) (0, 0))
857 { /* Attached */
858 ph_ig = (*ph_input_group) (0);
859 in_photon = 1;
865 /* We do not have Photon running. Assume we are in text
866 console or xterm */
867 if (in_photon == -1)
869 if (devctl (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status, sizeof (int), NULL) == -1)
870 return 0;
871 shift_ext_status = mod_status & 0xffffff00UL;
872 mod_status &= 0x7f;
873 if (mod_status & _LINESTATUS_CON_ALT)
874 result |= KEY_M_ALT;
875 if (mod_status & _LINESTATUS_CON_CTRL)
876 result |= KEY_M_CTRL;
877 if ((mod_status & _LINESTATUS_CON_SHIFT) || (shift_ext_status & 0x00000800UL))
878 result |= KEY_M_SHIFT;
880 else
882 (*ph_query_cursor) (ph_ig, &cursor_info);
883 if (cursor_info.key_mods & 0x04)
884 result |= KEY_M_ALT;
885 if (cursor_info.key_mods & 0x02)
886 result |= KEY_M_CTRL;
887 if (cursor_info.key_mods & 0x01)
888 result |= KEY_M_SHIFT;
890 #endif /* __QNXNTO__ */
892 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
894 unsigned char modifiers = 6;
896 if (ioctl (0, TIOCLINUX, &modifiers) < 0)
897 return 0;
899 /* Translate Linux modifiers into mc modifiers */
900 if (modifiers & SHIFT_PRESSED)
901 result |= KEY_M_SHIFT;
902 if (modifiers & (ALTL_PRESSED | ALTR_PRESSED))
903 result |= KEY_M_ALT;
904 if (modifiers & CONTROL_PRESSED)
905 result |= KEY_M_CTRL;
907 #endif /* !__linux__ */
908 return result;
911 /* --------------------------------------------------------------------------------------------- */
913 static gboolean
914 push_char (int c)
916 gboolean ret = FALSE;
918 if (seq_append == NULL)
919 seq_append = seq_buffer;
921 if (seq_append != &(seq_buffer[SEQ_BUFFER_LEN - 2]))
923 *(seq_append++) = c;
924 *seq_append = 0;
925 ret = TRUE;
928 return ret;
931 /* --------------------------------------------------------------------------------------------- */
932 /* Parse extended mouse coordinates.
933 Returns -1 if pending_keys (up to seq_append) cannot be a prefix of extended mouse coordinates.
934 Returns 0 if pending_keys (up to seq_append) is a valid (but still incomplete) prefix for
935 extended mouse coordinates, e.g. "^[[32;4".
936 Returns 1 and fills the mouse_btn, mouse_x, mouse_y values if pending_keys (up to seq_append) is
937 a complete extended mouse sequence, e.g. "^[[32;42;5M"
940 /* Technical info (Egmont Koblinger <egmont@gmail.com>):
942 The ancient way of reporting mouse coordinates only supports coordinates up to 223,
943 so if your terminal is wider (or taller, but that's unlikely), you cannot use your mouse
944 in the rightmost columns.
946 * The old way of reporting mouse coordinates is the following:
947 + Output DECSET 1000 to enable mouse
948 + Expect escape sequences in the format \e[M<action+32><x+32><y+32> whereas <action+32>,
949 <x+32> and <y+32> are single bytes. (Action is 0 for left click, 1 for middle click,
950 2 for right click, 3 for release, or something like this.)
951 + Disadvantages of this format:
952 + x and y can only go up to 223.
953 + Coordinates above 95 are not ascii-compatible, so any character set converting
954 layer (e.g. luit) messes them up.
955 + The stream is not valid UTF-8, even if everything else is.
957 * The first new extension, introduced by xterm-262, is the following:
958 + Output DECSET 1000 to enable mouse, followed by DECSET 1005 to activate extended mode.
959 + Expect escape sequences in the format \e[M<action+32><<x+32>><<y+32>> whereas <<x+32>>
960 and <<y+32>> each can be up to two bytes long: coordinate+32 is encoded in UTF-8.
961 + Disadvantates of this format:
962 + There's still a limit of 2015 rows/columns (okay, it's not a real life problem).
963 + Doesn't solve the luit issue.
964 + It is "horribly broken" (quoting urxvt's changelog) in terms of compatibility
965 with the previous standard. There is no way for an application to tell whether
966 the underlying terminal supports this new mode (whether DECSET 1005 did actually change
967 the behavior or not), but depending on this a completely different user action might
968 generate the same input. Example:
969 + If the terminal doesn't support this extension, then clicking at (162, 129)
970 generates \e[M<32><194><161>.
971 + If the terminal supports this extension, then clicking at (129, 1) [bit of math:
972 129+32 = 161, U+0161 in UTF-8 is 194 161] generates \e[M<32><194><161><33>.
973 + so there's no way to tell whether the terminal ignored the 1005 escape sequence,
974 the user clicked on (162, 129) and then typed an exclamation mark; or whether
975 the terminal recognized the escape, and the user clicked on (129, 1).
976 + Due to this horrible brokenness, there's no way to implement support it without
977 explicitly asking the user (via a setting) if the terminal can speak this extension.
979 * The second new extension, introduced by rxvt-unicode-9.10, is the following:
980 + Output DECSET 1000 to enable mouse, followed by DECSET 1015 to activate this extended mode.
981 + Expect escape sequences in the format \e[{action+32};{x};{y}M where this time I used
982 the braces to denote spelling out the numbers in decimal, rather than using raw bytes.
983 + The only thing I don't understand is why they kept the offset of 32 at action, but other
984 than that, this format is totally okay, and solves all the weaknesses of the previous ones.
986 Currently, at least the following terminal emulators have support for these:
987 * xterm supports the xterm extension
988 * rxvt-unicode >= 9.10 supports both extensions
989 * iterm2 supports both extensions
990 * vte >= 0.31 supports the urxvt extension
993 static int
994 parse_extended_mouse_coordinates (void)
996 int c, btn = 0, x = 0, y = 0;
997 const int *p = pending_keys;
998 const int *endp = seq_append;
1000 if (p == endp)
1001 return 0;
1002 c = *p++;
1003 if (c != ESC_CHAR)
1004 return -1;
1006 if (p == endp)
1007 return 0;
1008 c = *p++;
1009 if (c != '[')
1010 return -1;
1012 while (TRUE)
1014 if (p == endp)
1015 return 0;
1016 c = *p++;
1017 if (c == ';')
1018 break;
1019 if (c < '0' || c > '9')
1020 return -1;
1021 btn = 10 * btn + c - '0';
1023 if (btn < 32)
1024 return -1;
1025 btn -= 32;
1027 while (TRUE)
1029 if (p == endp)
1030 return 0;
1031 c = *p++;
1032 if (c == ';')
1033 break;
1034 if (c < '0' || c > '9')
1035 return -1;
1036 x = 10 * x + c - '0';
1038 if (x < 1)
1039 return -1;
1041 while (TRUE)
1043 if (p == endp)
1044 return 0;
1045 c = *p++;
1046 if (c == 'M')
1047 break;
1048 if (c < '0' || c > '9')
1049 return -1;
1050 y = 10 * y + c - '0';
1052 if (y < 1)
1053 return -1;
1055 mouse_btn = btn;
1056 mouse_x = x;
1057 mouse_y = y;
1058 return 1;
1061 /* --------------------------------------------------------------------------------------------- */
1062 /* Apply corrections for the keycode generated in get_key_code() */
1064 static int
1065 correct_key_code (int code)
1067 unsigned int c = code & ~KEY_M_MASK; /* code without modifier */
1068 unsigned int mod = code & KEY_M_MASK; /* modifier */
1069 #ifdef __QNXNTO__
1070 unsigned int qmod; /* bunch of the QNX console
1071 modifiers needs unchanged */
1072 #endif /* __QNXNTO__ */
1075 * Add key modifiers directly from X11 or OS.
1076 * Ordinary characters only get modifiers from sequences.
1078 if (c < 32 || c >= 256)
1080 mod |= get_modifier ();
1083 /* This is needed if the newline is reported as carriage return */
1084 if (c == '\r')
1085 c = '\n';
1087 /* This is reported to be useful on AIX */
1088 if (c == KEY_SCANCEL)
1089 c = '\t';
1091 /* Convert Shift+Tab and Ctrl+Tab to Back Tab */
1092 if ((c == '\t') && (mod & (KEY_M_SHIFT | KEY_M_CTRL)))
1094 c = KEY_BTAB;
1095 mod = 0;
1098 /* F0 is the same as F10 for out purposes */
1099 if (c == KEY_F (0))
1100 c = KEY_F (10);
1103 * We are not interested if Ctrl was pressed when entering control
1104 * characters, so assume that it was. When checking for such keys,
1105 * XCTRL macro should be used. In some cases, we are interested,
1106 * e.g. to distinguish Ctrl-Enter from Enter.
1108 if (c == '\b')
1110 /* Special case for backspase ('\b' < 32) */
1111 c = KEY_BACKSPACE;
1112 mod &= ~KEY_M_CTRL;
1114 else if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n')
1116 mod |= KEY_M_CTRL;
1119 #ifdef __QNXNTO__
1120 qmod = get_modifier ();
1122 if ((c == 127) && (mod == 0))
1123 { /* Add Ctrl/Alt/Shift-BackSpace */
1124 mod |= get_modifier ();
1125 c = KEY_BACKSPACE;
1128 if ((c == '0') && (mod == 0))
1129 { /* Add Shift-Insert on key pad */
1130 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1132 mod = KEY_M_SHIFT;
1133 c = KEY_IC;
1137 if ((c == '.') && (mod == 0))
1138 { /* Add Shift-Del on key pad */
1139 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1141 mod = KEY_M_SHIFT;
1142 c = KEY_DC;
1145 #endif /* __QNXNTO__ */
1147 /* Unrecognized 0177 is delete (preserve Ctrl) */
1148 if (c == 0177)
1150 c = KEY_BACKSPACE;
1153 #if 0
1154 /* Unrecognized Ctrl-d is delete */
1155 if (c == (31 & 'd'))
1157 c = KEY_DC;
1158 mod &= ~KEY_M_CTRL;
1161 /* Unrecognized Ctrl-h is backspace */
1162 if (c == (31 & 'h'))
1164 c = KEY_BACKSPACE;
1165 mod &= ~KEY_M_CTRL;
1167 #endif
1169 /* Shift+BackSpace is backspace */
1170 if (c == KEY_BACKSPACE && (mod & KEY_M_SHIFT))
1172 mod &= ~KEY_M_SHIFT;
1175 /* Convert Shift+Fn to F(n+10) */
1176 if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT))
1178 c += 10;
1181 /* Remove Shift information from function keys */
1182 if (c >= KEY_F (1) && c <= KEY_F (20))
1184 mod &= ~KEY_M_SHIFT;
1187 if (!mc_global.tty.alternate_plus_minus)
1188 switch (c)
1190 case KEY_KP_ADD:
1191 c = '+';
1192 break;
1193 case KEY_KP_SUBTRACT:
1194 c = '-';
1195 break;
1196 case KEY_KP_MULTIPLY:
1197 c = '*';
1198 break;
1201 return (mod | c);
1204 /* --------------------------------------------------------------------------------------------- */
1206 static int
1207 xgetch_second (void)
1209 fd_set Read_FD_Set;
1210 int c;
1211 struct timeval time_out;
1213 time_out.tv_sec = old_esc_mode_timeout / 1000000;
1214 time_out.tv_usec = old_esc_mode_timeout % 1000000;
1215 tty_nodelay (TRUE);
1216 FD_ZERO (&Read_FD_Set);
1217 FD_SET (input_fd, &Read_FD_Set);
1218 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
1219 c = tty_lowlevel_getch ();
1220 tty_nodelay (FALSE);
1221 return c;
1224 /* --------------------------------------------------------------------------------------------- */
1226 static void
1227 learn_store_key (char *buffer, char **p, int c)
1229 if (*p - buffer > 253)
1230 return;
1231 if (c == ESC_CHAR)
1233 *(*p)++ = '\\';
1234 *(*p)++ = 'e';
1236 else if (c < ' ')
1238 *(*p)++ = '^';
1239 *(*p)++ = c + 'a' - 1;
1241 else if (c == '^')
1243 *(*p)++ = '^';
1244 *(*p)++ = '^';
1246 else
1247 *(*p)++ = (char) c;
1250 /* --------------------------------------------------------------------------------------------- */
1252 static void
1253 k_dispose (key_def * k)
1255 if (k != NULL)
1257 k_dispose (k->child);
1258 k_dispose (k->next);
1259 g_free (k);
1263 /* --------------------------------------------------------------------------------------------- */
1265 static void
1266 s_dispose (SelectList * sel)
1268 if (sel != NULL)
1270 s_dispose (sel->next);
1271 g_free (sel);
1275 /* --------------------------------------------------------------------------------------------- */
1277 static int
1278 key_code_comparator_by_name (const void *p1, const void *p2)
1280 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1281 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1283 return g_ascii_strcasecmp (n1->name, n2->name);
1286 /* --------------------------------------------------------------------------------------------- */
1288 static int
1289 key_code_comparator_by_code (const void *p1, const void *p2)
1291 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1292 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1294 return n1->code - n2->code;
1297 /* --------------------------------------------------------------------------------------------- */
1299 static inline void
1300 sort_key_conv_tab (enum KeySortType type_sort)
1302 if (has_been_sorted != type_sort)
1304 size_t i;
1305 for (i = 0; i < key_conv_tab_size; i++)
1306 key_conv_tab_sorted[i] = &key_name_conv_tab[i];
1308 if (type_sort == KEY_SORTBYNAME)
1310 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1311 &key_code_comparator_by_name);
1313 else if (type_sort == KEY_SORTBYCODE)
1315 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1316 &key_code_comparator_by_code);
1318 has_been_sorted = type_sort;
1322 /* --------------------------------------------------------------------------------------------- */
1324 static int
1325 lookup_keyname (const char *name, int *idx)
1327 if (name[0] != '\0')
1329 const key_code_name_t key = { 0, name, NULL, NULL };
1330 const key_code_name_t *keyp = &key;
1331 key_code_name_t **res;
1333 if (name[1] == '\0')
1335 *idx = -1;
1336 return (int) name[0];
1339 sort_key_conv_tab (KEY_SORTBYNAME);
1341 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1342 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_name);
1344 if (res != NULL)
1346 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1347 return (*res)->code;
1351 *idx = -1;
1352 return 0;
1355 /* --------------------------------------------------------------------------------------------- */
1357 static gboolean
1358 lookup_keycode (const long code, int *idx)
1360 if (code != 0)
1362 const key_code_name_t key = { code, NULL, NULL, NULL };
1363 const key_code_name_t *keyp = &key;
1364 key_code_name_t **res;
1366 sort_key_conv_tab (KEY_SORTBYCODE);
1368 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1369 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_code);
1371 if (res != NULL)
1373 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1374 return TRUE;
1378 *idx = -1;
1379 return FALSE;
1382 /* --------------------------------------------------------------------------------------------- */
1383 /*** public functions ****************************************************************************/
1384 /* --------------------------------------------------------------------------------------------- */
1385 /* This has to be called before init_slang or whatever routine
1386 calls any define_sequence */
1388 void
1389 init_key (void)
1391 const char *term = getenv ("TERM");
1393 /* This has to be the first define_sequence */
1394 /* So, we can assume that the first keys member has ESC */
1395 define_sequences (mc_default_keys);
1397 /* Terminfo on irix does not have some keys */
1398 if (mc_global.tty.xterm_flag
1399 || (term != NULL
1400 && (strncmp (term, "iris-ansi", 9) == 0
1401 || strncmp (term, "xterm", 5) == 0
1402 || strncmp (term, "rxvt", 4) == 0 || strcmp (term, "screen") == 0)))
1403 define_sequences (xterm_key_defines);
1405 /* load some additional keys (e.g. direct Alt-? support) */
1406 load_xtra_key_defines ();
1408 #ifdef __QNX__
1409 if ((term != NULL) && (strncmp (term, "qnx", 3) == 0))
1411 /* Modify the default value of use_8th_bit_as_meta: we would
1412 * like to provide a working mc for a newbie who knows nothing
1413 * about [Options|Display bits|Full 8 bits input]...
1415 * Don't use 'meta'-bit, when we are dealing with a
1416 * 'qnx*'-type terminal: clear the default value!
1417 * These terminal types use 0xFF as an escape character,
1418 * so use_8th_bit_as_meta==1 must not be enabled!
1420 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1421 * is not used now (doesn't even depend on use_8th_bit_as_meta
1422 * as in mc-3.1.2)...GREAT!...no additional code is required!]
1424 use_8th_bit_as_meta = 0;
1426 #endif /* __QNX__ */
1428 init_key_x11 ();
1430 /* Load the qansi-m key definitions
1431 if we are running under the qansi-m terminal */
1432 if (term != NULL && (strncmp (term, "qansi-m", 7) == 0))
1433 define_sequences (qansi_key_defines);
1436 /* --------------------------------------------------------------------------------------------- */
1438 * This has to be called after SLang_init_tty/slint_init
1441 void
1442 init_key_input_fd (void)
1444 #ifdef HAVE_SLANG
1445 input_fd = SLang_TT_Read_FD;
1446 #endif
1449 /* --------------------------------------------------------------------------------------------- */
1451 void
1452 done_key (void)
1454 k_dispose (keys);
1455 s_dispose (select_list);
1457 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1458 if (x11_display)
1459 mc_XCloseDisplay (x11_display);
1460 #endif
1463 /* --------------------------------------------------------------------------------------------- */
1465 void
1466 add_select_channel (int fd, select_fn callback, void *info)
1468 SelectList *new;
1470 new = g_new (SelectList, 1);
1471 new->fd = fd;
1472 new->callback = callback;
1473 new->info = info;
1474 new->next = select_list;
1475 select_list = new;
1478 /* --------------------------------------------------------------------------------------------- */
1480 void
1481 delete_select_channel (int fd)
1483 SelectList *p = select_list;
1484 SelectList *p_prev = NULL;
1485 SelectList *p_next;
1487 while (p != NULL)
1488 if (p->fd == fd)
1490 p_next = p->next;
1492 if (p_prev != NULL)
1493 p_prev->next = p_next;
1494 else
1495 select_list = p_next;
1497 g_free (p);
1498 p = p_next;
1500 else
1502 p_prev = p;
1503 p = p->next;
1507 /* --------------------------------------------------------------------------------------------- */
1509 void
1510 channels_up (void)
1512 if (disabled_channels == 0)
1513 fputs ("Error: channels_up called with disabled_channels = 0\n", stderr);
1514 disabled_channels--;
1517 /* --------------------------------------------------------------------------------------------- */
1519 void
1520 channels_down (void)
1522 disabled_channels++;
1525 /* --------------------------------------------------------------------------------------------- */
1527 * Return the code associated with the symbolic name keyname
1530 long
1531 lookup_key (const char *name, char **label)
1533 char **lc_keys, **p;
1534 int k = -1;
1535 int key = 0;
1536 int lc_index = -1;
1538 int use_meta = -1;
1539 int use_ctrl = -1;
1540 int use_shift = -1;
1542 if (name == NULL)
1543 return 0;
1545 name = g_strstrip (g_strdup (name));
1546 p = lc_keys = g_strsplit_set (name, "-+ ", -1);
1547 g_free ((char *) name);
1549 while ((p != NULL) && (*p != NULL))
1551 if ((*p)[0] != '\0')
1553 int idx;
1555 key = lookup_keyname (g_strstrip (*p), &idx);
1557 if (key == KEY_M_ALT)
1558 use_meta = idx;
1559 else if (key == KEY_M_CTRL)
1560 use_ctrl = idx;
1561 else if (key == KEY_M_SHIFT)
1562 use_shift = idx;
1563 else
1565 k = key;
1566 lc_index = idx;
1567 break;
1571 p++;
1574 g_strfreev (lc_keys);
1576 /* output */
1577 if (k <= 0)
1578 return 0;
1581 if (label != NULL)
1583 GString *s;
1585 s = g_string_new ("");
1587 if (use_meta != -1)
1589 g_string_append (s, key_conv_tab_sorted[use_meta]->shortcut);
1590 g_string_append_c (s, '-');
1592 if (use_ctrl != -1)
1594 g_string_append (s, key_conv_tab_sorted[use_ctrl]->shortcut);
1595 g_string_append_c (s, '-');
1597 if (use_shift != -1)
1599 if (k < 127)
1600 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1601 else
1603 g_string_append (s, key_conv_tab_sorted[use_shift]->shortcut);
1604 g_string_append_c (s, '-');
1605 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1608 else if (k < 128)
1610 if ((k >= 'A') || (lc_index < 0) || (key_conv_tab_sorted[lc_index]->shortcut == NULL))
1611 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) k));
1612 else
1613 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1615 else if ((lc_index != -1) && (key_conv_tab_sorted[lc_index]->shortcut != NULL))
1616 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1617 else
1618 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) key));
1620 *label = g_string_free (s, FALSE);
1623 if (use_shift != -1)
1625 if (k < 127 && k > 31)
1626 k = g_ascii_toupper ((gchar) k);
1627 else
1628 k |= KEY_M_SHIFT;
1631 if (use_ctrl != -1)
1633 if (k < 256)
1634 k = XCTRL (k);
1635 else
1636 k |= KEY_M_CTRL;
1639 if (use_meta != -1)
1640 k = ALT (k);
1642 return (long) k;
1645 /* --------------------------------------------------------------------------------------------- */
1647 char *
1648 lookup_key_by_code (const int keycode)
1650 /* code without modifier */
1651 unsigned int k = keycode & ~KEY_M_MASK;
1652 /* modifier */
1653 unsigned int mod = keycode & KEY_M_MASK;
1655 int use_meta = -1;
1656 int use_ctrl = -1;
1657 int use_shift = -1;
1658 int key_idx = -1;
1660 GString *s;
1661 int idx;
1663 s = g_string_sized_new (8);
1665 if (lookup_keycode (k, &key_idx) || (k > 0 && k < 256))
1667 if (mod & KEY_M_ALT)
1669 if (lookup_keycode (KEY_M_ALT, &idx))
1671 use_meta = idx;
1672 g_string_append (s, key_conv_tab_sorted[use_meta]->name);
1673 g_string_append_c (s, '-');
1676 if (mod & KEY_M_CTRL)
1678 /* non printeble chars like a CTRL-[A..Z] */
1679 if (k < 32)
1680 k += 64;
1682 if (lookup_keycode (KEY_M_CTRL, &idx))
1684 use_ctrl = idx;
1685 g_string_append (s, key_conv_tab_sorted[use_ctrl]->name);
1686 g_string_append_c (s, '-');
1689 if (mod & KEY_M_SHIFT)
1691 if (lookup_keycode (KEY_M_ALT, &idx))
1693 use_shift = idx;
1694 if (k < 127)
1695 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1696 else
1698 g_string_append (s, key_conv_tab_sorted[use_shift]->name);
1699 g_string_append_c (s, '-');
1700 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1704 else if (k < 128)
1706 if ((k >= 'A') || (key_idx < 0) || (key_conv_tab_sorted[key_idx]->name == NULL))
1707 g_string_append_c (s, (gchar) k);
1708 else
1709 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1711 else if ((key_idx != -1) && (key_conv_tab_sorted[key_idx]->name != NULL))
1712 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1713 else
1714 g_string_append_c (s, (gchar) keycode);
1717 return g_string_free (s, s->len == 0);
1720 /* --------------------------------------------------------------------------------------------- */
1722 * Return TRUE on success, FALSE on error.
1723 * An error happens if SEQ is a beginning of an existing longer sequence.
1726 gboolean
1727 define_sequence (int code, const char *seq, int action)
1729 key_def *base;
1731 if (strlen (seq) > SEQ_BUFFER_LEN - 1)
1732 return FALSE;
1734 for (base = keys; (base != NULL) && (*seq != '\0');)
1735 if (*seq == base->ch)
1737 if (base->child == 0)
1739 if (*(seq + 1) != '\0')
1740 base->child = create_sequence (seq + 1, code, action);
1741 else
1743 /* The sequence matches an existing one. */
1744 base->code = code;
1745 base->action = action;
1747 return TRUE;
1750 base = base->child;
1751 seq++;
1753 else
1755 if (base->next)
1756 base = base->next;
1757 else
1759 base->next = create_sequence (seq, code, action);
1760 return TRUE;
1764 if (*seq == '\0')
1766 /* Attempt to redefine a sequence with a shorter sequence. */
1767 return FALSE;
1770 keys = create_sequence (seq, code, action);
1771 return TRUE;
1774 /* --------------------------------------------------------------------------------------------- */
1776 * Check if we are idle, i.e. there are no pending keyboard or mouse
1777 * events. Return 1 is idle, 0 is there are pending events.
1779 gboolean
1780 is_idle (void)
1782 int maxfdp;
1783 fd_set select_set;
1784 struct timeval time_out;
1786 FD_ZERO (&select_set);
1787 FD_SET (input_fd, &select_set);
1788 maxfdp = input_fd;
1789 #ifdef HAVE_LIBGPM
1790 if (mouse_enabled && (use_mouse_p == MOUSE_GPM) && (gpm_fd > 0))
1792 FD_SET (gpm_fd, &select_set);
1793 maxfdp = max (maxfdp, gpm_fd);
1795 #endif
1796 time_out.tv_sec = 0;
1797 time_out.tv_usec = 0;
1798 return (select (maxfdp + 1, &select_set, 0, 0, &time_out) <= 0);
1801 /* --------------------------------------------------------------------------------------------- */
1804 get_key_code (int no_delay)
1806 int c;
1807 static key_def *this = NULL, *parent;
1808 static struct timeval esctime = { -1, -1 };
1809 static int lastnodelay = -1;
1811 if (no_delay != lastnodelay)
1813 this = NULL;
1814 lastnodelay = no_delay;
1817 pend_send:
1818 if (pending_keys != NULL)
1820 int m;
1822 m = parse_extended_mouse_coordinates ();
1823 if (m == 1)
1825 pending_keys = seq_append = NULL;
1826 this = NULL;
1827 return MCKEY_EXTENDED_MOUSE;
1829 if (m == -1)
1831 int d = *pending_keys++;
1832 check_pend:
1833 if (*pending_keys == 0)
1835 pending_keys = NULL;
1836 seq_append = NULL;
1838 if ((d == ESC_CHAR) && (pending_keys != NULL))
1840 d = ALT (*pending_keys++);
1841 goto check_pend;
1843 if ((d > 127 && d < 256) && use_8th_bit_as_meta)
1844 d = ALT (d & 0x7f);
1845 this = NULL;
1846 return correct_key_code (d);
1848 /* else if (m == 0), just let it continue */
1851 nodelay_try_again:
1852 if (no_delay)
1853 tty_nodelay (TRUE);
1855 c = tty_lowlevel_getch ();
1856 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1857 if (c == KEY_RESIZE)
1858 goto nodelay_try_again;
1859 #endif
1860 if (no_delay)
1862 tty_nodelay (FALSE);
1863 if (c == -1)
1865 if (this != NULL && parent != NULL && parent->action == MCKEY_ESCAPE && old_esc_mode)
1867 struct timeval current, time_out;
1869 if (esctime.tv_sec == -1)
1870 return -1;
1871 GET_TIME (current);
1872 time_out.tv_sec = old_esc_mode_timeout / 1000000 + esctime.tv_sec;
1873 time_out.tv_usec = old_esc_mode_timeout % 1000000 + esctime.tv_usec;
1874 if (time_out.tv_usec > 1000000)
1876 time_out.tv_usec -= 1000000;
1877 time_out.tv_sec++;
1879 if (current.tv_sec < time_out.tv_sec)
1880 return -1;
1881 if (current.tv_sec == time_out.tv_sec && current.tv_usec < time_out.tv_usec)
1882 return -1;
1883 this = NULL;
1884 pending_keys = seq_append = NULL;
1885 return ESC_CHAR;
1887 return -1;
1890 else if (c == -1)
1892 /* Maybe we got an incomplete match.
1893 This we do only in delay mode, since otherwise
1894 tty_lowlevel_getch can return -1 at any time. */
1895 if (seq_append != NULL)
1897 pending_keys = seq_buffer;
1898 goto pend_send;
1900 this = NULL;
1901 return -1;
1904 /* Search the key on the root */
1905 if (!no_delay || this == NULL)
1907 this = keys;
1908 parent = NULL;
1910 if ((c > 127 && c < 256) && use_8th_bit_as_meta)
1912 c &= 0x7f;
1914 /* The first sequence defined starts with esc */
1915 parent = keys;
1916 this = keys->child;
1919 while (this != NULL)
1921 if (c == this->ch)
1923 if (this->child)
1925 if (!push_char (c))
1927 pending_keys = seq_buffer;
1928 goto pend_send;
1930 parent = this;
1931 this = this->child;
1932 if (parent->action == MCKEY_ESCAPE && old_esc_mode)
1934 if (no_delay)
1936 GET_TIME (esctime);
1937 if (this == NULL)
1939 /* Shouldn't happen */
1940 fputs ("Internal error\n", stderr);
1941 exit (EXIT_FAILURE);
1943 goto nodelay_try_again;
1945 esctime.tv_sec = -1;
1946 c = xgetch_second ();
1947 if (c == -1)
1949 pending_keys = seq_append = NULL;
1950 this = NULL;
1951 return ESC_CHAR;
1954 else
1956 if (no_delay)
1957 goto nodelay_try_again;
1958 c = tty_lowlevel_getch ();
1961 else
1963 /* We got a complete match, return and reset search */
1964 int code;
1966 pending_keys = seq_append = NULL;
1967 code = this->code;
1968 this = NULL;
1969 return correct_key_code (code);
1972 else
1974 if (this->next != NULL)
1975 this = this->next;
1976 else
1978 if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
1980 /* Convert escape-digits to F-keys */
1981 if (g_ascii_isdigit (c))
1982 c = KEY_F (c - '0');
1983 else if (c == ' ')
1984 c = ESC_CHAR;
1985 else
1986 c = ALT (c);
1988 pending_keys = seq_append = NULL;
1989 this = NULL;
1990 return correct_key_code (c);
1992 /* Did not find a match or {c} was changed in the if above,
1993 so we have to return everything we had skipped
1995 push_char (c);
1996 pending_keys = seq_buffer;
1997 goto pend_send;
2001 this = NULL;
2002 return correct_key_code (c);
2005 /* --------------------------------------------------------------------------------------------- */
2006 /* Returns a character read from stdin with appropriate interpretation */
2007 /* Also takes care of generated mouse events */
2008 /* Returns EV_MOUSE if it is a mouse event */
2009 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
2012 tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block)
2014 int c;
2015 static int flag = 0; /* Return value from select */
2016 #ifdef HAVE_LIBGPM
2017 static struct Gpm_Event ev; /* Mouse event */
2018 #endif
2019 struct timeval time_out;
2020 struct timeval *time_addr = NULL;
2021 static int dirty = 3;
2023 if ((dirty == 3) || is_idle ())
2025 mc_refresh ();
2026 dirty = 1;
2028 else
2029 dirty++;
2031 vfs_timeout_handler ();
2033 /* Ok, we use (event->x < 0) to signal that the event does not contain
2034 a suitable position for the mouse, so we can't use show_mouse_pointer
2035 on it.
2037 if (event->x > 0)
2039 show_mouse_pointer (event->x, event->y);
2040 if (!redo_event)
2041 event->x = -1;
2044 /* Repeat if using mouse */
2045 while (pending_keys == NULL)
2047 int maxfdp;
2048 fd_set select_set;
2050 FD_ZERO (&select_set);
2051 FD_SET (input_fd, &select_set);
2052 maxfdp = max (add_selects (&select_set), input_fd);
2054 #ifdef HAVE_LIBGPM
2055 if (mouse_enabled && (use_mouse_p == MOUSE_GPM))
2057 if (gpm_fd < 0)
2059 /* Connection to gpm broken, possibly gpm has died */
2060 mouse_enabled = FALSE;
2061 use_mouse_p = MOUSE_NONE;
2062 break;
2065 FD_SET (gpm_fd, &select_set);
2066 maxfdp = max (maxfdp, gpm_fd);
2068 #endif
2070 if (redo_event)
2072 time_out.tv_usec = mou_auto_repeat * 1000;
2073 time_out.tv_sec = 0;
2075 time_addr = &time_out;
2077 else
2079 int seconds;
2081 seconds = vfs_timeouts ();
2082 time_addr = NULL;
2084 if (seconds != 0)
2086 /* the timeout could be improved and actually be
2087 * the number of seconds until the next vfs entry
2088 * timeouts in the stamp list.
2091 time_out.tv_sec = seconds;
2092 time_out.tv_usec = 0;
2093 time_addr = &time_out;
2097 if (!block || mc_global.tty.winch_flag)
2099 time_addr = &time_out;
2100 time_out.tv_sec = 0;
2101 time_out.tv_usec = 0;
2104 tty_enable_interrupt_key ();
2105 flag = select (maxfdp + 1, &select_set, NULL, NULL, time_addr);
2106 tty_disable_interrupt_key ();
2108 /* select timed out: it could be for any of the following reasons:
2109 * redo_event -> it was because of the MOU_REPEAT handler
2110 * !block -> we did not block in the select call
2111 * else -> 10 second timeout to check the vfs status.
2113 if (flag == 0)
2115 if (redo_event)
2116 return EV_MOUSE;
2117 if (!block || mc_global.tty.winch_flag)
2118 return EV_NONE;
2119 vfs_timeout_handler ();
2121 if (flag == -1 && errno == EINTR)
2122 return EV_NONE;
2124 check_selects (&select_set);
2126 if (FD_ISSET (input_fd, &select_set))
2127 break;
2128 #ifdef HAVE_LIBGPM
2129 if (mouse_enabled && use_mouse_p == MOUSE_GPM
2130 && gpm_fd > 0 && FD_ISSET (gpm_fd, &select_set))
2132 Gpm_GetEvent (&ev);
2133 Gpm_FitEvent (&ev);
2134 *event = ev;
2135 return EV_MOUSE;
2137 #endif /* !HAVE_LIBGPM */
2140 #ifndef HAVE_SLANG
2141 flag = is_wintouched (stdscr);
2142 untouchwin (stdscr);
2143 #endif /* !HAVE_SLANG */
2144 c = block ? getch_with_delay () : get_key_code (1);
2146 #ifndef HAVE_SLANG
2147 if (flag > 0)
2148 tty_touch_screen ();
2149 #endif /* !HAVE_SLANG */
2151 if (mouse_enabled && (c == MCKEY_MOUSE
2152 #ifdef KEY_MOUSE
2153 || c == KEY_MOUSE
2154 #endif /* KEY_MOUSE */
2155 || c == MCKEY_EXTENDED_MOUSE))
2157 /* Mouse event */
2158 /* In case of extended coordinates, mouse_btn, mouse_x and mouse_y are already filled in. */
2159 if (c != MCKEY_EXTENDED_MOUSE)
2161 /* Variable btn has following meaning: */
2162 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
2163 mouse_btn = tty_lowlevel_getch () - 32;
2164 /* Coordinates are 33-based */
2165 /* Transform them to 1-based */
2166 mouse_x = tty_lowlevel_getch () - 32;
2167 mouse_y = tty_lowlevel_getch () - 32;
2169 xmouse_get_event (event);
2170 return (event->type != 0) ? EV_MOUSE : EV_NONE;
2173 return c;
2176 /* --------------------------------------------------------------------------------------------- */
2177 /* Returns a key press, mouse events are discarded */
2180 tty_getch (void)
2182 Gpm_Event ev;
2183 int key;
2185 ev.x = -1;
2186 while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE);
2187 return key;
2190 /* --------------------------------------------------------------------------------------------- */
2192 char *
2193 learn_key (void)
2195 /* LEARN_TIMEOUT in usec */
2196 #define LEARN_TIMEOUT 200000
2198 fd_set Read_FD_Set;
2199 struct timeval endtime;
2200 struct timeval time_out;
2201 int c;
2202 char buffer[256];
2203 char *p = buffer;
2205 tty_keypad (FALSE); /* disable intepreting keys by ncurses */
2206 c = tty_lowlevel_getch ();
2207 while (c == -1)
2208 c = tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
2209 learn_store_key (buffer, &p, c);
2210 GET_TIME (endtime);
2211 endtime.tv_usec += LEARN_TIMEOUT;
2212 if (endtime.tv_usec > 1000000)
2214 endtime.tv_usec -= 1000000;
2215 endtime.tv_sec++;
2217 tty_nodelay (TRUE);
2218 for (;;)
2220 while ((c = tty_lowlevel_getch ()) == -1)
2222 GET_TIME (time_out);
2223 time_out.tv_usec = endtime.tv_usec - time_out.tv_usec;
2224 if (time_out.tv_usec < 0)
2225 time_out.tv_sec++;
2226 time_out.tv_sec = endtime.tv_sec - time_out.tv_sec;
2227 if (time_out.tv_sec >= 0 && time_out.tv_usec > 0)
2229 FD_ZERO (&Read_FD_Set);
2230 FD_SET (input_fd, &Read_FD_Set);
2231 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
2233 else
2234 break;
2236 if (c == -1)
2237 break;
2238 learn_store_key (buffer, &p, c);
2240 tty_keypad (TRUE);
2241 tty_nodelay (FALSE);
2242 *p = '\0';
2243 return g_strdup (buffer);
2244 #undef LEARN_TIMEOUT
2247 /* --------------------------------------------------------------------------------------------- */
2248 /* xterm and linux console only: set keypad to numeric or application
2249 mode. Only in application keypad mode it's possible to distinguish
2250 the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2252 void
2253 numeric_keypad_mode (void)
2255 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2257 fputs (ESC_STR ">", stdout);
2258 fflush (stdout);
2262 /* --------------------------------------------------------------------------------------------- */
2264 void
2265 application_keypad_mode (void)
2267 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2269 fputs (ESC_STR "=", stdout);
2270 fflush (stdout);
2274 /* --------------------------------------------------------------------------------------------- */