mc/lib/keybind.c
2018-02-04 11:30:22 +03:00

493 lines
15 KiB
C

/*
Definitions of key bindings.
Copyright (C) 2005-2018
Free Software Foundation, Inc.
Written by:
Vitja Makarov, 2005
Ilia Maslakov <il.smind@gmail.com>, 2009, 2012
Andrew Borodin <aborodin@vmail.ru>, 2009, 2010, 2011, 2012
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 <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "lib/global.h"
#include "lib/tty/key.h" /* KEY_M_ */
#include "lib/keybind.h"
/*** global variables ****************************************************************************/
/*** file scope macro definitions ****************************************************************/
/*** file scope type declarations ****************************************************************/
/*** file scope variables ************************************************************************/
static name_keymap_t command_names[] = {
/* common */
{"InsertChar", CK_InsertChar},
{"Enter", CK_Enter},
{"ChangePanel", CK_ChangePanel},
{"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},
{"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},
{"DeleteToHome", CK_DeleteToHome},
{"DeleteToEnd", CK_DeleteToEnd},
{"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},
{"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_SFTP
{"ConnectSftp", CK_ConnectSftp},
#endif
#ifdef ENABLE_VFS_SMB
{"ConnectSmb", CK_ConnectSmb},
#endif
{"PanelInfo", CK_PanelInfo},
#ifdef ENABLE_BACKGROUND
{"Jobs", CK_Jobs},
#endif
{"OptionsLayout", CK_OptionsLayout},
{"OptionsAppearance", CK_OptionsAppearance},
{"Link", CK_Link},
{"SetupListingFormat", CK_SetupListingFormat},
{"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},
{"SplitEqual", CK_SplitEqual},
{"SplitMore", CK_SplitMore},
{"SplitLess", CK_SplitLess},
{"PutCurrentPath", CK_PutCurrentPath},
{"PutOtherPath", CK_PutOtherPath},
{"PutCurrentSelected", CK_PutCurrentSelected},
{"PutCurrentFullSelected", CK_PutCurrentFullSelected},
{"PutCurrentTagged", CK_PutCurrentTagged},
{"PutOtherTagged", CK_PutOtherTagged},
{"Select", CK_Select},
{"Unselect", CK_Unselect},
/* panel */
{"SelectExt", CK_SelectExt},
{"ScrollLeft", CK_ScrollLeft},
{"ScrollRight", CK_ScrollRight},
{"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},
{"CycleListingFormat", CK_CycleListingFormat},
/* 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
{"Close", CK_Close},
{"Tab", CK_Tab},
{"Undo", CK_Undo},
{"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},
{"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},
#ifdef HAVE_ASPELL
{"SpellCheck", CK_SpellCheck},
{"SpellCheckCurrentWord", CK_SpellCheckCurrentWord},
{"SpellCheckSelectLang", CK_SpellCheckSelectLang},
#endif /* HAVE_ASPELL */
{"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)},
{"WindowMove", CK_WindowMove},
{"WindowResize", CK_WindowResize},
{"WindowFullscreen", CK_WindowFullscreen},
{"WindowList", CK_WindowList},
{"WindowNext", CK_WindowNext},
{"WindowPrev", CK_WindowPrev},
#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},
{"SearchForward", CK_SearchForward},
{"SearchBackward", CK_SearchBackward},
{"SearchForwardContinue", CK_SearchForwardContinue},
{"SearchBackwardContinue", CK_SearchBackwardContinue},
#ifdef USE_DIFF_VIEW
/* diff viewer */
{"ShowSymbols", CK_ShowSymbols},
{"SplitFull", CK_SplitFull},
{"Tab2", CK_Tab2},
{"Tab3", CK_Tab3},
{"Tab4", CK_Tab4},
{"Tab8", CK_Tab8},
{"HunkNext", CK_HunkNext},
{"HunkPrev", CK_HunkPrev},
{"EditOther", CK_EditOther},
{"Merge", CK_Merge},
{"MergeOther", CK_MergeOther},
#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 g_ascii_strcasecmp (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, 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, long action)
{
char *caption = NULL;
long key;
key = lookup_key (keybind, &caption);
keymap_add (keymap, key, action, caption);
g_free (caption);
}
/* --------------------------------------------------------------------------------------------- */
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 (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, long action)
{
if (keymap != NULL)
{
size_t i;
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;
}
/* --------------------------------------------------------------------------------------------- */
long
keybind_lookup_keymap_command (const global_keymap_t * keymap, long key)
{
if (keymap != NULL)
{
size_t i;
for (i = 0; keymap[i].key != 0; i++)
if (keymap[i].key == key)
return keymap[i].command;
}
return CK_IgnoreKey;
}
/* --------------------------------------------------------------------------------------------- */