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

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