/* Editor key translation. Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Authors: 1996, 1997 Paul Sheer This program 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 2 of the License, or (at your option) any later version. This program 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, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include "../src/global.h" #include "edit.h" #include "edit-widget.h" /* edit->macro_i */ #include "editcmddef.h" /* list of commands */ #include "../src/key.h" /* KEY_M_SHIFT */ #include "../src/tty.h" /* keys */ #include "../src/charsets.h" /* convert_from_input_c() */ #include "../src/selcodepage.h" /* do_select_codepage() */ /* * Ordinary translations. Note that the keys listed first take priority * when the key is assigned to more than one command. */ static const edit_key_map_type cooledit_key_map[] = { { ALT ('b'), CK_Match_Bracket }, { ALT ('m'), CK_Mail }, { XCTRL ('f'), CK_Save_Block }, { XCTRL ('n'), CK_New }, { XCTRL ('p'), CK_Pipe_Block (1) }, /* spell check */ { XCTRL ('x'), CK_Word_Right }, { XCTRL ('y'), CK_Delete_Line }, { XCTRL ('z'), CK_Word_Left }, { 0, 0 } }; static const edit_key_map_type emacs_key_map[] = { { ALT ('$'), CK_Pipe_Block (1) }, /* spell check */ { ALT ('b'), CK_Word_Left }, { ALT ('f'), CK_Word_Right }, { ALT ('v'), CK_Page_Up }, { ALT ('w'), CK_XStore }, { XCTRL ('@'), CK_Mark }, { XCTRL ('a'), CK_Home }, { XCTRL ('b'), CK_Left }, { XCTRL ('e'), CK_End }, { XCTRL ('f'), CK_Right }, { XCTRL ('g'), CK_Ignore_Key }, { XCTRL ('n'), CK_Down }, { XCTRL ('p'), CK_Up }, { XCTRL ('s'), CK_Find }, { XCTRL ('v'), CK_Page_Down }, { XCTRL ('w'), CK_XCut }, { XCTRL ('y'), CK_XPaste }, { 0, 0 } }; static const edit_key_map_type common_key_map[] = { { '\n', CK_Enter }, { '\t', CK_Tab }, { ESC_CHAR, CK_Exit }, { KEY_BACKSPACE, CK_BackSpace }, { KEY_DC, CK_Delete }, { KEY_DOWN, CK_Down }, { KEY_END, CK_End }, { KEY_HOME, CK_Home }, { KEY_IC, CK_Toggle_Insert }, { KEY_LEFT, CK_Left }, { KEY_NPAGE, CK_Page_Down }, { KEY_PPAGE, CK_Page_Up }, { KEY_RIGHT, CK_Right }, { KEY_UP, CK_Up }, { ALT ('\n'), CK_Return }, { ALT ('\t'), CK_Complete_Word }, { ALT ('l'), CK_Goto }, { ALT ('L'), CK_Goto }, { ALT ('p'), CK_Paragraph_Format }, { ALT ('t'), CK_Sort }, { ALT ('u'), CK_ExtCmd }, { ALT ('<'), CK_Beginning_Of_Text }, { ALT ('>'), CK_End_Of_Text }, { ALT (KEY_BACKSPACE), CK_Delete_Word_Left }, { XCTRL ('k'), CK_Delete_To_Line_End }, { XCTRL ('l'), CK_Refresh }, { XCTRL ('o'), CK_Shell }, { XCTRL ('s'), CK_Toggle_Syntax }, { XCTRL ('u'), CK_Undo }, { XCTRL ('t'), CK_Select_Codepage }, { XCTRL ('q'), CK_Insert_Literal }, { XCTRL ('a'), CK_Execute_Macro }, { XCTRL ('r'), CK_Begin_End_Macro }, { KEY_F (1), CK_Help }, { KEY_F (2), CK_Save }, { KEY_F (3), CK_Mark }, { KEY_F (4), CK_Replace }, { KEY_F (5), CK_Copy }, { KEY_F (6), CK_Move }, { KEY_F (7), CK_Find }, { KEY_F (8), CK_Remove }, { KEY_F (10), CK_Exit }, { KEY_F (11), CK_User_Menu }, /* edit user menu */ { KEY_F (12), CK_Save_As }, { KEY_F (13), CK_Column_Mark }, { KEY_F (14), CK_Replace_Again }, { KEY_F (15), CK_Insert_File }, { KEY_F (17), CK_Find_Again }, { KEY_F (19), CK_Pipe_Block (0) }, /* C formatter */ /* Shift */ { KEY_M_SHIFT | KEY_PPAGE, CK_Page_Up_Highlight }, { KEY_M_SHIFT | KEY_NPAGE, CK_Page_Down_Highlight }, { KEY_M_SHIFT | KEY_LEFT, CK_Left_Highlight }, { KEY_M_SHIFT | KEY_RIGHT, CK_Right_Highlight }, { KEY_M_SHIFT | KEY_UP, CK_Up_Highlight }, { KEY_M_SHIFT | KEY_DOWN, CK_Down_Highlight }, { KEY_M_SHIFT | KEY_HOME, CK_Home_Highlight }, { KEY_M_SHIFT | KEY_END, CK_End_Highlight }, { KEY_M_SHIFT | KEY_IC, CK_XPaste }, { KEY_M_SHIFT | KEY_DC, CK_XCut }, { KEY_M_SHIFT | '\n', CK_Return }, /* useful for pasting multiline text */ /* Ctrl */ { KEY_M_CTRL | (KEY_F (2)), CK_Save_As }, { KEY_M_CTRL | (KEY_F (4)), CK_Replace_Again }, { KEY_M_CTRL | (KEY_F (7)), CK_Find_Again }, { KEY_M_CTRL | KEY_BACKSPACE, CK_Undo }, { KEY_M_CTRL | KEY_PPAGE, CK_Beginning_Of_Text }, { KEY_M_CTRL | KEY_NPAGE, CK_End_Of_Text }, { KEY_M_CTRL | KEY_HOME, CK_Beginning_Of_Text }, { KEY_M_CTRL | KEY_END, CK_End_Of_Text }, { KEY_M_CTRL | KEY_UP, CK_Scroll_Up }, { KEY_M_CTRL | KEY_DOWN, CK_Scroll_Down }, { KEY_M_CTRL | KEY_LEFT, CK_Word_Left }, { KEY_M_CTRL | KEY_RIGHT, CK_Word_Right }, { KEY_M_CTRL | KEY_IC, CK_XStore }, { KEY_M_CTRL | KEY_DC, CK_Remove }, /* Ctrl + Shift */ { KEY_M_SHIFT | KEY_M_CTRL | KEY_PPAGE, CK_Beginning_Of_Text_Highlight }, { KEY_M_SHIFT | KEY_M_CTRL | KEY_NPAGE, CK_End_Of_Text_Highlight }, { KEY_M_SHIFT | KEY_M_CTRL | KEY_LEFT, CK_Word_Left_Highlight }, { KEY_M_SHIFT | KEY_M_CTRL | KEY_RIGHT, CK_Word_Right_Highlight }, { KEY_M_SHIFT | KEY_M_CTRL | KEY_UP, CK_Scroll_Up_Highlight }, { KEY_M_SHIFT | KEY_M_CTRL | KEY_DOWN, CK_Scroll_Down_Highlight }, { 0, 0 } }; /* * Translate the keycode into either 'command' or 'char_for_insertion'. * 'command' is one of the editor commands from editcmddef.h. */ int edit_translate_key (WEdit *edit, long x_key, int *cmd, mc_wint_t *ch) { int command = CK_Insert_Char; mc_wint_t char_for_insertion = -1; int i = 0; int extmod = 0; const edit_key_map_type *key_map = NULL; switch (edit_key_emulation) { case EDIT_KEY_EMULATION_NORMAL: key_map = cooledit_key_map; break; case EDIT_KEY_EMULATION_EMACS: key_map = emacs_key_map; if (x_key == XCTRL ('x')) { int ext_key; ext_key = edit_raw_key_query (" Ctrl-X ", _(" Emacs key: "), 0); switch (ext_key) { case 's': command = CK_Save; goto fin; case 'x': command = CK_Exit; goto fin; case 'k': command = CK_New; goto fin; case 'e': command = CK_Macro (edit_raw_key_query (_(" Execute Macro "), _(" Press macro hotkey: "), 1)); if (command == CK_Macro (0)) command = CK_Insert_Char; goto fin; } goto fin; } break; case EDIT_KEY_EMULATION_USER: if (edit->user_map != NULL) { if (edit->extmod && edit->ext_map != NULL) { key_map = edit->ext_map; extmod = 1; } else { key_map = edit->user_map; } edit->extmod = 0; } else { key_map = edit->user_map = cooledit_key_map; } break; } assert (key_map != NULL); /* an ordinary insertable character */ if (x_key < 256 && !extmod) { int c = convert_from_input_c (x_key); #ifdef UTF8 mbstate_t mbs; int res; mc_wchar_t wc; memset (&mbs, 0, sizeof (mbs)); if (edit->charpoint >= MB_CUR_MAX) edit->charpoint = 0; edit->charbuf[edit->charpoint++] = c; res = mbrtowc(&wc, (char *)edit->charbuf, edit->charpoint, &mbs); if (res < 0) { if (res != -2) edit->charpoint = 0; /* broken multibyte char, skip */ return 0; } edit->charpoint = 0; if (iswprint (wc)) { char_for_insertion = wc; #else if (is_printable (c)) { char_for_insertion = c; #endif /* UTF8 */ goto fin; } } /* Commands specific to the key emulation */ for (i = 0; key_map[i].key != 0 && key_map[i].key != x_key; i++) continue; if (key_map[i].key != 0) { command = key_map[i].command; goto fin; } /* Commands common for the key emulations */ key_map = common_key_map; for (i = 0; key_map[i].key != 0 && key_map[i].key != x_key; i++) continue; if (key_map[i].key != 0) { command = key_map[i].command; goto fin; } /* Function still not found for this key, so try macros */ /* This allows the same macro to be enabled by either eg "ALT('f')" or "XCTRL('f')" or "XCTRL('a'), 'f'" */ if (x_key & ALT (0)) { /* is an alt key ? */ command = CK_Macro (x_key - ALT (0)); goto fin; } if (x_key < ' ') { /* is a ctrl key ? */ command = CK_Macro (x_key); goto fin; } fin: *cmd = command; *ch = char_for_insertion; if (command == CK_Insert_Char && char_for_insertion == (mc_wint_t)-1) { /* unchanged, key has no function here */ return 0; } return 1; }