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.
9 Miguel de Icaza, 1994, 1995
10 Janne Kukonlehto, 1994, 1995
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/>.
31 * \brief Source: keyboard support routines
42 #include <sys/types.h>
45 #include "lib/global.h"
47 #include "lib/vfs/vfs.h"
50 #include "tty-internal.h" /* mouse_enabled */
54 #include "lib/widget.h" /* mc_refresh() */
56 #ifdef HAVE_TEXTMODE_X11_SUPPORT
61 #if defined(__GLIBC__) && (__GLIBC__ < 2)
62 #include <linux/termios.h> /* TIOCLINUX */
66 #ifdef HAVE_SYS_IOCTL_H
67 #include <sys/ioctl.h>
69 #endif /* __linux__ */
73 #ifdef HAVE_SYS_IOCTL_H
74 #include <sys/ioctl.h>
76 #endif /* __CYGWIN__ */
81 #include <sys/dcmd_chr.h>
82 #endif /* __QNXNTO__ */
84 /*** global variables ****************************************************************************/
86 int mou_auto_repeat
= 100;
87 int double_click_speed
= 250;
89 /* timeout for old_esc_mode in usec */
90 int old_esc_mode_timeout
= 1000000; /* settable via env */
91 int use_8th_bit_as_meta
= 0;
93 /* This table is a mapping between names and the constants we use
94 * We use this to allow users to define alternate definitions for
95 * certain keys that may be missing from the terminal database
97 const key_code_name_t key_name_conv_tab
[] = {
98 /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
99 to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
100 {KEY_F (1), "f1", N_("Function key 1"), "F1"},
101 {KEY_F (2), "f2", N_("Function key 2"), "F2"},
102 {KEY_F (3), "f3", N_("Function key 3"), "F3"},
103 {KEY_F (4), "f4", N_("Function key 4"), "F4"},
104 {KEY_F (5), "f5", N_("Function key 5"), "F5"},
105 {KEY_F (6), "f6", N_("Function key 6"), "F6"},
106 {KEY_F (7), "f7", N_("Function key 7"), "F7"},
107 {KEY_F (8), "f8", N_("Function key 8"), "F8"},
108 {KEY_F (9), "f9", N_("Function key 9"), "F9"},
109 {KEY_F (10), "f10", N_("Function key 10"), "F10"},
110 {KEY_F (11), "f11", N_("Function key 11"), "F11"},
111 {KEY_F (12), "f12", N_("Function key 12"), "F12"},
112 {KEY_F (13), "f13", N_("Function key 13"), "F13"},
113 {KEY_F (14), "f14", N_("Function key 14"), "F14"},
114 {KEY_F (15), "f15", N_("Function key 15"), "F15"},
115 {KEY_F (16), "f16", N_("Function key 16"), "F16"},
116 {KEY_F (17), "f17", N_("Function key 17"), "F17"},
117 {KEY_F (18), "f18", N_("Function key 18"), "F18"},
118 {KEY_F (19), "f19", N_("Function key 19"), "F19"},
119 {KEY_F (20), "f20", N_("Function key 20"), "F20"},
120 {KEY_BACKSPACE
, "backspace", N_("Backspace key"), "Backspace"},
121 {KEY_END
, "end", N_("End key"), "End"},
122 {KEY_UP
, "up", N_("Up arrow key"), "Up"},
123 {KEY_DOWN
, "down", N_("Down arrow key"), "Down"},
124 {KEY_LEFT
, "left", N_("Left arrow key"), "Left"},
125 {KEY_RIGHT
, "right", N_("Right arrow key"), "Right"},
126 {KEY_HOME
, "home", N_("Home key"), "Home"},
127 {KEY_NPAGE
, "pgdn", N_("Page Down key"), "PgDn"},
128 {KEY_PPAGE
, "pgup", N_("Page Up key"), "PgUp"},
129 {KEY_IC
, "insert", N_("Insert key"), "Ins"},
130 {KEY_DC
, "delete", N_("Delete key"), "Del"},
131 {ALT ('\t'), "complete", N_("Completion/M-tab"), "Meta-Tab"},
132 {KEY_BTAB
, "backtab", N_("Back Tabulation S-tab"), "Shift-Tab"},
133 {KEY_KP_ADD
, "kpplus", N_("+ on keypad"), "+"},
134 {KEY_KP_SUBTRACT
, "kpminus", N_("- on keypad"), "-"},
135 {(int) '/', "kpslash", N_("Slash on keypad"), "/"},
136 {KEY_KP_MULTIPLY
, "kpasterisk", N_("* on keypad"), "*"},
138 /* From here on, these won't be shown in Learn keys (no space) */
139 {ESC_CHAR
, "escape", N_("Escape key"), "Esc"},
140 {KEY_LEFT
, "kpleft", N_("Left arrow keypad"), "Left"},
141 {KEY_RIGHT
, "kpright", N_("Right arrow keypad"), "Right"},
142 {KEY_UP
, "kpup", N_("Up arrow keypad"), "Up"},
143 {KEY_DOWN
, "kpdown", N_("Down arrow keypad"), "Down"},
144 {KEY_HOME
, "kphome", N_("Home on keypad"), "Home"},
145 {KEY_END
, "kpend", N_("End on keypad"), "End"},
146 {KEY_NPAGE
, "kpnpage", N_("Page Down keypad"), "PgDn"},
147 {KEY_PPAGE
, "kpppage", N_("Page Up keypad"), "PgUp"},
148 {KEY_IC
, "kpinsert", N_("Insert on keypad"), "Ins"},
149 {KEY_DC
, "kpdelete", N_("Delete on keypad"), "Del"},
150 {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
151 {KEY_F (21), "f21", N_("Function key 21"), "F21"},
152 {KEY_F (22), "f22", N_("Function key 22"), "F22"},
153 {KEY_F (23), "f23", N_("Function key 23"), "F23"},
154 {KEY_F (24), "f24", N_("Function key 24"), "F24"},
155 {KEY_A1
, "a1", N_("A1 key"), "A1"},
156 {KEY_C1
, "c1", N_("C1 key"), "C1"},
158 /* Alternative label */
159 {ESC_CHAR
, "esc", N_("Escape key"), "Esc"},
160 {KEY_BACKSPACE
, "bs", N_("Backspace key"), "Bakspace"},
161 {KEY_IC
, "ins", N_("Insert key"), "Ins"},
162 {KEY_DC
, "del", N_("Delete key"), "Del"},
163 {(int) '+', "plus", N_("Plus"), "+"},
164 {(int) '-', "minus", N_("Minus"), "-"},
165 {(int) '*', "asterisk", N_("Asterisk"), "*"},
166 {(int) '.', "dot", N_("Dot"), "."},
167 {(int) '<', "lt", N_("Less than"), "<"},
168 {(int) '>', "gt", N_("Great than"), ">"},
169 {(int) '=', "equal", N_("Equal"), "="},
170 {(int) ',', "comma", N_("Comma"), ","},
171 {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
172 {(int) ':', "colon", N_("Colon"), ":"},
173 {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
174 {(int) '?', "question", N_("Question mark"), "?"},
175 {(int) '&', "ampersand", N_("Ampersand"), "&"},
176 {(int) '$', "dollar", N_("Dollar sign"), "$"},
177 {(int) '"', "quota", N_("Quotation mark"), "\""},
178 {(int) '%', "percent", N_("Percent sign"), "%"},
179 {(int) '^', "caret", N_("Caret"), "^"},
180 {(int) '~', "tilda", N_("Tilda"), "~"},
181 {(int) '`', "prime", N_("Prime"), "`"},
182 {(int) '_', "underline", N_("Underline"), "_"},
183 {(int) '_', "understrike", N_("Understrike"), "_"},
184 {(int) '|', "pipe", N_("Pipe"), "|"},
185 {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
186 {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
187 {(int) '[', "lbracket", N_("Left bracket"), "["},
188 {(int) ']', "rbracket", N_("Right bracket"), "]"},
189 {(int) '{', "lbrace", N_("Left brace"), "{"},
190 {(int) '}', "rbrace", N_("Right brace"), "}"},
191 {(int) '\n', "enter", N_("Enter"), "Enter"},
192 {(int) '\t', "tab", N_("Tab key"), "Tab"},
193 {(int) ' ', "space", N_("Space key"), "Space"},
194 {(int) '/', "slash", N_("Slash key"), "/"},
195 {(int) '\\', "backslash", N_("Backslash key"), "\\"},
196 {(int) '#', "number", N_("Number sign #"), "#"},
197 {(int) '#', "hash", N_("Number sign #"), "#"},
198 /* TRANSLATORS: Please translate as in "at sign" (@). */
199 {(int) '@', "at", N_("At sign"), "@"},
202 {KEY_M_CTRL
, "control", N_("Ctrl"), "C"},
203 {KEY_M_CTRL
, "ctrl", N_("Ctrl"), "C"},
204 {KEY_M_ALT
, "meta", N_("Alt"), "M"},
205 {KEY_M_ALT
, "alt", N_("Alt"), "M"},
206 {KEY_M_ALT
, "ralt", N_("Alt"), "M"},
207 {KEY_M_SHIFT
, "shift", N_("Shift"), "S"},
209 {0, NULL
, NULL
, NULL
}
212 /*** file scope macro definitions ****************************************************************/
214 #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *) NULL))
215 #define DIF_TIME(t1, t2) ((t2.tv_sec - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000)
217 /* The maximum sequence length (32 + null terminator) */
218 #define SEQ_BUFFER_LEN 33
220 /*** file scope type declarations ****************************************************************/
222 /* Linux console keyboard modifiers */
225 SHIFT_PRESSED
= (1 << 0),
226 ALTR_PRESSED
= (1 << 1),
227 CONTROL_PRESSED
= (1 << 2),
228 ALTL_PRESSED
= (1 << 3)
231 typedef struct key_def
233 char ch
; /* Holds the matching char code */
234 int code
; /* The code returned, valid if child == NULL */
235 struct key_def
*next
;
236 struct key_def
*child
; /* sequence continuation */
237 int action
; /* optional action to be done. Now used only
238 to mark that we are just after the first
249 /* File descriptor monitoring add/remove routines */
250 typedef struct SelectList
255 struct SelectList
*next
;
258 typedef enum KeySortType
266 typedef int (*ph_dv_f
) (void *, void *);
267 typedef int (*ph_ov_f
) (void *);
268 typedef int (*ph_pqc_f
) (unsigned short, PhCursorInfo_t
*);
271 /*** file scope variables ************************************************************************/
273 static key_define_t mc_default_keys
[] = {
274 {ESC_CHAR
, ESC_STR
, MCKEY_ESCAPE
},
275 {ESC_CHAR
, ESC_STR ESC_STR
, MCKEY_NOACTION
},
276 {0, NULL
, MCKEY_NOACTION
},
279 /* Broken terminfo and termcap databases on xterminals */
280 static key_define_t xterm_key_defines
[] = {
281 {KEY_F (1), ESC_STR
"OP", MCKEY_NOACTION
},
282 {KEY_F (2), ESC_STR
"OQ", MCKEY_NOACTION
},
283 {KEY_F (3), ESC_STR
"OR", MCKEY_NOACTION
},
284 {KEY_F (4), ESC_STR
"OS", MCKEY_NOACTION
},
285 {KEY_F (1), ESC_STR
"[11~", MCKEY_NOACTION
},
286 {KEY_F (2), ESC_STR
"[12~", MCKEY_NOACTION
},
287 {KEY_F (3), ESC_STR
"[13~", MCKEY_NOACTION
},
288 {KEY_F (4), ESC_STR
"[14~", MCKEY_NOACTION
},
289 {KEY_F (5), ESC_STR
"[15~", MCKEY_NOACTION
},
290 {KEY_F (6), ESC_STR
"[17~", MCKEY_NOACTION
},
291 {KEY_F (7), ESC_STR
"[18~", MCKEY_NOACTION
},
292 {KEY_F (8), ESC_STR
"[19~", MCKEY_NOACTION
},
293 {KEY_F (9), ESC_STR
"[20~", MCKEY_NOACTION
},
294 {KEY_F (10), ESC_STR
"[21~", MCKEY_NOACTION
},
296 /* old xterm Shift-arrows */
297 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"O2A", MCKEY_NOACTION
},
298 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"O2B", MCKEY_NOACTION
},
299 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"O2C", MCKEY_NOACTION
},
300 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"O2D", MCKEY_NOACTION
},
302 /* new xterm Shift-arrows */
303 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[1;2A", MCKEY_NOACTION
},
304 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[1;2B", MCKEY_NOACTION
},
305 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[1;2C", MCKEY_NOACTION
},
306 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[1;2D", MCKEY_NOACTION
},
308 /* more xterm keys with modifiers */
309 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[5;5~", MCKEY_NOACTION
},
310 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[6;5~", MCKEY_NOACTION
},
311 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[2;5~", MCKEY_NOACTION
},
312 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[3;5~", MCKEY_NOACTION
},
313 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[1;5H", MCKEY_NOACTION
},
314 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[1;5F", MCKEY_NOACTION
},
315 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"[1;2H", MCKEY_NOACTION
},
316 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"[1;2F", MCKEY_NOACTION
},
317 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[1;5A", MCKEY_NOACTION
},
318 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[1;5B", MCKEY_NOACTION
},
319 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[1;5C", MCKEY_NOACTION
},
320 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[1;5D", MCKEY_NOACTION
},
321 {KEY_M_SHIFT
| KEY_IC
, ESC_STR
"[2;2~", MCKEY_NOACTION
},
322 {KEY_M_SHIFT
| KEY_DC
, ESC_STR
"[3;2~", MCKEY_NOACTION
},
323 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[1;6A", MCKEY_NOACTION
},
324 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[1;6B", MCKEY_NOACTION
},
325 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[1;6C", MCKEY_NOACTION
},
326 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[1;6D", MCKEY_NOACTION
},
329 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[[1;6A", MCKEY_NOACTION
},
330 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[[1;6B", MCKEY_NOACTION
},
331 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[[1;6C", MCKEY_NOACTION
},
332 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[[1;6D", MCKEY_NOACTION
},
334 /* putty alt-arrow keys */
335 /* removed as source esc esc esc trouble */
337 { KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "OA", MCKEY_NOACTION },
338 { KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "OB", MCKEY_NOACTION },
339 { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
340 { KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "OD", MCKEY_NOACTION },
341 { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
342 { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
343 { KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
344 { KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
346 { KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
347 { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
348 { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
349 { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
351 { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
352 { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
353 { KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
354 { KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
356 /* xterm alt-arrow keys */
357 {KEY_M_ALT
| KEY_UP
, ESC_STR
"[1;3A", MCKEY_NOACTION
},
358 {KEY_M_ALT
| KEY_DOWN
, ESC_STR
"[1;3B", MCKEY_NOACTION
},
359 {KEY_M_ALT
| KEY_RIGHT
, ESC_STR
"[1;3C", MCKEY_NOACTION
},
360 {KEY_M_ALT
| KEY_LEFT
, ESC_STR
"[1;3D", MCKEY_NOACTION
},
361 {KEY_M_ALT
| KEY_PPAGE
, ESC_STR
"[5;3~", MCKEY_NOACTION
},
362 {KEY_M_ALT
| KEY_NPAGE
, ESC_STR
"[6;3~", MCKEY_NOACTION
},
363 {KEY_M_ALT
| KEY_HOME
, ESC_STR
"[1~", MCKEY_NOACTION
},
364 {KEY_M_ALT
| KEY_END
, ESC_STR
"[4~", MCKEY_NOACTION
},
365 {KEY_M_CTRL
| KEY_M_ALT
| KEY_UP
, ESC_STR
"[1;7A", MCKEY_NOACTION
},
366 {KEY_M_CTRL
| KEY_M_ALT
| KEY_DOWN
, ESC_STR
"[1;7B", MCKEY_NOACTION
},
367 {KEY_M_CTRL
| KEY_M_ALT
| KEY_RIGHT
, ESC_STR
"[1;7C", MCKEY_NOACTION
},
368 {KEY_M_CTRL
| KEY_M_ALT
| KEY_LEFT
, ESC_STR
"[1;7D", MCKEY_NOACTION
},
369 {KEY_M_CTRL
| KEY_M_ALT
| KEY_PPAGE
, ESC_STR
"[5;7~", MCKEY_NOACTION
},
370 {KEY_M_CTRL
| KEY_M_ALT
| KEY_NPAGE
, ESC_STR
"[6;7~", MCKEY_NOACTION
},
371 {KEY_M_CTRL
| KEY_M_ALT
| KEY_HOME
, ESC_STR
"OH", MCKEY_NOACTION
},
372 {KEY_M_CTRL
| KEY_M_ALT
| KEY_END
, ESC_STR
"OF", MCKEY_NOACTION
},
374 /* rxvt keys with modifiers */
375 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[a", MCKEY_NOACTION
},
376 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[b", MCKEY_NOACTION
},
377 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[c", MCKEY_NOACTION
},
378 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[d", MCKEY_NOACTION
},
379 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"Oa", MCKEY_NOACTION
},
380 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"Ob", MCKEY_NOACTION
},
381 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"Oc", MCKEY_NOACTION
},
382 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"Od", MCKEY_NOACTION
},
383 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[5^", MCKEY_NOACTION
},
384 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[6^", MCKEY_NOACTION
},
385 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[7^", MCKEY_NOACTION
},
386 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[8^", MCKEY_NOACTION
},
387 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"[7$", MCKEY_NOACTION
},
388 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"[8$", MCKEY_NOACTION
},
389 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[2^", MCKEY_NOACTION
},
390 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[3^", MCKEY_NOACTION
},
391 {KEY_M_SHIFT
| KEY_DC
, ESC_STR
"[3$", MCKEY_NOACTION
},
393 /* konsole keys with modifiers */
394 {KEY_M_SHIFT
| KEY_HOME
, ESC_STR
"O2H", MCKEY_NOACTION
},
395 {KEY_M_SHIFT
| KEY_END
, ESC_STR
"O2F", MCKEY_NOACTION
},
398 {KEY_M_SHIFT
| KEY_UP
, ESC_STR
"[2A", MCKEY_NOACTION
},
399 {KEY_M_SHIFT
| KEY_DOWN
, ESC_STR
"[2B", MCKEY_NOACTION
},
400 {KEY_M_SHIFT
| KEY_RIGHT
, ESC_STR
"[2C", MCKEY_NOACTION
},
401 {KEY_M_SHIFT
| KEY_LEFT
, ESC_STR
"[2D", MCKEY_NOACTION
},
402 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[5A", MCKEY_NOACTION
},
403 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[5B", MCKEY_NOACTION
},
404 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[5C", MCKEY_NOACTION
},
405 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[5D", MCKEY_NOACTION
},
406 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"[6A", MCKEY_NOACTION
},
407 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[6B", MCKEY_NOACTION
},
408 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[6C", MCKEY_NOACTION
},
409 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[6D", MCKEY_NOACTION
},
411 /* gnome-terminal - application mode */
412 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"O5A", MCKEY_NOACTION
},
413 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"O5B", MCKEY_NOACTION
},
414 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"O5C", MCKEY_NOACTION
},
415 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"O5D", MCKEY_NOACTION
},
416 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_UP
, ESC_STR
"O6A", MCKEY_NOACTION
},
417 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"O6B", MCKEY_NOACTION
},
418 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"O6C", MCKEY_NOACTION
},
419 {KEY_M_SHIFT
| KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"O6D", MCKEY_NOACTION
},
422 {KEY_M_SHIFT
| KEY_PPAGE
, ESC_STR
"[5;2~", MCKEY_NOACTION
},
423 {KEY_M_SHIFT
| KEY_NPAGE
, ESC_STR
"[6;2~", MCKEY_NOACTION
},
426 {KEY_M_SHIFT
| KEY_PPAGE
, ESC_STR
"[[5;53~", MCKEY_NOACTION
},
427 {KEY_M_SHIFT
| KEY_NPAGE
, ESC_STR
"[[6;53~", MCKEY_NOACTION
},
430 {KEY_IC
, ESC_STR
"Op", MCKEY_NOACTION
},
431 {KEY_DC
, ESC_STR
"On", MCKEY_NOACTION
},
432 {'/', ESC_STR
"Oo", MCKEY_NOACTION
},
433 {'\n', ESC_STR
"OM", MCKEY_NOACTION
},
435 {0, NULL
, MCKEY_NOACTION
},
438 /* qansi-m terminals have a much more key combinatios,
439 which are undefined in termcap/terminfo */
440 static key_define_t qansi_key_defines
[] = {
441 /* qansi-m terminal */
442 {KEY_M_CTRL
| KEY_NPAGE
, ESC_STR
"[u", MCKEY_NOACTION
}, /* Ctrl-PgDown */
443 {KEY_M_CTRL
| KEY_PPAGE
, ESC_STR
"[v", MCKEY_NOACTION
}, /* Ctrl-PgUp */
444 {KEY_M_CTRL
| KEY_HOME
, ESC_STR
"[h", MCKEY_NOACTION
}, /* Ctrl-Home */
445 {KEY_M_CTRL
| KEY_END
, ESC_STR
"[y", MCKEY_NOACTION
}, /* Ctrl-End */
446 {KEY_M_CTRL
| KEY_IC
, ESC_STR
"[`", MCKEY_NOACTION
}, /* Ctrl-Insert */
447 {KEY_M_CTRL
| KEY_DC
, ESC_STR
"[p", MCKEY_NOACTION
}, /* Ctrl-Delete */
448 {KEY_M_CTRL
| KEY_LEFT
, ESC_STR
"[d", MCKEY_NOACTION
}, /* Ctrl-Left */
449 {KEY_M_CTRL
| KEY_RIGHT
, ESC_STR
"[c", MCKEY_NOACTION
}, /* Ctrl-Right */
450 {KEY_M_CTRL
| KEY_DOWN
, ESC_STR
"[b", MCKEY_NOACTION
}, /* Ctrl-Down */
451 {KEY_M_CTRL
| KEY_UP
, ESC_STR
"[a", MCKEY_NOACTION
}, /* Ctrl-Up */
452 {KEY_M_CTRL
| KEY_KP_ADD
, ESC_STR
"[s", MCKEY_NOACTION
}, /* Ctrl-Gr-Plus */
453 {KEY_M_CTRL
| KEY_KP_SUBTRACT
, ESC_STR
"[t", MCKEY_NOACTION
}, /* Ctrl-Gr-Minus */
454 {KEY_M_CTRL
| '\t', ESC_STR
"[z", MCKEY_NOACTION
}, /* Ctrl-Tab */
455 {KEY_M_SHIFT
| '\t', ESC_STR
"[Z", MCKEY_NOACTION
}, /* Shift-Tab */
456 {KEY_M_CTRL
| KEY_F (1), ESC_STR
"[1~", MCKEY_NOACTION
}, /* Ctrl-F1 */
457 {KEY_M_CTRL
| KEY_F (2), ESC_STR
"[2~", MCKEY_NOACTION
}, /* Ctrl-F2 */
458 {KEY_M_CTRL
| KEY_F (3), ESC_STR
"[3~", MCKEY_NOACTION
}, /* Ctrl-F3 */
459 {KEY_M_CTRL
| KEY_F (4), ESC_STR
"[4~", MCKEY_NOACTION
}, /* Ctrl-F4 */
460 {KEY_M_CTRL
| KEY_F (5), ESC_STR
"[5~", MCKEY_NOACTION
}, /* Ctrl-F5 */
461 {KEY_M_CTRL
| KEY_F (6), ESC_STR
"[6~", MCKEY_NOACTION
}, /* Ctrl-F6 */
462 {KEY_M_CTRL
| KEY_F (7), ESC_STR
"[7~", MCKEY_NOACTION
}, /* Ctrl-F7 */
463 {KEY_M_CTRL
| KEY_F (8), ESC_STR
"[8~", MCKEY_NOACTION
}, /* Ctrl-F8 */
464 {KEY_M_CTRL
| KEY_F (9), ESC_STR
"[9~", MCKEY_NOACTION
}, /* Ctrl-F9 */
465 {KEY_M_CTRL
| KEY_F (10), ESC_STR
"[10~", MCKEY_NOACTION
}, /* Ctrl-F10 */
466 {KEY_M_CTRL
| KEY_F (11), ESC_STR
"[11~", MCKEY_NOACTION
}, /* Ctrl-F11 */
467 {KEY_M_CTRL
| KEY_F (12), ESC_STR
"[12~", MCKEY_NOACTION
}, /* Ctrl-F12 */
468 {KEY_M_ALT
| KEY_F (1), ESC_STR
"[17~", MCKEY_NOACTION
}, /* Alt-F1 */
469 {KEY_M_ALT
| KEY_F (2), ESC_STR
"[18~", MCKEY_NOACTION
}, /* Alt-F2 */
470 {KEY_M_ALT
| KEY_F (3), ESC_STR
"[19~", MCKEY_NOACTION
}, /* Alt-F3 */
471 {KEY_M_ALT
| KEY_F (4), ESC_STR
"[20~", MCKEY_NOACTION
}, /* Alt-F4 */
472 {KEY_M_ALT
| KEY_F (5), ESC_STR
"[21~", MCKEY_NOACTION
}, /* Alt-F5 */
473 {KEY_M_ALT
| KEY_F (6), ESC_STR
"[22~", MCKEY_NOACTION
}, /* Alt-F6 */
474 {KEY_M_ALT
| KEY_F (7), ESC_STR
"[23~", MCKEY_NOACTION
}, /* Alt-F7 */
475 {KEY_M_ALT
| KEY_F (8), ESC_STR
"[24~", MCKEY_NOACTION
}, /* Alt-F8 */
476 {KEY_M_ALT
| KEY_F (9), ESC_STR
"[25~", MCKEY_NOACTION
}, /* Alt-F9 */
477 {KEY_M_ALT
| KEY_F (10), ESC_STR
"[26~", MCKEY_NOACTION
}, /* Alt-F10 */
478 {KEY_M_ALT
| KEY_F (11), ESC_STR
"[27~", MCKEY_NOACTION
}, /* Alt-F11 */
479 {KEY_M_ALT
| KEY_F (12), ESC_STR
"[28~", MCKEY_NOACTION
}, /* Alt-F12 */
480 {KEY_M_ALT
| 'a', ESC_STR
"Na", MCKEY_NOACTION
}, /* Alt-a */
481 {KEY_M_ALT
| 'b', ESC_STR
"Nb", MCKEY_NOACTION
}, /* Alt-b */
482 {KEY_M_ALT
| 'c', ESC_STR
"Nc", MCKEY_NOACTION
}, /* Alt-c */
483 {KEY_M_ALT
| 'd', ESC_STR
"Nd", MCKEY_NOACTION
}, /* Alt-d */
484 {KEY_M_ALT
| 'e', ESC_STR
"Ne", MCKEY_NOACTION
}, /* Alt-e */
485 {KEY_M_ALT
| 'f', ESC_STR
"Nf", MCKEY_NOACTION
}, /* Alt-f */
486 {KEY_M_ALT
| 'g', ESC_STR
"Ng", MCKEY_NOACTION
}, /* Alt-g */
487 {KEY_M_ALT
| 'h', ESC_STR
"Nh", MCKEY_NOACTION
}, /* Alt-h */
488 {KEY_M_ALT
| 'i', ESC_STR
"Ni", MCKEY_NOACTION
}, /* Alt-i */
489 {KEY_M_ALT
| 'j', ESC_STR
"Nj", MCKEY_NOACTION
}, /* Alt-j */
490 {KEY_M_ALT
| 'k', ESC_STR
"Nk", MCKEY_NOACTION
}, /* Alt-k */
491 {KEY_M_ALT
| 'l', ESC_STR
"Nl", MCKEY_NOACTION
}, /* Alt-l */
492 {KEY_M_ALT
| 'm', ESC_STR
"Nm", MCKEY_NOACTION
}, /* Alt-m */
493 {KEY_M_ALT
| 'n', ESC_STR
"Nn", MCKEY_NOACTION
}, /* Alt-n */
494 {KEY_M_ALT
| 'o', ESC_STR
"No", MCKEY_NOACTION
}, /* Alt-o */
495 {KEY_M_ALT
| 'p', ESC_STR
"Np", MCKEY_NOACTION
}, /* Alt-p */
496 {KEY_M_ALT
| 'q', ESC_STR
"Nq", MCKEY_NOACTION
}, /* Alt-q */
497 {KEY_M_ALT
| 'r', ESC_STR
"Nr", MCKEY_NOACTION
}, /* Alt-r */
498 {KEY_M_ALT
| 's', ESC_STR
"Ns", MCKEY_NOACTION
}, /* Alt-s */
499 {KEY_M_ALT
| 't', ESC_STR
"Nt", MCKEY_NOACTION
}, /* Alt-t */
500 {KEY_M_ALT
| 'u', ESC_STR
"Nu", MCKEY_NOACTION
}, /* Alt-u */
501 {KEY_M_ALT
| 'v', ESC_STR
"Nv", MCKEY_NOACTION
}, /* Alt-v */
502 {KEY_M_ALT
| 'w', ESC_STR
"Nw", MCKEY_NOACTION
}, /* Alt-w */
503 {KEY_M_ALT
| 'x', ESC_STR
"Nx", MCKEY_NOACTION
}, /* Alt-x */
504 {KEY_M_ALT
| 'y', ESC_STR
"Ny", MCKEY_NOACTION
}, /* Alt-y */
505 {KEY_M_ALT
| 'z', ESC_STR
"Nz", MCKEY_NOACTION
}, /* Alt-z */
506 {KEY_KP_SUBTRACT
, ESC_STR
"[S", MCKEY_NOACTION
}, /* Gr-Minus */
507 {KEY_KP_ADD
, ESC_STR
"[T", MCKEY_NOACTION
}, /* Gr-Plus */
508 {0, NULL
, MCKEY_NOACTION
},
511 /* This holds all the key definitions */
512 static key_def
*keys
= NULL
;
515 static int disabled_channels
= 0; /* Disable channels checking */
517 static SelectList
*select_list
= NULL
;
519 static int seq_buffer
[SEQ_BUFFER_LEN
];
520 static int *seq_append
= NULL
;
522 static int *pending_keys
= NULL
;
524 static int mouse_btn
, mouse_x
, mouse_y
;
528 ph_ov_f ph_input_group
;
529 ph_pqc_f ph_query_cursor
;
532 #ifdef HAVE_TEXTMODE_X11_SUPPORT
533 static Display
*x11_display
;
534 static Window x11_window
;
535 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
537 static KeySortType has_been_sorted
= KEY_NOSORT
;
540 static const size_t key_conv_tab_size
= G_N_ELEMENTS (key_name_conv_tab
) - 1;
543 static const key_code_name_t
*key_conv_tab_sorted
[G_N_ELEMENTS (key_name_conv_tab
) - 1];
545 /*** file scope functions ************************************************************************/
546 /* --------------------------------------------------------------------------------------------- */
549 add_selects (fd_set
* select_set
)
553 if (disabled_channels
== 0)
557 for (p
= select_list
; p
!= NULL
; p
= p
->next
)
559 FD_SET (p
->fd
, select_set
);
568 /* --------------------------------------------------------------------------------------------- */
571 check_selects (fd_set
* select_set
)
573 if (disabled_channels
== 0)
582 for (p
= select_list
; p
; p
= p
->next
)
583 if (FD_ISSET (p
->fd
, select_set
))
585 FD_CLR (p
->fd
, select_set
);
586 (*p
->callback
) (p
->fd
, p
->info
);
595 /* --------------------------------------------------------------------------------------------- */
596 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
599 try_channels (int set_timeout
)
601 struct timeval time_out
;
602 static fd_set select_set
;
603 struct timeval
*timeptr
;
609 FD_ZERO (&select_set
);
610 FD_SET (input_fd
, &select_set
); /* Add stdin */
611 maxfdp
= max (add_selects (&select_set
), input_fd
);
617 time_out
.tv_usec
= 100000;
621 v
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, timeptr
);
624 check_selects (&select_set
);
625 if (FD_ISSET (input_fd
, &select_set
))
631 /* --------------------------------------------------------------------------------------------- */
634 create_sequence (const char *seq
, int code
, int action
)
636 key_def
*base
, *p
, *attach
;
638 for (base
= attach
= NULL
; *seq
; seq
++)
640 p
= g_new (key_def
, 1);
648 p
->child
= p
->next
= NULL
;
652 p
->action
= MCKEY_NOACTION
;
658 /* --------------------------------------------------------------------------------------------- */
661 define_sequences (const key_define_t
* kd
)
665 for (i
= 0; kd
[i
].code
!= 0; i
++)
666 define_sequence (kd
[i
].code
, kd
[i
].seq
, kd
[i
].action
);
669 /* --------------------------------------------------------------------------------------------- */
674 #ifdef HAVE_TEXTMODE_X11_SUPPORT
675 if (getenv ("DISPLAY") != NULL
&& !mc_global
.tty
.disable_x11
)
677 x11_display
= mc_XOpenDisplay (0);
679 if (x11_display
!= NULL
)
680 x11_window
= DefaultRootWindow (x11_display
);
682 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
685 /* --------------------------------------------------------------------------------------------- */
686 /* Workaround for System V Curses vt100 bug */
689 getch_with_delay (void)
693 /* This routine could be used on systems without mouse support,
694 so we need to do the select check :-( */
697 if (pending_keys
== NULL
)
700 /* Try to get a character */
701 c
= get_key_code (0);
704 /* Failed -> wait 0.1 secs and try again */
707 /* Success -> return the character */
711 /* --------------------------------------------------------------------------------------------- */
714 xmouse_get_event (Gpm_Event
* ev
)
716 static struct timeval tv1
= { 0, 0 }; /* Force first click as single */
717 static struct timeval tv2
;
718 static int clicks
= 0;
719 static int last_btn
= 0;
722 /* Decode Xterm mouse information to a GPM style event */
724 /* There seems to be no way of knowing which button was released */
725 /* So we assume all the buttons were released */
731 if ((last_btn
& (GPM_B_UP
| GPM_B_DOWN
)) != 0)
733 /* FIXME: DIRTY HACK */
734 /* don't generate GPM_UP after mouse wheel */
735 /* need for menu event handling */
742 ev
->type
= GPM_UP
| (GPM_SINGLE
<< clicks
);
751 /* Bogus event, maybe mouse wheel */
757 if (btn
>= 32 && btn
<= 34)
766 if (tv1
.tv_sec
&& (DIF_TIME (tv1
, tv2
) < double_click_speed
))
777 ev
->buttons
= GPM_B_LEFT
;
780 ev
->buttons
= GPM_B_MIDDLE
;
783 ev
->buttons
= GPM_B_RIGHT
;
786 ev
->buttons
= GPM_B_UP
;
790 ev
->buttons
= GPM_B_DOWN
;
799 last_btn
= ev
->buttons
;
805 /* --------------------------------------------------------------------------------------------- */
807 * Get modifier state (shift, alt, ctrl) for the last key pressed.
808 * We are assuming that the state didn't change since the key press.
809 * This is only correct if get_modifier() is called very fast after
810 * the input was received, so that the user didn't release the
819 int mod_status
, shift_ext_status
;
820 static int in_photon
= 0;
821 static int ph_ig
= 0;
822 PhCursorInfo_t cursor_info
;
823 #endif /* __QNXNTO__ */
825 #ifdef HAVE_TEXTMODE_X11_SUPPORT
833 mc_XQueryPointer (x11_display
, x11_window
, &root
, &child
, &root_x
,
834 &root_y
, &win_x
, &win_y
, &mask
);
836 if (mask
& ShiftMask
)
837 result
|= KEY_M_SHIFT
;
838 if (mask
& ControlMask
)
839 result
|= KEY_M_CTRL
;
842 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
847 /* First time here, let's load Photon library and attach
850 if (getenv ("PHOTON2_PATH") != NULL
)
852 /* QNX 6.x has no support for RTLD_LAZY */
853 void *ph_handle
= dlopen ("/usr/lib/libph.so", RTLD_NOW
);
854 if (ph_handle
!= NULL
)
856 ph_attach
= (ph_dv_f
) dlsym (ph_handle
, "PhAttach");
857 ph_input_group
= (ph_ov_f
) dlsym (ph_handle
, "PhInputGroup");
858 ph_query_cursor
= (ph_pqc_f
) dlsym (ph_handle
, "PhQueryCursor");
859 if ((ph_attach
!= NULL
) && (ph_input_group
!= NULL
) && (ph_query_cursor
!= NULL
))
861 if ((*ph_attach
) (0, 0))
863 ph_ig
= (*ph_input_group
) (0);
870 /* We do not have Photon running. Assume we are in text
874 if (devctl (fileno (stdin
), DCMD_CHR_LINESTATUS
, &mod_status
, sizeof (int), NULL
) == -1)
876 shift_ext_status
= mod_status
& 0xffffff00UL
;
878 if (mod_status
& _LINESTATUS_CON_ALT
)
880 if (mod_status
& _LINESTATUS_CON_CTRL
)
881 result
|= KEY_M_CTRL
;
882 if ((mod_status
& _LINESTATUS_CON_SHIFT
) || (shift_ext_status
& 0x00000800UL
))
883 result
|= KEY_M_SHIFT
;
887 (*ph_query_cursor
) (ph_ig
, &cursor_info
);
888 if (cursor_info
.key_mods
& 0x04)
890 if (cursor_info
.key_mods
& 0x02)
891 result
|= KEY_M_CTRL
;
892 if (cursor_info
.key_mods
& 0x01)
893 result
|= KEY_M_SHIFT
;
895 #endif /* __QNXNTO__ */
897 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
899 unsigned char modifiers
= 6;
901 if (ioctl (0, TIOCLINUX
, &modifiers
) < 0)
904 /* Translate Linux modifiers into mc modifiers */
905 if (modifiers
& SHIFT_PRESSED
)
906 result
|= KEY_M_SHIFT
;
907 if (modifiers
& (ALTL_PRESSED
| ALTR_PRESSED
))
909 if (modifiers
& CONTROL_PRESSED
)
910 result
|= KEY_M_CTRL
;
912 #endif /* !__linux__ */
916 /* --------------------------------------------------------------------------------------------- */
921 gboolean ret
= FALSE
;
923 if (seq_append
== NULL
)
924 seq_append
= seq_buffer
;
926 if (seq_append
!= &(seq_buffer
[SEQ_BUFFER_LEN
- 2]))
936 /* --------------------------------------------------------------------------------------------- */
937 /* Parse extended mouse coordinates.
938 Returns -1 if pending_keys (up to seq_append) cannot be a prefix of extended mouse coordinates.
939 Returns 0 if pending_keys (up to seq_append) is a valid (but still incomplete) prefix for
940 extended mouse coordinates, e.g. "^[[32;4".
941 Returns 1 and fills the mouse_btn, mouse_x, mouse_y values if pending_keys (up to seq_append) is
942 a complete extended mouse sequence, e.g. "^[[32;42;5M"
945 /* Technical info (Egmont Koblinger <egmont@gmail.com>):
947 The ancient way of reporting mouse coordinates only supports coordinates up to 223,
948 so if your terminal is wider (or taller, but that's unlikely), you cannot use your mouse
949 in the rightmost columns.
951 * The old way of reporting mouse coordinates is the following:
952 + Output DECSET 1000 to enable mouse
953 + Expect escape sequences in the format \e[M<action+32><x+32><y+32> whereas <action+32>,
954 <x+32> and <y+32> are single bytes. (Action is 0 for left click, 1 for middle click,
955 2 for right click, 3 for release, or something like this.)
956 + Disadvantages of this format:
957 + x and y can only go up to 223.
958 + Coordinates above 95 are not ascii-compatible, so any character set converting
959 layer (e.g. luit) messes them up.
960 + The stream is not valid UTF-8, even if everything else is.
962 * The first new extension, introduced by xterm-262, is the following:
963 + Output DECSET 1000 to enable mouse, followed by DECSET 1005 to activate extended mode.
964 + Expect escape sequences in the format \e[M<action+32><<x+32>><<y+32>> whereas <<x+32>>
965 and <<y+32>> each can be up to two bytes long: coordinate+32 is encoded in UTF-8.
966 + Disadvantates of this format:
967 + There's still a limit of 2015 rows/columns (okay, it's not a real life problem).
968 + Doesn't solve the luit issue.
969 + It is "horribly broken" (quoting urxvt's changelog) in terms of compatibility
970 with the previous standard. There is no way for an application to tell whether
971 the underlying terminal supports this new mode (whether DECSET 1005 did actually change
972 the behavior or not), but depending on this a completely different user action might
973 generate the same input. Example:
974 + If the terminal doesn't support this extension, then clicking at (162, 129)
975 generates \e[M<32><194><161>.
976 + If the terminal supports this extension, then clicking at (129, 1) [bit of math:
977 129+32 = 161, U+0161 in UTF-8 is 194 161] generates \e[M<32><194><161><33>.
978 + so there's no way to tell whether the terminal ignored the 1005 escape sequence,
979 the user clicked on (162, 129) and then typed an exclamation mark; or whether
980 the terminal recognized the escape, and the user clicked on (129, 1).
981 + Due to this horrible brokenness, there's no way to implement support it without
982 explicitly asking the user (via a setting) if the terminal can speak this extension.
984 * The second new extension, introduced by rxvt-unicode-9.10, is the following:
985 + Output DECSET 1000 to enable mouse, followed by DECSET 1015 to activate this extended mode.
986 + Expect escape sequences in the format \e[{action+32};{x};{y}M where this time I used
987 the braces to denote spelling out the numbers in decimal, rather than using raw bytes.
988 + The only thing I don't understand is why they kept the offset of 32 at action, but other
989 than that, this format is totally okay, and solves all the weaknesses of the previous ones.
991 Currently, at least the following terminal emulators have support for these:
992 * xterm supports the xterm extension
993 * rxvt-unicode >= 9.10 supports both extensions
994 * iterm2 supports both extensions
995 * vte >= 0.31 supports the urxvt extension
999 parse_extended_mouse_coordinates (void)
1001 int c
, btn
= 0, x
= 0, y
= 0;
1002 const int *p
= pending_keys
;
1003 const int *endp
= seq_append
;
1024 if (c
< '0' || c
> '9')
1026 btn
= 10 * btn
+ c
- '0';
1039 if (c
< '0' || c
> '9')
1041 x
= 10 * x
+ c
- '0';
1053 if (c
< '0' || c
> '9')
1055 y
= 10 * y
+ c
- '0';
1066 /* --------------------------------------------------------------------------------------------- */
1067 /* Apply corrections for the keycode generated in get_key_code() */
1070 correct_key_code (int code
)
1072 unsigned int c
= code
& ~KEY_M_MASK
; /* code without modifier */
1073 unsigned int mod
= code
& KEY_M_MASK
; /* modifier */
1075 unsigned int qmod
; /* bunch of the QNX console
1076 modifiers needs unchanged */
1077 #endif /* __QNXNTO__ */
1080 * Add key modifiers directly from X11 or OS.
1081 * Ordinary characters only get modifiers from sequences.
1083 if (c
< 32 || c
>= 256)
1085 mod
|= get_modifier ();
1088 /* This is needed if the newline is reported as carriage return */
1092 /* This is reported to be useful on AIX */
1093 if (c
== KEY_SCANCEL
)
1096 /* Convert Shift+Tab and Ctrl+Tab to Back Tab
1097 * only if modifiers directly from X11
1099 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1100 if (x11_window
!= 0)
1101 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
1103 if ((c
== '\t') && (mod
& (KEY_M_SHIFT
| KEY_M_CTRL
)))
1110 /* F0 is the same as F10 for out purposes */
1115 * We are not interested if Ctrl was pressed when entering control
1116 * characters, so assume that it was. When checking for such keys,
1117 * XCTRL macro should be used. In some cases, we are interested,
1118 * e.g. to distinguish Ctrl-Enter from Enter.
1122 /* Special case for backspase ('\b' < 32) */
1126 else if (c
< 32 && c
!= ESC_CHAR
&& c
!= '\t' && c
!= '\n')
1132 qmod
= get_modifier ();
1134 if ((c
== 127) && (mod
== 0))
1135 { /* Add Ctrl/Alt/Shift-BackSpace */
1136 mod
|= get_modifier ();
1140 if ((c
== '0') && (mod
== 0))
1141 { /* Add Shift-Insert on key pad */
1142 if ((qmod
& KEY_M_SHIFT
) == KEY_M_SHIFT
)
1149 if ((c
== '.') && (mod
== 0))
1150 { /* Add Shift-Del on key pad */
1151 if ((qmod
& KEY_M_SHIFT
) == KEY_M_SHIFT
)
1157 #endif /* __QNXNTO__ */
1159 /* Unrecognized 0177 is delete (preserve Ctrl) */
1166 /* Unrecognized Ctrl-d is delete */
1167 if (c
== (31 & 'd'))
1173 /* Unrecognized Ctrl-h is backspace */
1174 if (c
== (31 & 'h'))
1181 /* Shift+BackSpace is backspace */
1182 if (c
== KEY_BACKSPACE
&& (mod
& KEY_M_SHIFT
))
1184 mod
&= ~KEY_M_SHIFT
;
1187 /* Convert Shift+Fn to F(n+10) */
1188 if (c
>= KEY_F (1) && c
<= KEY_F (10) && (mod
& KEY_M_SHIFT
))
1193 /* Remove Shift information from function keys */
1194 if (c
>= KEY_F (1) && c
<= KEY_F (20))
1196 mod
&= ~KEY_M_SHIFT
;
1199 if (!mc_global
.tty
.alternate_plus_minus
)
1205 case KEY_KP_SUBTRACT
:
1208 case KEY_KP_MULTIPLY
:
1216 /* --------------------------------------------------------------------------------------------- */
1219 xgetch_second (void)
1223 struct timeval time_out
;
1225 time_out
.tv_sec
= old_esc_mode_timeout
/ 1000000;
1226 time_out
.tv_usec
= old_esc_mode_timeout
% 1000000;
1228 FD_ZERO (&Read_FD_Set
);
1229 FD_SET (input_fd
, &Read_FD_Set
);
1230 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &time_out
);
1231 c
= tty_lowlevel_getch ();
1232 tty_nodelay (FALSE
);
1236 /* --------------------------------------------------------------------------------------------- */
1239 learn_store_key (char *buffer
, char **p
, int c
)
1241 if (*p
- buffer
> 253)
1251 *(*p
)++ = c
+ 'a' - 1;
1262 /* --------------------------------------------------------------------------------------------- */
1265 k_dispose (key_def
* k
)
1269 k_dispose (k
->child
);
1270 k_dispose (k
->next
);
1275 /* --------------------------------------------------------------------------------------------- */
1278 s_dispose (SelectList
* sel
)
1282 s_dispose (sel
->next
);
1287 /* --------------------------------------------------------------------------------------------- */
1290 key_code_comparator_by_name (const void *p1
, const void *p2
)
1292 const key_code_name_t
*n1
= *(const key_code_name_t
**) p1
;
1293 const key_code_name_t
*n2
= *(const key_code_name_t
**) p2
;
1295 return g_ascii_strcasecmp (n1
->name
, n2
->name
);
1298 /* --------------------------------------------------------------------------------------------- */
1301 key_code_comparator_by_code (const void *p1
, const void *p2
)
1303 const key_code_name_t
*n1
= *(const key_code_name_t
**) p1
;
1304 const key_code_name_t
*n2
= *(const key_code_name_t
**) p2
;
1306 return n1
->code
- n2
->code
;
1309 /* --------------------------------------------------------------------------------------------- */
1312 sort_key_conv_tab (enum KeySortType type_sort
)
1314 if (has_been_sorted
!= type_sort
)
1317 for (i
= 0; i
< key_conv_tab_size
; i
++)
1318 key_conv_tab_sorted
[i
] = &key_name_conv_tab
[i
];
1320 if (type_sort
== KEY_SORTBYNAME
)
1322 qsort (key_conv_tab_sorted
, key_conv_tab_size
, sizeof (key_conv_tab_sorted
[0]),
1323 &key_code_comparator_by_name
);
1325 else if (type_sort
== KEY_SORTBYCODE
)
1327 qsort (key_conv_tab_sorted
, key_conv_tab_size
, sizeof (key_conv_tab_sorted
[0]),
1328 &key_code_comparator_by_code
);
1330 has_been_sorted
= type_sort
;
1334 /* --------------------------------------------------------------------------------------------- */
1337 lookup_keyname (const char *name
, int *idx
)
1339 if (name
[0] != '\0')
1341 const key_code_name_t key
= { 0, name
, NULL
, NULL
};
1342 const key_code_name_t
*keyp
= &key
;
1343 key_code_name_t
**res
;
1345 if (name
[1] == '\0')
1348 return (int) name
[0];
1351 sort_key_conv_tab (KEY_SORTBYNAME
);
1353 res
= bsearch (&keyp
, key_conv_tab_sorted
, key_conv_tab_size
,
1354 sizeof (key_conv_tab_sorted
[0]), key_code_comparator_by_name
);
1358 *idx
= (int) (res
- (key_code_name_t
**) key_conv_tab_sorted
);
1359 return (*res
)->code
;
1367 /* --------------------------------------------------------------------------------------------- */
1370 lookup_keycode (const long code
, int *idx
)
1374 const key_code_name_t key
= { code
, NULL
, NULL
, NULL
};
1375 const key_code_name_t
*keyp
= &key
;
1376 key_code_name_t
**res
;
1378 sort_key_conv_tab (KEY_SORTBYCODE
);
1380 res
= bsearch (&keyp
, key_conv_tab_sorted
, key_conv_tab_size
,
1381 sizeof (key_conv_tab_sorted
[0]), key_code_comparator_by_code
);
1385 *idx
= (int) (res
- (key_code_name_t
**) key_conv_tab_sorted
);
1394 /* --------------------------------------------------------------------------------------------- */
1395 /*** public functions ****************************************************************************/
1396 /* --------------------------------------------------------------------------------------------- */
1397 /* This has to be called before init_slang or whatever routine
1398 calls any define_sequence */
1403 const char *term
= getenv ("TERM");
1405 /* This has to be the first define_sequence */
1406 /* So, we can assume that the first keys member has ESC */
1407 define_sequences (mc_default_keys
);
1409 /* Terminfo on irix does not have some keys */
1410 if (mc_global
.tty
.xterm_flag
1412 && (strncmp (term
, "iris-ansi", 9) == 0
1413 || strncmp (term
, "xterm", 5) == 0
1414 || strncmp (term
, "rxvt", 4) == 0 || strcmp (term
, "screen") == 0)))
1415 define_sequences (xterm_key_defines
);
1417 /* load some additional keys (e.g. direct Alt-? support) */
1418 load_xtra_key_defines ();
1421 if ((term
!= NULL
) && (strncmp (term
, "qnx", 3) == 0))
1423 /* Modify the default value of use_8th_bit_as_meta: we would
1424 * like to provide a working mc for a newbie who knows nothing
1425 * about [Options|Display bits|Full 8 bits input]...
1427 * Don't use 'meta'-bit, when we are dealing with a
1428 * 'qnx*'-type terminal: clear the default value!
1429 * These terminal types use 0xFF as an escape character,
1430 * so use_8th_bit_as_meta==1 must not be enabled!
1432 * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1433 * is not used now (doesn't even depend on use_8th_bit_as_meta
1434 * as in mc-3.1.2)...GREAT!...no additional code is required!]
1436 use_8th_bit_as_meta
= 0;
1438 #endif /* __QNX__ */
1442 /* Load the qansi-m key definitions
1443 if we are running under the qansi-m terminal */
1444 if (term
!= NULL
&& (strncmp (term
, "qansi-m", 7) == 0))
1445 define_sequences (qansi_key_defines
);
1448 /* --------------------------------------------------------------------------------------------- */
1450 * This has to be called after SLang_init_tty/slint_init
1454 init_key_input_fd (void)
1457 input_fd
= SLang_TT_Read_FD
;
1461 /* --------------------------------------------------------------------------------------------- */
1467 s_dispose (select_list
);
1469 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1471 mc_XCloseDisplay (x11_display
);
1475 /* --------------------------------------------------------------------------------------------- */
1478 add_select_channel (int fd
, select_fn callback
, void *info
)
1482 new = g_new (SelectList
, 1);
1484 new->callback
= callback
;
1486 new->next
= select_list
;
1490 /* --------------------------------------------------------------------------------------------- */
1493 delete_select_channel (int fd
)
1495 SelectList
*p
= select_list
;
1496 SelectList
*p_prev
= NULL
;
1505 p_prev
->next
= p_next
;
1507 select_list
= p_next
;
1519 /* --------------------------------------------------------------------------------------------- */
1524 if (disabled_channels
== 0)
1525 fputs ("Error: channels_up called with disabled_channels = 0\n", stderr
);
1526 disabled_channels
--;
1529 /* --------------------------------------------------------------------------------------------- */
1532 channels_down (void)
1534 disabled_channels
++;
1537 /* --------------------------------------------------------------------------------------------- */
1539 * Return the code associated with the symbolic name keyname
1543 lookup_key (const char *name
, char **label
)
1545 char **lc_keys
, **p
;
1557 name
= g_strstrip (g_strdup (name
));
1558 p
= lc_keys
= g_strsplit_set (name
, "-+ ", -1);
1559 g_free ((char *) name
);
1561 while ((p
!= NULL
) && (*p
!= NULL
))
1563 if ((*p
)[0] != '\0')
1567 key
= lookup_keyname (g_strstrip (*p
), &idx
);
1569 if (key
== KEY_M_ALT
)
1571 else if (key
== KEY_M_CTRL
)
1573 else if (key
== KEY_M_SHIFT
)
1586 g_strfreev (lc_keys
);
1597 s
= g_string_new ("");
1601 g_string_append (s
, key_conv_tab_sorted
[use_meta
]->shortcut
);
1602 g_string_append_c (s
, '-');
1606 g_string_append (s
, key_conv_tab_sorted
[use_ctrl
]->shortcut
);
1607 g_string_append_c (s
, '-');
1609 if (use_shift
!= -1)
1612 g_string_append_c (s
, (gchar
) g_ascii_toupper ((gchar
) k
));
1615 g_string_append (s
, key_conv_tab_sorted
[use_shift
]->shortcut
);
1616 g_string_append_c (s
, '-');
1617 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1622 if ((k
>= 'A') || (lc_index
< 0) || (key_conv_tab_sorted
[lc_index
]->shortcut
== NULL
))
1623 g_string_append_c (s
, (gchar
) g_ascii_tolower ((gchar
) k
));
1625 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1627 else if ((lc_index
!= -1) && (key_conv_tab_sorted
[lc_index
]->shortcut
!= NULL
))
1628 g_string_append (s
, key_conv_tab_sorted
[lc_index
]->shortcut
);
1630 g_string_append_c (s
, (gchar
) g_ascii_tolower ((gchar
) key
));
1632 *label
= g_string_free (s
, FALSE
);
1635 if (use_shift
!= -1)
1637 if (k
< 127 && k
> 31)
1638 k
= g_ascii_toupper ((gchar
) k
);
1657 /* --------------------------------------------------------------------------------------------- */
1660 lookup_key_by_code (const int keycode
)
1662 /* code without modifier */
1663 unsigned int k
= keycode
& ~KEY_M_MASK
;
1665 unsigned int mod
= keycode
& KEY_M_MASK
;
1675 s
= g_string_sized_new (8);
1677 if (lookup_keycode (k
, &key_idx
) || (k
> 0 && k
< 256))
1679 if (mod
& KEY_M_ALT
)
1681 if (lookup_keycode (KEY_M_ALT
, &idx
))
1684 g_string_append (s
, key_conv_tab_sorted
[use_meta
]->name
);
1685 g_string_append_c (s
, '-');
1688 if (mod
& KEY_M_CTRL
)
1690 /* non printeble chars like a CTRL-[A..Z] */
1694 if (lookup_keycode (KEY_M_CTRL
, &idx
))
1697 g_string_append (s
, key_conv_tab_sorted
[use_ctrl
]->name
);
1698 g_string_append_c (s
, '-');
1701 if (mod
& KEY_M_SHIFT
)
1703 if (lookup_keycode (KEY_M_ALT
, &idx
))
1707 g_string_append_c (s
, (gchar
) g_ascii_toupper ((gchar
) k
));
1710 g_string_append (s
, key_conv_tab_sorted
[use_shift
]->name
);
1711 g_string_append_c (s
, '-');
1712 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1718 if ((k
>= 'A') || (key_idx
< 0) || (key_conv_tab_sorted
[key_idx
]->name
== NULL
))
1719 g_string_append_c (s
, (gchar
) k
);
1721 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1723 else if ((key_idx
!= -1) && (key_conv_tab_sorted
[key_idx
]->name
!= NULL
))
1724 g_string_append (s
, key_conv_tab_sorted
[key_idx
]->name
);
1726 g_string_append_c (s
, (gchar
) keycode
);
1729 return g_string_free (s
, s
->len
== 0);
1732 /* --------------------------------------------------------------------------------------------- */
1734 * Return TRUE on success, FALSE on error.
1735 * An error happens if SEQ is a beginning of an existing longer sequence.
1739 define_sequence (int code
, const char *seq
, int action
)
1743 if (strlen (seq
) > SEQ_BUFFER_LEN
- 1)
1746 for (base
= keys
; (base
!= NULL
) && (*seq
!= '\0');)
1747 if (*seq
== base
->ch
)
1749 if (base
->child
== 0)
1751 if (*(seq
+ 1) != '\0')
1752 base
->child
= create_sequence (seq
+ 1, code
, action
);
1755 /* The sequence matches an existing one. */
1757 base
->action
= action
;
1771 base
->next
= create_sequence (seq
, code
, action
);
1778 /* Attempt to redefine a sequence with a shorter sequence. */
1782 keys
= create_sequence (seq
, code
, action
);
1786 /* --------------------------------------------------------------------------------------------- */
1788 * Check if we are idle, i.e. there are no pending keyboard or mouse
1789 * events. Return 1 is idle, 0 is there are pending events.
1796 struct timeval time_out
;
1798 FD_ZERO (&select_set
);
1799 FD_SET (input_fd
, &select_set
);
1802 if (mouse_enabled
&& (use_mouse_p
== MOUSE_GPM
) && (gpm_fd
> 0))
1804 FD_SET (gpm_fd
, &select_set
);
1805 maxfdp
= max (maxfdp
, gpm_fd
);
1808 time_out
.tv_sec
= 0;
1809 time_out
.tv_usec
= 0;
1810 return (select (maxfdp
+ 1, &select_set
, 0, 0, &time_out
) <= 0);
1813 /* --------------------------------------------------------------------------------------------- */
1816 get_key_code (int no_delay
)
1819 static key_def
*this = NULL
, *parent
;
1820 static struct timeval esctime
= { -1, -1 };
1821 static int lastnodelay
= -1;
1823 if (no_delay
!= lastnodelay
)
1826 lastnodelay
= no_delay
;
1830 if (pending_keys
!= NULL
)
1834 m
= parse_extended_mouse_coordinates ();
1837 pending_keys
= seq_append
= NULL
;
1839 return MCKEY_EXTENDED_MOUSE
;
1843 int d
= *pending_keys
++;
1845 if (*pending_keys
== 0)
1847 pending_keys
= NULL
;
1850 if ((d
== ESC_CHAR
) && (pending_keys
!= NULL
))
1852 d
= ALT (*pending_keys
++);
1855 if ((d
> 127 && d
< 256) && use_8th_bit_as_meta
)
1858 return correct_key_code (d
);
1860 /* else if (m == 0), just let it continue */
1867 c
= tty_lowlevel_getch ();
1868 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1869 if (c
== KEY_RESIZE
)
1870 goto nodelay_try_again
;
1874 tty_nodelay (FALSE
);
1877 if (this != NULL
&& parent
!= NULL
&& parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
)
1879 struct timeval current
, time_out
;
1881 if (esctime
.tv_sec
== -1)
1884 time_out
.tv_sec
= old_esc_mode_timeout
/ 1000000 + esctime
.tv_sec
;
1885 time_out
.tv_usec
= old_esc_mode_timeout
% 1000000 + esctime
.tv_usec
;
1886 if (time_out
.tv_usec
> 1000000)
1888 time_out
.tv_usec
-= 1000000;
1891 if (current
.tv_sec
< time_out
.tv_sec
)
1893 if (current
.tv_sec
== time_out
.tv_sec
&& current
.tv_usec
< time_out
.tv_usec
)
1896 pending_keys
= seq_append
= NULL
;
1904 /* Maybe we got an incomplete match.
1905 This we do only in delay mode, since otherwise
1906 tty_lowlevel_getch can return -1 at any time. */
1907 if (seq_append
!= NULL
)
1909 pending_keys
= seq_buffer
;
1916 /* Search the key on the root */
1917 if (!no_delay
|| this == NULL
)
1922 if ((c
> 127 && c
< 256) && use_8th_bit_as_meta
)
1926 /* The first sequence defined starts with esc */
1931 while (this != NULL
)
1939 pending_keys
= seq_buffer
;
1944 if (parent
->action
== MCKEY_ESCAPE
&& old_esc_mode
)
1951 /* Shouldn't happen */
1952 fputs ("Internal error\n", stderr
);
1953 exit (EXIT_FAILURE
);
1955 goto nodelay_try_again
;
1957 esctime
.tv_sec
= -1;
1958 c
= xgetch_second ();
1961 pending_keys
= seq_append
= NULL
;
1969 goto nodelay_try_again
;
1970 c
= tty_lowlevel_getch ();
1975 /* We got a complete match, return and reset search */
1978 pending_keys
= seq_append
= NULL
;
1981 return correct_key_code (code
);
1986 if (this->next
!= NULL
)
1990 if ((parent
!= NULL
) && (parent
->action
== MCKEY_ESCAPE
))
1992 /* Convert escape-digits to F-keys */
1993 if (g_ascii_isdigit (c
))
1994 c
= KEY_F (c
- '0');
2000 pending_keys
= seq_append
= NULL
;
2002 return correct_key_code (c
);
2004 /* Did not find a match or {c} was changed in the if above,
2005 so we have to return everything we had skipped
2008 pending_keys
= seq_buffer
;
2014 return correct_key_code (c
);
2017 /* --------------------------------------------------------------------------------------------- */
2018 /* Returns a character read from stdin with appropriate interpretation */
2019 /* Also takes care of generated mouse events */
2020 /* Returns EV_MOUSE if it is a mouse event */
2021 /* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
2024 tty_get_event (struct Gpm_Event
*event
, gboolean redo_event
, gboolean block
)
2027 static int flag
= 0; /* Return value from select */
2029 static struct Gpm_Event ev
; /* Mouse event */
2031 struct timeval time_out
;
2032 struct timeval
*time_addr
= NULL
;
2033 static int dirty
= 3;
2035 if ((dirty
== 3) || is_idle ())
2043 vfs_timeout_handler ();
2045 /* Ok, we use (event->x < 0) to signal that the event does not contain
2046 a suitable position for the mouse, so we can't use show_mouse_pointer
2051 show_mouse_pointer (event
->x
, event
->y
);
2056 /* Repeat if using mouse */
2057 while (pending_keys
== NULL
)
2062 FD_ZERO (&select_set
);
2063 FD_SET (input_fd
, &select_set
);
2064 maxfdp
= max (add_selects (&select_set
), input_fd
);
2067 if (mouse_enabled
&& (use_mouse_p
== MOUSE_GPM
))
2071 /* Connection to gpm broken, possibly gpm has died */
2072 mouse_enabled
= FALSE
;
2073 use_mouse_p
= MOUSE_NONE
;
2077 FD_SET (gpm_fd
, &select_set
);
2078 maxfdp
= max (maxfdp
, gpm_fd
);
2084 time_out
.tv_usec
= mou_auto_repeat
* 1000;
2085 time_out
.tv_sec
= 0;
2087 time_addr
= &time_out
;
2093 seconds
= vfs_timeouts ();
2098 /* the timeout could be improved and actually be
2099 * the number of seconds until the next vfs entry
2100 * timeouts in the stamp list.
2103 time_out
.tv_sec
= seconds
;
2104 time_out
.tv_usec
= 0;
2105 time_addr
= &time_out
;
2109 if (!block
|| mc_global
.tty
.winch_flag
)
2111 time_addr
= &time_out
;
2112 time_out
.tv_sec
= 0;
2113 time_out
.tv_usec
= 0;
2116 tty_enable_interrupt_key ();
2117 flag
= select (maxfdp
+ 1, &select_set
, NULL
, NULL
, time_addr
);
2118 tty_disable_interrupt_key ();
2120 /* select timed out: it could be for any of the following reasons:
2121 * redo_event -> it was because of the MOU_REPEAT handler
2122 * !block -> we did not block in the select call
2123 * else -> 10 second timeout to check the vfs status.
2129 if (!block
|| mc_global
.tty
.winch_flag
)
2131 vfs_timeout_handler ();
2133 if (flag
== -1 && errno
== EINTR
)
2136 check_selects (&select_set
);
2138 if (FD_ISSET (input_fd
, &select_set
))
2141 if (mouse_enabled
&& use_mouse_p
== MOUSE_GPM
2142 && gpm_fd
> 0 && FD_ISSET (gpm_fd
, &select_set
))
2149 #endif /* !HAVE_LIBGPM */
2153 flag
= is_wintouched (stdscr
);
2154 untouchwin (stdscr
);
2155 #endif /* !HAVE_SLANG */
2156 c
= block
? getch_with_delay () : get_key_code (1);
2160 tty_touch_screen ();
2161 #endif /* !HAVE_SLANG */
2163 if (mouse_enabled
&& (c
== MCKEY_MOUSE
2166 #endif /* KEY_MOUSE */
2167 || c
== MCKEY_EXTENDED_MOUSE
))
2170 /* In case of extended coordinates, mouse_btn, mouse_x and mouse_y are already filled in. */
2171 if (c
!= MCKEY_EXTENDED_MOUSE
)
2173 /* Variable btn has following meaning: */
2174 /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
2175 mouse_btn
= tty_lowlevel_getch () - 32;
2176 /* Coordinates are 33-based */
2177 /* Transform them to 1-based */
2178 mouse_x
= tty_lowlevel_getch () - 32;
2179 mouse_y
= tty_lowlevel_getch () - 32;
2181 xmouse_get_event (event
);
2182 return (event
->type
!= 0) ? EV_MOUSE
: EV_NONE
;
2188 /* --------------------------------------------------------------------------------------------- */
2189 /* Returns a key press, mouse events are discarded */
2198 while ((key
= tty_get_event (&ev
, FALSE
, TRUE
)) == EV_NONE
);
2202 /* --------------------------------------------------------------------------------------------- */
2207 /* LEARN_TIMEOUT in usec */
2208 #define LEARN_TIMEOUT 200000
2211 struct timeval endtime
;
2212 struct timeval time_out
;
2217 tty_keypad (FALSE
); /* disable intepreting keys by ncurses */
2218 c
= tty_lowlevel_getch ();
2220 c
= tty_lowlevel_getch (); /* Sanity check, should be unnecessary */
2221 learn_store_key (buffer
, &p
, c
);
2223 endtime
.tv_usec
+= LEARN_TIMEOUT
;
2224 if (endtime
.tv_usec
> 1000000)
2226 endtime
.tv_usec
-= 1000000;
2232 while ((c
= tty_lowlevel_getch ()) == -1)
2234 GET_TIME (time_out
);
2235 time_out
.tv_usec
= endtime
.tv_usec
- time_out
.tv_usec
;
2236 if (time_out
.tv_usec
< 0)
2238 time_out
.tv_sec
= endtime
.tv_sec
- time_out
.tv_sec
;
2239 if (time_out
.tv_sec
>= 0 && time_out
.tv_usec
> 0)
2241 FD_ZERO (&Read_FD_Set
);
2242 FD_SET (input_fd
, &Read_FD_Set
);
2243 select (input_fd
+ 1, &Read_FD_Set
, NULL
, NULL
, &time_out
);
2250 learn_store_key (buffer
, &p
, c
);
2253 tty_nodelay (FALSE
);
2255 return g_strdup (buffer
);
2256 #undef LEARN_TIMEOUT
2259 /* --------------------------------------------------------------------------------------------- */
2260 /* xterm and linux console only: set keypad to numeric or application
2261 mode. Only in application keypad mode it's possible to distinguish
2262 the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2265 numeric_keypad_mode (void)
2267 if (mc_global
.tty
.console_flag
!= '\0' || mc_global
.tty
.xterm_flag
)
2269 fputs (ESC_STR
">", stdout
);
2274 /* --------------------------------------------------------------------------------------------- */
2277 application_keypad_mode (void)
2279 if (mc_global
.tty
.console_flag
!= '\0' || mc_global
.tty
.xterm_flag
)
2281 fputs (ESC_STR
"=", stdout
);
2286 /* --------------------------------------------------------------------------------------------- */