Tweak EN and RU man pages.
[midnight-commander.git] / lib / tty / key.c
blob13952169fe0b9c9486646db10ec9941426cae80b
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_BTAB, "backtab", N_("Back Tabulation S-tab"), "Shift-Tab"},
129 {KEY_KP_ADD, "kpplus", N_("+ on keypad"), "+"},
130 {KEY_KP_SUBTRACT, "kpminus", N_("- on keypad"), "-"},
131 {(int) '/', "kpslash", N_("Slash on keypad"), "/"},
132 {KEY_KP_MULTIPLY, "kpasterisk", N_("* on keypad"), "*"},
134 /* From here on, these won't be shown in Learn keys (no space) */
135 {ESC_CHAR, "escape", N_("Escape key"), "Esc"},
136 {KEY_LEFT, "kpleft", N_("Left arrow keypad"), "Left"},
137 {KEY_RIGHT, "kpright", N_("Right arrow keypad"), "Right"},
138 {KEY_UP, "kpup", N_("Up arrow keypad"), "Up"},
139 {KEY_DOWN, "kpdown", N_("Down arrow keypad"), "Down"},
140 {KEY_HOME, "kphome", N_("Home on keypad"), "Home"},
141 {KEY_END, "kpend", N_("End on keypad"), "End"},
142 {KEY_NPAGE, "kpnpage", N_("Page Down keypad"), "PgDn"},
143 {KEY_PPAGE, "kpppage", N_("Page Up keypad"), "PgUp"},
144 {KEY_IC, "kpinsert", N_("Insert on keypad"), "Ins"},
145 {KEY_DC, "kpdelete", N_("Delete on keypad"), "Del"},
146 {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
147 {KEY_F (21), "f21", N_("Function key 21"), "F21"},
148 {KEY_F (22), "f22", N_("Function key 22"), "F22"},
149 {KEY_F (23), "f23", N_("Function key 23"), "F23"},
150 {KEY_F (24), "f24", N_("Function key 24"), "F24"},
151 {KEY_A1, "a1", N_("A1 key"), "A1"},
152 {KEY_C1, "c1", N_("C1 key"), "C1"},
154 /* Alternative label */
155 {ESC_CHAR, "esc", N_("Escape key"), "Esc"},
156 {KEY_BACKSPACE, "bs", N_("Backspace key"), "Bakspace"},
157 {KEY_IC, "ins", N_("Insert key"), "Ins"},
158 {KEY_DC, "del", N_("Delete key"), "Del"},
159 {(int) '+', "plus", N_("Plus"), "+"},
160 {(int) '-', "minus", N_("Minus"), "-"},
161 {(int) '*', "asterisk", N_("Asterisk"), "*"},
162 {(int) '.', "dot", N_("Dot"), "."},
163 {(int) '<', "lt", N_("Less than"), "<"},
164 {(int) '>', "gt", N_("Great than"), ">"},
165 {(int) '=', "equal", N_("Equal"), "="},
166 {(int) ',', "comma", N_("Comma"), ","},
167 {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
168 {(int) ':', "colon", N_("Colon"), ":"},
169 {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
170 {(int) '?', "question", N_("Question mark"), "?"},
171 {(int) '&', "ampersand", N_("Ampersand"), "&"},
172 {(int) '$', "dollar", N_("Dollar sign"), "$"},
173 {(int) '"', "quota", N_("Quotation mark"), "\""},
174 {(int) '%', "percent", N_("Percent sign"), "%"},
175 {(int) '^', "caret", N_("Caret"), "^"},
176 {(int) '~', "tilda", N_("Tilda"), "~"},
177 {(int) '`', "prime", N_("Prime"), "`"},
178 {(int) '_', "underline", N_("Underline"), "_"},
179 {(int) '_', "understrike", N_("Understrike"), "_"},
180 {(int) '|', "pipe", N_("Pipe"), "|"},
181 {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
182 {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
183 {(int) '[', "lbracket", N_("Left bracket"), "["},
184 {(int) ']', "rbracket", N_("Right bracket"), "]"},
185 {(int) '{', "lbrace", N_("Left brace"), "{"},
186 {(int) '}', "rbrace", N_("Right brace"), "}"},
187 {(int) '\n', "enter", N_("Enter"), "Enter"},
188 {(int) '\t', "tab", N_("Tab key"), "Tab"},
189 {(int) ' ', "space", N_("Space key"), "Space"},
190 {(int) '/', "slash", N_("Slash key"), "/"},
191 {(int) '\\', "backslash", N_("Backslash key"), "\\"},
192 {(int) '#', "number", N_("Number sign #"), "#"},
193 {(int) '#', "hash", N_("Number sign #"), "#"},
194 /* TRANSLATORS: Please translate as in "at sign" (@). */
195 {(int) '@', "at", N_("At sign"), "@"},
197 /* meta keys */
198 {KEY_M_CTRL, "control", N_("Ctrl"), "C"},
199 {KEY_M_CTRL, "ctrl", N_("Ctrl"), "C"},
200 {KEY_M_ALT, "meta", N_("Alt"), "M"},
201 {KEY_M_ALT, "alt", N_("Alt"), "M"},
202 {KEY_M_ALT, "ralt", N_("Alt"), "M"},
203 {KEY_M_SHIFT, "shift", N_("Shift"), "S"},
205 {0, NULL, NULL, NULL}
208 /*** file scope macro definitions ****************************************************************/
210 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *) NULL))
211 #define DIF_TIME(t1, t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000)
213 /* The maximum sequence length (32 + null terminator) */
214 #define SEQ_BUFFER_LEN 33
216 /*** file scope type declarations ****************************************************************/
218 /* Linux console keyboard modifiers */
219 typedef enum
221 SHIFT_PRESSED = (1 << 0),
222 ALTR_PRESSED = (1 << 1),
223 CONTROL_PRESSED = (1 << 2),
224 ALTL_PRESSED = (1 << 3)
225 } mod_pressed_t;
227 typedef struct key_def
229 char ch; /* Holds the matching char code */
230 int code; /* The code returned, valid if child == NULL */
231 struct key_def *next;
232 struct key_def *child; /* sequence continuation */
233 int action; /* optional action to be done. Now used only
234 to mark that we are just after the first
235 Escape */
236 } key_def;
238 typedef struct
240 int code;
241 const char *seq;
242 int action;
243 } key_define_t;
245 /* File descriptor monitoring add/remove routines */
246 typedef struct SelectList
248 int fd;
249 select_fn callback;
250 void *info;
251 struct SelectList *next;
252 } SelectList;
254 typedef enum KeySortType
256 KEY_NOSORT = 0,
257 KEY_SORTBYNAME,
258 KEY_SORTBYCODE
259 } KeySortType;
261 #ifdef __QNXNTO__
262 typedef int (*ph_dv_f) (void *, void *);
263 typedef int (*ph_ov_f) (void *);
264 typedef int (*ph_pqc_f) (unsigned short, PhCursorInfo_t *);
265 #endif
267 /*** file scope variables ************************************************************************/
269 static key_define_t mc_default_keys[] = {
270 {ESC_CHAR, ESC_STR, MCKEY_ESCAPE},
271 {ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION},
272 {0, NULL, MCKEY_NOACTION},
275 /* Broken terminfo and termcap databases on xterminals */
276 static key_define_t xterm_key_defines[] = {
277 {KEY_F (1), ESC_STR "OP", MCKEY_NOACTION},
278 {KEY_F (2), ESC_STR "OQ", MCKEY_NOACTION},
279 {KEY_F (3), ESC_STR "OR", MCKEY_NOACTION},
280 {KEY_F (4), ESC_STR "OS", MCKEY_NOACTION},
281 {KEY_F (1), ESC_STR "[11~", MCKEY_NOACTION},
282 {KEY_F (2), ESC_STR "[12~", MCKEY_NOACTION},
283 {KEY_F (3), ESC_STR "[13~", MCKEY_NOACTION},
284 {KEY_F (4), ESC_STR "[14~", MCKEY_NOACTION},
285 {KEY_F (5), ESC_STR "[15~", MCKEY_NOACTION},
286 {KEY_F (6), ESC_STR "[17~", MCKEY_NOACTION},
287 {KEY_F (7), ESC_STR "[18~", MCKEY_NOACTION},
288 {KEY_F (8), ESC_STR "[19~", MCKEY_NOACTION},
289 {KEY_F (9), ESC_STR "[20~", MCKEY_NOACTION},
290 {KEY_F (10), ESC_STR "[21~", MCKEY_NOACTION},
292 /* old xterm Shift-arrows */
293 {KEY_M_SHIFT | KEY_UP, ESC_STR "O2A", MCKEY_NOACTION},
294 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "O2B", MCKEY_NOACTION},
295 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "O2C", MCKEY_NOACTION},
296 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "O2D", MCKEY_NOACTION},
298 /* new xterm Shift-arrows */
299 {KEY_M_SHIFT | KEY_UP, ESC_STR "[1;2A", MCKEY_NOACTION},
300 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[1;2B", MCKEY_NOACTION},
301 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[1;2C", MCKEY_NOACTION},
302 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[1;2D", MCKEY_NOACTION},
304 /* more xterm keys with modifiers */
305 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5;5~", MCKEY_NOACTION},
306 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6;5~", MCKEY_NOACTION},
307 {KEY_M_CTRL | KEY_IC, ESC_STR "[2;5~", MCKEY_NOACTION},
308 {KEY_M_CTRL | KEY_DC, ESC_STR "[3;5~", MCKEY_NOACTION},
309 {KEY_M_CTRL | KEY_HOME, ESC_STR "[1;5H", MCKEY_NOACTION},
310 {KEY_M_CTRL | KEY_END, ESC_STR "[1;5F", MCKEY_NOACTION},
311 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[1;2H", MCKEY_NOACTION},
312 {KEY_M_SHIFT | KEY_END, ESC_STR "[1;2F", MCKEY_NOACTION},
313 {KEY_M_CTRL | KEY_UP, ESC_STR "[1;5A", MCKEY_NOACTION},
314 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;5B", MCKEY_NOACTION},
315 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;5C", MCKEY_NOACTION},
316 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;5D", MCKEY_NOACTION},
317 {KEY_M_SHIFT | KEY_IC, ESC_STR "[2;2~", MCKEY_NOACTION},
318 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3;2~", MCKEY_NOACTION},
319 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[1;6A", MCKEY_NOACTION},
320 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;6B", MCKEY_NOACTION},
321 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;6C", MCKEY_NOACTION},
322 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;6D", MCKEY_NOACTION},
324 /* putty */
325 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[[1;6A", MCKEY_NOACTION},
326 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[[1;6B", MCKEY_NOACTION},
327 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[[1;6C", MCKEY_NOACTION},
328 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[[1;6D", MCKEY_NOACTION},
330 /* putty alt-arrow keys */
331 /* removed as source esc esc esc trouble */
333 { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
334 { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
335 { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
336 { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
337 { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
338 { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
339 { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
340 { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
342 { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
343 { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
344 { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
345 { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
347 { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
348 { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
349 { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
350 { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
352 /* xterm alt-arrow keys */
353 {KEY_M_ALT | KEY_UP, ESC_STR "[1;3A", MCKEY_NOACTION},
354 {KEY_M_ALT | KEY_DOWN, ESC_STR "[1;3B", MCKEY_NOACTION},
355 {KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;3C", MCKEY_NOACTION},
356 {KEY_M_ALT | KEY_LEFT, ESC_STR "[1;3D", MCKEY_NOACTION},
357 {KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;3~", MCKEY_NOACTION},
358 {KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;3~", MCKEY_NOACTION},
359 {KEY_M_ALT | KEY_HOME, ESC_STR "[1~", MCKEY_NOACTION},
360 {KEY_M_ALT | KEY_END, ESC_STR "[4~", MCKEY_NOACTION},
361 {KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR "[1;7A", MCKEY_NOACTION},
362 {KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR "[1;7B", MCKEY_NOACTION},
363 {KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;7C", MCKEY_NOACTION},
364 {KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR "[1;7D", MCKEY_NOACTION},
365 {KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;7~", MCKEY_NOACTION},
366 {KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;7~", MCKEY_NOACTION},
367 {KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR "OH", MCKEY_NOACTION},
368 {KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR "OF", MCKEY_NOACTION},
370 /* rxvt keys with modifiers */
371 {KEY_M_SHIFT | KEY_UP, ESC_STR "[a", MCKEY_NOACTION},
372 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION},
373 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION},
374 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION},
375 {KEY_M_CTRL | KEY_UP, ESC_STR "Oa", MCKEY_NOACTION},
376 {KEY_M_CTRL | KEY_DOWN, ESC_STR "Ob", MCKEY_NOACTION},
377 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "Oc", MCKEY_NOACTION},
378 {KEY_M_CTRL | KEY_LEFT, ESC_STR "Od", MCKEY_NOACTION},
379 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5^", MCKEY_NOACTION},
380 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6^", MCKEY_NOACTION},
381 {KEY_M_CTRL | KEY_HOME, ESC_STR "[7^", MCKEY_NOACTION},
382 {KEY_M_CTRL | KEY_END, ESC_STR "[8^", MCKEY_NOACTION},
383 {KEY_M_SHIFT | KEY_HOME, ESC_STR "[7$", MCKEY_NOACTION},
384 {KEY_M_SHIFT | KEY_END, ESC_STR "[8$", MCKEY_NOACTION},
385 {KEY_M_CTRL | KEY_IC, ESC_STR "[2^", MCKEY_NOACTION},
386 {KEY_M_CTRL | KEY_DC, ESC_STR "[3^", MCKEY_NOACTION},
387 {KEY_M_SHIFT | KEY_DC, ESC_STR "[3$", MCKEY_NOACTION},
389 /* konsole keys with modifiers */
390 {KEY_M_SHIFT | KEY_HOME, ESC_STR "O2H", MCKEY_NOACTION},
391 {KEY_M_SHIFT | KEY_END, ESC_STR "O2F", MCKEY_NOACTION},
393 /* gnome-terminal */
394 {KEY_M_SHIFT | KEY_UP, ESC_STR "[2A", MCKEY_NOACTION},
395 {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[2B", MCKEY_NOACTION},
396 {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[2C", MCKEY_NOACTION},
397 {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[2D", MCKEY_NOACTION},
398 {KEY_M_CTRL | KEY_UP, ESC_STR "[5A", MCKEY_NOACTION},
399 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[5B", MCKEY_NOACTION},
400 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[5C", MCKEY_NOACTION},
401 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[5D", MCKEY_NOACTION},
402 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[6A", MCKEY_NOACTION},
403 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[6B", MCKEY_NOACTION},
404 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[6C", MCKEY_NOACTION},
405 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[6D", MCKEY_NOACTION},
407 /* gnome-terminal - application mode */
408 {KEY_M_CTRL | KEY_UP, ESC_STR "O5A", MCKEY_NOACTION},
409 {KEY_M_CTRL | KEY_DOWN, ESC_STR "O5B", MCKEY_NOACTION},
410 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "O5C", MCKEY_NOACTION},
411 {KEY_M_CTRL | KEY_LEFT, ESC_STR "O5D", MCKEY_NOACTION},
412 {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "O6A", MCKEY_NOACTION},
413 {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "O6B", MCKEY_NOACTION},
414 {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "O6C", MCKEY_NOACTION},
415 {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "O6D", MCKEY_NOACTION},
417 /* iTerm */
418 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[5;2~", MCKEY_NOACTION},
419 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[6;2~", MCKEY_NOACTION},
421 /* putty */
422 {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[[5;53~", MCKEY_NOACTION},
423 {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[[6;53~", MCKEY_NOACTION},
425 /* keypad keys */
426 {KEY_IC, ESC_STR "Op", MCKEY_NOACTION},
427 {KEY_DC, ESC_STR "On", MCKEY_NOACTION},
428 {'/', ESC_STR "Oo", MCKEY_NOACTION},
429 {'\n', ESC_STR "OM", MCKEY_NOACTION},
431 {0, NULL, MCKEY_NOACTION},
434 /* qansi-m terminals have a much more key combinatios,
435 which are undefined in termcap/terminfo */
436 static key_define_t qansi_key_defines[] = {
437 /* qansi-m terminal */
438 {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[u", MCKEY_NOACTION}, /* Ctrl-PgDown */
439 {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[v", MCKEY_NOACTION}, /* Ctrl-PgUp */
440 {KEY_M_CTRL | KEY_HOME, ESC_STR "[h", MCKEY_NOACTION}, /* Ctrl-Home */
441 {KEY_M_CTRL | KEY_END, ESC_STR "[y", MCKEY_NOACTION}, /* Ctrl-End */
442 {KEY_M_CTRL | KEY_IC, ESC_STR "[`", MCKEY_NOACTION}, /* Ctrl-Insert */
443 {KEY_M_CTRL | KEY_DC, ESC_STR "[p", MCKEY_NOACTION}, /* Ctrl-Delete */
444 {KEY_M_CTRL | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION}, /* Ctrl-Left */
445 {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION}, /* Ctrl-Right */
446 {KEY_M_CTRL | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION}, /* Ctrl-Down */
447 {KEY_M_CTRL | KEY_UP, ESC_STR "[a", MCKEY_NOACTION}, /* Ctrl-Up */
448 {KEY_M_CTRL | KEY_KP_ADD, ESC_STR "[s", MCKEY_NOACTION}, /* Ctrl-Gr-Plus */
449 {KEY_M_CTRL | KEY_KP_SUBTRACT, ESC_STR "[t", MCKEY_NOACTION}, /* Ctrl-Gr-Minus */
450 {KEY_M_CTRL | '\t', ESC_STR "[z", MCKEY_NOACTION}, /* Ctrl-Tab */
451 {KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION}, /* Shift-Tab */
452 {KEY_M_CTRL | KEY_F (1), ESC_STR "[1~", MCKEY_NOACTION}, /* Ctrl-F1 */
453 {KEY_M_CTRL | KEY_F (2), ESC_STR "[2~", MCKEY_NOACTION}, /* Ctrl-F2 */
454 {KEY_M_CTRL | KEY_F (3), ESC_STR "[3~", MCKEY_NOACTION}, /* Ctrl-F3 */
455 {KEY_M_CTRL | KEY_F (4), ESC_STR "[4~", MCKEY_NOACTION}, /* Ctrl-F4 */
456 {KEY_M_CTRL | KEY_F (5), ESC_STR "[5~", MCKEY_NOACTION}, /* Ctrl-F5 */
457 {KEY_M_CTRL | KEY_F (6), ESC_STR "[6~", MCKEY_NOACTION}, /* Ctrl-F6 */
458 {KEY_M_CTRL | KEY_F (7), ESC_STR "[7~", MCKEY_NOACTION}, /* Ctrl-F7 */
459 {KEY_M_CTRL | KEY_F (8), ESC_STR "[8~", MCKEY_NOACTION}, /* Ctrl-F8 */
460 {KEY_M_CTRL | KEY_F (9), ESC_STR "[9~", MCKEY_NOACTION}, /* Ctrl-F9 */
461 {KEY_M_CTRL | KEY_F (10), ESC_STR "[10~", MCKEY_NOACTION}, /* Ctrl-F10 */
462 {KEY_M_CTRL | KEY_F (11), ESC_STR "[11~", MCKEY_NOACTION}, /* Ctrl-F11 */
463 {KEY_M_CTRL | KEY_F (12), ESC_STR "[12~", MCKEY_NOACTION}, /* Ctrl-F12 */
464 {KEY_M_ALT | KEY_F (1), ESC_STR "[17~", MCKEY_NOACTION}, /* Alt-F1 */
465 {KEY_M_ALT | KEY_F (2), ESC_STR "[18~", MCKEY_NOACTION}, /* Alt-F2 */
466 {KEY_M_ALT | KEY_F (3), ESC_STR "[19~", MCKEY_NOACTION}, /* Alt-F3 */
467 {KEY_M_ALT | KEY_F (4), ESC_STR "[20~", MCKEY_NOACTION}, /* Alt-F4 */
468 {KEY_M_ALT | KEY_F (5), ESC_STR "[21~", MCKEY_NOACTION}, /* Alt-F5 */
469 {KEY_M_ALT | KEY_F (6), ESC_STR "[22~", MCKEY_NOACTION}, /* Alt-F6 */
470 {KEY_M_ALT | KEY_F (7), ESC_STR "[23~", MCKEY_NOACTION}, /* Alt-F7 */
471 {KEY_M_ALT | KEY_F (8), ESC_STR "[24~", MCKEY_NOACTION}, /* Alt-F8 */
472 {KEY_M_ALT | KEY_F (9), ESC_STR "[25~", MCKEY_NOACTION}, /* Alt-F9 */
473 {KEY_M_ALT | KEY_F (10), ESC_STR "[26~", MCKEY_NOACTION}, /* Alt-F10 */
474 {KEY_M_ALT | KEY_F (11), ESC_STR "[27~", MCKEY_NOACTION}, /* Alt-F11 */
475 {KEY_M_ALT | KEY_F (12), ESC_STR "[28~", MCKEY_NOACTION}, /* Alt-F12 */
476 {KEY_M_ALT | 'a', ESC_STR "Na", MCKEY_NOACTION}, /* Alt-a */
477 {KEY_M_ALT | 'b', ESC_STR "Nb", MCKEY_NOACTION}, /* Alt-b */
478 {KEY_M_ALT | 'c', ESC_STR "Nc", MCKEY_NOACTION}, /* Alt-c */
479 {KEY_M_ALT | 'd', ESC_STR "Nd", MCKEY_NOACTION}, /* Alt-d */
480 {KEY_M_ALT | 'e', ESC_STR "Ne", MCKEY_NOACTION}, /* Alt-e */
481 {KEY_M_ALT | 'f', ESC_STR "Nf", MCKEY_NOACTION}, /* Alt-f */
482 {KEY_M_ALT | 'g', ESC_STR "Ng", MCKEY_NOACTION}, /* Alt-g */
483 {KEY_M_ALT | 'h', ESC_STR "Nh", MCKEY_NOACTION}, /* Alt-h */
484 {KEY_M_ALT | 'i', ESC_STR "Ni", MCKEY_NOACTION}, /* Alt-i */
485 {KEY_M_ALT | 'j', ESC_STR "Nj", MCKEY_NOACTION}, /* Alt-j */
486 {KEY_M_ALT | 'k', ESC_STR "Nk", MCKEY_NOACTION}, /* Alt-k */
487 {KEY_M_ALT | 'l', ESC_STR "Nl", MCKEY_NOACTION}, /* Alt-l */
488 {KEY_M_ALT | 'm', ESC_STR "Nm", MCKEY_NOACTION}, /* Alt-m */
489 {KEY_M_ALT | 'n', ESC_STR "Nn", MCKEY_NOACTION}, /* Alt-n */
490 {KEY_M_ALT | 'o', ESC_STR "No", MCKEY_NOACTION}, /* Alt-o */
491 {KEY_M_ALT | 'p', ESC_STR "Np", MCKEY_NOACTION}, /* Alt-p */
492 {KEY_M_ALT | 'q', ESC_STR "Nq", MCKEY_NOACTION}, /* Alt-q */
493 {KEY_M_ALT | 'r', ESC_STR "Nr", MCKEY_NOACTION}, /* Alt-r */
494 {KEY_M_ALT | 's', ESC_STR "Ns", MCKEY_NOACTION}, /* Alt-s */
495 {KEY_M_ALT | 't', ESC_STR "Nt", MCKEY_NOACTION}, /* Alt-t */
496 {KEY_M_ALT | 'u', ESC_STR "Nu", MCKEY_NOACTION}, /* Alt-u */
497 {KEY_M_ALT | 'v', ESC_STR "Nv", MCKEY_NOACTION}, /* Alt-v */
498 {KEY_M_ALT | 'w', ESC_STR "Nw", MCKEY_NOACTION}, /* Alt-w */
499 {KEY_M_ALT | 'x', ESC_STR "Nx", MCKEY_NOACTION}, /* Alt-x */
500 {KEY_M_ALT | 'y', ESC_STR "Ny", MCKEY_NOACTION}, /* Alt-y */
501 {KEY_M_ALT | 'z', ESC_STR "Nz", MCKEY_NOACTION}, /* Alt-z */
502 {KEY_KP_SUBTRACT, ESC_STR "[S", MCKEY_NOACTION}, /* Gr-Minus */
503 {KEY_KP_ADD, ESC_STR "[T", MCKEY_NOACTION}, /* Gr-Plus */
504 {0, NULL, MCKEY_NOACTION},
507 /* This holds all the key definitions */
508 static key_def *keys = NULL;
510 static int input_fd;
511 static int disabled_channels = 0; /* Disable channels checking */
513 static SelectList *select_list = NULL;
515 static int seq_buffer[SEQ_BUFFER_LEN];
516 static int *seq_append = NULL;
518 static int *pending_keys = NULL;
520 static int mouse_btn, mouse_x, mouse_y;
522 #ifdef __QNXNTO__
523 ph_dv_f ph_attach;
524 ph_ov_f ph_input_group;
525 ph_pqc_f ph_query_cursor;
526 #endif
528 #ifdef HAVE_TEXTMODE_X11_SUPPORT
529 static Display *x11_display;
530 static Window x11_window;
531 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
533 static KeySortType has_been_sorted = KEY_NOSORT;
535 /* *INDENT-OFF* */
536 static const size_t key_conv_tab_size = G_N_ELEMENTS (key_name_conv_tab) - 1;
537 /* *INDENT-ON* */
539 static const key_code_name_t *key_conv_tab_sorted[G_N_ELEMENTS (key_name_conv_tab) - 1];
541 /*** file scope functions ************************************************************************/
542 /* --------------------------------------------------------------------------------------------- */
544 static int
545 add_selects (fd_set * select_set)
547 int top_fd = 0;
549 if (disabled_channels == 0)
551 SelectList *p;
553 for (p = select_list; p != NULL; p = p->next)
555 FD_SET (p->fd, select_set);
556 if (p->fd > top_fd)
557 top_fd = p->fd;
561 return top_fd;
564 /* --------------------------------------------------------------------------------------------- */
566 static void
567 check_selects (fd_set * select_set)
569 if (disabled_channels == 0)
571 gboolean retry;
575 SelectList *p;
577 retry = FALSE;
578 for (p = select_list; p; p = p->next)
579 if (FD_ISSET (p->fd, select_set))
581 FD_CLR (p->fd, select_set);
582 (*p->callback) (p->fd, p->info);
583 retry = TRUE;
584 break;
587 while (retry);
591 /* --------------------------------------------------------------------------------------------- */
592 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
594 static void
595 try_channels (int set_timeout)
597 struct timeval time_out;
598 static fd_set select_set;
599 struct timeval *timeptr;
600 int v;
601 int maxfdp;
603 while (1)
605 FD_ZERO (&select_set);
606 FD_SET (input_fd, &select_set); /* Add stdin */
607 maxfdp = max (add_selects (&select_set), input_fd);
609 timeptr = NULL;
610 if (set_timeout)
612 time_out.tv_sec = 0;
613 time_out.tv_usec = 100000;
614 timeptr = &time_out;
617 v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr);
618 if (v > 0)
620 check_selects (&select_set);
621 if (FD_ISSET (input_fd, &select_set))
622 break;
627 /* --------------------------------------------------------------------------------------------- */
629 static key_def *
630 create_sequence (const char *seq, int code, int action)
632 key_def *base, *p, *attach;
634 for (base = attach = NULL; *seq; seq++)
636 p = g_new (key_def, 1);
637 if (base == NULL)
638 base = p;
639 if (attach != NULL)
640 attach->child = p;
642 p->ch = *seq;
643 p->code = code;
644 p->child = p->next = NULL;
645 if (seq[1] == '\0')
646 p->action = action;
647 else
648 p->action = MCKEY_NOACTION;
649 attach = p;
651 return base;
654 /* --------------------------------------------------------------------------------------------- */
656 static void
657 define_sequences (const key_define_t * kd)
659 int i;
661 for (i = 0; kd[i].code != 0; i++)
662 define_sequence (kd[i].code, kd[i].seq, kd[i].action);
665 /* --------------------------------------------------------------------------------------------- */
667 static void
668 init_key_x11 (void)
670 #ifdef HAVE_TEXTMODE_X11_SUPPORT
671 if (getenv ("DISPLAY") != NULL && !mc_global.tty.disable_x11)
673 x11_display = mc_XOpenDisplay (0);
675 if (x11_display != NULL)
676 x11_window = DefaultRootWindow (x11_display);
678 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
681 /* --------------------------------------------------------------------------------------------- */
682 /* Workaround for System V Curses vt100 bug */
684 static int
685 getch_with_delay (void)
687 int c;
689 /* This routine could be used on systems without mouse support,
690 so we need to do the select check :-( */
691 while (1)
693 if (pending_keys == NULL)
694 try_channels (0);
696 /* Try to get a character */
697 c = get_key_code (0);
698 if (c != -1)
699 break;
700 /* Failed -> wait 0.1 secs and try again */
701 try_channels (1);
703 /* Success -> return the character */
704 return c;
707 /* --------------------------------------------------------------------------------------------- */
709 static void
710 xmouse_get_event (Gpm_Event * ev)
712 static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
713 static struct timeval tv2;
714 static int clicks = 0;
715 static int last_btn = 0;
716 int btn = mouse_btn;
718 /* Decode Xterm mouse information to a GPM style event */
720 /* There seems to be no way of knowing which button was released */
721 /* So we assume all the buttons were released */
723 if (btn == 3)
725 if (last_btn != 0)
727 if ((last_btn & (GPM_B_UP | GPM_B_DOWN)) != 0)
729 /* FIXME: DIRTY HACK */
730 /* don't generate GPM_UP after mouse wheel */
731 /* need for menu event handling */
732 ev->type = 0;
733 tv1.tv_sec = 0;
734 tv1.tv_usec = 0;
736 else
738 ev->type = GPM_UP | (GPM_SINGLE << clicks);
739 GET_TIME (tv1);
741 ev->buttons = 0;
742 last_btn = 0;
743 clicks = 0;
745 else
747 /* Bogus event, maybe mouse wheel */
748 ev->type = 0;
751 else
753 if (btn >= 32 && btn <= 34)
755 btn -= 32;
756 ev->type = GPM_DRAG;
758 else
759 ev->type = GPM_DOWN;
761 GET_TIME (tv2);
762 if (tv1.tv_sec && (DIF_TIME (tv1, tv2) < double_click_speed))
764 clicks++;
765 clicks %= 3;
767 else
768 clicks = 0;
770 switch (btn)
772 case 0:
773 ev->buttons = GPM_B_LEFT;
774 break;
775 case 1:
776 ev->buttons = GPM_B_MIDDLE;
777 break;
778 case 2:
779 ev->buttons = GPM_B_RIGHT;
780 break;
781 case 64:
782 ev->buttons = GPM_B_UP;
783 clicks = 0;
784 break;
785 case 65:
786 ev->buttons = GPM_B_DOWN;
787 clicks = 0;
788 break;
789 default:
790 /* Nothing */
791 ev->type = 0;
792 ev->buttons = 0;
793 break;
795 last_btn = ev->buttons;
797 ev->x = mouse_x;
798 ev->y = mouse_y;
801 /* --------------------------------------------------------------------------------------------- */
803 * Get modifier state (shift, alt, ctrl) for the last key pressed.
804 * We are assuming that the state didn't change since the key press.
805 * This is only correct if get_modifier() is called very fast after
806 * the input was received, so that the user didn't release the
807 * modifier keys yet.
810 static int
811 get_modifier (void)
813 int result = 0;
814 #ifdef __QNXNTO__
815 int mod_status, shift_ext_status;
816 static int in_photon = 0;
817 static int ph_ig = 0;
818 PhCursorInfo_t cursor_info;
819 #endif /* __QNXNTO__ */
821 #ifdef HAVE_TEXTMODE_X11_SUPPORT
822 if (x11_window != 0)
824 Window root, child;
825 int root_x, root_y;
826 int win_x, win_y;
827 unsigned int mask;
829 mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x,
830 &root_y, &win_x, &win_y, &mask);
832 if (mask & ShiftMask)
833 result |= KEY_M_SHIFT;
834 if (mask & ControlMask)
835 result |= KEY_M_CTRL;
836 return result;
838 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
839 #ifdef __QNXNTO__
841 if (in_photon == 0)
843 /* First time here, let's load Photon library and attach
844 to Photon */
845 in_photon = -1;
846 if (getenv ("PHOTON2_PATH") != NULL)
848 /* QNX 6.x has no support for RTLD_LAZY */
849 void *ph_handle = dlopen ("/usr/lib/libph.so", RTLD_NOW);
850 if (ph_handle != NULL)
852 ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach");
853 ph_input_group = (ph_ov_f) dlsym (ph_handle, "PhInputGroup");
854 ph_query_cursor = (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor");
855 if ((ph_attach != NULL) && (ph_input_group != NULL) && (ph_query_cursor != NULL))
857 if ((*ph_attach) (0, 0))
858 { /* Attached */
859 ph_ig = (*ph_input_group) (0);
860 in_photon = 1;
866 /* We do not have Photon running. Assume we are in text
867 console or xterm */
868 if (in_photon == -1)
870 if (devctl (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status, sizeof (int), NULL) == -1)
871 return 0;
872 shift_ext_status = mod_status & 0xffffff00UL;
873 mod_status &= 0x7f;
874 if (mod_status & _LINESTATUS_CON_ALT)
875 result |= KEY_M_ALT;
876 if (mod_status & _LINESTATUS_CON_CTRL)
877 result |= KEY_M_CTRL;
878 if ((mod_status & _LINESTATUS_CON_SHIFT) || (shift_ext_status & 0x00000800UL))
879 result |= KEY_M_SHIFT;
881 else
883 (*ph_query_cursor) (ph_ig, &cursor_info);
884 if (cursor_info.key_mods & 0x04)
885 result |= KEY_M_ALT;
886 if (cursor_info.key_mods & 0x02)
887 result |= KEY_M_CTRL;
888 if (cursor_info.key_mods & 0x01)
889 result |= KEY_M_SHIFT;
891 #endif /* __QNXNTO__ */
893 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
895 unsigned char modifiers = 6;
897 if (ioctl (0, TIOCLINUX, &modifiers) < 0)
898 return 0;
900 /* Translate Linux modifiers into mc modifiers */
901 if (modifiers & SHIFT_PRESSED)
902 result |= KEY_M_SHIFT;
903 if (modifiers & (ALTL_PRESSED | ALTR_PRESSED))
904 result |= KEY_M_ALT;
905 if (modifiers & CONTROL_PRESSED)
906 result |= KEY_M_CTRL;
908 #endif /* !__linux__ */
909 return result;
912 /* --------------------------------------------------------------------------------------------- */
914 static gboolean
915 push_char (int c)
917 gboolean ret = FALSE;
919 if (seq_append == NULL)
920 seq_append = seq_buffer;
922 if (seq_append != &(seq_buffer[SEQ_BUFFER_LEN - 2]))
924 *(seq_append++) = c;
925 *seq_append = 0;
926 ret = TRUE;
929 return ret;
932 /* --------------------------------------------------------------------------------------------- */
933 /* Parse extended mouse coordinates.
934 Returns -1 if pending_keys (up to seq_append) cannot be a prefix of extended mouse coordinates.
935 Returns 0 if pending_keys (up to seq_append) is a valid (but still incomplete) prefix for
936 extended mouse coordinates, e.g. "^[[32;4".
937 Returns 1 and fills the mouse_btn, mouse_x, mouse_y values if pending_keys (up to seq_append) is
938 a complete extended mouse sequence, e.g. "^[[32;42;5M"
941 /* Technical info (Egmont Koblinger <egmont@gmail.com>):
943 The ancient way of reporting mouse coordinates only supports coordinates up to 223,
944 so if your terminal is wider (or taller, but that's unlikely), you cannot use your mouse
945 in the rightmost columns.
947 * The old way of reporting mouse coordinates is the following:
948 + Output DECSET 1000 to enable mouse
949 + Expect escape sequences in the format \e[M<action+32><x+32><y+32> whereas <action+32>,
950 <x+32> and <y+32> are single bytes. (Action is 0 for left click, 1 for middle click,
951 2 for right click, 3 for release, or something like this.)
952 + Disadvantages of this format:
953 + x and y can only go up to 223.
954 + Coordinates above 95 are not ascii-compatible, so any character set converting
955 layer (e.g. luit) messes them up.
956 + The stream is not valid UTF-8, even if everything else is.
958 * The first new extension, introduced by xterm-262, is the following:
959 + Output DECSET 1000 to enable mouse, followed by DECSET 1005 to activate extended mode.
960 + Expect escape sequences in the format \e[M<action+32><<x+32>><<y+32>> whereas <<x+32>>
961 and <<y+32>> each can be up to two bytes long: coordinate+32 is encoded in UTF-8.
962 + Disadvantates of this format:
963 + There's still a limit of 2015 rows/columns (okay, it's not a real life problem).
964 + Doesn't solve the luit issue.
965 + It is "horribly broken" (quoting urxvt's changelog) in terms of compatibility
966 with the previous standard. There is no way for an application to tell whether
967 the underlying terminal supports this new mode (whether DECSET 1005 did actually change
968 the behavior or not), but depending on this a completely different user action might
969 generate the same input. Example:
970 + If the terminal doesn't support this extension, then clicking at (162, 129)
971 generates \e[M<32><194><161>.
972 + If the terminal supports this extension, then clicking at (129, 1) [bit of math:
973 129+32 = 161, U+0161 in UTF-8 is 194 161] generates \e[M<32><194><161><33>.
974 + so there's no way to tell whether the terminal ignored the 1005 escape sequence,
975 the user clicked on (162, 129) and then typed an exclamation mark; or whether
976 the terminal recognized the escape, and the user clicked on (129, 1).
977 + Due to this horrible brokenness, there's no way to implement support it without
978 explicitly asking the user (via a setting) if the terminal can speak this extension.
980 * The second new extension, introduced by rxvt-unicode-9.10, is the following:
981 + Output DECSET 1000 to enable mouse, followed by DECSET 1015 to activate this extended mode.
982 + Expect escape sequences in the format \e[{action+32};{x};{y}M where this time I used
983 the braces to denote spelling out the numbers in decimal, rather than using raw bytes.
984 + The only thing I don't understand is why they kept the offset of 32 at action, but other
985 than that, this format is totally okay, and solves all the weaknesses of the previous ones.
987 Currently, at least the following terminal emulators have support for these:
988 * xterm supports the xterm extension
989 * rxvt-unicode >= 9.10 supports both extensions
990 * iterm2 supports both extensions
991 * vte >= 0.31 supports the urxvt extension
994 static int
995 parse_extended_mouse_coordinates (void)
997 int c, btn = 0, x = 0, y = 0;
998 const int *p = pending_keys;
999 const int *endp = seq_append;
1001 if (p == endp)
1002 return 0;
1003 c = *p++;
1004 if (c != ESC_CHAR)
1005 return -1;
1007 if (p == endp)
1008 return 0;
1009 c = *p++;
1010 if (c != '[')
1011 return -1;
1013 while (TRUE)
1015 if (p == endp)
1016 return 0;
1017 c = *p++;
1018 if (c == ';')
1019 break;
1020 if (c < '0' || c > '9')
1021 return -1;
1022 btn = 10 * btn + c - '0';
1024 if (btn < 32)
1025 return -1;
1026 btn -= 32;
1028 while (TRUE)
1030 if (p == endp)
1031 return 0;
1032 c = *p++;
1033 if (c == ';')
1034 break;
1035 if (c < '0' || c > '9')
1036 return -1;
1037 x = 10 * x + c - '0';
1039 if (x < 1)
1040 return -1;
1042 while (TRUE)
1044 if (p == endp)
1045 return 0;
1046 c = *p++;
1047 if (c == 'M')
1048 break;
1049 if (c < '0' || c > '9')
1050 return -1;
1051 y = 10 * y + c - '0';
1053 if (y < 1)
1054 return -1;
1056 mouse_btn = btn;
1057 mouse_x = x;
1058 mouse_y = y;
1059 return 1;
1062 /* --------------------------------------------------------------------------------------------- */
1063 /* Apply corrections for the keycode generated in get_key_code() */
1065 static int
1066 correct_key_code (int code)
1068 unsigned int c = code & ~KEY_M_MASK; /* code without modifier */
1069 unsigned int mod = code & KEY_M_MASK; /* modifier */
1070 #ifdef __QNXNTO__
1071 unsigned int qmod; /* bunch of the QNX console
1072 modifiers needs unchanged */
1073 #endif /* __QNXNTO__ */
1076 * Add key modifiers directly from X11 or OS.
1077 * Ordinary characters only get modifiers from sequences.
1079 if (c < 32 || c >= 256)
1081 mod |= get_modifier ();
1084 /* This is needed if the newline is reported as carriage return */
1085 if (c == '\r')
1086 c = '\n';
1088 /* This is reported to be useful on AIX */
1089 if (c == KEY_SCANCEL)
1090 c = '\t';
1092 /* Convert Shift+Tab and Ctrl+Tab to Back Tab
1093 * only if modifiers directly from X11
1095 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1096 if (x11_window != 0)
1097 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
1099 if ((c == '\t') && (mod & (KEY_M_SHIFT | KEY_M_CTRL)))
1101 c = KEY_BTAB;
1102 mod = 0;
1106 /* F0 is the same as F10 for out purposes */
1107 if (c == KEY_F (0))
1108 c = KEY_F (10);
1111 * We are not interested if Ctrl was pressed when entering control
1112 * characters, so assume that it was. When checking for such keys,
1113 * XCTRL macro should be used. In some cases, we are interested,
1114 * e.g. to distinguish Ctrl-Enter from Enter.
1116 if (c == '\b')
1118 /* Special case for backspase ('\b' < 32) */
1119 c = KEY_BACKSPACE;
1120 mod &= ~KEY_M_CTRL;
1122 else if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n')
1124 mod |= KEY_M_CTRL;
1127 #ifdef __QNXNTO__
1128 qmod = get_modifier ();
1130 if ((c == 127) && (mod == 0))
1131 { /* Add Ctrl/Alt/Shift-BackSpace */
1132 mod |= get_modifier ();
1133 c = KEY_BACKSPACE;
1136 if ((c == '0') && (mod == 0))
1137 { /* Add Shift-Insert on key pad */
1138 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1140 mod = KEY_M_SHIFT;
1141 c = KEY_IC;
1145 if ((c == '.') && (mod == 0))
1146 { /* Add Shift-Del on key pad */
1147 if ((qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1149 mod = KEY_M_SHIFT;
1150 c = KEY_DC;
1153 #endif /* __QNXNTO__ */
1155 /* Unrecognized 0177 is delete (preserve Ctrl) */
1156 if (c == 0177)
1158 c = KEY_BACKSPACE;
1161 #if 0
1162 /* Unrecognized Ctrl-d is delete */
1163 if (c == (31 & 'd'))
1165 c = KEY_DC;
1166 mod &= ~KEY_M_CTRL;
1169 /* Unrecognized Ctrl-h is backspace */
1170 if (c == (31 & 'h'))
1172 c = KEY_BACKSPACE;
1173 mod &= ~KEY_M_CTRL;
1175 #endif
1177 /* Shift+BackSpace is backspace */
1178 if (c == KEY_BACKSPACE && (mod & KEY_M_SHIFT))
1180 mod &= ~KEY_M_SHIFT;
1183 /* Convert Shift+Fn to F(n+10) */
1184 if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT))
1186 c += 10;
1189 /* Remove Shift information from function keys */
1190 if (c >= KEY_F (1) && c <= KEY_F (20))
1192 mod &= ~KEY_M_SHIFT;
1195 if (!mc_global.tty.alternate_plus_minus)
1196 switch (c)
1198 case KEY_KP_ADD:
1199 c = '+';
1200 break;
1201 case KEY_KP_SUBTRACT:
1202 c = '-';
1203 break;
1204 case KEY_KP_MULTIPLY:
1205 c = '*';
1206 break;
1209 return (mod | c);
1212 /* --------------------------------------------------------------------------------------------- */
1214 static int
1215 xgetch_second (void)
1217 fd_set Read_FD_Set;
1218 int c;
1219 struct timeval time_out;
1221 time_out.tv_sec = old_esc_mode_timeout / 1000000;
1222 time_out.tv_usec = old_esc_mode_timeout % 1000000;
1223 tty_nodelay (TRUE);
1224 FD_ZERO (&Read_FD_Set);
1225 FD_SET (input_fd, &Read_FD_Set);
1226 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
1227 c = tty_lowlevel_getch ();
1228 tty_nodelay (FALSE);
1229 return c;
1232 /* --------------------------------------------------------------------------------------------- */
1234 static void
1235 learn_store_key (char *buffer, char **p, int c)
1237 if (*p - buffer > 253)
1238 return;
1239 if (c == ESC_CHAR)
1241 *(*p)++ = '\\';
1242 *(*p)++ = 'e';
1244 else if (c < ' ')
1246 *(*p)++ = '^';
1247 *(*p)++ = c + 'a' - 1;
1249 else if (c == '^')
1251 *(*p)++ = '^';
1252 *(*p)++ = '^';
1254 else
1255 *(*p)++ = (char) c;
1258 /* --------------------------------------------------------------------------------------------- */
1260 static void
1261 k_dispose (key_def * k)
1263 if (k != NULL)
1265 k_dispose (k->child);
1266 k_dispose (k->next);
1267 g_free (k);
1271 /* --------------------------------------------------------------------------------------------- */
1273 static void
1274 s_dispose (SelectList * sel)
1276 if (sel != NULL)
1278 s_dispose (sel->next);
1279 g_free (sel);
1283 /* --------------------------------------------------------------------------------------------- */
1285 static int
1286 key_code_comparator_by_name (const void *p1, const void *p2)
1288 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1289 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1291 return g_ascii_strcasecmp (n1->name, n2->name);
1294 /* --------------------------------------------------------------------------------------------- */
1296 static int
1297 key_code_comparator_by_code (const void *p1, const void *p2)
1299 const key_code_name_t *n1 = *(const key_code_name_t **) p1;
1300 const key_code_name_t *n2 = *(const key_code_name_t **) p2;
1302 return n1->code - n2->code;
1305 /* --------------------------------------------------------------------------------------------- */
1307 static inline void
1308 sort_key_conv_tab (enum KeySortType type_sort)
1310 if (has_been_sorted != type_sort)
1312 size_t i;
1313 for (i = 0; i < key_conv_tab_size; i++)
1314 key_conv_tab_sorted[i] = &key_name_conv_tab[i];
1316 if (type_sort == KEY_SORTBYNAME)
1318 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1319 &key_code_comparator_by_name);
1321 else if (type_sort == KEY_SORTBYCODE)
1323 qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1324 &key_code_comparator_by_code);
1326 has_been_sorted = type_sort;
1330 /* --------------------------------------------------------------------------------------------- */
1332 static int
1333 lookup_keyname (const char *name, int *idx)
1335 if (name[0] != '\0')
1337 const key_code_name_t key = { 0, name, NULL, NULL };
1338 const key_code_name_t *keyp = &key;
1339 key_code_name_t **res;
1341 if (name[1] == '\0')
1343 *idx = -1;
1344 return (int) name[0];
1347 sort_key_conv_tab (KEY_SORTBYNAME);
1349 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1350 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_name);
1352 if (res != NULL)
1354 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1355 return (*res)->code;
1359 *idx = -1;
1360 return 0;
1363 /* --------------------------------------------------------------------------------------------- */
1365 static gboolean
1366 lookup_keycode (const long code, int *idx)
1368 if (code != 0)
1370 const key_code_name_t key = { code, NULL, NULL, NULL };
1371 const key_code_name_t *keyp = &key;
1372 key_code_name_t **res;
1374 sort_key_conv_tab (KEY_SORTBYCODE);
1376 res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1377 sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_code);
1379 if (res != NULL)
1381 *idx = (int) (res - (key_code_name_t **) key_conv_tab_sorted);
1382 return TRUE;
1386 *idx = -1;
1387 return FALSE;
1390 /* --------------------------------------------------------------------------------------------- */
1391 /*** public functions ****************************************************************************/
1392 /* --------------------------------------------------------------------------------------------- */
1393 /* This has to be called before init_slang or whatever routine
1394 calls any define_sequence */
1396 void
1397 init_key (void)
1399 const char *term = getenv ("TERM");
1401 /* This has to be the first define_sequence */
1402 /* So, we can assume that the first keys member has ESC */
1403 define_sequences (mc_default_keys);
1405 /* Terminfo on irix does not have some keys */
1406 if (mc_global.tty.xterm_flag
1407 || (term != NULL
1408 && (strncmp (term, "iris-ansi", 9) == 0
1409 || strncmp (term, "xterm", 5) == 0
1410 || strncmp (term, "rxvt", 4) == 0 || strcmp (term, "screen") == 0)))
1411 define_sequences (xterm_key_defines);
1413 /* load some additional keys (e.g. direct Alt-? support) */
1414 load_xtra_key_defines ();
1416 #ifdef __QNX__
1417 if ((term != NULL) && (strncmp (term, "qnx", 3) == 0))
1419 /* Modify the default value of use_8th_bit_as_meta: we would
1420 * like to provide a working mc for a newbie who knows nothing
1421 * about [Options|Display bits|Full 8 bits input]...
1423 * Don't use 'meta'-bit, when we are dealing with a
1424 * 'qnx*'-type terminal: clear the default value!
1425 * These terminal types use 0xFF as an escape character,
1426 * so use_8th_bit_as_meta==1 must not be enabled!
1428 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1429 * is not used now (doesn't even depend on use_8th_bit_as_meta
1430 * as in mc-3.1.2)...GREAT!...no additional code is required!]
1432 use_8th_bit_as_meta = 0;
1434 #endif /* __QNX__ */
1436 init_key_x11 ();
1438 /* Load the qansi-m key definitions
1439 if we are running under the qansi-m terminal */
1440 if (term != NULL && (strncmp (term, "qansi-m", 7) == 0))
1441 define_sequences (qansi_key_defines);
1444 /* --------------------------------------------------------------------------------------------- */
1446 * This has to be called after SLang_init_tty/slint_init
1449 void
1450 init_key_input_fd (void)
1452 #ifdef HAVE_SLANG
1453 input_fd = SLang_TT_Read_FD;
1454 #endif
1457 /* --------------------------------------------------------------------------------------------- */
1459 void
1460 done_key (void)
1462 k_dispose (keys);
1463 s_dispose (select_list);
1465 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1466 if (x11_display)
1467 mc_XCloseDisplay (x11_display);
1468 #endif
1471 /* --------------------------------------------------------------------------------------------- */
1473 void
1474 add_select_channel (int fd, select_fn callback, void *info)
1476 SelectList *new;
1478 new = g_new (SelectList, 1);
1479 new->fd = fd;
1480 new->callback = callback;
1481 new->info = info;
1482 new->next = select_list;
1483 select_list = new;
1486 /* --------------------------------------------------------------------------------------------- */
1488 void
1489 delete_select_channel (int fd)
1491 SelectList *p = select_list;
1492 SelectList *p_prev = NULL;
1493 SelectList *p_next;
1495 while (p != NULL)
1496 if (p->fd == fd)
1498 p_next = p->next;
1500 if (p_prev != NULL)
1501 p_prev->next = p_next;
1502 else
1503 select_list = p_next;
1505 g_free (p);
1506 p = p_next;
1508 else
1510 p_prev = p;
1511 p = p->next;
1515 /* --------------------------------------------------------------------------------------------- */
1517 void
1518 channels_up (void)
1520 if (disabled_channels == 0)
1521 fputs ("Error: channels_up called with disabled_channels = 0\n", stderr);
1522 disabled_channels--;
1525 /* --------------------------------------------------------------------------------------------- */
1527 void
1528 channels_down (void)
1530 disabled_channels++;
1533 /* --------------------------------------------------------------------------------------------- */
1535 * Return the code associated with the symbolic name keyname
1538 long
1539 lookup_key (const char *name, char **label)
1541 char **lc_keys, **p;
1542 int k = -1;
1543 int key = 0;
1544 int lc_index = -1;
1546 int use_meta = -1;
1547 int use_ctrl = -1;
1548 int use_shift = -1;
1550 if (name == NULL)
1551 return 0;
1553 name = g_strstrip (g_strdup (name));
1554 p = lc_keys = g_strsplit_set (name, "-+ ", -1);
1555 g_free ((char *) name);
1557 while ((p != NULL) && (*p != NULL))
1559 if ((*p)[0] != '\0')
1561 int idx;
1563 key = lookup_keyname (g_strstrip (*p), &idx);
1565 if (key == KEY_M_ALT)
1566 use_meta = idx;
1567 else if (key == KEY_M_CTRL)
1568 use_ctrl = idx;
1569 else if (key == KEY_M_SHIFT)
1570 use_shift = idx;
1571 else
1573 k = key;
1574 lc_index = idx;
1575 break;
1579 p++;
1582 g_strfreev (lc_keys);
1584 /* output */
1585 if (k <= 0)
1586 return 0;
1589 if (label != NULL)
1591 GString *s;
1593 s = g_string_new ("");
1595 if (use_meta != -1)
1597 g_string_append (s, key_conv_tab_sorted[use_meta]->shortcut);
1598 g_string_append_c (s, '-');
1600 if (use_ctrl != -1)
1602 g_string_append (s, key_conv_tab_sorted[use_ctrl]->shortcut);
1603 g_string_append_c (s, '-');
1605 if (use_shift != -1)
1607 if (k < 127)
1608 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1609 else
1611 g_string_append (s, key_conv_tab_sorted[use_shift]->shortcut);
1612 g_string_append_c (s, '-');
1613 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1616 else if (k < 128)
1618 if ((k >= 'A') || (lc_index < 0) || (key_conv_tab_sorted[lc_index]->shortcut == NULL))
1619 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) k));
1620 else
1621 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1623 else if ((lc_index != -1) && (key_conv_tab_sorted[lc_index]->shortcut != NULL))
1624 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1625 else
1626 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) key));
1628 *label = g_string_free (s, FALSE);
1631 if (use_shift != -1)
1633 if (k < 127 && k > 31)
1634 k = g_ascii_toupper ((gchar) k);
1635 else
1636 k |= KEY_M_SHIFT;
1639 if (use_ctrl != -1)
1641 if (k < 256)
1642 k = XCTRL (k);
1643 else
1644 k |= KEY_M_CTRL;
1647 if (use_meta != -1)
1648 k = ALT (k);
1650 return (long) k;
1653 /* --------------------------------------------------------------------------------------------- */
1655 char *
1656 lookup_key_by_code (const int keycode)
1658 /* code without modifier */
1659 unsigned int k = keycode & ~KEY_M_MASK;
1660 /* modifier */
1661 unsigned int mod = keycode & KEY_M_MASK;
1663 int use_meta = -1;
1664 int use_ctrl = -1;
1665 int use_shift = -1;
1666 int key_idx = -1;
1668 GString *s;
1669 int idx;
1671 s = g_string_sized_new (8);
1673 if (lookup_keycode (k, &key_idx) || (k > 0 && k < 256))
1675 if (mod & KEY_M_ALT)
1677 if (lookup_keycode (KEY_M_ALT, &idx))
1679 use_meta = idx;
1680 g_string_append (s, key_conv_tab_sorted[use_meta]->name);
1681 g_string_append_c (s, '-');
1684 if (mod & KEY_M_CTRL)
1686 /* non printeble chars like a CTRL-[A..Z] */
1687 if (k < 32)
1688 k += 64;
1690 if (lookup_keycode (KEY_M_CTRL, &idx))
1692 use_ctrl = idx;
1693 g_string_append (s, key_conv_tab_sorted[use_ctrl]->name);
1694 g_string_append_c (s, '-');
1697 if (mod & KEY_M_SHIFT)
1699 if (lookup_keycode (KEY_M_ALT, &idx))
1701 use_shift = idx;
1702 if (k < 127)
1703 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1704 else
1706 g_string_append (s, key_conv_tab_sorted[use_shift]->name);
1707 g_string_append_c (s, '-');
1708 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1712 else if (k < 128)
1714 if ((k >= 'A') || (key_idx < 0) || (key_conv_tab_sorted[key_idx]->name == NULL))
1715 g_string_append_c (s, (gchar) k);
1716 else
1717 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1719 else if ((key_idx != -1) && (key_conv_tab_sorted[key_idx]->name != NULL))
1720 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1721 else
1722 g_string_append_c (s, (gchar) keycode);
1725 return g_string_free (s, s->len == 0);
1728 /* --------------------------------------------------------------------------------------------- */
1730 * Return TRUE on success, FALSE on error.
1731 * An error happens if SEQ is a beginning of an existing longer sequence.
1734 gboolean
1735 define_sequence (int code, const char *seq, int action)
1737 key_def *base;
1739 if (strlen (seq) > SEQ_BUFFER_LEN - 1)
1740 return FALSE;
1742 for (base = keys; (base != NULL) && (*seq != '\0');)
1743 if (*seq == base->ch)
1745 if (base->child == 0)
1747 if (*(seq + 1) != '\0')
1748 base->child = create_sequence (seq + 1, code, action);
1749 else
1751 /* The sequence matches an existing one. */
1752 base->code = code;
1753 base->action = action;
1755 return TRUE;
1758 base = base->child;
1759 seq++;
1761 else
1763 if (base->next)
1764 base = base->next;
1765 else
1767 base->next = create_sequence (seq, code, action);
1768 return TRUE;
1772 if (*seq == '\0')
1774 /* Attempt to redefine a sequence with a shorter sequence. */
1775 return FALSE;
1778 keys = create_sequence (seq, code, action);
1779 return TRUE;
1782 /* --------------------------------------------------------------------------------------------- */
1784 * Check if we are idle, i.e. there are no pending keyboard or mouse
1785 * events. Return 1 is idle, 0 is there are pending events.
1787 gboolean
1788 is_idle (void)
1790 int maxfdp;
1791 fd_set select_set;
1792 struct timeval time_out;
1794 FD_ZERO (&select_set);
1795 FD_SET (input_fd, &select_set);
1796 maxfdp = input_fd;
1797 #ifdef HAVE_LIBGPM
1798 if (mouse_enabled && (use_mouse_p == MOUSE_GPM) && (gpm_fd > 0))
1800 FD_SET (gpm_fd, &select_set);
1801 maxfdp = max (maxfdp, gpm_fd);
1803 #endif
1804 time_out.tv_sec = 0;
1805 time_out.tv_usec = 0;
1806 return (select (maxfdp + 1, &select_set, 0, 0, &time_out) <= 0);
1809 /* --------------------------------------------------------------------------------------------- */
1812 get_key_code (int no_delay)
1814 int c;
1815 static key_def *this = NULL, *parent;
1816 static struct timeval esctime = { -1, -1 };
1817 static int lastnodelay = -1;
1819 if (no_delay != lastnodelay)
1821 this = NULL;
1822 lastnodelay = no_delay;
1825 pend_send:
1826 if (pending_keys != NULL)
1828 int m;
1830 m = parse_extended_mouse_coordinates ();
1831 if (m == 1)
1833 pending_keys = seq_append = NULL;
1834 this = NULL;
1835 return MCKEY_EXTENDED_MOUSE;
1837 if (m == -1)
1839 int d = *pending_keys++;
1840 check_pend:
1841 if (*pending_keys == 0)
1843 pending_keys = NULL;
1844 seq_append = NULL;
1846 if ((d == ESC_CHAR) && (pending_keys != NULL))
1848 d = ALT (*pending_keys++);
1849 goto check_pend;
1851 if ((d > 127 && d < 256) && use_8th_bit_as_meta)
1852 d = ALT (d & 0x7f);
1853 this = NULL;
1854 return correct_key_code (d);
1856 /* else if (m == 0), just let it continue */
1859 nodelay_try_again:
1860 if (no_delay)
1861 tty_nodelay (TRUE);
1863 c = tty_lowlevel_getch ();
1864 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1865 if (c == KEY_RESIZE)
1866 goto nodelay_try_again;
1867 #endif
1868 if (no_delay)
1870 tty_nodelay (FALSE);
1871 if (c == -1)
1873 if (this != NULL && parent != NULL && parent->action == MCKEY_ESCAPE && old_esc_mode)
1875 struct timeval current, time_out;
1877 if (esctime.tv_sec == -1)
1878 return -1;
1879 GET_TIME (current);
1880 time_out.tv_sec = old_esc_mode_timeout / 1000000 + esctime.tv_sec;
1881 time_out.tv_usec = old_esc_mode_timeout % 1000000 + esctime.tv_usec;
1882 if (time_out.tv_usec > 1000000)
1884 time_out.tv_usec -= 1000000;
1885 time_out.tv_sec++;
1887 if (current.tv_sec < time_out.tv_sec)
1888 return -1;
1889 if (current.tv_sec == time_out.tv_sec && current.tv_usec < time_out.tv_usec)
1890 return -1;
1891 this = NULL;
1892 pending_keys = seq_append = NULL;
1893 return ESC_CHAR;
1895 return -1;
1898 else if (c == -1)
1900 /* Maybe we got an incomplete match.
1901 This we do only in delay mode, since otherwise
1902 tty_lowlevel_getch can return -1 at any time. */
1903 if (seq_append != NULL)
1905 pending_keys = seq_buffer;
1906 goto pend_send;
1908 this = NULL;
1909 return -1;
1912 /* Search the key on the root */
1913 if (!no_delay || this == NULL)
1915 this = keys;
1916 parent = NULL;
1918 if ((c > 127 && c < 256) && use_8th_bit_as_meta)
1920 c &= 0x7f;
1922 /* The first sequence defined starts with esc */
1923 parent = keys;
1924 this = keys->child;
1927 while (this != NULL)
1929 if (c == this->ch)
1931 if (this->child)
1933 if (!push_char (c))
1935 pending_keys = seq_buffer;
1936 goto pend_send;
1938 parent = this;
1939 this = this->child;
1940 if (parent->action == MCKEY_ESCAPE && old_esc_mode)
1942 if (no_delay)
1944 GET_TIME (esctime);
1945 if (this == NULL)
1947 /* Shouldn't happen */
1948 fputs ("Internal error\n", stderr);
1949 exit (EXIT_FAILURE);
1951 goto nodelay_try_again;
1953 esctime.tv_sec = -1;
1954 c = xgetch_second ();
1955 if (c == -1)
1957 pending_keys = seq_append = NULL;
1958 this = NULL;
1959 return ESC_CHAR;
1962 else
1964 if (no_delay)
1965 goto nodelay_try_again;
1966 c = tty_lowlevel_getch ();
1969 else
1971 /* We got a complete match, return and reset search */
1972 int code;
1974 pending_keys = seq_append = NULL;
1975 code = this->code;
1976 this = NULL;
1977 return correct_key_code (code);
1980 else
1982 if (this->next != NULL)
1983 this = this->next;
1984 else
1986 if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
1988 /* Convert escape-digits to F-keys */
1989 if (g_ascii_isdigit (c))
1990 c = KEY_F (c - '0');
1991 else if (c == ' ')
1992 c = ESC_CHAR;
1993 else
1994 c = ALT (c);
1996 pending_keys = seq_append = NULL;
1997 this = NULL;
1998 return correct_key_code (c);
2000 /* Did not find a match or {c} was changed in the if above,
2001 so we have to return everything we had skipped
2003 push_char (c);
2004 pending_keys = seq_buffer;
2005 goto pend_send;
2009 this = NULL;
2010 return correct_key_code (c);
2013 /* --------------------------------------------------------------------------------------------- */
2014 /* Returns a character read from stdin with appropriate interpretation */
2015 /* Also takes care of generated mouse events */
2016 /* Returns EV_MOUSE if it is a mouse event */
2017 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
2020 tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block)
2022 int c;
2023 static int flag = 0; /* Return value from select */
2024 #ifdef HAVE_LIBGPM
2025 static struct Gpm_Event ev; /* Mouse event */
2026 #endif
2027 struct timeval time_out;
2028 struct timeval *time_addr = NULL;
2029 static int dirty = 3;
2031 if ((dirty == 3) || is_idle ())
2033 mc_refresh ();
2034 dirty = 1;
2036 else
2037 dirty++;
2039 vfs_timeout_handler ();
2041 /* Ok, we use (event->x < 0) to signal that the event does not contain
2042 a suitable position for the mouse, so we can't use show_mouse_pointer
2043 on it.
2045 if (event->x > 0)
2047 show_mouse_pointer (event->x, event->y);
2048 if (!redo_event)
2049 event->x = -1;
2052 /* Repeat if using mouse */
2053 while (pending_keys == NULL)
2055 int maxfdp;
2056 fd_set select_set;
2058 FD_ZERO (&select_set);
2059 FD_SET (input_fd, &select_set);
2060 maxfdp = max (add_selects (&select_set), input_fd);
2062 #ifdef HAVE_LIBGPM
2063 if (mouse_enabled && (use_mouse_p == MOUSE_GPM))
2065 if (gpm_fd < 0)
2067 /* Connection to gpm broken, possibly gpm has died */
2068 mouse_enabled = FALSE;
2069 use_mouse_p = MOUSE_NONE;
2070 break;
2073 FD_SET (gpm_fd, &select_set);
2074 maxfdp = max (maxfdp, gpm_fd);
2076 #endif
2078 if (redo_event)
2080 time_out.tv_usec = mou_auto_repeat * 1000;
2081 time_out.tv_sec = 0;
2083 time_addr = &time_out;
2085 else
2087 int seconds;
2089 seconds = vfs_timeouts ();
2090 time_addr = NULL;
2092 if (seconds != 0)
2094 /* the timeout could be improved and actually be
2095 * the number of seconds until the next vfs entry
2096 * timeouts in the stamp list.
2099 time_out.tv_sec = seconds;
2100 time_out.tv_usec = 0;
2101 time_addr = &time_out;
2105 if (!block || mc_global.tty.winch_flag)
2107 time_addr = &time_out;
2108 time_out.tv_sec = 0;
2109 time_out.tv_usec = 0;
2112 tty_enable_interrupt_key ();
2113 flag = select (maxfdp + 1, &select_set, NULL, NULL, time_addr);
2114 tty_disable_interrupt_key ();
2116 /* select timed out: it could be for any of the following reasons:
2117 * redo_event -> it was because of the MOU_REPEAT handler
2118 * !block -> we did not block in the select call
2119 * else -> 10 second timeout to check the vfs status.
2121 if (flag == 0)
2123 if (redo_event)
2124 return EV_MOUSE;
2125 if (!block || mc_global.tty.winch_flag)
2126 return EV_NONE;
2127 vfs_timeout_handler ();
2129 if (flag == -1 && errno == EINTR)
2130 return EV_NONE;
2132 check_selects (&select_set);
2134 if (FD_ISSET (input_fd, &select_set))
2135 break;
2136 #ifdef HAVE_LIBGPM
2137 if (mouse_enabled && use_mouse_p == MOUSE_GPM
2138 && gpm_fd > 0 && FD_ISSET (gpm_fd, &select_set))
2140 Gpm_GetEvent (&ev);
2141 Gpm_FitEvent (&ev);
2142 *event = ev;
2143 return EV_MOUSE;
2145 #endif /* !HAVE_LIBGPM */
2148 #ifndef HAVE_SLANG
2149 flag = is_wintouched (stdscr);
2150 untouchwin (stdscr);
2151 #endif /* !HAVE_SLANG */
2152 c = block ? getch_with_delay () : get_key_code (1);
2154 #ifndef HAVE_SLANG
2155 if (flag > 0)
2156 tty_touch_screen ();
2157 #endif /* !HAVE_SLANG */
2159 if (mouse_enabled && (c == MCKEY_MOUSE
2160 #ifdef KEY_MOUSE
2161 || c == KEY_MOUSE
2162 #endif /* KEY_MOUSE */
2163 || c == MCKEY_EXTENDED_MOUSE))
2165 /* Mouse event */
2166 /* In case of extended coordinates, mouse_btn, mouse_x and mouse_y are already filled in. */
2167 if (c != MCKEY_EXTENDED_MOUSE)
2169 /* Variable btn has following meaning: */
2170 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
2171 mouse_btn = tty_lowlevel_getch () - 32;
2172 /* Coordinates are 33-based */
2173 /* Transform them to 1-based */
2174 mouse_x = tty_lowlevel_getch () - 32;
2175 mouse_y = tty_lowlevel_getch () - 32;
2177 xmouse_get_event (event);
2178 return (event->type != 0) ? EV_MOUSE : EV_NONE;
2181 return c;
2184 /* --------------------------------------------------------------------------------------------- */
2185 /* Returns a key press, mouse events are discarded */
2188 tty_getch (void)
2190 Gpm_Event ev;
2191 int key;
2193 ev.x = -1;
2194 while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE);
2195 return key;
2198 /* --------------------------------------------------------------------------------------------- */
2200 char *
2201 learn_key (void)
2203 /* LEARN_TIMEOUT in usec */
2204 #define LEARN_TIMEOUT 200000
2206 fd_set Read_FD_Set;
2207 struct timeval endtime;
2208 struct timeval time_out;
2209 int c;
2210 char buffer[256];
2211 char *p = buffer;
2213 tty_keypad (FALSE); /* disable intepreting keys by ncurses */
2214 c = tty_lowlevel_getch ();
2215 while (c == -1)
2216 c = tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
2217 learn_store_key (buffer, &p, c);
2218 GET_TIME (endtime);
2219 endtime.tv_usec += LEARN_TIMEOUT;
2220 if (endtime.tv_usec > 1000000)
2222 endtime.tv_usec -= 1000000;
2223 endtime.tv_sec++;
2225 tty_nodelay (TRUE);
2226 for (;;)
2228 while ((c = tty_lowlevel_getch ()) == -1)
2230 GET_TIME (time_out);
2231 time_out.tv_usec = endtime.tv_usec - time_out.tv_usec;
2232 if (time_out.tv_usec < 0)
2233 time_out.tv_sec++;
2234 time_out.tv_sec = endtime.tv_sec - time_out.tv_sec;
2235 if (time_out.tv_sec >= 0 && time_out.tv_usec > 0)
2237 FD_ZERO (&Read_FD_Set);
2238 FD_SET (input_fd, &Read_FD_Set);
2239 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
2241 else
2242 break;
2244 if (c == -1)
2245 break;
2246 learn_store_key (buffer, &p, c);
2248 tty_keypad (TRUE);
2249 tty_nodelay (FALSE);
2250 *p = '\0';
2251 return g_strdup (buffer);
2252 #undef LEARN_TIMEOUT
2255 /* --------------------------------------------------------------------------------------------- */
2256 /* xterm and linux console only: set keypad to numeric or application
2257 mode. Only in application keypad mode it's possible to distinguish
2258 the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2260 void
2261 numeric_keypad_mode (void)
2263 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2265 fputs (ESC_STR ">", stdout);
2266 fflush (stdout);
2270 /* --------------------------------------------------------------------------------------------- */
2272 void
2273 application_keypad_mode (void)
2275 if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2277 fputs (ESC_STR "=", stdout);
2278 fflush (stdout);
2282 /* --------------------------------------------------------------------------------------------- */