/* Definitions of key bindings. Copyright (C) 2009, 2011 The Free Software Foundation, Inc. Written by: Vitja Makarov, 2005 Ilia Maslakov , 2009 Andrew Borodin , 2009, 2010 This file is part of the Midnight Commander. The Midnight Commander is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The Midnight Commander is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include "lib/global.h" #include "lib/tty/key.h" /* KEY_M_ */ #include "lib/strutil.h" /* str_casecmp() */ #include "lib/keybind.h" /*** global variables ****************************************************************************/ /*** file scope macro definitions ****************************************************************/ /*** file scope type declarations ****************************************************************/ /*** file scope variables ************************************************************************/ static name_keymap_t command_names[] = { /* common */ {"Enter", CK_Enter}, {"Up", CK_Up}, {"Down", CK_Down}, {"Left", CK_Left}, {"Right", CK_Right}, {"LeftQuick", CK_LeftQuick}, {"RightQuick", CK_RightQuick}, {"Home", CK_Home}, {"End", CK_End}, {"PageUp", CK_PageUp}, {"PageDown", CK_PageDown}, {"HalfPageUp", CK_HalfPageUp}, {"HalfPageDown", CK_HalfPageDown}, {"Top", CK_Top}, {"Bottom", CK_Bottom}, {"TopOnScreen", CK_TopOnScreen}, {"MiddleOnScreen", CK_MiddleOnScreen}, {"BottomOnScreen", CK_BottomOnScreen}, {"WordLeft", CK_WordLeft}, {"WordRight", CK_WordRight}, {"Copy", CK_Copy}, {"Move", CK_Move}, {"Delete", CK_Delete}, {"MakeDir", CK_MakeDir}, {"ChangeMode", CK_ChangeMode}, {"ChangeOwn", CK_ChangeOwn}, {"ChangeOwnAdvanced", CK_ChangeOwnAdvanced}, {"Remove", CK_Remove}, {"BackSpace", CK_BackSpace}, {"Undo", CK_Undo}, {"Redo", CK_Redo}, {"Clear", CK_Clear}, {"Menu", CK_Menu}, {"MenuLastSelected", CK_MenuLastSelected}, {"UserMenu", CK_UserMenu}, {"EditUserMenu", CK_EditUserMenu}, {"Search", CK_Search}, {"SearchContinue", CK_SearchContinue}, {"Replace", CK_Replace}, {"ReplaceContinue", CK_ReplaceContinue}, {"Help", CK_Help}, {"Shell", CK_Shell}, {"Edit", CK_Edit}, {"EditNew", CK_EditNew}, #ifdef HAVE_CHARSET {"SelectCodepage", CK_SelectCodepage}, #endif {"History", CK_History}, {"HistoryNext", CK_HistoryNext}, {"HistoryPrev", CK_HistoryPrev}, {"Complete", CK_Complete}, {"Save", CK_Save}, {"SaveAs", CK_SaveAs}, {"Goto", CK_Goto}, {"Reread", CK_Reread}, {"Refresh", CK_Refresh}, {"Suspend", CK_Suspend}, {"Swap", CK_Swap}, {"HotList", CK_HotList}, {"SelectInvert", CK_SelectInvert}, {"ScreenList", CK_ScreenList}, {"ScreenNext", CK_ScreenNext}, {"ScreenPrev", CK_ScreenPrev}, {"FileNext", CK_FileNext}, {"FilePrev", CK_FilePrev}, {"DeleteToWordBegin", CK_DeleteToWordBegin}, {"DeleteToWordEnd", CK_DeleteToWordEnd}, {"Cut", CK_Cut}, {"Store", CK_Store}, {"Paste", CK_Paste}, {"Mark", CK_Mark}, {"MarkLeft", CK_MarkLeft}, {"MarkRight", CK_MarkRight}, {"MarkUp", CK_MarkUp}, {"MarkDown", CK_MarkDown}, {"MarkToWordBegin", CK_MarkToWordBegin}, {"MarkToWordEnd", CK_MarkToWordEnd}, {"MarkToHome", CK_MarkToHome}, {"MarkToEnd", CK_MarkToEnd}, {"ToggleNavigation", CK_ToggleNavigation}, {"Sort", CK_Sort}, {"Options", CK_Options}, {"LearnKeys", CK_LearnKeys}, {"Bookmark", CK_Bookmark}, {"Quit", CK_Quit}, {"QuitQuiet", CK_QuitQuiet}, {"ExtendedKeyMap", CK_ExtendedKeyMap}, /* main commands */ #ifdef USE_INTERNAL_EDIT {"EditForceInternal", CK_EditForceInternal}, #endif {"View", CK_View}, {"ViewRaw", CK_ViewRaw}, {"ViewFile", CK_ViewFile}, {"ViewFiltered", CK_ViewFiltered}, {"Find", CK_Find}, {"DirSize", CK_DirSize}, {"PanelListingSwitch", CK_PanelListingSwitch}, {"CompareDirs", CK_CompareDirs}, #ifdef USE_DIFF_VIEW {"CompareFiles", CK_CompareFiles}, #endif {"OptionsVfs", CK_OptionsVfs}, {"OptionsConfirm", CK_OptionsConfirm}, {"OptionsDisplayBits", CK_OptionsDisplayBits}, {"EditExtensionsFile", CK_EditExtensionsFile}, {"EditFileHighlightFile", CK_EditFileHighlightFile}, {"LinkSymbolicEdit", CK_LinkSymbolicEdit}, {"ExternalPanelize", CK_ExternalPanelize}, {"Filter", CK_Filter}, #ifdef ENABLE_VFS_FISH {"ConnectFish", CK_ConnectFish}, #endif #ifdef ENABLE_VFS_FTP {"ConnectFtp", CK_ConnectFtp}, #endif #ifdef ENABLE_VFS_SMB {"ConnectSmb", CK_ConnectSmb}, #endif {"PanelInfo", CK_PanelInfo}, #ifdef WITH_BACKGROUND {"Jobs", CK_Jobs}, #endif {"OptionsLayout", CK_OptionsLayout}, {"Link", CK_Link}, {"PanelListingChange", CK_PanelListingChange}, {"PanelListing", CK_PanelListing}, #ifdef LISTMODE_EDITOR {"ListMode", CK_ListMode}. #endif {"OptionsPanel", CK_OptionsPanel}, {"CdQuick", CK_CdQuick}, {"PanelQuickView", CK_PanelQuickView}, {"LinkSymbolicRelative", CK_LinkSymbolicRelative}, {"VfsList", CK_VfsList}, {"SaveSetup", CK_SaveSetup}, {"LinkSymbolic", CK_LinkSymbolic}, {"PanelTree", CK_PanelTree}, {"Tree", CK_Tree}, #ifdef ENABLE_VFS_UNDELFS {"Undelete", CK_Undelete}, #endif {"PutCurrentLink", CK_PutCurrentLink}, {"PutOtherLink", CK_PutOtherLink}, {"HotListAdd", CK_HotListAdd}, {"ShowHidden", CK_ShowHidden}, {"SplitVertHoriz", CK_SplitVertHoriz}, {"PutCurrentPath", CK_PutCurrentPath}, {"PutOtherPath", CK_PutOtherPath}, {"PutCurrentTagged", CK_PutCurrentTagged}, {"PutOtherTagged", CK_PutOtherTagged}, {"Select", CK_Select}, {"Unselect", CK_Unselect}, /* panel */ {"PanelOtherCd", CK_PanelOtherCd}, {"PanelOtherCdLink", CK_PanelOtherCdLink}, {"CopySingle", CK_CopySingle}, {"MoveSingle", CK_MoveSingle}, {"DeleteSingle", CK_DeleteSingle}, {"CdParent", CK_CdParent}, {"CdChild", CK_CdChild}, {"Panelize", CK_Panelize}, {"PanelOtherSync", CK_PanelOtherSync}, {"SortNext", CK_SortNext}, {"SortPrev", CK_SortPrev}, {"SortReverse", CK_SortReverse}, {"SortByName", CK_SortByName}, {"SortByExt", CK_SortByExt}, {"SortBySize", CK_SortBySize}, {"SortByMTime", CK_SortByMTime}, {"CdParentSmart", CK_CdParentSmart}, /* dialog */ {"Ok", CK_Ok}, {"Cancel", CK_Cancel}, /* input line */ {"Yank", CK_Yank}, /* help */ {"Index", CK_Index}, {"Back", CK_Back}, {"LinkNext", CK_LinkNext}, {"LinkPrev", CK_LinkPrev}, {"NodeNext", CK_NodeNext}, {"NodePrev", CK_NodePrev}, /* tree */ {"Forget", CK_Forget}, #if defined (USE_INTERNAL_EDIT) || defined (USE_DIFF_VIEW) {"ShowNumbers", CK_ShowNumbers}, #endif #ifdef USE_INTERNAL_EDIT {"Tab", CK_Tab}, {"ScrollUp", CK_ScrollUp}, {"ScrollDown", CK_ScrollDown}, {"Return", CK_Return}, {"ParagraphUp", CK_ParagraphUp}, {"ParagraphDown", CK_ParagraphDown}, {"EditFile", CK_EditFile}, {"MarkWord", CK_MarkWord}, {"MarkLine", CK_MarkLine}, {"MarkAll", CK_MarkAll}, {"Unmark", CK_Unmark}, {"MarkColumn", CK_MarkColumn}, {"BlockSave", CK_BlockSave}, {"InsertFile", CK_InsertFile}, {"InsertOverwrite", CK_InsertOverwrite}, {"Date", CK_Date}, {"DeleteLine", CK_DeleteLine}, {"DeleteToHome", CK_DeleteToHome}, {"DeleteToEnd", CK_DeleteToEnd}, {"EditMail", CK_Mail}, {"ParagraphFormat", CK_ParagraphFormat}, {"MatchBracket", CK_MatchBracket}, {"ExternalCommand", CK_ExternalCommand}, {"MacroStartRecord", CK_MacroStartRecord}, {"MacroStopRecord", CK_MacroStopRecord}, {"MacroStartStopRecord", CK_MacroStartStopRecord}, {"MacroDelete", CK_MacroDelete}, {"RepeatStartStopRecord", CK_RepeatStartStopRecord}, {"BookmarkFlush", CK_BookmarkFlush}, {"BookmarkNext", CK_BookmarkNext}, {"BookmarkPrev", CK_BookmarkPrev}, {"MarkPageUp", CK_MarkPageUp}, {"MarkPageDown", CK_MarkPageDown}, {"MarkToFileBegin", CK_MarkToFileBegin}, {"MarkToFileEnd", CK_MarkToFileEnd}, {"MarkToPageBegin", CK_MarkToPageBegin}, {"MarkToPageEnd", CK_MarkToPageEnd}, {"MarkScrollUp", CK_MarkScrollUp}, {"MarkScrollDown", CK_MarkScrollDown}, {"MarkParagraphUp", CK_MarkParagraphUp}, {"MarkParagraphDown", CK_MarkParagraphDown}, {"MarkColumnPageUp", CK_MarkColumnPageUp}, {"MarkColumnPageDown", CK_MarkColumnPageDown}, {"MarkColumnLeft", CK_MarkColumnLeft}, {"MarkColumnRight", CK_MarkColumnRight}, {"MarkColumnUp", CK_MarkColumnUp}, {"MarkColumnDown", CK_MarkColumnDown}, {"MarkColumnScrollUp", CK_MarkColumnScrollUp}, {"MarkColumnScrollDown", CK_MarkColumnScrollDown}, {"MarkColumnParagraphUp", CK_MarkColumnParagraphUp}, {"MarkColumnParagraphDown", CK_MarkColumnParagraphDown}, {"BlockShiftLeft", CK_BlockShiftLeft}, {"BlockShiftRight", CK_BlockShiftRight}, {"InsertLiteral", CK_InsertLiteral}, {"ShowTabTws", CK_ShowTabTws}, {"SyntaxOnOff", CK_SyntaxOnOff}, {"SyntaxChoose", CK_SyntaxChoose}, {"ShowMargin", CK_ShowMargin}, {"OptionsSaveMode", CK_OptionsSaveMode}, {"About", CK_About}, /* An action to run external script from macro */ {"ExecuteScript", CK_PipeBlock (0)}, #endif /* USE_INTERNAL_EDIT */ /* viewer */ {"WrapMode", CK_WrapMode}, {"HexEditMode", CK_HexEditMode}, {"HexMode", CK_HexMode}, {"MagicMode", CK_MagicMode}, {"NroffMode", CK_NroffMode}, {"BookmarkGoto", CK_BookmarkGoto}, {"Ruler", CK_Ruler}, #ifdef USE_DIFF_VIEW /* diff viewer */ {"ShowSymbols", CK_ShowSymbols}, {"SplitFull", CK_SplitFull}, {"SplitEqual", CK_SplitEqual}, {"SplitMore", CK_SplitMore}, {"SplitLess", CK_SplitLess}, {"Tab2", CK_Tab2}, {"Tab3", CK_Tab3}, {"Tab4", CK_Tab4}, {"Tab8", CK_Tab8}, {"HunkNext", CK_HunkNext}, {"HunkPrev", CK_HunkPrev}, {"EditOther", CK_EditOther}, {"Merge", CK_Merge}, #endif /* USE_DIFF_VIEW */ {NULL, CK_IgnoreKey} }; /* *INDENT-OFF* */ static const size_t num_command_names = G_N_ELEMENTS (command_names) - 1; /* *INDENT-ON* */ /*** file scope functions ************************************************************************/ /* --------------------------------------------------------------------------------------------- */ static int name_keymap_comparator (const void *p1, const void *p2) { const name_keymap_t *m1 = (const name_keymap_t *) p1; const name_keymap_t *m2 = (const name_keymap_t *) p2; return str_casecmp (m1->name, m2->name); } /* --------------------------------------------------------------------------------------------- */ static inline void sort_command_names (void) { static gboolean has_been_sorted = FALSE; if (!has_been_sorted) { qsort (command_names, num_command_names, sizeof (command_names[0]), &name_keymap_comparator); has_been_sorted = TRUE; } } /* --------------------------------------------------------------------------------------------- */ static void keymap_add (GArray * keymap, long key, unsigned long cmd, const char *caption) { if (key != 0 && cmd != CK_IgnoreKey) { global_keymap_t new_bind; new_bind.key = key; new_bind.command = cmd; g_snprintf (new_bind.caption, sizeof (new_bind.caption), "%s", caption); g_array_append_val (keymap, new_bind); } } /* --------------------------------------------------------------------------------------------- */ /*** public functions ****************************************************************************/ /* --------------------------------------------------------------------------------------------- */ void keybind_cmd_bind (GArray * keymap, const char *keybind, unsigned long action) { char *caption = NULL; long key; key = lookup_key (keybind, &caption); keymap_add (keymap, key, action, caption); g_free (caption); } /* --------------------------------------------------------------------------------------------- */ unsigned long keybind_lookup_action (const char *name) { const name_keymap_t key = { name, 0 }; name_keymap_t *res; sort_command_names (); res = bsearch (&key, command_names, num_command_names, sizeof (command_names[0]), name_keymap_comparator); return (res != NULL) ? res->val : CK_IgnoreKey; } /* --------------------------------------------------------------------------------------------- */ const char * keybind_lookup_actionname (unsigned long action) { size_t i; for (i = 0; command_names[i].name != NULL; i++) if (command_names[i].val == action) return command_names[i].name; return NULL; } /* --------------------------------------------------------------------------------------------- */ const char * keybind_lookup_keymap_shortcut (const global_keymap_t * keymap, unsigned long action) { size_t i; if (keymap != NULL) for (i = 0; keymap[i].key != 0; i++) if (keymap[i].command == action) return (keymap[i].caption[0] != '\0') ? keymap[i].caption : NULL; return NULL; } /* --------------------------------------------------------------------------------------------- */ unsigned long keybind_lookup_keymap_command (const global_keymap_t * keymap, long key) { size_t i; if (keymap != NULL) for (i = 0; keymap[i].key != 0; i++) if (keymap[i].key == key) return keymap[i].command; return CK_IgnoreKey; } /* --------------------------------------------------------------------------------------------- */