/* 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() */ #include "../src/main.h" /* display_codepage */ #include "../src/strutil.h" /* str_isutf8 () */ /* * 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_Find_Definition }, { 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 ('-'), CK_Load_Prev_File }, { ALT ('='), CK_Load_Next_File }, { 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, int *ch) { int command = CK_Insert_Char; int char_for_insertion = -1; int i = 0; int extmod = 0; int c; 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) { #ifdef HAVE_CHARSET if ( edit->charpoint >= 4 ) { edit->charpoint = 0; edit->charbuf[edit->charpoint] = '\0'; } if ( edit->charpoint < 4 ) { edit->charbuf[edit->charpoint++] = x_key; edit->charbuf[edit->charpoint] = '\0'; } /* input from 8-bit locale */ if ( !utf8_display ) { /* source in 8-bit codeset */ if (!edit->utf8) { #endif c = convert_from_input_c (x_key); if (is_printable (c)) { char_for_insertion = c; goto fin; } #ifdef HAVE_CHARSET } else { c = convert_from_input_c (x_key); if (is_printable (c)) { char_for_insertion = convert_from_8bit_to_utf_c2((unsigned char) x_key); goto fin; } } /* UTF-8 locale */ } else { /* source in UTF-8 codeset */ if ( edit->utf8 ) { int res = str_is_valid_char (edit->charbuf, edit->charpoint); if (res < 0) { if (res != -2) { edit->charpoint = 0; /* broken multibyte char, skip */ goto fin; } char_for_insertion = x_key; goto fin; } else { edit->charbuf[edit->charpoint]='\0'; edit->charpoint = 0; if ( g_unichar_isprint (g_utf8_get_char(edit->charbuf))) { char_for_insertion = x_key; goto fin; } } /* 8-bit source */ } else { int res = str_is_valid_char (edit->charbuf, edit->charpoint); if (res < 0) { if (res != -2) { edit->charpoint = 0; /* broken multibyte char, skip */ goto fin; } /* not finised multibyte input (in meddle multibyte utf-8 char) */ goto fin; } else { if ( g_unichar_isprint (g_utf8_get_char(edit->charbuf)) ) { c = convert_from_utf_to_current ( edit->charbuf ); edit->charbuf[0] = '\0'; edit->charpoint = 0; char_for_insertion = c; goto fin; } /* unprinteble utf input, skip it */ edit->charbuf[0] = '\0'; edit->charpoint = 0; } } } #endif } /* 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 == -1) { /* unchanged, key has no function here */ return 0; } return 1; }