root/lib/tty/key.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. select_cmp_by_fd_set
  2. select_cmp_by_fd
  3. add_selects
  4. check_selects
  5. try_channels
  6. create_sequence
  7. define_sequences
  8. init_key_x11
  9. getch_with_delay
  10. xmouse_get_event
  11. get_modifier
  12. push_char
  13. correct_key_code
  14. getch_with_timeout
  15. learn_store_key
  16. k_dispose
  17. key_code_comparator_by_name
  18. key_code_comparator_by_code
  19. sort_key_conv_tab
  20. lookup_keyname
  21. lookup_keycode
  22. init_key
  23. init_key_input_fd
  24. done_key
  25. add_select_channel
  26. delete_select_channel
  27. channels_up
  28. channels_down
  29. lookup_key
  30. lookup_key_by_code
  31. define_sequence
  32. is_idle
  33. get_key_code
  34. tty_get_event
  35. tty_getch
  36. learn_key
  37. numeric_keypad_mode
  38. application_keypad_mode
  39. enable_bracketed_paste
  40. disable_bracketed_paste

   1 /*
   2    Keyboard support routines.
   3 
   4    Copyright (C) 1994-2020
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Miguel de Icaza, 1994, 1995
   9    Janne Kukonlehto, 1994, 1995
  10    Jakub Jelinek, 1995
  11    Norbert Warmuth, 1997
  12    Denys Vlasenko <vda.linux@googlemail.com>, 2013
  13    Slava Zanko <slavazanko@gmail.com>, 2013
  14    Egmont Koblinger <egmont@gmail.com>, 2013
  15 
  16    This file is part of the Midnight Commander.
  17 
  18    The Midnight Commander is free software: you can redistribute it
  19    and/or modify it under the terms of the GNU General Public License as
  20    published by the Free Software Foundation, either version 3 of the License,
  21    or (at your option) any later version.
  22 
  23    The Midnight Commander is distributed in the hope that it will be useful,
  24    but WITHOUT ANY WARRANTY; without even the implied warranty of
  25    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26    GNU General Public License for more details.
  27 
  28    You should have received a copy of the GNU General Public License
  29    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  30  */
  31 
  32 /** \file key.c
  33  *  \brief Source: keyboard support routines
  34  */
  35 
  36 #include <config.h>
  37 
  38 #include <ctype.h>
  39 #include <errno.h>
  40 #include <stdio.h>
  41 #include <stdlib.h>
  42 #include <string.h>
  43 #ifdef HAVE_SYS_SELECT_H
  44 #include <sys/select.h>
  45 #else
  46 #include <sys/time.h>
  47 #include <sys/types.h>
  48 #include <unistd.h>
  49 #endif
  50 
  51 #include "lib/global.h"
  52 
  53 #include "lib/vfs/vfs.h"
  54 
  55 #include "tty.h"
  56 #include "tty-internal.h"       /* mouse_enabled */
  57 #include "mouse.h"
  58 #include "key.h"
  59 
  60 #include "lib/widget.h"         /* mc_refresh() */
  61 
  62 #ifdef HAVE_TEXTMODE_X11_SUPPORT
  63 #include "x11conn.h"
  64 #endif
  65 
  66 #ifdef __linux__
  67 #if defined(__GLIBC__) && (__GLIBC__ < 2)
  68 #include <linux/termios.h>      /* TIOCLINUX */
  69 #else
  70 #include <termios.h>
  71 #endif
  72 #ifdef HAVE_SYS_IOCTL_H
  73 #include <sys/ioctl.h>
  74 #endif
  75 #endif /* __linux__ */
  76 
  77 #ifdef __CYGWIN__
  78 #include <termios.h>
  79 #ifdef HAVE_SYS_IOCTL_H
  80 #include <sys/ioctl.h>
  81 #endif
  82 #endif /* __CYGWIN__ */
  83 
  84 #ifdef __QNXNTO__
  85 #include <dlfcn.h>
  86 #include <Ph.h>
  87 #include <sys/dcmd_chr.h>
  88 #endif /* __QNXNTO__ */
  89 
  90 /*** global variables ****************************************************************************/
  91 
  92 int mou_auto_repeat = 100;
  93 int double_click_speed = 250;
  94 gboolean old_esc_mode = TRUE;
  95 /* timeout for old_esc_mode in usec */
  96 int old_esc_mode_timeout = 1000000;     /* settable via env */
  97 gboolean use_8th_bit_as_meta = FALSE;
  98 
  99 gboolean bracketed_pasting_in_progress = FALSE;
 100 
 101 /* This table is a mapping between names and the constants we use
 102  * We use this to allow users to define alternate definitions for
 103  * certain keys that may be missing from the terminal database
 104  */
 105 const key_code_name_t key_name_conv_tab[] = {
 106     {ESC_CHAR, "escape", N_("Escape"), "Esc"},
 107     /* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
 108        to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
 109     {KEY_F (1), "f1", N_("Function key 1"), "F1"},
 110     {KEY_F (2), "f2", N_("Function key 2"), "F2"},
 111     {KEY_F (3), "f3", N_("Function key 3"), "F3"},
 112     {KEY_F (4), "f4", N_("Function key 4"), "F4"},
 113     {KEY_F (5), "f5", N_("Function key 5"), "F5"},
 114     {KEY_F (6), "f6", N_("Function key 6"), "F6"},
 115     {KEY_F (7), "f7", N_("Function key 7"), "F7"},
 116     {KEY_F (8), "f8", N_("Function key 8"), "F8"},
 117     {KEY_F (9), "f9", N_("Function key 9"), "F9"},
 118     {KEY_F (10), "f10", N_("Function key 10"), "F10"},
 119     {KEY_F (11), "f11", N_("Function key 11"), "F11"},
 120     {KEY_F (12), "f12", N_("Function key 12"), "F12"},
 121     {KEY_F (13), "f13", N_("Function key 13"), "F13"},
 122     {KEY_F (14), "f14", N_("Function key 14"), "F14"},
 123     {KEY_F (15), "f15", N_("Function key 15"), "F15"},
 124     {KEY_F (16), "f16", N_("Function key 16"), "F16"},
 125     {KEY_F (17), "f17", N_("Function key 17"), "F17"},
 126     {KEY_F (18), "f18", N_("Function key 18"), "F18"},
 127     {KEY_F (19), "f19", N_("Function key 19"), "F19"},
 128     {KEY_F (20), "f20", N_("Function key 20"), "F20"},
 129     {ALT ('\t'), "complete", N_("Completion/M-tab"), "Meta-Tab"},
 130     {KEY_BTAB, "backtab", N_("BackTab/S-tab"), "Shift-Tab"},
 131     {KEY_BACKSPACE, "backspace", N_("Backspace"), "Backspace"},
 132     {KEY_UP, "up", N_("Up arrow"), "Up"},
 133     {KEY_DOWN, "down", N_("Down arrow"), "Down"},
 134     {KEY_LEFT, "left", N_("Left arrow"), "Left"},
 135     {KEY_RIGHT, "right", N_("Right arrow"), "Right"},
 136     {KEY_IC, "insert", N_("Insert"), "Ins"},
 137     {KEY_DC, "delete", N_("Delete"), "Del"},
 138     {KEY_HOME, "home", N_("Home"), "Home"},
 139     {KEY_END, "end", N_("End key"), "End"},
 140     {KEY_PPAGE, "pgup", N_("Page Up"), "PgUp"},
 141     {KEY_NPAGE, "pgdn", N_("Page Down"), "PgDn"},
 142     {(int) '/', "kpslash", N_("/ on keypad"), "/"},
 143     {KEY_KP_MULTIPLY, "kpasterisk", N_("* on keypad"), "*"},
 144     {KEY_KP_SUBTRACT, "kpminus", N_("- on keypad"), "-"},
 145     {KEY_KP_ADD, "kpplus", N_("+ on keypad"), "+"},
 146 
 147     /* From here on, these won't be shown in Learn keys (no space) */
 148     {KEY_LEFT, "kpleft", N_("Left arrow keypad"), "Left"},
 149     {KEY_RIGHT, "kpright", N_("Right arrow keypad"), "Right"},
 150     {KEY_UP, "kpup", N_("Up arrow keypad"), "Up"},
 151     {KEY_DOWN, "kpdown", N_("Down arrow keypad"), "Down"},
 152     {KEY_HOME, "kphome", N_("Home on keypad"), "Home"},
 153     {KEY_END, "kpend", N_("End on keypad"), "End"},
 154     {KEY_NPAGE, "kpnpage", N_("Page Down keypad"), "PgDn"},
 155     {KEY_PPAGE, "kpppage", N_("Page Up keypad"), "PgUp"},
 156     {KEY_IC, "kpinsert", N_("Insert on keypad"), "Ins"},
 157     {KEY_DC, "kpdelete", N_("Delete on keypad"), "Del"},
 158     {(int) '\n', "kpenter", N_("Enter on keypad"), "Enter"},
 159     {KEY_F (21), "f21", N_("Function key 21"), "F21"},
 160     {KEY_F (22), "f22", N_("Function key 22"), "F22"},
 161     {KEY_F (23), "f23", N_("Function key 23"), "F23"},
 162     {KEY_F (24), "f24", N_("Function key 24"), "F24"},
 163     {KEY_A1, "a1", N_("A1 key"), "A1"},
 164     {KEY_C1, "c1", N_("C1 key"), "C1"},
 165 
 166     /* Alternative label */
 167     {ESC_CHAR, "esc", N_("Escape"), "Esc"},
 168     {KEY_BACKSPACE, "bs", N_("Backspace"), "Bakspace"},
 169     {KEY_IC, "ins", N_("Insert"), "Ins"},
 170     {KEY_DC, "del", N_("Delete"), "Del"},
 171     {(int) '*', "asterisk", N_("Asterisk"), "*"},
 172     {(int) '-', "minus", N_("Minus"), "-"},
 173     {(int) '+', "plus", N_("Plus"), "+"},
 174     {(int) '.', "dot", N_("Dot"), "."},
 175     {(int) '<', "lt", N_("Less than"), "<"},
 176     {(int) '>', "gt", N_("Great than"), ">"},
 177     {(int) '=', "equal", N_("Equal"), "="},
 178     {(int) ',', "comma", N_("Comma"), ","},
 179     {(int) '\'', "apostrophe", N_("Apostrophe"), "\'"},
 180     {(int) ':', "colon", N_("Colon"), ":"},
 181     {(int) ';', "semicolon", N_("Semicolon"), ";"},
 182     {(int) '!', "exclamation", N_("Exclamation mark"), "!"},
 183     {(int) '?', "question", N_("Question mark"), "?"},
 184     {(int) '&', "ampersand", N_("Ampersand"), "&"},
 185     {(int) '$', "dollar", N_("Dollar sign"), "$"},
 186     {(int) '"', "quota", N_("Quotation mark"), "\""},
 187     {(int) '%', "percent", N_("Percent sign"), "%"},
 188     {(int) '^', "caret", N_("Caret"), "^"},
 189     {(int) '~', "tilda", N_("Tilda"), "~"},
 190     {(int) '`', "prime", N_("Prime"), "`"},
 191     {(int) '_', "underline", N_("Underline"), "_"},
 192     {(int) '_', "understrike", N_("Understrike"), "_"},
 193     {(int) '|', "pipe", N_("Pipe"), "|"},
 194     {(int) '(', "lparenthesis", N_("Left parenthesis"), "("},
 195     {(int) ')', "rparenthesis", N_("Right parenthesis"), ")"},
 196     {(int) '[', "lbracket", N_("Left bracket"), "["},
 197     {(int) ']', "rbracket", N_("Right bracket"), "]"},
 198     {(int) '{', "lbrace", N_("Left brace"), "{"},
 199     {(int) '}', "rbrace", N_("Right brace"), "}"},
 200     {(int) '\n', "enter", N_("Enter"), "Enter"},
 201     {(int) '\t', "tab", N_("Tab key"), "Tab"},
 202     {(int) ' ', "space", N_("Space key"), "Space"},
 203     {(int) '/', "slash", N_("Slash key"), "/"},
 204     {(int) '\\', "backslash", N_("Backslash key"), "\\"},
 205     {(int) '#', "number", N_("Number sign #"), "#"},
 206     {(int) '#', "hash", N_("Number sign #"), "#"},
 207     /* TRANSLATORS: Please translate as in "at sign" (@). */
 208     {(int) '@', "at", N_("At sign"), "@"},
 209 
 210     /* meta keys */
 211     {KEY_M_CTRL, "control", N_("Ctrl"), "C"},
 212     {KEY_M_CTRL, "ctrl", N_("Ctrl"), "C"},
 213     {KEY_M_ALT, "meta", N_("Alt"), "M"},
 214     {KEY_M_ALT, "alt", N_("Alt"), "M"},
 215     {KEY_M_ALT, "ralt", N_("Alt"), "M"},
 216     {KEY_M_SHIFT, "shift", N_("Shift"), "S"},
 217 
 218     {0, NULL, NULL, NULL}
 219 };
 220 
 221 /*** file scope macro definitions ****************************************************************/
 222 
 223 #define GET_TIME(tv)     (gettimeofday(&tv, (struct timezone *) NULL))
 224 #define DIF_TIME(t1, t2) ((t2.tv_sec  - t1.tv_sec) * 1000 + (t2.tv_usec - t1.tv_usec)/1000)
 225 
 226 /* The maximum sequence length (32 + null terminator) */
 227 #define SEQ_BUFFER_LEN 33
 228 
 229 /*** file scope type declarations ****************************************************************/
 230 
 231 /* Linux console keyboard modifiers */
 232 typedef enum
 233 {
 234     SHIFT_PRESSED = (1 << 0),
 235     ALTR_PRESSED = (1 << 1),
 236     CONTROL_PRESSED = (1 << 2),
 237     ALTL_PRESSED = (1 << 3)
 238 } mod_pressed_t;
 239 
 240 typedef struct key_def
 241 {
 242     char ch;                    /* Holds the matching char code */
 243     int code;                   /* The code returned, valid if child == NULL */
 244     struct key_def *next;
 245     struct key_def *child;      /* sequence continuation */
 246     int action;                 /* optional action to be done. Now used only
 247                                    to mark that we are just after the first
 248                                    Escape */
 249 } key_def;
 250 
 251 typedef struct
 252 {
 253     int code;
 254     const char *seq;
 255     int action;
 256 } key_define_t;
 257 
 258 /* File descriptor monitoring add/remove routines */
 259 typedef struct
 260 {
 261     int fd;
 262     select_fn callback;
 263     void *info;
 264 } select_t;
 265 
 266 typedef enum KeySortType
 267 {
 268     KEY_NOSORT = 0,
 269     KEY_SORTBYNAME,
 270     KEY_SORTBYCODE
 271 } KeySortType;
 272 
 273 #ifdef __QNXNTO__
 274 typedef int (*ph_dv_f) (void *, void *);
 275 typedef int (*ph_ov_f) (void *);
 276 typedef int (*ph_pqc_f) (unsigned short, PhCursorInfo_t *);
 277 #endif
 278 
 279 /*** file scope variables ************************************************************************/
 280 
 281 static key_define_t mc_default_keys[] = {
 282     {ESC_CHAR, ESC_STR, MCKEY_ESCAPE},
 283     {ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION},
 284     {MCKEY_BRACKETED_PASTING_START, ESC_STR "[200~", MCKEY_NOACTION},
 285     {MCKEY_BRACKETED_PASTING_END, ESC_STR "[201~", MCKEY_NOACTION},
 286     {0, NULL, MCKEY_NOACTION},
 287 };
 288 
 289 /* Broken terminfo and termcap databases on xterminals */
 290 static key_define_t xterm_key_defines[] = {
 291     {KEY_F (1), ESC_STR "OP", MCKEY_NOACTION},
 292     {KEY_F (2), ESC_STR "OQ", MCKEY_NOACTION},
 293     {KEY_F (3), ESC_STR "OR", MCKEY_NOACTION},
 294     {KEY_F (4), ESC_STR "OS", MCKEY_NOACTION},
 295     {KEY_F (1), ESC_STR "[11~", MCKEY_NOACTION},
 296     {KEY_F (2), ESC_STR "[12~", MCKEY_NOACTION},
 297     {KEY_F (3), ESC_STR "[13~", MCKEY_NOACTION},
 298     {KEY_F (4), ESC_STR "[14~", MCKEY_NOACTION},
 299     {KEY_F (5), ESC_STR "[15~", MCKEY_NOACTION},
 300     {KEY_F (6), ESC_STR "[17~", MCKEY_NOACTION},
 301     {KEY_F (7), ESC_STR "[18~", MCKEY_NOACTION},
 302     {KEY_F (8), ESC_STR "[19~", MCKEY_NOACTION},
 303     {KEY_F (9), ESC_STR "[20~", MCKEY_NOACTION},
 304     {KEY_F (10), ESC_STR "[21~", MCKEY_NOACTION},
 305 
 306     /* old xterm Shift-arrows */
 307     {KEY_M_SHIFT | KEY_UP, ESC_STR "O2A", MCKEY_NOACTION},
 308     {KEY_M_SHIFT | KEY_DOWN, ESC_STR "O2B", MCKEY_NOACTION},
 309     {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "O2C", MCKEY_NOACTION},
 310     {KEY_M_SHIFT | KEY_LEFT, ESC_STR "O2D", MCKEY_NOACTION},
 311 
 312     /* new xterm Shift-arrows */
 313     {KEY_M_SHIFT | KEY_UP, ESC_STR "[1;2A", MCKEY_NOACTION},
 314     {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[1;2B", MCKEY_NOACTION},
 315     {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[1;2C", MCKEY_NOACTION},
 316     {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[1;2D", MCKEY_NOACTION},
 317 
 318     /* more xterm keys with modifiers */
 319     {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5;5~", MCKEY_NOACTION},
 320     {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6;5~", MCKEY_NOACTION},
 321     {KEY_M_CTRL | KEY_IC, ESC_STR "[2;5~", MCKEY_NOACTION},
 322     {KEY_M_CTRL | KEY_DC, ESC_STR "[3;5~", MCKEY_NOACTION},
 323     {KEY_M_CTRL | KEY_HOME, ESC_STR "[1;5H", MCKEY_NOACTION},
 324     {KEY_M_CTRL | KEY_END, ESC_STR "[1;5F", MCKEY_NOACTION},
 325     {KEY_M_SHIFT | KEY_HOME, ESC_STR "[1;2H", MCKEY_NOACTION},
 326     {KEY_M_SHIFT | KEY_END, ESC_STR "[1;2F", MCKEY_NOACTION},
 327     {KEY_M_CTRL | KEY_UP, ESC_STR "[1;5A", MCKEY_NOACTION},
 328     {KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;5B", MCKEY_NOACTION},
 329     {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;5C", MCKEY_NOACTION},
 330     {KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;5D", MCKEY_NOACTION},
 331     {KEY_M_SHIFT | KEY_IC, ESC_STR "[2;2~", MCKEY_NOACTION},
 332     {KEY_M_SHIFT | KEY_DC, ESC_STR "[3;2~", MCKEY_NOACTION},
 333     {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[1;6A", MCKEY_NOACTION},
 334     {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[1;6B", MCKEY_NOACTION},
 335     {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[1;6C", MCKEY_NOACTION},
 336     {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[1;6D", MCKEY_NOACTION},
 337     {KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION},
 338 
 339     /* putty */
 340     {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[[1;6A", MCKEY_NOACTION},
 341     {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[[1;6B", MCKEY_NOACTION},
 342     {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[[1;6C", MCKEY_NOACTION},
 343     {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[[1;6D", MCKEY_NOACTION},
 344 
 345     /* putty alt-arrow keys */
 346     /* removed as source esc esc esc trouble */
 347     /*
 348        { KEY_M_ALT | KEY_UP,    ESC_STR ESC_STR "OA", MCKEY_NOACTION },
 349        { KEY_M_ALT | KEY_DOWN,  ESC_STR ESC_STR "OB", MCKEY_NOACTION },
 350        { KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "OC", MCKEY_NOACTION },
 351        { KEY_M_ALT | KEY_LEFT,  ESC_STR ESC_STR "OD", MCKEY_NOACTION },
 352        { KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[5~", MCKEY_NOACTION },
 353        { KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[6~", MCKEY_NOACTION },
 354        { KEY_M_ALT | KEY_HOME,  ESC_STR ESC_STR "[1~", MCKEY_NOACTION },
 355        { KEY_M_ALT | KEY_END,   ESC_STR ESC_STR "[4~", MCKEY_NOACTION },
 356 
 357        { KEY_M_CTRL | KEY_M_ALT | KEY_UP,    ESC_STR ESC_STR "[1;2A", MCKEY_NOACTION },
 358        { KEY_M_CTRL | KEY_M_ALT | KEY_DOWN,  ESC_STR ESC_STR "[1;2B", MCKEY_NOACTION },
 359        { KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR ESC_STR "[1;2C", MCKEY_NOACTION },
 360        { KEY_M_CTRL | KEY_M_ALT | KEY_LEFT,  ESC_STR ESC_STR "[1;2D", MCKEY_NOACTION },
 361 
 362        { KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR ESC_STR "[[5;5~", MCKEY_NOACTION },
 363        { KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR ESC_STR "[[6;5~", MCKEY_NOACTION },
 364        { KEY_M_CTRL | KEY_M_ALT | KEY_HOME,  ESC_STR ESC_STR "[1;5H", MCKEY_NOACTION },
 365        { KEY_M_CTRL | KEY_M_ALT | KEY_END,   ESC_STR ESC_STR "[1;5F", MCKEY_NOACTION },
 366      */
 367     /* xterm alt-arrow keys */
 368     {KEY_M_ALT | KEY_UP, ESC_STR "[1;3A", MCKEY_NOACTION},
 369     {KEY_M_ALT | KEY_DOWN, ESC_STR "[1;3B", MCKEY_NOACTION},
 370     {KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;3C", MCKEY_NOACTION},
 371     {KEY_M_ALT | KEY_LEFT, ESC_STR "[1;3D", MCKEY_NOACTION},
 372     {KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;3~", MCKEY_NOACTION},
 373     {KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;3~", MCKEY_NOACTION},
 374     {KEY_M_ALT | KEY_HOME, ESC_STR "[1~", MCKEY_NOACTION},
 375     {KEY_M_ALT | KEY_END, ESC_STR "[4~", MCKEY_NOACTION},
 376     {KEY_M_CTRL | KEY_M_ALT | KEY_UP, ESC_STR "[1;7A", MCKEY_NOACTION},
 377     {KEY_M_CTRL | KEY_M_ALT | KEY_DOWN, ESC_STR "[1;7B", MCKEY_NOACTION},
 378     {KEY_M_CTRL | KEY_M_ALT | KEY_RIGHT, ESC_STR "[1;7C", MCKEY_NOACTION},
 379     {KEY_M_CTRL | KEY_M_ALT | KEY_LEFT, ESC_STR "[1;7D", MCKEY_NOACTION},
 380     {KEY_M_CTRL | KEY_M_ALT | KEY_PPAGE, ESC_STR "[5;7~", MCKEY_NOACTION},
 381     {KEY_M_CTRL | KEY_M_ALT | KEY_NPAGE, ESC_STR "[6;7~", MCKEY_NOACTION},
 382     {KEY_M_CTRL | KEY_M_ALT | KEY_HOME, ESC_STR "OH", MCKEY_NOACTION},
 383     {KEY_M_CTRL | KEY_M_ALT | KEY_END, ESC_STR "OF", MCKEY_NOACTION},
 384 
 385     /* rxvt keys with modifiers */
 386     {KEY_M_SHIFT | KEY_UP, ESC_STR "[a", MCKEY_NOACTION},
 387     {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION},
 388     {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION},
 389     {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION},
 390     {KEY_M_CTRL | KEY_UP, ESC_STR "Oa", MCKEY_NOACTION},
 391     {KEY_M_CTRL | KEY_DOWN, ESC_STR "Ob", MCKEY_NOACTION},
 392     {KEY_M_CTRL | KEY_RIGHT, ESC_STR "Oc", MCKEY_NOACTION},
 393     {KEY_M_CTRL | KEY_LEFT, ESC_STR "Od", MCKEY_NOACTION},
 394     {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[5^", MCKEY_NOACTION},
 395     {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[6^", MCKEY_NOACTION},
 396     {KEY_M_CTRL | KEY_HOME, ESC_STR "[7^", MCKEY_NOACTION},
 397     {KEY_M_CTRL | KEY_END, ESC_STR "[8^", MCKEY_NOACTION},
 398     {KEY_M_SHIFT | KEY_HOME, ESC_STR "[7$", MCKEY_NOACTION},
 399     {KEY_M_SHIFT | KEY_END, ESC_STR "[8$", MCKEY_NOACTION},
 400     {KEY_M_CTRL | KEY_IC, ESC_STR "[2^", MCKEY_NOACTION},
 401     {KEY_M_CTRL | KEY_DC, ESC_STR "[3^", MCKEY_NOACTION},
 402     {KEY_M_SHIFT | KEY_DC, ESC_STR "[3$", MCKEY_NOACTION},
 403 
 404     /* konsole keys with modifiers */
 405     {KEY_M_SHIFT | KEY_HOME, ESC_STR "O2H", MCKEY_NOACTION},
 406     {KEY_M_SHIFT | KEY_END, ESC_STR "O2F", MCKEY_NOACTION},
 407 
 408     /* gnome-terminal */
 409     {KEY_M_SHIFT | KEY_UP, ESC_STR "[2A", MCKEY_NOACTION},
 410     {KEY_M_SHIFT | KEY_DOWN, ESC_STR "[2B", MCKEY_NOACTION},
 411     {KEY_M_SHIFT | KEY_RIGHT, ESC_STR "[2C", MCKEY_NOACTION},
 412     {KEY_M_SHIFT | KEY_LEFT, ESC_STR "[2D", MCKEY_NOACTION},
 413     {KEY_M_CTRL | KEY_UP, ESC_STR "[5A", MCKEY_NOACTION},
 414     {KEY_M_CTRL | KEY_DOWN, ESC_STR "[5B", MCKEY_NOACTION},
 415     {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[5C", MCKEY_NOACTION},
 416     {KEY_M_CTRL | KEY_LEFT, ESC_STR "[5D", MCKEY_NOACTION},
 417     {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "[6A", MCKEY_NOACTION},
 418     {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "[6B", MCKEY_NOACTION},
 419     {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "[6C", MCKEY_NOACTION},
 420     {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "[6D", MCKEY_NOACTION},
 421 
 422     /* gnome-terminal - application mode */
 423     {KEY_M_CTRL | KEY_UP, ESC_STR "O5A", MCKEY_NOACTION},
 424     {KEY_M_CTRL | KEY_DOWN, ESC_STR "O5B", MCKEY_NOACTION},
 425     {KEY_M_CTRL | KEY_RIGHT, ESC_STR "O5C", MCKEY_NOACTION},
 426     {KEY_M_CTRL | KEY_LEFT, ESC_STR "O5D", MCKEY_NOACTION},
 427     {KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, ESC_STR "O6A", MCKEY_NOACTION},
 428     {KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, ESC_STR "O6B", MCKEY_NOACTION},
 429     {KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, ESC_STR "O6C", MCKEY_NOACTION},
 430     {KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, ESC_STR "O6D", MCKEY_NOACTION},
 431 
 432     /* iTerm */
 433     {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[5;2~", MCKEY_NOACTION},
 434     {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[6;2~", MCKEY_NOACTION},
 435 
 436     /* putty */
 437     {KEY_M_SHIFT | KEY_PPAGE, ESC_STR "[[5;53~", MCKEY_NOACTION},
 438     {KEY_M_SHIFT | KEY_NPAGE, ESC_STR "[[6;53~", MCKEY_NOACTION},
 439 
 440     /* keypad keys */
 441     {KEY_IC, ESC_STR "Op", MCKEY_NOACTION},
 442     {KEY_DC, ESC_STR "On", MCKEY_NOACTION},
 443     {'/', ESC_STR "Oo", MCKEY_NOACTION},
 444     {'\n', ESC_STR "OM", MCKEY_NOACTION},
 445 
 446     {0, NULL, MCKEY_NOACTION},
 447 };
 448 
 449 /* qansi-m terminals have a much more key combinatios,
 450    which are undefined in termcap/terminfo */
 451 static key_define_t qansi_key_defines[] = {
 452     /* qansi-m terminal */
 453     {KEY_M_CTRL | KEY_NPAGE, ESC_STR "[u", MCKEY_NOACTION},     /* Ctrl-PgDown */
 454     {KEY_M_CTRL | KEY_PPAGE, ESC_STR "[v", MCKEY_NOACTION},     /* Ctrl-PgUp   */
 455     {KEY_M_CTRL | KEY_HOME, ESC_STR "[h", MCKEY_NOACTION},      /* Ctrl-Home   */
 456     {KEY_M_CTRL | KEY_END, ESC_STR "[y", MCKEY_NOACTION},       /* Ctrl-End    */
 457     {KEY_M_CTRL | KEY_IC, ESC_STR "[`", MCKEY_NOACTION},        /* Ctrl-Insert */
 458     {KEY_M_CTRL | KEY_DC, ESC_STR "[p", MCKEY_NOACTION},        /* Ctrl-Delete */
 459     {KEY_M_CTRL | KEY_LEFT, ESC_STR "[d", MCKEY_NOACTION},      /* Ctrl-Left   */
 460     {KEY_M_CTRL | KEY_RIGHT, ESC_STR "[c", MCKEY_NOACTION},     /* Ctrl-Right  */
 461     {KEY_M_CTRL | KEY_DOWN, ESC_STR "[b", MCKEY_NOACTION},      /* Ctrl-Down   */
 462     {KEY_M_CTRL | KEY_UP, ESC_STR "[a", MCKEY_NOACTION},        /* Ctrl-Up     */
 463     {KEY_M_CTRL | KEY_KP_ADD, ESC_STR "[s", MCKEY_NOACTION},    /* Ctrl-Gr-Plus */
 464     {KEY_M_CTRL | KEY_KP_SUBTRACT, ESC_STR "[t", MCKEY_NOACTION},       /* Ctrl-Gr-Minus */
 465     {KEY_M_CTRL | '\t', ESC_STR "[z", MCKEY_NOACTION},  /* Ctrl-Tab    */
 466     {KEY_M_SHIFT | '\t', ESC_STR "[Z", MCKEY_NOACTION}, /* Shift-Tab   */
 467     {KEY_M_CTRL | KEY_F (1), ESC_STR "[1~", MCKEY_NOACTION},    /* Ctrl-F1    */
 468     {KEY_M_CTRL | KEY_F (2), ESC_STR "[2~", MCKEY_NOACTION},    /* Ctrl-F2    */
 469     {KEY_M_CTRL | KEY_F (3), ESC_STR "[3~", MCKEY_NOACTION},    /* Ctrl-F3    */
 470     {KEY_M_CTRL | KEY_F (4), ESC_STR "[4~", MCKEY_NOACTION},    /* Ctrl-F4    */
 471     {KEY_M_CTRL | KEY_F (5), ESC_STR "[5~", MCKEY_NOACTION},    /* Ctrl-F5    */
 472     {KEY_M_CTRL | KEY_F (6), ESC_STR "[6~", MCKEY_NOACTION},    /* Ctrl-F6    */
 473     {KEY_M_CTRL | KEY_F (7), ESC_STR "[7~", MCKEY_NOACTION},    /* Ctrl-F7    */
 474     {KEY_M_CTRL | KEY_F (8), ESC_STR "[8~", MCKEY_NOACTION},    /* Ctrl-F8    */
 475     {KEY_M_CTRL | KEY_F (9), ESC_STR "[9~", MCKEY_NOACTION},    /* Ctrl-F9    */
 476     {KEY_M_CTRL | KEY_F (10), ESC_STR "[10~", MCKEY_NOACTION},  /* Ctrl-F10  */
 477     {KEY_M_CTRL | KEY_F (11), ESC_STR "[11~", MCKEY_NOACTION},  /* Ctrl-F11  */
 478     {KEY_M_CTRL | KEY_F (12), ESC_STR "[12~", MCKEY_NOACTION},  /* Ctrl-F12  */
 479     {KEY_M_ALT | KEY_F (1), ESC_STR "[17~", MCKEY_NOACTION},    /* Alt-F1    */
 480     {KEY_M_ALT | KEY_F (2), ESC_STR "[18~", MCKEY_NOACTION},    /* Alt-F2    */
 481     {KEY_M_ALT | KEY_F (3), ESC_STR "[19~", MCKEY_NOACTION},    /* Alt-F3    */
 482     {KEY_M_ALT | KEY_F (4), ESC_STR "[20~", MCKEY_NOACTION},    /* Alt-F4    */
 483     {KEY_M_ALT | KEY_F (5), ESC_STR "[21~", MCKEY_NOACTION},    /* Alt-F5    */
 484     {KEY_M_ALT | KEY_F (6), ESC_STR "[22~", MCKEY_NOACTION},    /* Alt-F6    */
 485     {KEY_M_ALT | KEY_F (7), ESC_STR "[23~", MCKEY_NOACTION},    /* Alt-F7    */
 486     {KEY_M_ALT | KEY_F (8), ESC_STR "[24~", MCKEY_NOACTION},    /* Alt-F8    */
 487     {KEY_M_ALT | KEY_F (9), ESC_STR "[25~", MCKEY_NOACTION},    /* Alt-F9    */
 488     {KEY_M_ALT | KEY_F (10), ESC_STR "[26~", MCKEY_NOACTION},   /* Alt-F10   */
 489     {KEY_M_ALT | KEY_F (11), ESC_STR "[27~", MCKEY_NOACTION},   /* Alt-F11   */
 490     {KEY_M_ALT | KEY_F (12), ESC_STR "[28~", MCKEY_NOACTION},   /* Alt-F12   */
 491     {KEY_M_ALT | 'a', ESC_STR "Na", MCKEY_NOACTION},    /* Alt-a     */
 492     {KEY_M_ALT | 'b', ESC_STR "Nb", MCKEY_NOACTION},    /* Alt-b     */
 493     {KEY_M_ALT | 'c', ESC_STR "Nc", MCKEY_NOACTION},    /* Alt-c     */
 494     {KEY_M_ALT | 'd', ESC_STR "Nd", MCKEY_NOACTION},    /* Alt-d     */
 495     {KEY_M_ALT | 'e', ESC_STR "Ne", MCKEY_NOACTION},    /* Alt-e     */
 496     {KEY_M_ALT | 'f', ESC_STR "Nf", MCKEY_NOACTION},    /* Alt-f     */
 497     {KEY_M_ALT | 'g', ESC_STR "Ng", MCKEY_NOACTION},    /* Alt-g     */
 498     {KEY_M_ALT | 'h', ESC_STR "Nh", MCKEY_NOACTION},    /* Alt-h     */
 499     {KEY_M_ALT | 'i', ESC_STR "Ni", MCKEY_NOACTION},    /* Alt-i     */
 500     {KEY_M_ALT | 'j', ESC_STR "Nj", MCKEY_NOACTION},    /* Alt-j     */
 501     {KEY_M_ALT | 'k', ESC_STR "Nk", MCKEY_NOACTION},    /* Alt-k     */
 502     {KEY_M_ALT | 'l', ESC_STR "Nl", MCKEY_NOACTION},    /* Alt-l     */
 503     {KEY_M_ALT | 'm', ESC_STR "Nm", MCKEY_NOACTION},    /* Alt-m     */
 504     {KEY_M_ALT | 'n', ESC_STR "Nn", MCKEY_NOACTION},    /* Alt-n     */
 505     {KEY_M_ALT | 'o', ESC_STR "No", MCKEY_NOACTION},    /* Alt-o     */
 506     {KEY_M_ALT | 'p', ESC_STR "Np", MCKEY_NOACTION},    /* Alt-p     */
 507     {KEY_M_ALT | 'q', ESC_STR "Nq", MCKEY_NOACTION},    /* Alt-q     */
 508     {KEY_M_ALT | 'r', ESC_STR "Nr", MCKEY_NOACTION},    /* Alt-r     */
 509     {KEY_M_ALT | 's', ESC_STR "Ns", MCKEY_NOACTION},    /* Alt-s     */
 510     {KEY_M_ALT | 't', ESC_STR "Nt", MCKEY_NOACTION},    /* Alt-t     */
 511     {KEY_M_ALT | 'u', ESC_STR "Nu", MCKEY_NOACTION},    /* Alt-u     */
 512     {KEY_M_ALT | 'v', ESC_STR "Nv", MCKEY_NOACTION},    /* Alt-v     */
 513     {KEY_M_ALT | 'w', ESC_STR "Nw", MCKEY_NOACTION},    /* Alt-w     */
 514     {KEY_M_ALT | 'x', ESC_STR "Nx", MCKEY_NOACTION},    /* Alt-x     */
 515     {KEY_M_ALT | 'y', ESC_STR "Ny", MCKEY_NOACTION},    /* Alt-y     */
 516     {KEY_M_ALT | 'z', ESC_STR "Nz", MCKEY_NOACTION},    /* Alt-z     */
 517     {KEY_KP_SUBTRACT, ESC_STR "[S", MCKEY_NOACTION},    /* Gr-Minus  */
 518     {KEY_KP_ADD, ESC_STR "[T", MCKEY_NOACTION}, /* Gr-Plus   */
 519     {0, NULL, MCKEY_NOACTION},
 520 };
 521 
 522 /* This holds all the key definitions */
 523 static key_def *keys = NULL;
 524 
 525 static int input_fd;
 526 static int disabled_channels = 0;       /* Disable channels checking */
 527 
 528 static GSList *select_list = NULL;
 529 
 530 static int seq_buffer[SEQ_BUFFER_LEN];
 531 static int *seq_append = NULL;
 532 
 533 static int *pending_keys = NULL;
 534 
 535 #ifdef __QNXNTO__
 536 ph_dv_f ph_attach;
 537 ph_ov_f ph_input_group;
 538 ph_pqc_f ph_query_cursor;
 539 #endif
 540 
 541 #ifdef HAVE_TEXTMODE_X11_SUPPORT
 542 static Display *x11_display;
 543 static Window x11_window;
 544 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
 545 
 546 static KeySortType has_been_sorted = KEY_NOSORT;
 547 
 548 /* *INDENT-OFF* */
 549 static const size_t key_conv_tab_size = G_N_ELEMENTS (key_name_conv_tab) - 1;
 550 /* *INDENT-ON* */
 551 
 552 static const key_code_name_t *key_conv_tab_sorted[G_N_ELEMENTS (key_name_conv_tab) - 1];
 553 
 554 /* --------------------------------------------------------------------------------------------- */
 555 /*** file scope functions ************************************************************************/
 556 /* --------------------------------------------------------------------------------------------- */
 557 
 558 static int
 559 select_cmp_by_fd_set (gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 560 {
 561     const select_t *s = (const select_t *) a;
 562     const fd_set *f = (const fd_set *) b;
 563 
 564     return (FD_ISSET (s->fd, f) ? 0 : 1);
 565 }
 566 
 567 /* --------------------------------------------------------------------------------------------- */
 568 
 569 static int
 570 select_cmp_by_fd (gconstpointer a, gconstpointer b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 571 {
 572     const select_t *s = (const select_t *) a;
 573     const int fd = GPOINTER_TO_INT (b);
 574 
 575     return (s->fd == fd ? 0 : 1);
 576 }
 577 
 578 /* --------------------------------------------------------------------------------------------- */
 579 
 580 static int
 581 add_selects (fd_set * select_set)
     /* [previous][next][first][last][top][bottom][index][help]  */
 582 {
 583     int top_fd = 0;
 584 
 585     if (disabled_channels == 0)
 586     {
 587         GSList *s;
 588 
 589         for (s = select_list; s != NULL; s = g_slist_next (s))
 590         {
 591             select_t *p = (select_t *) s->data;
 592 
 593             FD_SET (p->fd, select_set);
 594             if (p->fd > top_fd)
 595                 top_fd = p->fd;
 596         }
 597     }
 598 
 599     return top_fd;
 600 }
 601 
 602 /* --------------------------------------------------------------------------------------------- */
 603 
 604 static void
 605 check_selects (fd_set * select_set)
     /* [previous][next][first][last][top][bottom][index][help]  */
 606 {
 607     while (disabled_channels == 0)
 608     {
 609         GSList *s;
 610         select_t *p;
 611 
 612         s = g_slist_find_custom (select_list, select_set, select_cmp_by_fd_set);
 613         if (s == NULL)
 614             break;
 615 
 616         p = (select_t *) s->data;
 617         FD_CLR (p->fd, select_set);
 618         p->callback (p->fd, p->info);
 619     }
 620 }
 621 
 622 /* --------------------------------------------------------------------------------------------- */
 623 /* If set timeout is set, then we wait 0.1 seconds, else, we block */
 624 
 625 static void
 626 try_channels (gboolean set_timeout)
     /* [previous][next][first][last][top][bottom][index][help]  */
 627 {
 628     struct timeval time_out;
 629     static fd_set select_set;
 630 
 631     while (TRUE)
 632     {
 633         struct timeval *timeptr = NULL;
 634         int maxfdp, v;
 635 
 636         FD_ZERO (&select_set);
 637         FD_SET (input_fd, &select_set); /* Add stdin */
 638         maxfdp = MAX (add_selects (&select_set), input_fd);
 639 
 640         if (set_timeout)
 641         {
 642             time_out.tv_sec = 0;
 643             time_out.tv_usec = 100000;
 644             timeptr = &time_out;
 645         }
 646 
 647         v = select (maxfdp + 1, &select_set, NULL, NULL, timeptr);
 648         if (v > 0)
 649         {
 650             check_selects (&select_set);
 651             if (FD_ISSET (input_fd, &select_set))
 652                 break;
 653         }
 654     }
 655 }
 656 
 657 /* --------------------------------------------------------------------------------------------- */
 658 
 659 static key_def *
 660 create_sequence (const char *seq, int code, int action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 661 {
 662     key_def *base, *p, *attach;
 663 
 664     for (base = attach = NULL; *seq != '\0'; seq++)
 665     {
 666         p = g_new (key_def, 1);
 667         if (base == NULL)
 668             base = p;
 669         if (attach != NULL)
 670             attach->child = p;
 671 
 672         p->ch = *seq;
 673         p->code = code;
 674         p->child = p->next = NULL;
 675         if (seq[1] == '\0')
 676             p->action = action;
 677         else
 678             p->action = MCKEY_NOACTION;
 679         attach = p;
 680     }
 681     return base;
 682 }
 683 
 684 /* --------------------------------------------------------------------------------------------- */
 685 
 686 static void
 687 define_sequences (const key_define_t * kd)
     /* [previous][next][first][last][top][bottom][index][help]  */
 688 {
 689     int i;
 690 
 691     for (i = 0; kd[i].code != 0; i++)
 692         define_sequence (kd[i].code, kd[i].seq, kd[i].action);
 693 }
 694 
 695 /* --------------------------------------------------------------------------------------------- */
 696 
 697 #ifdef HAVE_TEXTMODE_X11_SUPPORT
 698 static void
 699 init_key_x11 (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 700 {
 701     if (getenv ("DISPLAY") != NULL && !mc_global.tty.disable_x11)
 702     {
 703         x11_display = mc_XOpenDisplay (0);
 704 
 705         if (x11_display != NULL)
 706             x11_window = DefaultRootWindow (x11_display);
 707     }
 708 }
 709 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
 710 
 711 /* --------------------------------------------------------------------------------------------- */
 712 /* Workaround for System V Curses vt100 bug */
 713 
 714 static int
 715 getch_with_delay (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 716 {
 717     int c;
 718 
 719     /* This routine could be used on systems without mouse support,
 720        so we need to do the select check :-( */
 721     while (TRUE)
 722     {
 723         if (pending_keys == NULL)
 724             try_channels (FALSE);
 725 
 726         /* Try to get a character */
 727         c = get_key_code (0);
 728         if (c != -1)
 729             break;
 730 
 731         /* Failed -> wait 0.1 secs and try again */
 732         try_channels (TRUE);
 733     }
 734 
 735     /* Success -> return the character */
 736     return c;
 737 }
 738 
 739 /* --------------------------------------------------------------------------------------------- */
 740 
 741 static void
 742 xmouse_get_event (Gpm_Event * ev, gboolean extended)
     /* [previous][next][first][last][top][bottom][index][help]  */
 743 {
 744     static struct timeval tv1 = { 0, 0 };       /* Force first click as single */
 745     static struct timeval tv2;
 746     static int clicks = 0;
 747     static int last_btn = 0;
 748     int btn;
 749 
 750     /* Decode Xterm mouse information to a GPM style event */
 751 
 752     if (!extended)
 753     {
 754         /* Variable btn has following meaning: */
 755         /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
 756         btn = tty_lowlevel_getch () - 32;
 757         /* Coordinates are 33-based */
 758         /* Transform them to 1-based */
 759         ev->x = tty_lowlevel_getch () - 32;
 760         ev->y = tty_lowlevel_getch () - 32;
 761     }
 762     else
 763     {
 764         /* SGR 1006 extension (e.g. "\e[<0;12;300M"):
 765            - Numbers are encoded in decimal to make it ASCII-safe
 766            and to overcome the limit of 223 columns/rows.
 767            - Mouse release is encoded by trailing 'm' rather than 'M'
 768            so that the released button can be reported.
 769            - Numbers are no longer offset by 32. */
 770         char c;
 771 
 772         btn = ev->x = ev->y = 0;
 773         ev->type = 0;           /* In case we return on an invalid sequence */
 774 
 775         while ((c = tty_lowlevel_getch ()) != ';')
 776         {
 777             if (c < '0' || c > '9')
 778                 return;
 779             btn = 10 * btn + (c - '0');
 780         }
 781         while ((c = tty_lowlevel_getch ()) != ';')
 782         {
 783             if (c < '0' || c > '9')
 784                 return;
 785             ev->x = 10 * ev->x + (c - '0');
 786         }
 787         while ((c = tty_lowlevel_getch ()) != 'M' && c != 'm')
 788         {
 789             if (c < '0' || c > '9')
 790                 return;
 791             ev->y = 10 * ev->y + (c - '0');
 792         }
 793         /* Legacy mouse protocol doesn't tell which button was released,
 794            conveniently all of mc's widgets are written not to rely on this
 795            information. With the SGR extension the released button becomes
 796            known, but for the sake of simplicity we just ignore it. */
 797         if (c == 'm')
 798             btn = 3;
 799     }
 800 
 801     /* There seems to be no way of knowing which button was released */
 802     /* So we assume all the buttons were released */
 803 
 804     if (btn == 3)
 805     {
 806         if (last_btn != 0)
 807         {
 808             if ((last_btn & (GPM_B_UP | GPM_B_DOWN)) != 0)
 809             {
 810                 /* FIXME: DIRTY HACK */
 811                 /* don't generate GPM_UP after mouse wheel */
 812                 /* need for menu event handling */
 813                 ev->type = 0;
 814                 tv1.tv_sec = 0;
 815                 tv1.tv_usec = 0;
 816             }
 817             else
 818             {
 819                 ev->type = GPM_UP | (GPM_SINGLE << clicks);
 820                 GET_TIME (tv1);
 821             }
 822             ev->buttons = 0;
 823             last_btn = 0;
 824             clicks = 0;
 825         }
 826         else
 827         {
 828             /* Bogus event, maybe mouse wheel */
 829             ev->type = 0;
 830         }
 831     }
 832     else
 833     {
 834         if (btn >= 32 && btn <= 34)
 835         {
 836             btn -= 32;
 837             ev->type = GPM_DRAG;
 838         }
 839         else
 840             ev->type = GPM_DOWN;
 841 
 842         GET_TIME (tv2);
 843         if (tv1.tv_sec != 0 && DIF_TIME (tv1, tv2) < double_click_speed)
 844         {
 845             clicks++;
 846             clicks %= 3;
 847         }
 848         else
 849             clicks = 0;
 850 
 851         switch (btn)
 852         {
 853         case 0:
 854             ev->buttons = GPM_B_LEFT;
 855             break;
 856         case 1:
 857             ev->buttons = GPM_B_MIDDLE;
 858             break;
 859         case 2:
 860             ev->buttons = GPM_B_RIGHT;
 861             break;
 862         case 64:
 863             ev->buttons = GPM_B_UP;
 864             clicks = 0;
 865             break;
 866         case 65:
 867             ev->buttons = GPM_B_DOWN;
 868             clicks = 0;
 869             break;
 870         default:
 871             /* Nothing */
 872             ev->type = 0;
 873             ev->buttons = 0;
 874             break;
 875         }
 876         last_btn = ev->buttons;
 877     }
 878 }
 879 
 880 /* --------------------------------------------------------------------------------------------- */
 881 /**
 882  * Get modifier state (shift, alt, ctrl) for the last key pressed.
 883  * We are assuming that the state didn't change since the key press.
 884  * This is only correct if get_modifier() is called very fast after
 885  * the input was received, so that the user didn't release the
 886  * modifier keys yet.
 887  */
 888 
 889 static int
 890 get_modifier (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 891 {
 892     int result = 0;
 893 #ifdef __QNXNTO__
 894     static int in_photon = 0;
 895     static int ph_ig = 0;
 896 #endif /* __QNXNTO__ */
 897 
 898 #ifdef HAVE_TEXTMODE_X11_SUPPORT
 899     if (x11_window != 0)
 900     {
 901         Window root, child;
 902         int root_x, root_y;
 903         int win_x, win_y;
 904         unsigned int mask;
 905 
 906         mc_XQueryPointer (x11_display, x11_window, &root, &child, &root_x,
 907                           &root_y, &win_x, &win_y, &mask);
 908 
 909         if ((mask & ShiftMask) != 0)
 910             result |= KEY_M_SHIFT;
 911         if ((mask & ControlMask) != 0)
 912             result |= KEY_M_CTRL;
 913         return result;
 914     }
 915 #endif /* HAVE_TEXTMODE_X11_SUPPORT */
 916 
 917 #ifdef __QNXNTO__
 918     if (in_photon == 0)
 919     {
 920         /* First time here, let's load Photon library and attach to Photon */
 921         in_photon = -1;
 922 
 923         if (getenv ("PHOTON2_PATH") != NULL)
 924         {
 925             /* QNX 6.x has no support for RTLD_LAZY */
 926             void *ph_handle;
 927 
 928             ph_handle = dlopen ("/usr/lib/libph.so", RTLD_NOW);
 929             if (ph_handle != NULL)
 930             {
 931                 ph_attach = (ph_dv_f) dlsym (ph_handle, "PhAttach");
 932                 ph_input_group = (ph_ov_f) dlsym (ph_handle, "PhInputGroup");
 933                 ph_query_cursor = (ph_pqc_f) dlsym (ph_handle, "PhQueryCursor");
 934                 if ((ph_attach != NULL) && (ph_input_group != NULL) && (ph_query_cursor != NULL)
 935                     && (*ph_attach) (0, 0) != NULL)
 936                 {
 937                     /* Attached */
 938                     ph_ig = (*ph_input_group) (0);
 939                     in_photon = 1;
 940                 }
 941             }
 942         }
 943     }
 944     /* We do not have Photon running. Assume we are in text console or xterm */
 945     if (in_photon == -1)
 946     {
 947         int mod_status;
 948         int shift_ext_status;
 949 
 950         if (devctl (fileno (stdin), DCMD_CHR_LINESTATUS, &mod_status, sizeof (mod_status), NULL) ==
 951             -1)
 952             return 0;
 953 
 954         shift_ext_status = mod_status & 0xffffff00UL;
 955         mod_status &= 0x7f;
 956         if ((mod_status & _LINESTATUS_CON_ALT) != 0)
 957             result |= KEY_M_ALT;
 958         if ((mod_status & _LINESTATUS_CON_CTRL) != 0)
 959             result |= KEY_M_CTRL;
 960         if ((mod_status & _LINESTATUS_CON_SHIFT) != 0 || (shift_ext_status & 0x00000800UL) != 0)
 961             result |= KEY_M_SHIFT;
 962     }
 963     else
 964     {
 965         PhCursorInfo_t cursor_info;
 966 
 967         (*ph_query_cursor) (ph_ig, &cursor_info);
 968         if ((cursor_info.key_mods & 0x04) != 0)
 969             result |= KEY_M_ALT;
 970         if ((cursor_info.key_mods & 0x02) != 0)
 971             result |= KEY_M_CTRL;
 972         if ((cursor_info.key_mods & 0x01) != 0)
 973             result |= KEY_M_SHIFT;
 974     }
 975 #endif /* __QNXNTO__ */
 976 
 977 #if defined __linux__ || (defined __CYGWIN__ && defined TIOCLINUX)
 978     {
 979         unsigned char modifiers = 6;
 980 
 981         if (ioctl (0, TIOCLINUX, &modifiers) < 0)
 982             return 0;
 983 
 984         /* Translate Linux modifiers into mc modifiers */
 985         if ((modifiers & SHIFT_PRESSED) != 0)
 986             result |= KEY_M_SHIFT;
 987         if ((modifiers & (ALTL_PRESSED | ALTR_PRESSED)) != 0)
 988             result |= KEY_M_ALT;
 989         if ((modifiers & CONTROL_PRESSED) != 0)
 990             result |= KEY_M_CTRL;
 991     }
 992 #endif /* !__linux__ */
 993 
 994     return result;
 995 }
 996 
 997 /* --------------------------------------------------------------------------------------------- */
 998 
 999 static gboolean
1000 push_char (int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
1001 {
1002     gboolean ret = FALSE;
1003 
1004     if (seq_append == NULL)
1005         seq_append = seq_buffer;
1006 
1007     if (seq_append != &(seq_buffer[SEQ_BUFFER_LEN - 2]))
1008     {
1009         *(seq_append++) = c;
1010         *seq_append = '\0';
1011         ret = TRUE;
1012     }
1013 
1014     return ret;
1015 }
1016 
1017 /* --------------------------------------------------------------------------------------------- */
1018 /* Apply corrections for the keycode generated in get_key_code() */
1019 
1020 static int
1021 correct_key_code (int code)
     /* [previous][next][first][last][top][bottom][index][help]  */
1022 {
1023     unsigned int c = code & ~KEY_M_MASK;        /* code without modifier */
1024     unsigned int mod = code & KEY_M_MASK;       /* modifier */
1025 #ifdef __QNXNTO__
1026     unsigned int qmod;          /* bunch of the QNX console
1027                                    modifiers needs unchanged */
1028 #endif /* __QNXNTO__ */
1029 
1030     /*
1031      * Add key modifiers directly from X11 or OS.
1032      * Ordinary characters only get modifiers from sequences.
1033      */
1034     if (c < 32 || c >= 256)
1035         mod |= get_modifier ();
1036 
1037     /* This is needed if the newline is reported as carriage return */
1038     if (c == '\r')
1039         c = '\n';
1040 
1041     /* This is reported to be useful on AIX */
1042     if (c == KEY_SCANCEL)
1043         c = '\t';
1044 
1045     /* Convert Back Tab to Shift+Tab */
1046     if (c == KEY_BTAB)
1047     {
1048         c = '\t';
1049         mod = KEY_M_SHIFT;
1050     }
1051 
1052     /* F0 is the same as F10 for out purposes */
1053     if (c == KEY_F (0))
1054         c = KEY_F (10);
1055 
1056     /*
1057      * We are not interested if Ctrl was pressed when entering control
1058      * characters, so assume that it was.  When checking for such keys,
1059      * XCTRL macro should be used.  In some cases, we are interested,
1060      * e.g. to distinguish Ctrl-Enter from Enter.
1061      */
1062     if (c == '\b')
1063     {
1064         /* Special case for backspase ('\b' < 32) */
1065         c = KEY_BACKSPACE;
1066         mod &= ~KEY_M_CTRL;
1067     }
1068     else if (c < 32 && c != ESC_CHAR && c != '\t' && c != '\n')
1069         mod |= KEY_M_CTRL;
1070 
1071 #ifdef __QNXNTO__
1072     qmod = get_modifier ();
1073 
1074     if (c == 127 && mod == 0)
1075     {
1076         /* Add Ctrl/Alt/Shift-BackSpace */
1077         mod |= get_modifier ();
1078         c = KEY_BACKSPACE;
1079     }
1080 
1081     if (c == '0' && mod == 0 && (qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1082     {
1083         /* Add Shift-Insert on key pad */
1084         mod = KEY_M_SHIFT;
1085         c = KEY_IC;
1086     }
1087 
1088     if (c == '.' && mod == 0 && (qmod & KEY_M_SHIFT) == KEY_M_SHIFT)
1089     {
1090         /* Add Shift-Del on key pad */
1091         mod = KEY_M_SHIFT;
1092         c = KEY_DC;
1093     }
1094 #endif /* __QNXNTO__ */
1095 
1096     /* Unrecognized 0177 is delete (preserve Ctrl) */
1097     if (c == 0177)
1098         c = KEY_BACKSPACE;
1099 
1100 #if 0
1101     /* Unrecognized Ctrl-d is delete */
1102     if (c == 'd' & 31)
1103     {
1104         c = KEY_DC;
1105         mod &= ~KEY_M_CTRL;
1106     }
1107 
1108     /* Unrecognized Ctrl-h is backspace */
1109     if (c == 'h' & 31)
1110     {
1111         c = KEY_BACKSPACE;
1112         mod &= ~KEY_M_CTRL;
1113     }
1114 #endif
1115 
1116     /* Shift+BackSpace is backspace */
1117     if (c == KEY_BACKSPACE && (mod & KEY_M_SHIFT) != 0)
1118         mod &= ~KEY_M_SHIFT;
1119 
1120     /* Convert Shift+Fn to F(n+10) */
1121     if (c >= KEY_F (1) && c <= KEY_F (10) && (mod & KEY_M_SHIFT) != 0)
1122         c += 10;
1123 
1124     /* Remove Shift information from function keys */
1125     if (c >= KEY_F (1) && c <= KEY_F (20))
1126         mod &= ~KEY_M_SHIFT;
1127 
1128     if (!mc_global.tty.alternate_plus_minus)
1129         switch (c)
1130         {
1131         case KEY_KP_ADD:
1132             c = '+';
1133             break;
1134         case KEY_KP_SUBTRACT:
1135             c = '-';
1136             break;
1137         case KEY_KP_MULTIPLY:
1138             c = '*';
1139             break;
1140         default:
1141             break;
1142         }
1143 
1144     return (mod | c);
1145 }
1146 
1147 /* --------------------------------------------------------------------------------------------- */
1148 
1149 static int
1150 getch_with_timeout (unsigned int delay_us)
     /* [previous][next][first][last][top][bottom][index][help]  */
1151 {
1152     fd_set Read_FD_Set;
1153     int c;
1154     struct timeval time_out;
1155 
1156     time_out.tv_sec = delay_us / 1000000u;
1157     time_out.tv_usec = delay_us % 1000000u;
1158     tty_nodelay (TRUE);
1159     FD_ZERO (&Read_FD_Set);
1160     FD_SET (input_fd, &Read_FD_Set);
1161     select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
1162     c = tty_lowlevel_getch ();
1163     tty_nodelay (FALSE);
1164     return c;
1165 }
1166 
1167 /* --------------------------------------------------------------------------------------------- */
1168 
1169 static void
1170 learn_store_key (char *buffer, char **p, int c)
     /* [previous][next][first][last][top][bottom][index][help]  */
1171 {
1172     if (*p - buffer > 253)
1173         return;
1174 
1175     if (c == ESC_CHAR)
1176     {
1177         *(*p)++ = '\\';
1178         *(*p)++ = 'e';
1179     }
1180     else if (c < ' ')
1181     {
1182         *(*p)++ = '^';
1183         *(*p)++ = c + 'a' - 1;
1184     }
1185     else if (c == '^')
1186     {
1187         *(*p)++ = '^';
1188         *(*p)++ = '^';
1189     }
1190     else
1191         *(*p)++ = (char) c;
1192 }
1193 
1194 /* --------------------------------------------------------------------------------------------- */
1195 
1196 static void
1197 k_dispose (key_def * k)
     /* [previous][next][first][last][top][bottom][index][help]  */
1198 {
1199     if (k != NULL)
1200     {
1201         k_dispose (k->child);
1202         k_dispose (k->next);
1203         g_free (k);
1204     }
1205 }
1206 
1207 /* --------------------------------------------------------------------------------------------- */
1208 
1209 static int
1210 key_code_comparator_by_name (const void *p1, const void *p2)
     /* [previous][next][first][last][top][bottom][index][help]  */
1211 {
1212     const key_code_name_t *n1 = *(const key_code_name_t * const *) p1;
1213     const key_code_name_t *n2 = *(const key_code_name_t * const *) p2;
1214 
1215     return g_ascii_strcasecmp (n1->name, n2->name);
1216 }
1217 
1218 /* --------------------------------------------------------------------------------------------- */
1219 
1220 static int
1221 key_code_comparator_by_code (const void *p1, const void *p2)
     /* [previous][next][first][last][top][bottom][index][help]  */
1222 {
1223     const key_code_name_t *n1 = *(const key_code_name_t * const *) p1;
1224     const key_code_name_t *n2 = *(const key_code_name_t * const *) p2;
1225 
1226     return n1->code - n2->code;
1227 }
1228 
1229 /* --------------------------------------------------------------------------------------------- */
1230 
1231 static inline void
1232 sort_key_conv_tab (enum KeySortType type_sort)
     /* [previous][next][first][last][top][bottom][index][help]  */
1233 {
1234     if (has_been_sorted != type_sort)
1235     {
1236         size_t i;
1237 
1238         for (i = 0; i < key_conv_tab_size; i++)
1239             key_conv_tab_sorted[i] = &key_name_conv_tab[i];
1240 
1241         if (type_sort == KEY_SORTBYNAME)
1242             qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1243                    &key_code_comparator_by_name);
1244         else if (type_sort == KEY_SORTBYCODE)
1245             qsort (key_conv_tab_sorted, key_conv_tab_size, sizeof (key_conv_tab_sorted[0]),
1246                    &key_code_comparator_by_code);
1247 
1248         has_been_sorted = type_sort;
1249     }
1250 }
1251 
1252 /* --------------------------------------------------------------------------------------------- */
1253 
1254 static int
1255 lookup_keyname (const char *name, int *idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1256 {
1257     if (name[0] != '\0')
1258     {
1259         const key_code_name_t key = { 0, name, NULL, NULL };
1260         const key_code_name_t *keyp = &key;
1261         const key_code_name_t **res;
1262 
1263         if (name[1] == '\0')
1264         {
1265             *idx = -1;
1266             return (int) name[0];
1267         }
1268 
1269         sort_key_conv_tab (KEY_SORTBYNAME);
1270 
1271         res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1272                        sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_name);
1273 
1274         if (res != NULL)
1275         {
1276             *idx = (int) (res - key_conv_tab_sorted);
1277             return (*res)->code;
1278         }
1279     }
1280 
1281     *idx = -1;
1282     return 0;
1283 }
1284 
1285 /* --------------------------------------------------------------------------------------------- */
1286 
1287 static gboolean
1288 lookup_keycode (const long code, int *idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1289 {
1290     if (code != 0)
1291     {
1292         const key_code_name_t key = { code, NULL, NULL, NULL };
1293         const key_code_name_t *keyp = &key;
1294         const key_code_name_t **res;
1295 
1296         sort_key_conv_tab (KEY_SORTBYCODE);
1297 
1298         res = bsearch (&keyp, key_conv_tab_sorted, key_conv_tab_size,
1299                        sizeof (key_conv_tab_sorted[0]), key_code_comparator_by_code);
1300 
1301         if (res != NULL)
1302         {
1303             *idx = (int) (res - key_conv_tab_sorted);
1304             return TRUE;
1305         }
1306     }
1307 
1308     *idx = -1;
1309     return FALSE;
1310 }
1311 
1312 /* --------------------------------------------------------------------------------------------- */
1313 /*** public functions ****************************************************************************/
1314 /* --------------------------------------------------------------------------------------------- */
1315 /* This has to be called before init_slang or whatever routine
1316    calls any define_sequence */
1317 
1318 void
1319 init_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1320 {
1321     const char *term;
1322 
1323     term = getenv ("TERM");
1324 
1325     /* This has to be the first define_sequence */
1326     /* So, we can assume that the first keys member has ESC */
1327     define_sequences (mc_default_keys);
1328 
1329     /* Terminfo on irix does not have some keys */
1330     if (mc_global.tty.xterm_flag
1331         || (term != NULL
1332             && (strncmp (term, "iris-ansi", 9) == 0
1333                 || strncmp (term, "xterm", 5) == 0
1334                 || strncmp (term, "rxvt", 4) == 0 || strncmp (term, "screen", 6) == 0)))
1335         define_sequences (xterm_key_defines);
1336 
1337     /* load some additional keys (e.g. direct Alt-? support) */
1338     load_xtra_key_defines ();
1339 
1340 #ifdef __QNX__
1341     if ((term != NULL) && (strncmp (term, "qnx", 3) == 0))
1342     {
1343         /* Modify the default value of use_8th_bit_as_meta: we would
1344          * like to provide a working mc for a newbie who knows nothing
1345          * about [Options|Display bits|Full 8 bits input]...
1346          *
1347          * Don't use 'meta'-bit, when we are dealing with a
1348          * 'qnx*'-type terminal: clear the default value!
1349          * These terminal types use 0xFF as an escape character,
1350          * so use_8th_bit_as_meta==1 must not be enabled!
1351          *
1352          * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
1353          * is not used now (doesn't even depend on use_8th_bit_as_meta
1354          * as in mc-3.1.2)...GREAT!...no additional code is required!]
1355          */
1356         use_8th_bit_as_meta = FALSE;
1357     }
1358 #endif /* __QNX__ */
1359 
1360 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1361     init_key_x11 ();
1362 #endif
1363 
1364     /* Load the qansi-m key definitions
1365        if we are running under the qansi-m terminal */
1366     if (term != NULL && (strncmp (term, "qansi-m", 7) == 0))
1367         define_sequences (qansi_key_defines);
1368 }
1369 
1370 /* --------------------------------------------------------------------------------------------- */
1371 /**
1372  * This has to be called after SLang_init_tty/slint_init
1373  */
1374 
1375 void
1376 init_key_input_fd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1377 {
1378 #ifdef HAVE_SLANG
1379     input_fd = SLang_TT_Read_FD;
1380 #endif
1381 }
1382 
1383 /* --------------------------------------------------------------------------------------------- */
1384 
1385 void
1386 done_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1387 {
1388     k_dispose (keys);
1389     g_slist_free_full (select_list, g_free);
1390 
1391 #ifdef HAVE_TEXTMODE_X11_SUPPORT
1392     if (x11_display)
1393         mc_XCloseDisplay (x11_display);
1394 #endif
1395 }
1396 
1397 /* --------------------------------------------------------------------------------------------- */
1398 
1399 void
1400 add_select_channel (int fd, select_fn callback, void *info)
     /* [previous][next][first][last][top][bottom][index][help]  */
1401 {
1402     select_t *new;
1403 
1404     new = g_new (select_t, 1);
1405     new->fd = fd;
1406     new->callback = callback;
1407     new->info = info;
1408 
1409     select_list = g_slist_prepend (select_list, new);
1410 }
1411 
1412 /* --------------------------------------------------------------------------------------------- */
1413 
1414 void
1415 delete_select_channel (int fd)
     /* [previous][next][first][last][top][bottom][index][help]  */
1416 {
1417     GSList *p;
1418 
1419     p = g_slist_find_custom (select_list, GINT_TO_POINTER (fd), select_cmp_by_fd);
1420     if (p != NULL)
1421         select_list = g_slist_delete_link (select_list, p);
1422 }
1423 
1424 /* --------------------------------------------------------------------------------------------- */
1425 
1426 void
1427 channels_up (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1428 {
1429     if (disabled_channels == 0)
1430         fputs ("Error: channels_up called with disabled_channels = 0\n", stderr);
1431     disabled_channels--;
1432 }
1433 
1434 /* --------------------------------------------------------------------------------------------- */
1435 
1436 void
1437 channels_down (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1438 {
1439     disabled_channels++;
1440 }
1441 
1442 /* --------------------------------------------------------------------------------------------- */
1443 /**
1444  * Return the code associated with the symbolic name keyname
1445  */
1446 
1447 long
1448 lookup_key (const char *name, char **label)
     /* [previous][next][first][last][top][bottom][index][help]  */
1449 {
1450     char **lc_keys, **p;
1451     char *cname;
1452     int k = -1;
1453     int key = 0;
1454     int lc_index = -1;
1455 
1456     int use_meta = -1;
1457     int use_ctrl = -1;
1458     int use_shift = -1;
1459 
1460     if (name == NULL)
1461         return 0;
1462 
1463     cname = g_strstrip (g_strdup (name));
1464     lc_keys = g_strsplit_set (cname, "-+ ", -1);
1465     g_free (cname);
1466 
1467     for (p = lc_keys; p != NULL && *p != NULL; p++)
1468     {
1469         if ((*p)[0] != '\0')
1470         {
1471             int idx;
1472 
1473             key = lookup_keyname (g_strstrip (*p), &idx);
1474 
1475             if (key == KEY_M_ALT)
1476                 use_meta = idx;
1477             else if (key == KEY_M_CTRL)
1478                 use_ctrl = idx;
1479             else if (key == KEY_M_SHIFT)
1480                 use_shift = idx;
1481             else
1482             {
1483                 k = key;
1484                 lc_index = idx;
1485                 break;
1486             }
1487         }
1488     }
1489 
1490     g_strfreev (lc_keys);
1491 
1492     /* output */
1493     if (k <= 0)
1494         return 0;
1495 
1496     if (label != NULL)
1497     {
1498         GString *s;
1499 
1500         s = g_string_new ("");
1501 
1502         if (use_meta != -1)
1503         {
1504             g_string_append (s, key_conv_tab_sorted[use_meta]->shortcut);
1505             g_string_append_c (s, '-');
1506         }
1507         if (use_ctrl != -1)
1508         {
1509             g_string_append (s, key_conv_tab_sorted[use_ctrl]->shortcut);
1510             g_string_append_c (s, '-');
1511         }
1512         if (use_shift != -1)
1513         {
1514             if (k < 127)
1515                 g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1516             else
1517             {
1518                 g_string_append (s, key_conv_tab_sorted[use_shift]->shortcut);
1519                 g_string_append_c (s, '-');
1520                 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1521             }
1522         }
1523         else if (k < 128)
1524         {
1525             if ((k >= 'A') || (lc_index < 0) || (key_conv_tab_sorted[lc_index]->shortcut == NULL))
1526                 g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) k));
1527             else
1528                 g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1529         }
1530         else if ((lc_index != -1) && (key_conv_tab_sorted[lc_index]->shortcut != NULL))
1531             g_string_append (s, key_conv_tab_sorted[lc_index]->shortcut);
1532         else
1533             g_string_append_c (s, (gchar) g_ascii_tolower ((gchar) key));
1534 
1535         *label = g_string_free (s, FALSE);
1536     }
1537 
1538     if (use_shift != -1)
1539     {
1540         if (k < 127 && k > 31)
1541             k = g_ascii_toupper ((gchar) k);
1542         else
1543             k |= KEY_M_SHIFT;
1544     }
1545 
1546     if (use_ctrl != -1)
1547     {
1548         if (k < 256)
1549             k = XCTRL (k);
1550         else
1551             k |= KEY_M_CTRL;
1552     }
1553 
1554     if (use_meta != -1)
1555         k = ALT (k);
1556 
1557     return (long) k;
1558 }
1559 
1560 /* --------------------------------------------------------------------------------------------- */
1561 
1562 char *
1563 lookup_key_by_code (const int keycode)
     /* [previous][next][first][last][top][bottom][index][help]  */
1564 {
1565     /* code without modifier */
1566     unsigned int k = keycode & ~KEY_M_MASK;
1567     /* modifier */
1568     unsigned int mod = keycode & KEY_M_MASK;
1569 
1570     int key_idx = -1;
1571 
1572     GString *s;
1573     int idx;
1574 
1575     s = g_string_sized_new (8);
1576 
1577     if (lookup_keycode (k, &key_idx) || (k > 0 && k < 256))
1578     {
1579         if ((mod & KEY_M_ALT) != 0 && lookup_keycode (KEY_M_ALT, &idx))
1580         {
1581             g_string_append (s, key_conv_tab_sorted[idx]->name);
1582             g_string_append_c (s, '-');
1583         }
1584 
1585         if ((mod & KEY_M_CTRL) != 0)
1586         {
1587             /* non printeble chars like a CTRL-[A..Z] */
1588             if (k < 32)
1589                 k += 64;
1590 
1591             if (lookup_keycode (KEY_M_CTRL, &idx))
1592             {
1593                 g_string_append (s, key_conv_tab_sorted[idx]->name);
1594                 g_string_append_c (s, '-');
1595             }
1596         }
1597 
1598         if ((mod & KEY_M_SHIFT) != 0)
1599         {
1600             if (lookup_keycode (KEY_M_ALT, &idx))
1601             {
1602                 if (k < 127)
1603                     g_string_append_c (s, (gchar) g_ascii_toupper ((gchar) k));
1604                 else
1605                 {
1606                     g_string_append (s, key_conv_tab_sorted[idx]->name);
1607                     g_string_append_c (s, '-');
1608                     g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1609                 }
1610             }
1611         }
1612         else if (k < 128)
1613         {
1614             if ((k >= 'A') || (key_idx < 0) || (key_conv_tab_sorted[key_idx]->name == NULL))
1615                 g_string_append_c (s, (gchar) k);
1616             else
1617                 g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1618         }
1619         else if ((key_idx != -1) && (key_conv_tab_sorted[key_idx]->name != NULL))
1620             g_string_append (s, key_conv_tab_sorted[key_idx]->name);
1621         else
1622             g_string_append_c (s, (gchar) keycode);
1623     }
1624 
1625     return g_string_free (s, s->len == 0);
1626 }
1627 
1628 /* --------------------------------------------------------------------------------------------- */
1629 /**
1630  * Return TRUE on success, FALSE on error.
1631  * An error happens if SEQ is a beginning of an existing longer sequence.
1632  */
1633 
1634 gboolean
1635 define_sequence (int code, const char *seq, int action)
     /* [previous][next][first][last][top][bottom][index][help]  */
1636 {
1637     key_def *base;
1638 
1639     if (strlen (seq) > SEQ_BUFFER_LEN - 1)
1640         return FALSE;
1641 
1642     for (base = keys; (base != NULL) && (*seq != '\0');)
1643         if (*seq == base->ch)
1644         {
1645             if (base->child == NULL)
1646             {
1647                 if (*(seq + 1) != '\0')
1648                     base->child = create_sequence (seq + 1, code, action);
1649                 else
1650                 {
1651                     /* The sequence matches an existing one.  */
1652                     base->code = code;
1653                     base->action = action;
1654                 }
1655                 return TRUE;
1656             }
1657 
1658             base = base->child;
1659             seq++;
1660         }
1661         else
1662         {
1663             if (base->next != NULL)
1664                 base = base->next;
1665             else
1666             {
1667                 base->next = create_sequence (seq, code, action);
1668                 return TRUE;
1669             }
1670         }
1671 
1672     if (*seq == '\0')
1673     {
1674         /* Attempt to redefine a sequence with a shorter sequence.  */
1675         return FALSE;
1676     }
1677 
1678     keys = create_sequence (seq, code, action);
1679     return TRUE;
1680 }
1681 
1682 /* --------------------------------------------------------------------------------------------- */
1683 /**
1684  * Check if we are idle, i.e. there are no pending keyboard or mouse
1685  * events.  Return 1 is idle, 0 is there are pending events.
1686  */
1687 gboolean
1688 is_idle (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1689 {
1690     int nfd;
1691     fd_set select_set;
1692     struct timeval time_out;
1693 
1694     FD_ZERO (&select_set);
1695     FD_SET (input_fd, &select_set);
1696     nfd = MAX (0, input_fd) + 1;
1697     time_out.tv_sec = 0;
1698     time_out.tv_usec = 0;
1699 #ifdef HAVE_LIBGPM
1700     if (mouse_enabled && use_mouse_p == MOUSE_GPM)
1701     {
1702         if (gpm_fd >= 0)
1703         {
1704             FD_SET (gpm_fd, &select_set);
1705             nfd = MAX (nfd, gpm_fd + 1);
1706         }
1707         else
1708         {
1709             if (mouse_fd >= 0)  /* error indicative */
1710             {
1711                 if (FD_ISSET (mouse_fd, &select_set))
1712                     FD_CLR (mouse_fd, &select_set);
1713                 mouse_fd = gpm_fd;
1714             }
1715             /* gpm_fd == -2 means under some X terminal */
1716             if (gpm_fd == -1)
1717             {
1718                 mouse_enabled = FALSE;
1719                 use_mouse_p = MOUSE_NONE;
1720             }
1721         }
1722     }
1723 #endif
1724     return (select (nfd, &select_set, 0, 0, &time_out) <= 0);
1725 }
1726 
1727 /* --------------------------------------------------------------------------------------------- */
1728 
1729 int
1730 get_key_code (int no_delay)
     /* [previous][next][first][last][top][bottom][index][help]  */
1731 {
1732     int c;
1733     static key_def *this = NULL, *parent;
1734     static struct timeval esctime = { -1, -1 };
1735     static int lastnodelay = -1;
1736 
1737     if (no_delay != lastnodelay)
1738     {
1739         this = NULL;
1740         lastnodelay = no_delay;
1741     }
1742 
1743   pend_send:
1744     if (pending_keys != NULL)
1745     {
1746         gboolean bad_seq;
1747 
1748         c = *pending_keys++;
1749         while (c == ESC_CHAR)
1750             c = ALT (*pending_keys++);
1751 
1752         bad_seq = (*pending_keys != ESC_CHAR && *pending_keys != '\0');
1753         if (*pending_keys == '\0' || bad_seq)
1754             pending_keys = seq_append = NULL;
1755 
1756         if (bad_seq)
1757         {
1758             /* This is an unknown ESC sequence.
1759              * To prevent interpreting its tail as a random garbage,
1760              * eat and discard all buffered and quickly following chars.
1761              * Small, but non-zero timeout is needed to reconnect
1762              * escape sequence split up by e.g. a serial line.
1763              */
1764             int paranoia = 20;
1765 
1766             while (getch_with_timeout (old_esc_mode_timeout) >= 0 && --paranoia != 0)
1767                 ;
1768         }
1769         else
1770         {
1771             if (c > 127 && c < 256 && use_8th_bit_as_meta)
1772                 c = ALT (c & 0x7f);
1773 
1774             goto done;
1775         }
1776     }
1777 
1778   nodelay_try_again:
1779     if (no_delay != 0)
1780         tty_nodelay (TRUE);
1781 
1782     c = tty_lowlevel_getch ();
1783 #if (defined(USE_NCURSES) || defined(USE_NCURSESW)) && defined(KEY_RESIZE)
1784     if (c == KEY_RESIZE)
1785         goto nodelay_try_again;
1786 #endif
1787 
1788     if (no_delay != 0)
1789     {
1790         tty_nodelay (FALSE);
1791         if (c == -1)
1792         {
1793             struct timeval current, time_out;
1794 
1795             if (this == NULL || parent == NULL || parent->action != MCKEY_ESCAPE || !old_esc_mode ||
1796                 esctime.tv_sec == -1)
1797                 return -1;
1798 
1799             GET_TIME (current);
1800             time_out.tv_sec = old_esc_mode_timeout / 1000000 + esctime.tv_sec;
1801             time_out.tv_usec = old_esc_mode_timeout % 1000000 + esctime.tv_usec;
1802             if (time_out.tv_usec > 1000000)
1803             {
1804                 time_out.tv_usec -= 1000000;
1805                 time_out.tv_sec++;
1806             }
1807             if (current.tv_sec < time_out.tv_sec ||
1808                 (current.tv_sec == time_out.tv_sec && current.tv_usec < time_out.tv_usec))
1809                 return -1;
1810 
1811             this = NULL;
1812             pending_keys = seq_append = NULL;
1813             return ESC_CHAR;
1814         }
1815     }
1816     else if (c == -1)
1817     {
1818         /* Maybe we got an incomplete match.
1819            This we do only in delay mode, since otherwise
1820            tty_lowlevel_getch can return -1 at any time. */
1821         if (seq_append == NULL)
1822         {
1823             this = NULL;
1824             return -1;
1825         }
1826 
1827         pending_keys = seq_buffer;
1828         goto pend_send;
1829     }
1830 
1831     /* Search the key on the root */
1832     if (no_delay == 0 || this == NULL)
1833     {
1834         this = keys;
1835         parent = NULL;
1836 
1837         if (c > 127 && c < 256 && use_8th_bit_as_meta)
1838         {
1839             c &= 0x7f;
1840 
1841             /* The first sequence defined starts with esc */
1842             parent = keys;
1843             this = keys->child;
1844         }
1845     }
1846 
1847     while (this != NULL)
1848     {
1849         if (c == this->ch)
1850         {
1851             if (this->child == NULL)
1852             {
1853                 /* We got a complete match, return and reset search */
1854                 pending_keys = seq_append = NULL;
1855                 c = this->code;
1856                 goto done;
1857             }
1858 
1859             /* No match yet, but it may be a prefix for a valid seq */
1860             if (!push_char (c))
1861             {
1862                 pending_keys = seq_buffer;
1863                 goto pend_send;
1864             }
1865 
1866             parent = this;
1867             this = this->child;
1868             if (parent->action == MCKEY_ESCAPE && old_esc_mode)
1869             {
1870                 if (no_delay != 0)
1871                 {
1872                     GET_TIME (esctime);
1873                     goto nodelay_try_again;
1874                 }
1875 
1876                 esctime.tv_sec = -1;
1877                 c = getch_with_timeout (old_esc_mode_timeout);
1878                 if (c != -1)
1879                     continue;
1880 
1881                 pending_keys = seq_append = NULL;
1882                 this = NULL;
1883                 return ESC_CHAR;
1884             }
1885 
1886             if (no_delay != 0)
1887                 goto nodelay_try_again;
1888             c = tty_lowlevel_getch ();
1889             continue;
1890         }
1891 
1892         /* c != this->ch. Try other keys with this prefix */
1893         if (this->next != NULL)
1894         {
1895             this = this->next;
1896             continue;
1897         }
1898 
1899         /* No match found. Is it one of our ESC <key> specials? */
1900         if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
1901         {
1902             /* Convert escape-digits to F-keys */
1903             if (g_ascii_isdigit (c))
1904                 c = KEY_F (c - '0');
1905             else if (c == ' ')
1906                 c = ESC_CHAR;
1907             else
1908                 c = ALT (c);
1909 
1910             pending_keys = seq_append = NULL;
1911             goto done;
1912         }
1913 
1914         /* Unknown sequence. Maybe a prefix of a longer one. Save it. */
1915         push_char (c);
1916         pending_keys = seq_buffer;
1917         goto pend_send;
1918     }                           /* while (this != NULL) */
1919 
1920   done:
1921     this = NULL;
1922     return correct_key_code (c);
1923 }
1924 
1925 /* --------------------------------------------------------------------------------------------- */
1926 /* Returns a character read from stdin with appropriate interpretation */
1927 /* Also takes care of generated mouse events */
1928 /* Returns EV_MOUSE if it is a mouse event */
1929 /* Returns EV_NONE  if non-blocking or interrupt set and nothing was done */
1930 
1931 int
1932 tty_get_event (struct Gpm_Event *event, gboolean redo_event, gboolean block)
     /* [previous][next][first][last][top][bottom][index][help]  */
1933 {
1934     int c;
1935     int flag = 0;               /* Return value from select */
1936 #ifdef HAVE_LIBGPM
1937     static struct Gpm_Event ev; /* Mouse event */
1938 #endif
1939     struct timeval time_out;
1940     struct timeval *time_addr = NULL;
1941     static int dirty = 3;
1942 
1943     if ((dirty == 3) || is_idle ())
1944     {
1945         mc_refresh ();
1946         dirty = 1;
1947     }
1948     else
1949         dirty++;
1950 
1951     vfs_timeout_handler ();
1952 
1953     /* Ok, we use (event->x < 0) to signal that the event does not contain
1954        a suitable position for the mouse, so we can't use show_mouse_pointer
1955        on it.
1956      */
1957     if (event->x > 0)
1958     {
1959         show_mouse_pointer (event->x, event->y);
1960         if (!redo_event)
1961             event->x = -1;
1962     }
1963 
1964     /* Repeat if using mouse */
1965     while (pending_keys == NULL)
1966     {
1967         int nfd;
1968         fd_set select_set;
1969 
1970         FD_ZERO (&select_set);
1971         FD_SET (input_fd, &select_set);
1972         nfd = MAX (add_selects (&select_set), MAX (0, input_fd)) + 1;
1973 
1974 #ifdef HAVE_LIBGPM
1975         if (mouse_enabled && (use_mouse_p == MOUSE_GPM))
1976         {
1977             if (gpm_fd >= 0)
1978             {
1979                 FD_SET (gpm_fd, &select_set);
1980                 nfd = MAX (nfd, gpm_fd + 1);
1981             }
1982             else
1983             {
1984                 if (mouse_fd >= 0)      /* error indicative */
1985                 {
1986                     if (FD_ISSET (mouse_fd, &select_set))
1987                         FD_CLR (mouse_fd, &select_set);
1988                     mouse_fd = gpm_fd;
1989                 }
1990                 /* gpm_fd == -2 means under some X terminal */
1991                 if (gpm_fd == -1)
1992                 {
1993                     mouse_enabled = FALSE;
1994                     use_mouse_p = MOUSE_NONE;
1995                 }
1996                 break;
1997             }
1998         }
1999 #endif
2000 
2001         if (redo_event)
2002         {
2003             time_out.tv_usec = mou_auto_repeat * 1000;
2004             time_out.tv_sec = 0;
2005 
2006             time_addr = &time_out;
2007         }
2008         else
2009         {
2010             int seconds;
2011 
2012             seconds = vfs_timeouts ();
2013             time_addr = NULL;
2014 
2015             if (seconds != 0)
2016             {
2017                 /* the timeout could be improved and actually be
2018                  * the number of seconds until the next vfs entry
2019                  * timeouts in the stamp list.
2020                  */
2021 
2022                 time_out.tv_sec = seconds;
2023                 time_out.tv_usec = 0;
2024                 time_addr = &time_out;
2025             }
2026         }
2027 
2028         if (!block || tty_got_winch ())
2029         {
2030             time_addr = &time_out;
2031             time_out.tv_sec = 0;
2032             time_out.tv_usec = 0;
2033         }
2034 
2035         tty_enable_interrupt_key ();
2036         flag = select (nfd, &select_set, NULL, NULL, time_addr);
2037         tty_disable_interrupt_key ();
2038 
2039         /* select timed out: it could be for any of the following reasons:
2040          * redo_event -> it was because of the MOU_REPEAT handler
2041          * !block     -> we did not block in the select call
2042          * else       -> 10 second timeout to check the vfs status.
2043          */
2044         if (flag == 0)
2045         {
2046             if (redo_event)
2047                 return EV_MOUSE;
2048             if (!block || tty_got_winch ())
2049                 return EV_NONE;
2050             vfs_timeout_handler ();
2051         }
2052         if (flag == -1 && errno == EINTR)
2053             return EV_NONE;
2054 
2055         check_selects (&select_set);
2056 
2057         if (FD_ISSET (input_fd, &select_set))
2058             break;
2059 
2060 #ifdef HAVE_LIBGPM
2061         if (mouse_enabled && use_mouse_p == MOUSE_GPM)
2062         {
2063             if (gpm_fd >= 0)
2064             {
2065                 if (FD_ISSET (gpm_fd, &select_set))
2066                 {
2067                     int status;
2068 
2069                     status = Gpm_GetEvent (&ev);
2070                     if (status == 1)    /* success */
2071                     {
2072                         Gpm_FitEvent (&ev);
2073                         *event = ev;
2074                         return EV_MOUSE;
2075                     }
2076                     if (status <= 0)    /* connection closed; -1 == error */
2077                     {
2078                         if (mouse_fd >= 0 && FD_ISSET (mouse_fd, &select_set))
2079                             FD_CLR (mouse_fd, &select_set);
2080 
2081                         disable_mouse ();
2082                         return EV_NONE;
2083                     }
2084                 }
2085             }
2086             else
2087             {
2088                 if (mouse_fd >= 0)      /* error indicative */
2089                 {
2090                     if (FD_ISSET (mouse_fd, &select_set))
2091                         FD_CLR (mouse_fd, &select_set);
2092                     mouse_fd = gpm_fd;
2093                 }
2094                 /* gpm_fd == -2 means under some X terminal */
2095                 if (gpm_fd == -1)
2096                 {
2097                     mouse_enabled = FALSE;
2098                     use_mouse_p = MOUSE_NONE;
2099                 }
2100                 break;
2101             }
2102         }
2103 #endif /* !HAVE_LIBGPM */
2104     }
2105 
2106 #ifndef HAVE_SLANG
2107     flag = is_wintouched (stdscr);
2108     untouchwin (stdscr);
2109 #endif /* !HAVE_SLANG */
2110     c = block ? getch_with_delay () : get_key_code (1);
2111 
2112 #ifndef HAVE_SLANG
2113     if (flag > 0)
2114         tty_touch_screen ();
2115 #endif /* !HAVE_SLANG */
2116 
2117     if (mouse_enabled && (c == MCKEY_MOUSE
2118 #ifdef KEY_MOUSE
2119                           || c == KEY_MOUSE
2120 #endif /* KEY_MOUSE */
2121                           || c == MCKEY_EXTENDED_MOUSE))
2122     {
2123         /* Mouse event */
2124         xmouse_get_event (event, c == MCKEY_EXTENDED_MOUSE);
2125         c = (event->type != 0) ? EV_MOUSE : EV_NONE;
2126     }
2127     else if (c == MCKEY_BRACKETED_PASTING_START)
2128     {
2129         bracketed_pasting_in_progress = TRUE;
2130         c = EV_NONE;
2131     }
2132     else if (c == MCKEY_BRACKETED_PASTING_END)
2133     {
2134         bracketed_pasting_in_progress = FALSE;
2135         c = EV_NONE;
2136     }
2137 
2138     return c;
2139 }
2140 
2141 /* --------------------------------------------------------------------------------------------- */
2142 /* Returns a key press, mouse events are discarded */
2143 
2144 int
2145 tty_getch (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2146 {
2147     Gpm_Event ev;
2148     int key;
2149 
2150     ev.x = -1;
2151     while ((key = tty_get_event (&ev, FALSE, TRUE)) == EV_NONE)
2152         ;
2153     return key;
2154 }
2155 
2156 /* --------------------------------------------------------------------------------------------- */
2157 
2158 char *
2159 learn_key (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2160 {
2161     /* LEARN_TIMEOUT in usec */
2162 #define LEARN_TIMEOUT 200000
2163 
2164     fd_set Read_FD_Set;
2165     struct timeval endtime;
2166     struct timeval time_out;
2167     int c;
2168     char buffer[256];
2169     char *p = buffer;
2170 
2171     tty_keypad (FALSE);         /* disable intepreting keys by ncurses */
2172     c = tty_lowlevel_getch ();
2173     while (c == -1)
2174         c = tty_lowlevel_getch ();      /* Sanity check, should be unnecessary */
2175     learn_store_key (buffer, &p, c);
2176 
2177     GET_TIME (endtime);
2178     endtime.tv_usec += LEARN_TIMEOUT;
2179     if (endtime.tv_usec > 1000000)
2180     {
2181         endtime.tv_usec -= 1000000;
2182         endtime.tv_sec++;
2183     }
2184 
2185     tty_nodelay (TRUE);
2186     while (TRUE)
2187     {
2188         while ((c = tty_lowlevel_getch ()) == -1)
2189         {
2190             GET_TIME (time_out);
2191             time_out.tv_usec = endtime.tv_usec - time_out.tv_usec;
2192             if (time_out.tv_usec < 0)
2193                 time_out.tv_sec++;
2194             time_out.tv_sec = endtime.tv_sec - time_out.tv_sec;
2195             if (time_out.tv_sec >= 0 && time_out.tv_usec > 0)
2196             {
2197                 FD_ZERO (&Read_FD_Set);
2198                 FD_SET (input_fd, &Read_FD_Set);
2199                 select (input_fd + 1, &Read_FD_Set, NULL, NULL, &time_out);
2200             }
2201             else
2202                 break;
2203         }
2204         if (c == -1)
2205             break;
2206         learn_store_key (buffer, &p, c);
2207     }
2208     tty_keypad (TRUE);
2209     tty_nodelay (FALSE);
2210     *p = '\0';
2211     return g_strdup (buffer);
2212 #undef LEARN_TIMEOUT
2213 }
2214 
2215 /* --------------------------------------------------------------------------------------------- */
2216 /* xterm and linux console only: set keypad to numeric or application
2217    mode. Only in application keypad mode it's possible to distinguish
2218    the '+' key and the '+' on the keypad ('*' and '-' ditto) */
2219 
2220 void
2221 numeric_keypad_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2222 {
2223     if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2224     {
2225         fputs (ESC_STR ">", stdout);
2226         fflush (stdout);
2227     }
2228 }
2229 
2230 /* --------------------------------------------------------------------------------------------- */
2231 
2232 void
2233 application_keypad_mode (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2234 {
2235     if (mc_global.tty.console_flag != '\0' || mc_global.tty.xterm_flag)
2236     {
2237         fputs (ESC_STR "=", stdout);
2238         fflush (stdout);
2239     }
2240 }
2241 
2242 /* --------------------------------------------------------------------------------------------- */
2243 
2244 void
2245 enable_bracketed_paste (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2246 {
2247     printf (ESC_STR "[?2004h");
2248     fflush (stdout);
2249 }
2250 
2251 /* --------------------------------------------------------------------------------------------- */
2252 
2253 void
2254 disable_bracketed_paste (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
2255 {
2256     printf (ESC_STR "[?2004l");
2257     fflush (stdout);
2258     bracketed_pasting_in_progress = FALSE;
2259 }
2260 
2261 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */