root/src/keymap.c

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

DEFINITIONS

This source file includes following definitions.
  1. create_default_keymap_section
  2. create_default_keymap
  3. load_keymap_from_section
  4. load_setup_get_full_config_name
  5. load_setup_init_config_from_file
  6. load_setup_get_keymap_profile_config
  7. keymap_load
  8. keymap_free

   1 /*
   2    Default values and initialization of keybinding engine
   3 
   4    Copyright (C) 2009-2025
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Vitja Makarov, 2005
   9    Ilia Maslakov <il.smind@gmail.com>, 2009, 2010
  10    Andrew Borodin <aborodin@vmail.ru>, 2010-2021
  11 
  12    This file is part of the Midnight Commander.
  13 
  14    The Midnight Commander is free software: you can redistribute it
  15    and/or modify it under the terms of the GNU General Public License as
  16    published by the Free Software Foundation, either version 3 of the License,
  17    or (at your option) any later version.
  18 
  19    The Midnight Commander is distributed in the hope that it will be useful,
  20    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22    GNU General Public License for more details.
  23 
  24    You should have received a copy of the GNU General Public License
  25    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  26  */
  27 
  28 #include <config.h>
  29 
  30 #include "lib/global.h"
  31 
  32 #include "lib/fileloc.h"
  33 #include "lib/keybind.h"
  34 #include "lib/mcconfig.h"  // mc_config_t
  35 #include "lib/util.h"
  36 #include "lib/widget.h"  // dialog_map, input_map, listbox_map, menu_map, radio_map
  37 
  38 #include "args.h"  // mc_args__keymap_file
  39 
  40 #include "keymap.h"
  41 
  42 /*** global variables ****************************************************************************/
  43 
  44 GArray *filemanager_keymap = NULL;
  45 GArray *filemanager_x_keymap = NULL;
  46 GArray *panel_keymap = NULL;
  47 GArray *dialog_keymap = NULL;
  48 GArray *menu_keymap = NULL;
  49 GArray *input_keymap = NULL;
  50 GArray *listbox_keymap = NULL;
  51 GArray *radio_keymap = NULL;
  52 GArray *tree_keymap = NULL;
  53 GArray *help_keymap = NULL;
  54 #ifdef ENABLE_EXT2FS_ATTR
  55 GArray *chattr_keymap = NULL;
  56 #endif
  57 #ifdef USE_INTERNAL_EDIT
  58 GArray *editor_keymap = NULL;
  59 GArray *editor_x_keymap = NULL;
  60 #endif
  61 GArray *viewer_keymap = NULL;
  62 GArray *viewer_hex_keymap = NULL;
  63 #ifdef USE_DIFF_VIEW
  64 GArray *diff_keymap = NULL;
  65 #endif
  66 
  67 const global_keymap_t *filemanager_map = NULL;
  68 const global_keymap_t *filemanager_x_map = NULL;
  69 const global_keymap_t *panel_map = NULL;
  70 const global_keymap_t *tree_map = NULL;
  71 const global_keymap_t *help_map = NULL;
  72 #ifdef ENABLE_EXT2FS_ATTR
  73 const global_keymap_t *chattr_map = NULL;
  74 #endif
  75 #ifdef USE_INTERNAL_EDIT
  76 const global_keymap_t *editor_map = NULL;
  77 const global_keymap_t *editor_x_map = NULL;
  78 #endif
  79 const global_keymap_t *viewer_map = NULL;
  80 const global_keymap_t *viewer_hex_map = NULL;
  81 #ifdef USE_DIFF_VIEW
  82 const global_keymap_t *diff_map = NULL;
  83 #endif
  84 
  85 /*** file scope macro definitions ****************************************************************/
  86 
  87 /*** file scope type declarations ****************************************************************/
  88 
  89 /* default keymaps in ini (key=value) format */
  90 typedef struct global_keymap_ini_t
  91 {
  92     const char *key;
  93     const char *value;
  94 } global_keymap_ini_t;
  95 
  96 /*** forward declarations (file scope functions) *************************************************/
  97 
  98 /*** file scope variables ************************************************************************/
  99 
 100 /* midnight */
 101 static const global_keymap_ini_t default_filemanager_keymap[] = {
 102     { "ChangePanel", "tab; ctrl-i" },
 103     { "Help", "f1" },
 104     { "UserMenu", "f2" },
 105     { "View", "f3" },
 106     { "Edit", "f4" },
 107     { "Copy", "f5" },
 108     { "Move", "f6" },
 109     { "MakeDir", "f7" },
 110     { "Delete", "f8" },
 111     { "Menu", "f9" },
 112     { "Quit", "f10" },
 113     { "MenuLastSelected", "f19" },
 114     { "QuitQuiet", "f20" },
 115     { "History", "alt-h" },
 116     { "EditorViewerHistory", "alt-shift-e" },
 117     { "DirSize", "ctrl-space" },
 118     // Copy useful information to the command line
 119     { "PutCurrentPath", "alt-a" },
 120     { "PutOtherPath", "alt-shift-a" },
 121     { "PutCurrentSelected", "alt-enter; ctrl-enter" },
 122     { "PutCurrentFullSelected", "ctrl-shift-enter" },
 123     { "CdQuick", "alt-c" },
 124     // To access the directory hotlist
 125     { "HotList", "ctrl-backslash" },
 126     // Suspend
 127     { "Suspend", "ctrl-z" },
 128     // The filtered view command
 129     { "ViewFiltered", "alt-exclamation" },
 130     // Find file
 131     { "Find", "alt-question" },
 132     // Panel refresh
 133     { "Reread", "ctrl-r" },
 134     // Switch listing between long, user defined and full formats
 135     // Swap panels
 136     { "Swap", "ctrl-u" },
 137     // Resize panels
 138     { "SplitEqual", "alt-equal" },
 139     { "SplitMore", "alt-shift-right" },
 140     { "SplitLess", "alt-shift-left" },
 141     // View output
 142     { "Shell", "ctrl-o" },
 143     { "ShowHidden", "alt-dot" },
 144     { "SplitVertHoriz", "alt-comma" },
 145     { "ExtendedKeyMap", "ctrl-x" },
 146     // Select/unselect group
 147     { "Select", "kpplus" },
 148     { "Unselect", "kpminus" },
 149     { "SelectInvert", "kpasterisk" },
 150     // List of screens
 151     { "ScreenList", "alt-prime" },
 152     {
 153         NULL,
 154         NULL,
 155     },
 156 };
 157 
 158 static const global_keymap_ini_t default_filemanager_x_keymap[] = {
 159     { "CompareDirs", "d" },
 160 #ifdef USE_DIFF_VIEW
 161     { "CompareFiles", "ctrl-d" },
 162 #endif
 163 #ifdef ENABLE_VFS
 164     { "VfsList", "a" },
 165 #endif
 166     { "PutCurrentPath", "p" },
 167     { "PutOtherPath", "ctrl-p" },
 168     { "PutCurrentTagged", "t" },
 169     { "PutOtherTagged", "ctrl-t" },
 170     { "ChangeMode", "c" },
 171     { "ChangeOwn", "o" },
 172 #ifdef ENABLE_EXT2FS_ATTR
 173     { "ChangeAttributes", "e" },
 174 #endif
 175     { "PutCurrentLink", "r" },
 176     { "PutOtherLink", "ctrl-r" },
 177     { "Link", "l" },
 178     { "LinkSymbolic", "s" },
 179     { "LinkSymbolicRelative", "v" },
 180     { "LinkSymbolicEdit", "ctrl-s" },
 181     { "PanelInfo", "i" },
 182     { "PanelQuickView", "q" },
 183     { "HotListAdd", "h" },
 184 #ifdef ENABLE_BACKGROUND
 185     { "Jobs", "j" },
 186 #endif
 187     { "ExternalPanelize", "!" },
 188     {
 189         NULL,
 190         NULL,
 191     },
 192 };
 193 
 194 /* panel */
 195 static const global_keymap_ini_t default_panel_keymap[] = {
 196     { "CycleListingFormat", "alt-t" },
 197     { "PanelOtherCd", "alt-o" },
 198     { "PanelOtherCdLink", "alt-l" },
 199     { "CopySingle", "f15" },
 200     { "DeleteSingle", "f18" },
 201     { "Enter", "enter" },
 202     { "EditNew", "f14" },
 203     { "MoveSingle", "f16" },
 204     { "SelectInvert", "alt-asterisk" },
 205     { "Select", "alt-plus" },
 206     { "Unselect", "alt-minus" },
 207     { "ViewRaw", "f13" },
 208     { "CdChild", "ctrl-pgdn" },
 209     { "CdParent", "ctrl-pgup" },
 210     { "History", "alt-shift-h" },
 211     { "HistoryNext", "alt-u" },
 212     { "HistoryPrev", "alt-y" },
 213     { "BottomOnScreen", "alt-j" },
 214     { "MiddleOnScreen", "alt-r" },
 215     { "TopOnScreen", "alt-g" },
 216     { "Mark", "insert; ctrl-t" },
 217     { "MarkDown", "shift-down" },
 218     { "MarkUp", "shift-up" },
 219     { "Up", "up; ctrl-p" },
 220     { "Down", "down; ctrl-n" },
 221     { "Left", "left" },
 222     { "Right", "right" },
 223     { "Top", "alt-lt; home; a1" },
 224     { "Bottom", "alt-gt; end; c1" },
 225     { "PageDown", "pgdn; ctrl-v" },
 226     { "PageUp", "pgup; alt-v" },
 227 #ifdef HAVE_CHARSET
 228     { "SelectCodepage", "alt-e" },
 229 #endif
 230     { "Search", "ctrl-s; alt-s" },
 231     { "PanelOtherSync", "alt-i" },
 232     {
 233         NULL,
 234         NULL,
 235     },
 236 };
 237 
 238 /* dialog */
 239 static const global_keymap_ini_t default_dialog_keymap[] = {
 240     { "Ok", "enter" },
 241     { "Cancel", "f10; esc; ctrl-g" },
 242     { "Up", "up; left" },
 243     { "Down", "down; right" },
 244 #if 0
 245     {"Left", "up; left"},
 246     {"Right", "down; right"},
 247 #endif
 248     { "Help", "f1" },
 249     { "Suspend", "ctrl-z" },
 250     { "Refresh", "ctrl-l" },
 251     { "ScreenList", "alt-prime" },
 252     { "ScreenNext", "alt-rbrace" },
 253     { "ScreenPrev", "alt-lbrace" },
 254     {
 255         NULL,
 256         NULL,
 257     },
 258 };
 259 
 260 /* menubar */
 261 static const global_keymap_ini_t default_menu_keymap[] = {
 262     { "Help", "f1" },
 263     { "Left", "left; ctrl-b" },
 264     { "Right", "right; ctrl-f" },
 265     { "Up", "up; ctrl-p" },
 266     { "Down", "down; ctrl-n" },
 267     { "Home", "home; alt-lt; ctrl-a" },
 268     { "End", "end; alt-gt; ctrl-e" },
 269     { "Enter", "enter" },
 270     { "Quit", "f10; ctrl-g; esc" },
 271     {
 272         NULL,
 273         NULL,
 274     },
 275 };
 276 
 277 /* input line */
 278 static const global_keymap_ini_t default_input_keymap[] = {
 279     // Motion
 280     { "Home", "ctrl-a; alt-lt; home; a1" },
 281     { "End", "ctrl-e; alt-gt; end; c1" },
 282     { "Left", "left; alt-left; ctrl-b" },
 283     { "Right", "right; alt-right; ctrl-f" },
 284     { "WordLeft", "ctrl-left; alt-b" },
 285     { "WordRight", "ctrl-right; alt-f" },
 286     // Mark
 287     { "MarkLeft", "shift-left" },
 288     { "MarkRight", "shift-right" },
 289     { "MarkToWordBegin", "ctrl-shift-left" },
 290     { "MarkToWordEnd", "ctrl-shift-right" },
 291     { "MarkToHome", "shift-home" },
 292     { "MarkToEnd", "shift-end" },
 293     // Editing
 294     { "Backspace", "backspace; ctrl-h" },
 295     { "Delete", "delete; ctrl-d" },
 296     { "DeleteToWordEnd", "alt-d" },
 297     { "DeleteToWordBegin", "alt-backspace" },
 298     // Region manipulation
 299     { "Remove", "ctrl-w" },
 300     { "Store", "alt-w" },
 301     { "Yank", "ctrl-y" },
 302     { "DeleteToEnd", "ctrl-k" },
 303     // History
 304     { "History", "alt-h" },
 305     { "HistoryPrev", "alt-p; ctrl-down" },
 306     { "HistoryNext", "alt-n; ctrl-up" },
 307     // Completion
 308     { "Complete", "alt-tab" },
 309     {
 310         NULL,
 311         NULL,
 312     },
 313 };
 314 
 315 /* listbox */
 316 static const global_keymap_ini_t default_listbox_keymap[] = {
 317     { "Up", "up; ctrl-p" },
 318     { "Down", "down; ctrl-n" },
 319     { "Top", "home; alt-lt; a1" },
 320     { "Bottom", "end; alt-gt; c1" },
 321     { "PageUp", "pgup; alt-v" },
 322     { "PageDown", "pgdn; ctrl-v" },
 323     { "Delete", "delete; d" },
 324     { "Clear", "shift-delete; shift-d" },
 325     { "View", "f3" },
 326     { "Edit", "f4" },
 327     { "Enter", "enter" },
 328     {
 329         NULL,
 330         NULL,
 331     },
 332 };
 333 
 334 /* radio */
 335 static const global_keymap_ini_t default_radio_keymap[] = {
 336     { "Up", "up; ctrl-p" },
 337     { "Down", "down; ctrl-n" },
 338     { "Top", "home; alt-lt; a1" },
 339     { "Bottom", "end; alt-gt; c1" },
 340     { "Select", "space" },
 341     {
 342         NULL,
 343         NULL,
 344     },
 345 };
 346 
 347 /* tree */
 348 static const global_keymap_ini_t default_tree_keymap[] = {
 349     { "Help", "f1" },
 350     { "Rescan", "f2; ctrl-r" },
 351     { "Forget", "f3" },
 352     { "ToggleNavigation", "f4" },
 353     { "Copy", "f5" },
 354     { "Move", "f6" },
 355 #if 0
 356     {"MakeDir", "f7"},
 357 #endif
 358     { "Delete", "f8; delete" },
 359     { "Up", "up; ctrl-p" },
 360     { "Down", "down; ctrl-n" },
 361     { "Left", "left" },
 362     { "Right", "right" },
 363     { "Top", "home; alt-lt; a1" },
 364     { "Bottom", "end; alt-gt; c1" },
 365     { "PageUp", "pgup; alt-v" },
 366     { "PageDown", "pgdn; ctrl-v" },
 367     { "Enter", "enter" },
 368     { "Search", "ctrl-s; alt-s" },
 369     {
 370         NULL,
 371         NULL,
 372     },
 373 };
 374 
 375 /* help */
 376 static const global_keymap_ini_t default_help_keymap[] = {
 377     { "Help", "f1" },
 378     { "Index", "f2; c" },
 379     { "Back", "f3; left; l" },
 380     { "Quit", "f10; esc" },
 381     { "Up", "up; ctrl-p" },
 382     { "Down", "down; ctrl-n" },
 383     { "PageDown", "f; space; pgdn; ctrl-v" },
 384     { "PageUp", "b; pgup; alt-v; backspace" },
 385     { "HalfPageDown", "d" },
 386     { "HalfPageUp", "u" },
 387     { "Top", "home; ctrl-home; ctrl-pgup; a1; alt-lt; g" },
 388     { "Bottom", "end; ctrl-end; ctrl-pgdn; c1; alt-gt; shift-g" },
 389     { "Enter", "right; enter" },
 390     { "LinkNext", "tab" },
 391     { "LinkPrev", "alt-tab" },
 392     { "NodeNext", "n" },
 393     { "NodePrev", "p" },
 394     {
 395         NULL,
 396         NULL,
 397     },
 398 };
 399 
 400 #ifdef ENABLE_EXT2FS_ATTR
 401 /* chattr dialog */
 402 static const global_keymap_ini_t default_chattr_keymap[] = {
 403     { "Up", "up; left; ctrl-p" },
 404     { "Down", "down; right; ctrl-n" },
 405     { "Top", "home; alt-lt; a1" },
 406     { "Bottom", "end; alt-gt; c1" },
 407     { "PageUp", "pgup; alt-v" },
 408     { "PageDown", "pgdn; ctrl-v" },
 409     { "Mark", "t; shift-t" },
 410     { "MarkAndDown", "insert" },
 411     {
 412         NULL,
 413         NULL,
 414     },
 415 };
 416 #endif
 417 
 418 #ifdef USE_INTERNAL_EDIT
 419 static const global_keymap_ini_t default_editor_keymap[] = {
 420     { "Enter", "enter" },
 421     { "Return", "shift-enter; ctrl-enter; ctrl-shift-enter" },  // useful for pasting multiline text
 422     { "Tab", "tab; shift-tab; ctrl-tab; ctrl-shift-tab" },      // ditto
 423     { "BackSpace", "backspace; ctrl-h" },
 424     { "Delete", "delete; ctrl-d" },
 425     { "Left", "left" },
 426     { "Right", "right" },
 427     { "Up", "up" },
 428     { "Down", "down" },
 429     { "Home", "home" },
 430     { "End", "end" },
 431     { "PageUp", "pgup" },
 432     { "PageDown", "pgdn" },
 433     { "WordLeft", "ctrl-left; ctrl-z" },
 434     { "WordRight", "ctrl-right; ctrl-x" },
 435     { "InsertOverwrite", "insert" },
 436     { "Help", "f1" },
 437     { "Save", "f2" },
 438     { "Mark", "f3" },
 439     { "Replace", "f4" },
 440     { "Copy", "f5" },
 441     { "Move", "f6" },
 442     { "Search", "f7" },
 443     { "Remove", "f8; ctrl-delete" },
 444     { "Menu", "f9" },
 445     { "Quit", "f10; esc" },
 446     { "UserMenu", "f11" },
 447     { "SaveAs", "f12; ctrl-f2" },
 448     { "MarkColumn", "f13" },
 449     { "ReplaceContinue", "f14; ctrl-f4" },
 450     { "InsertFile", "f15" },
 451     { "SearchContinue", "f17; ctrl-f7" },
 452     { "EditNew", "ctrl-n" },
 453     { "DeleteToWordBegin", "alt-backspace" },
 454     { "DeleteToWordEnd", "alt-d" },
 455     { "DeleteLine", "ctrl-y" },
 456     { "DeleteToEnd", "ctrl-k" },
 457     { "Undo", "ctrl-u; ctrl-backspace" },
 458     { "Redo", "alt-r" },
 459 #    ifdef HAVE_CHARSET
 460     { "SelectCodepage", "alt-e" },
 461 #    endif
 462     { "Goto", "alt-l; alt-shift-l" },
 463     { "Refresh", "ctrl-l" },
 464     { "Shell", "ctrl-o" },
 465     { "Top", "ctrl-home; ctrl-pgup; alt-lt" },
 466     { "Bottom", "ctrl-end; ctrl-pgdn; alt-gt" },
 467     { "TopOnScreen", "ctrl-pgup" },
 468     { "BottomOnScreen", "ctrl-pgdn" },
 469     { "ScrollUp", "ctrl-up" },
 470     { "ScrollDown", "ctrl-down" },
 471     { "Store", "ctrl-insert" },
 472     { "Paste", "shift-insert" },
 473     { "Cut", "shift-delete" },
 474     { "BlockSave", "ctrl-f" },
 475     { "MarkLeft", "shift-left" },
 476     { "MarkRight", "shift-right" },
 477     { "MarkUp", "shift-up" },
 478     { "MarkDown", "shift-down" },
 479     { "MarkPageUp", "shift-pgup" },
 480     { "MarkPageDown", "shift-pgdn" },
 481     { "MarkToWordBegin", "ctrl-shift-left" },
 482     { "MarkToWordEnd", "ctrl-shift-right" },
 483     { "MarkToHome", "shift-home" },
 484     { "MarkToEnd", "shift-end" },
 485     { "MarkToFileBegin", "ctrl-shift-home" },
 486     { "MarkToFileEnd", "ctrl-shift-end" },
 487     { "MarkToPageBegin", "ctrl-shift-pgup" },
 488     { "MarkToPageEnd", "ctrl-shift-pgdn" },
 489     { "MarkScrollUp", "ctrl-shift-up" },
 490     { "MarkScrollDown", "ctrl-shift-down" },
 491     { "MarkColumnLeft", "alt-left" },
 492     { "MarkColumnRight", "alt-right" },
 493     { "MarkColumnUp", "alt-up" },
 494     { "MarkColumnDown", "alt-down" },
 495     { "MarkColumnPageUp", "alt-pgup" },
 496     { "MarkColumnPageDown", "alt-pgdn" },
 497     { "InsertLiteral", "ctrl-q" },
 498     { "Complete", "alt-tab" },
 499     { "MatchBracket", "alt-b" },
 500     { "ParagraphFormat", "alt-p" },
 501     { "Bookmark", "alt-k" },
 502     { "BookmarkFlush", "alt-o" },
 503     { "BookmarkNext", "alt-j" },
 504     { "BookmarkPrev", "alt-i" },
 505     { "MacroStartStopRecord", "ctrl-r" },
 506     { "MacroExecute", "ctrl-a" },
 507     { "ShowNumbers", "alt-n" },
 508     { "ShowTabTws", "alt-underline" },
 509     { "SyntaxOnOff", "ctrl-s" },
 510     { "Find", "alt-enter" },
 511     { "FilePrev", "alt-minus" },
 512     { "FileNext", "alt-plus" },
 513     { "Sort", "alt-t" },
 514     { "Mail", "alt-m" },
 515     { "ExternalCommand", "alt-u" },
 516 #    ifdef HAVE_ASPELL
 517     { "SpellCheckCurrentWord", "ctrl-p" },
 518 #    endif
 519     { "ExtendedKeyMap", "ctrl-x" },
 520     {
 521         NULL,
 522         NULL,
 523     },
 524 };
 525 
 526 /* emacs keyboard layout emulation */
 527 static const global_keymap_ini_t default_editor_x_keymap[] = {
 528     { NULL, NULL },
 529 };
 530 #endif
 531 
 532 /* viewer */
 533 static const global_keymap_ini_t default_viewer_keymap[] = {
 534     { "Help", "f1" },
 535     { "WrapMode", "f2" },
 536     { "Quit", "f3; f10; q; esc" },
 537     { "HexMode", "f4" },
 538     { "Goto", "f5" },
 539     { "Search", "f7" },
 540     { "SearchContinue", "f17; n" },
 541     { "MagicMode", "f8" },
 542     { "NroffMode", "f9" },
 543     { "Home", "ctrl-a" },
 544     { "End", "ctrl-e" },
 545     { "Left", "h; left" },
 546     { "Right", "l; right" },
 547     { "LeftQuick", "ctrl-left" },
 548     { "RightQuick", "ctrl-right" },
 549     { "Up", "k; y; insert; up; ctrl-p" },
 550     { "Down", "j; e; delete; down; enter; ctrl-n" },
 551     { "PageDown", "f; space; pgdn; ctrl-v" },
 552     { "PageUp", "b; pgup; alt-v; backspace" },
 553     { "HalfPageDown", "d" },
 554     { "HalfPageUp", "u" },
 555     { "Top", "home; ctrl-home; ctrl-pgup; a1; alt-lt; g" },
 556     { "Bottom", "end; ctrl-end; ctrl-pgdn; c1; alt-gt; shift-g" },
 557     { "BookmarkGoto", "m" },
 558     { "Bookmark", "r" },
 559     { "FileNext", "ctrl-f" },
 560     { "FilePrev", "ctrl-b" },
 561 #ifdef HAVE_CHARSET
 562     { "SelectCodepage", "alt-e" },
 563 #endif
 564     { "Shell", "ctrl-o" },
 565     { "Ruler", "alt-r" },
 566     { "SearchForward", "slash" },
 567     { "SearchBackward", "question" },
 568     { "SearchForwardContinue", "ctrl-s" },
 569     { "SearchBackwardContinue", "ctrl-r" },
 570     { "SearchOppositeContinue", "shift-n" },
 571     { "History", "alt-shift-e" },
 572     {
 573         NULL,
 574         NULL,
 575     },
 576 };
 577 
 578 /* hex viewer */
 579 static const global_keymap_ini_t default_viewer_hex_keymap[] = {
 580     { "Help", "f1" },
 581     { "HexEditMode", "f2" },
 582     { "Quit", "f3; f10; q; esc" },
 583     { "HexMode", "f4" },
 584     { "Goto", "f5" },
 585     { "Save", "f6" },
 586     { "Search", "f7" },
 587     { "SearchContinue", "f17; n" },
 588     { "MagicMode", "f8" },
 589     { "NroffMode", "f9" },
 590     { "ToggleNavigation", "tab" },
 591     { "Home", "ctrl-a; home" },
 592     { "End", "ctrl-e; end" },
 593     { "Left", "b; left" },
 594     { "Right", "f; right" },
 595     { "Up", "k; y; up" },
 596     { "Down", "j; delete; down" },
 597     { "PageDown", "pgdn; ctrl-v" },
 598     { "PageUp", "pgup; alt-v" },
 599     { "Top", "ctrl-home; ctrl-pgup; a1; alt-lt; g" },
 600     { "Bottom", "ctrl-end; ctrl-pgdn; c1; alt-gt; shift-g" },
 601 #ifdef HAVE_CHARSET
 602     { "SelectCodepage", "alt-e" },
 603 #endif
 604     { "Shell", "ctrl-o" },
 605     { "SearchForward", "slash" },
 606     { "SearchBackward", "question" },
 607     { "SearchForwardContinue", "ctrl-s" },
 608     { "SearchBackwardContinue", "ctrl-r" },
 609     { "SearchOppositeContinue", "shift-n" },
 610     { "History", "alt-shift-e" },
 611     {
 612         NULL,
 613         NULL,
 614     },
 615 };
 616 
 617 #ifdef USE_DIFF_VIEW
 618 /* diff viewer */
 619 static const global_keymap_ini_t default_diff_keymap[] = {
 620     { "ShowSymbols", "alt-s; s" },
 621     { "ShowNumbers", "alt-n; l" },
 622     { "SplitFull", "f" },
 623     { "SplitEqual", "equal" },
 624     { "SplitMore", "gt" },
 625     { "SplitLess", "lt" },
 626     { "Tab2", "2" },
 627     { "Tab3", "3" },
 628     { "Tab4", "4" },
 629     { "Tab8", "8" },
 630     { "Swap", "ctrl-u" },
 631     { "Redo", "ctrl-r" },
 632     { "HunkNext", "n; enter; space" },
 633     { "HunkPrev", "p; backspace" },
 634     { "Goto", "g; shift-g" },
 635     { "Save", "f2" },
 636     { "Edit", "f4" },
 637     { "EditOther", "f14" },
 638     { "Merge", "f5" },
 639     { "MergeOther", "f15" },
 640     { "Search", "f7" },
 641     { "SearchContinue", "f17" },
 642     { "Options", "f9" },
 643     { "Top", "ctrl-home" },
 644     { "Bottom", "ctrl-end" },
 645     { "Down", "down" },
 646     { "Up", "up" },
 647     { "LeftQuick", "ctrl-left" },
 648     { "RightQuick", "ctrl-right" },
 649     { "Left", "left" },
 650     { "Right", "right" },
 651     { "PageDown", "pgdn" },
 652     { "PageUp", "pgup" },
 653     { "Home", "home" },
 654     { "End", "end" },
 655     { "Help", "f1" },
 656     { "Quit", "f10; q; shift-q; esc" },
 657 #    ifdef HAVE_CHARSET
 658     { "SelectCodepage", "alt-e" },
 659 #    endif
 660     { "Shell", "ctrl-o" },
 661     {
 662         NULL,
 663         NULL,
 664     },
 665 };
 666 #endif
 667 
 668 /* --------------------------------------------------------------------------------------------- */
 669 /*** file scope functions ************************************************************************/
 670 /* --------------------------------------------------------------------------------------------- */
 671 
 672 static void
 673 create_default_keymap_section (mc_config_t *keymap, const char *section,
     /* [previous][next][first][last][top][bottom][index][help]  */
 674                                const global_keymap_ini_t *k)
 675 {
 676     size_t i;
 677 
 678     for (i = 0; k[i].key != NULL; i++)
 679         mc_config_set_string_raw (keymap, section, k[i].key, k[i].value);
 680 }
 681 
 682 /* --------------------------------------------------------------------------------------------- */
 683 
 684 static mc_config_t *
 685 create_default_keymap (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 686 {
 687     mc_config_t *keymap;
 688 
 689     keymap = mc_config_init (NULL, TRUE);
 690 
 691     create_default_keymap_section (keymap, KEYMAP_SECTION_FILEMANAGER, default_filemanager_keymap);
 692     create_default_keymap_section (keymap, KEYMAP_SECTION_FILEMANAGER_EXT,
 693                                    default_filemanager_x_keymap);
 694     create_default_keymap_section (keymap, KEYMAP_SECTION_PANEL, default_panel_keymap);
 695     create_default_keymap_section (keymap, KEYMAP_SECTION_DIALOG, default_dialog_keymap);
 696     create_default_keymap_section (keymap, KEYMAP_SECTION_MENU, default_menu_keymap);
 697     create_default_keymap_section (keymap, KEYMAP_SECTION_INPUT, default_input_keymap);
 698     create_default_keymap_section (keymap, KEYMAP_SECTION_LISTBOX, default_listbox_keymap);
 699     create_default_keymap_section (keymap, KEYMAP_SECTION_RADIO, default_radio_keymap);
 700     create_default_keymap_section (keymap, KEYMAP_SECTION_TREE, default_tree_keymap);
 701     create_default_keymap_section (keymap, KEYMAP_SECTION_HELP, default_help_keymap);
 702 #ifdef ENABLE_EXT2FS_ATTR
 703     create_default_keymap_section (keymap, KEYMAP_SECTION_HELP, default_chattr_keymap);
 704 #endif
 705 #ifdef USE_INTERNAL_EDIT
 706     create_default_keymap_section (keymap, KEYMAP_SECTION_EDITOR, default_editor_keymap);
 707     create_default_keymap_section (keymap, KEYMAP_SECTION_EDITOR_EXT, default_editor_x_keymap);
 708 #endif
 709     create_default_keymap_section (keymap, KEYMAP_SECTION_VIEWER, default_viewer_keymap);
 710     create_default_keymap_section (keymap, KEYMAP_SECTION_VIEWER_HEX, default_viewer_hex_keymap);
 711 #ifdef USE_DIFF_VIEW
 712     create_default_keymap_section (keymap, KEYMAP_SECTION_DIFFVIEWER, default_diff_keymap);
 713 #endif
 714 
 715     return keymap;
 716 }
 717 
 718 /* --------------------------------------------------------------------------------------------- */
 719 
 720 static void
 721 load_keymap_from_section (const char *section_name, GArray *keymap, mc_config_t *cfg)
     /* [previous][next][first][last][top][bottom][index][help]  */
 722 {
 723     gchar **profile_keys, **keys;
 724 
 725     if (section_name == NULL)
 726         return;
 727 
 728     keys = mc_config_get_keys (cfg, section_name, NULL);
 729 
 730     for (profile_keys = keys; *profile_keys != NULL; profile_keys++)
 731     {
 732         gchar **values;
 733 
 734         values = mc_config_get_string_list (cfg, section_name, *profile_keys, NULL);
 735         if (values != NULL)
 736         {
 737             long action;
 738 
 739             action = keybind_lookup_action (*profile_keys);
 740             if (action > 0)
 741             {
 742                 gchar **curr_values;
 743 
 744                 for (curr_values = values; *curr_values != NULL; curr_values++)
 745                     keybind_cmd_bind (keymap, *curr_values, action);
 746             }
 747 
 748             g_strfreev (values);
 749         }
 750     }
 751 
 752     g_strfreev (keys);
 753 }
 754 
 755 /* --------------------------------------------------------------------------------------------- */
 756 /**
 757  * Get name of config file.
 758  *
 759  * @param subdir If not NULL, config is also searched in specified subdir.
 760  * @param config_file_name If relative, file if searched in standard paths.
 761  *
 762  * @return newly allocated string with config name or NULL if file is not found.
 763  */
 764 
 765 static char *
 766 load_setup_get_full_config_name (const char *subdir, const char *config_file_name)
     /* [previous][next][first][last][top][bottom][index][help]  */
 767 {
 768     /*
 769        TODO: IMHO, in future, this function shall be placed in mcconfig module.
 770      */
 771     char *lc_basename, *ret;
 772     char *file_name;
 773 
 774     if (config_file_name == NULL)
 775         return NULL;
 776 
 777     // check for .keymap suffix
 778     if (g_str_has_suffix (config_file_name, ".keymap"))
 779         file_name = g_strdup (config_file_name);
 780     else
 781         file_name = g_strconcat (config_file_name, ".keymap", (char *) NULL);
 782 
 783     canonicalize_pathname (file_name);
 784 
 785     if (g_path_is_absolute (file_name))
 786         return file_name;
 787 
 788     lc_basename = g_path_get_basename (file_name);
 789     g_free (file_name);
 790 
 791     if (lc_basename == NULL)
 792         return NULL;
 793 
 794     if (subdir != NULL)
 795         ret = g_build_filename (mc_config_get_path (), subdir, lc_basename, (char *) NULL);
 796     else
 797         ret = g_build_filename (mc_config_get_path (), lc_basename, (char *) NULL);
 798 
 799     if (exist_file (ret))
 800     {
 801         g_free (lc_basename);
 802         canonicalize_pathname (ret);
 803         return ret;
 804     }
 805     g_free (ret);
 806 
 807     if (subdir != NULL)
 808         ret = g_build_filename (mc_global.share_data_dir, subdir, lc_basename, (char *) NULL);
 809     else
 810         ret = g_build_filename (mc_global.share_data_dir, lc_basename, (char *) NULL);
 811 
 812     g_free (lc_basename);
 813 
 814     if (exist_file (ret))
 815     {
 816         canonicalize_pathname (ret);
 817         return ret;
 818     }
 819 
 820     g_free (ret);
 821     return NULL;
 822 }
 823 
 824 /* --------------------------------------------------------------------------------------------- */
 825 /**
 826   Create new mc_config object from specified ini-file or
 827   append data to existing mc_config object from ini-file
 828 */
 829 
 830 static void
 831 load_setup_init_config_from_file (mc_config_t **config, const char *fname, gboolean read_only)
     /* [previous][next][first][last][top][bottom][index][help]  */
 832 {
 833     /*
 834        TODO: IMHO, in future, this function shall be placed in mcconfig module.
 835      */
 836     if (exist_file (fname))
 837     {
 838         if (*config != NULL)
 839             mc_config_read_file (*config, fname, read_only, TRUE);
 840         else
 841             *config = mc_config_init (fname, read_only);
 842     }
 843 }
 844 
 845 /* --------------------------------------------------------------------------------------------- */
 846 
 847 static mc_config_t *
 848 load_setup_get_keymap_profile_config (gboolean load_from_file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 849 {
 850     /*
 851        TODO: IMHO, in future, this function shall be placed in mcconfig module.
 852      */
 853     mc_config_t *keymap_config;
 854     char *share_keymap, *sysconfig_keymap;
 855     char *fname, *fname2;
 856 
 857     // 0) Create default keymap
 858     keymap_config = create_default_keymap ();
 859     if (!load_from_file)
 860         return keymap_config;
 861 
 862     // load and merge global keymaps
 863 
 864     // 1) /usr/share/mc (mc_global.share_data_dir)
 865     share_keymap = g_build_filename (mc_global.share_data_dir, GLOBAL_KEYMAP_FILE, (char *) NULL);
 866     load_setup_init_config_from_file (&keymap_config, share_keymap, TRUE);
 867 
 868     // 2) /etc/mc (mc_global.sysconfig_dir)
 869     sysconfig_keymap =
 870         g_build_filename (mc_global.sysconfig_dir, GLOBAL_KEYMAP_FILE, (char *) NULL);
 871     load_setup_init_config_from_file (&keymap_config, sysconfig_keymap, TRUE);
 872 
 873     // then load and merge one of user-defined keymap
 874 
 875     // 3) --keymap=<keymap>
 876     fname = load_setup_get_full_config_name (NULL, mc_args__keymap_file);
 877     if (fname != NULL && strcmp (fname, sysconfig_keymap) != 0 && strcmp (fname, share_keymap) != 0)
 878     {
 879         load_setup_init_config_from_file (&keymap_config, fname, TRUE);
 880         goto done;
 881     }
 882     g_free (fname);
 883 
 884     // 4) getenv("MC_KEYMAP")
 885     fname = load_setup_get_full_config_name (NULL, g_getenv ("MC_KEYMAP"));
 886     if (fname != NULL && strcmp (fname, sysconfig_keymap) != 0 && strcmp (fname, share_keymap) != 0)
 887     {
 888         load_setup_init_config_from_file (&keymap_config, fname, TRUE);
 889         goto done;
 890     }
 891 
 892     MC_PTR_FREE (fname);
 893 
 894     // 5) main config; [Midnight Commander] -> keymap
 895     fname2 = mc_config_get_string (mc_global.main_config, CONFIG_APP_SECTION, "keymap", NULL);
 896     if (fname2 != NULL && *fname2 != '\0')
 897         fname = load_setup_get_full_config_name (NULL, fname2);
 898     g_free (fname2);
 899     if (fname != NULL && strcmp (fname, sysconfig_keymap) != 0 && strcmp (fname, share_keymap) != 0)
 900     {
 901         load_setup_init_config_from_file (&keymap_config, fname, TRUE);
 902         goto done;
 903     }
 904     g_free (fname);
 905 
 906     // 6) ${XDG_CONFIG_HOME}/mc/mc.keymap
 907     fname = mc_config_get_full_path (GLOBAL_KEYMAP_FILE);
 908     load_setup_init_config_from_file (&keymap_config, fname, TRUE);
 909 
 910 done:
 911     g_free (fname);
 912     g_free (sysconfig_keymap);
 913     g_free (share_keymap);
 914 
 915     return keymap_config;
 916 }
 917 
 918 /* --------------------------------------------------------------------------------------------- */
 919 /*** public functions ****************************************************************************/
 920 /* --------------------------------------------------------------------------------------------- */
 921 
 922 void
 923 keymap_load (gboolean load_from_file)
     /* [previous][next][first][last][top][bottom][index][help]  */
 924 {
 925     /*
 926      * Load keymap from GLOBAL_KEYMAP_FILE before ${XDG_CONFIG_HOME}/mc/mc.keymap, so that the user
 927      * definitions override global settings.
 928      */
 929     mc_config_t *mc_global_keymap;
 930 
 931     mc_global_keymap = load_setup_get_keymap_profile_config (load_from_file);
 932 
 933     if (mc_global_keymap != NULL)
 934     {
 935 #define LOAD_KEYMAP(s, km)                                                                         \
 936     km##_keymap = g_array_new (TRUE, FALSE, sizeof (global_keymap_t));                             \
 937     load_keymap_from_section (KEYMAP_SECTION_##s, km##_keymap, mc_global_keymap)
 938 
 939         LOAD_KEYMAP (FILEMANAGER, filemanager);
 940         LOAD_KEYMAP (FILEMANAGER_EXT, filemanager_x);
 941         LOAD_KEYMAP (PANEL, panel);
 942         LOAD_KEYMAP (DIALOG, dialog);
 943         LOAD_KEYMAP (MENU, menu);
 944         LOAD_KEYMAP (INPUT, input);
 945         LOAD_KEYMAP (LISTBOX, listbox);
 946         LOAD_KEYMAP (RADIO, radio);
 947         LOAD_KEYMAP (TREE, tree);
 948         LOAD_KEYMAP (HELP, help);
 949 #ifdef ENABLE_EXT2FS_ATTR
 950         LOAD_KEYMAP (CHATTR, chattr);
 951 #endif
 952 #ifdef USE_INTERNAL_EDIT
 953         LOAD_KEYMAP (EDITOR, editor);
 954         LOAD_KEYMAP (EDITOR_EXT, editor_x);
 955 #endif
 956         LOAD_KEYMAP (VIEWER, viewer);
 957         LOAD_KEYMAP (VIEWER_HEX, viewer_hex);
 958 #ifdef USE_DIFF_VIEW
 959         LOAD_KEYMAP (DIFFVIEWER, diff);
 960 #endif
 961 
 962 #undef LOAD_KEYMAP
 963         mc_config_deinit (mc_global_keymap);
 964     }
 965 
 966 #define SET_MAP(m) m##_map = (global_keymap_t *) m##_keymap->data
 967 
 968     SET_MAP (filemanager);
 969     SET_MAP (filemanager_x);
 970     SET_MAP (panel);
 971     SET_MAP (dialog);
 972     SET_MAP (menu);
 973     SET_MAP (input);
 974     SET_MAP (listbox);
 975     SET_MAP (radio);
 976     SET_MAP (tree);
 977     SET_MAP (help);
 978 #ifdef ENABLE_EXT2FS_ATTR
 979     SET_MAP (chattr);
 980 #endif
 981 #ifdef USE_INTERNAL_EDIT
 982     SET_MAP (editor);
 983     SET_MAP (editor_x);
 984 #endif
 985     SET_MAP (viewer);
 986     SET_MAP (viewer_hex);
 987 #ifdef USE_DIFF_VIEW
 988     SET_MAP (diff);
 989 #endif
 990 
 991 #undef SET_MAP
 992 }
 993 
 994 /* --------------------------------------------------------------------------------------------- */
 995 
 996 void
 997 keymap_free (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 998 {
 999 #define FREE_KEYMAP(km)                                                                            \
1000     if (km##_keymap != NULL)                                                                       \
1001     g_array_free (km##_keymap, TRUE)
1002 
1003     FREE_KEYMAP (filemanager);
1004     FREE_KEYMAP (filemanager_x);
1005     FREE_KEYMAP (panel);
1006     FREE_KEYMAP (dialog);
1007     FREE_KEYMAP (menu);
1008     FREE_KEYMAP (input);
1009     FREE_KEYMAP (listbox);
1010     FREE_KEYMAP (radio);
1011     FREE_KEYMAP (tree);
1012     FREE_KEYMAP (help);
1013 #ifdef ENABLE_EXT2FS_ATTR
1014     FREE_KEYMAP (chattr);
1015 #endif
1016 #ifdef USE_INTERNAL_EDIT
1017     FREE_KEYMAP (editor);
1018     FREE_KEYMAP (editor_x);
1019 #endif
1020     FREE_KEYMAP (viewer);
1021     FREE_KEYMAP (viewer_hex);
1022 #ifdef USE_DIFF_VIEW
1023     FREE_KEYMAP (diff);
1024 #endif
1025 
1026 #undef FREE_KEYMAP
1027 }
1028 
1029 /* --------------------------------------------------------------------------------------------- */

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