diff options
Diffstat (limited to 'src/LYKeymap.c')
-rw-r--r-- | src/LYKeymap.c | 1539 |
1 files changed, 1539 insertions, 0 deletions
diff --git a/src/LYKeymap.c b/src/LYKeymap.c new file mode 100644 index 0000000..b05d0a3 --- /dev/null +++ b/src/LYKeymap.c @@ -0,0 +1,1539 @@ +/* $LynxId: LYKeymap.c,v 1.122 2021/06/09 21:58:11 tom Exp $ */ +#include <HTUtils.h> +#include <LYUtils.h> +#include <LYGlobalDefs.h> +#include <LYKeymap.h> +#include <LYCharSets.h> /* for LYlowest_eightbit - kw */ +#include <HTAccess.h> +#include <HTFormat.h> +#include <HTAlert.h> +#include <LYStrings.h> /* for USE_KEYMAP stuff - kw */ + +#include <LYLeaks.h> + +#ifdef EXP_KEYBOARD_LAYOUT +#include <jcuken_kb.h> +#include <yawerty_kb.h> +#include <rot13_kb.h> +#endif + +#define PUTS(buf) (*target->isa->put_block)(target, buf, (int) strlen(buf)) + +#ifdef EXP_KEYBOARD_LAYOUT +int current_layout = 0; /* Index into LYKbLayouts[] */ + +LYKbLayout_t *LYKbLayouts[] = +{ + kb_layout_rot13, + kb_layout_jcuken, + kb_layout_yawerty +}; + +const char *LYKbLayoutNames[] = +{ + "ROT13'd keyboard layout", + "JCUKEN Cyrillic, for AT 101-key kbd", + "YAWERTY Cyrillic, for DEC LK201 kbd", + (char *) 0 +}; +#endif /* EXP_KEYBOARD_LAYOUT */ + +/* * * Tables mapping LynxKeyCodes to LynxActionCodes * * */ + +/* + * Lynxkeycodes include all single-byte keys as well as codes for function keys + * and some special purposes. See LYStrings.h. Extended lynxkeycode values + * can also contain flags for modifiers and other purposes, but here only the + * base values are mapped to lynxactioncodes. They are called `keystrokes' in + * lynx.cfg. + * + * Lynxactioncodes (confusingly, constants are named LYK_foo and typed as + * specify key `functions', see LYKeymap.h. + */ + +/* the character gets 1 added to it before lookup, + * so that EOF maps to 0 + */ +LYKeymap_t keymap[KEYMAP_SIZE]; + +static const LYEditInit initKeymapData[] = +{ + {KTL('@'), LYK_DO_NOTHING}, + {KTL('A'), LYK_HOME}, + {KTL('B'), LYK_PREV_PAGE}, + {KTL('D'), LYK_ABORT}, + {KTL('E'), LYK_END}, + {KTL('F'), LYK_NEXT_PAGE}, + {KTL('H'), LYK_HISTORY}, + {KTL('I'), LYK_FASTFORW_LINK}, + {KTL('J'), LYK_ACTIVATE}, + {KTL('K'), LYK_COOKIE_JAR}, + {KTL('L'), LYK_REFRESH}, + {KTL('M'), LYK_ACTIVATE}, + {KTL('N'), LYK_DOWN_TWO}, + {KTL('P'), LYK_UP_TWO}, + {KTL('Q'), LYK_CHANGE_CENTER}, + {KTL('R'), LYK_RELOAD}, + {KTL('S'), LYK_TO_CLIPBOARD}, + {KTL('T'), LYK_TRACE_TOGGLE}, + {KTL('U'), LYK_NEXT_DOC}, + {KTL('V'), LYK_SWITCH_DTD}, + {KTL('W'), LYK_REFRESH}, + {KTL('X'), LYK_CACHE_JAR}, + {KTL('Z'), LYK_MAXSCREEN_TOGGLE}, + {KHR(' '), LYK_NEXT_PAGE}, + {KHR('!'), LYK_SHELL}, + {KHR('"'), LYK_SOFT_DQUOTES}, + {KHR('#'), LYK_TOOLBAR}, + {KHR('$'), LYK_LAST_LINK}, + {KHR('\''), LYK_HISTORICAL}, + {KHR('('), LYK_UP_HALF}, + {KHR(')'), LYK_DOWN_HALF}, + {KHR('*'), LYK_IMAGE_TOGGLE}, + {KHR('+'), LYK_NEXT_PAGE}, + {KHR(','), LYK_EXTERN_PAGE}, + {KHR('-'), LYK_PREV_PAGE}, + {KHR('.'), LYK_EXTERN_LINK}, + {KHR('/'), LYK_WHEREIS}, + {KHR('0'), LYK_F_LINK_NUM}, + {KHR('1'), LYK_1}, + {KHR('2'), LYK_2}, + {KHR('3'), LYK_3}, + {KHR('4'), LYK_4}, + {KHR('5'), LYK_5}, + {KHR('6'), LYK_6}, + {KHR('7'), LYK_7}, + {KHR('8'), LYK_8}, + {KHR('9'), LYK_9}, + {KHR(':'), LYK_COMMAND}, + {KHR(';'), LYK_TRACE_LOG}, + {KHR('<'), LYK_UP_LINK}, + {KHR('='), LYK_INFO}, + {KHR('>'), LYK_DOWN_LINK}, + {KHR('?'), LYK_HELP}, + {KHR('@'), LYK_RAW_TOGGLE}, + {KHR('A'), LYK_ADDRLIST}, + {KHR('B'), LYK_PREV_PAGE}, +#ifdef SUPPORT_CHDIR + {KHR('C'), LYK_CHDIR}, +#else + {KHR('C'), LYK_COMMENT}, +#endif + {KHR('D'), LYK_DOWNLOAD}, + {KHR('E'), LYK_ELGOTO}, + {KHR('F'), LYK_DIRED_MENU}, + {KHR('G'), LYK_ECGOTO}, + {KHR('H'), LYK_HELP}, + {KHR('I'), LYK_INDEX}, +#ifdef KANJI_CODE_OVERRIDE + {KHR('J'), LYK_CHANGE_KCODE}, +#else + {KHR('J'), LYK_JUMP}, +#endif + {KHR('K'), LYK_KEYMAP}, + {KHR('L'), LYK_LIST}, + {KHR('M'), LYK_MAIN_MENU}, + {KHR('N'), LYK_PREV}, + {KHR('O'), LYK_OPTIONS}, + {KHR('P'), LYK_PRINT}, + {KHR('Q'), LYK_ABORT}, + {KHR('R'), LYK_DEL_BOOKMARK}, + {KHR('S'), LYK_INDEX_SEARCH}, + {KHR('T'), LYK_TAG_LINK}, + {KHR('U'), LYK_PREV_DOC}, + {KHR('V'), LYK_VLINKS}, + {KHR('X'), LYK_NOCACHE}, + {KHR('Z'), LYK_INTERRUPT}, + {KHR('['), LYK_INLINE_TOGGLE}, + {KHR('\\'), LYK_SOURCE}, + {KHR(']'), LYK_HEAD}, + {KHR('^'), LYK_FIRST_LINK}, + {KHR('_'), LYK_CLEAR_AUTH}, + {KHR('`'), LYK_MINIMAL}, + {KHR('a'), LYK_ADD_BOOKMARK}, + {KHR('b'), LYK_PREV_PAGE}, + {KHR('c'), LYK_COMMENT}, + {KHR('d'), LYK_DOWNLOAD}, + {KHR('e'), LYK_EDIT}, + {KHR('f'), LYK_DIRED_MENU}, + {KHR('g'), LYK_GOTO}, + {KHR('h'), LYK_HELP}, + {KHR('i'), LYK_INDEX}, + {KHR('j'), LYK_JUMP}, + {KHR('k'), LYK_KEYMAP}, + {KHR('l'), LYK_LIST}, + {KHR('m'), LYK_MAIN_MENU}, + {KHR('n'), LYK_NEXT}, + {KHR('o'), LYK_OPTIONS}, + {KHR('p'), LYK_PRINT}, + {KHR('q'), LYK_QUIT}, + {KHR('r'), LYK_DEL_BOOKMARK}, + {KHR('s'), LYK_INDEX_SEARCH}, + {KHR('t'), LYK_TAG_LINK}, + {KHR('u'), LYK_PREV_DOC}, + {KHR('v'), LYK_VIEW_BOOKMARK}, + {KHR('x'), LYK_NOCACHE}, + {KHR('z'), LYK_INTERRUPT}, + {KHR('{'), LYK_SHIFT_LEFT}, + {KHR('|'), LYK_LINEWRAP_TOGGLE}, + {KHR('}'), LYK_SHIFT_RIGHT}, + {KHR('~'), LYK_NESTED_TABLES}, + {KHR(DEL_KEY), LYK_HISTORY}, + {KHR(UPARROW_KEY), LYK_PREV_LINK}, + {KHR(DNARROW_KEY), LYK_NEXT_LINK}, + {KHR(RTARROW_KEY), LYK_ACTIVATE}, + {KHR(LTARROW_KEY), LYK_PREV_DOC}, + {KHR(PGDOWN_KEY), LYK_NEXT_PAGE}, + {KHR(PGUP_KEY), LYK_PREV_PAGE}, + {KHR(HOME_KEY), LYK_HOME}, + {KHR(END_KEY), LYK_END}, + {KHR(F1_KEY), LYK_DWIMHELP}, +#if !(defined(_WINDOWS) || defined(__DJGPP__)) + {KHR(DO_KEY), LYK_ACTIVATE}, + {KHR(FIND_KEY), LYK_HOME}, + {KHR(SELECT_KEY), LYK_END}, +#endif + {KHR(INSERT_KEY), LYK_UP_TWO}, + {KHR(REMOVE_KEY), LYK_DOWN_TWO}, + {KHR(DO_NOTHING), LYK_DO_NOTHING}, + {KHR(BACKTAB_KEY), LYK_FASTBACKW_LINK}, + {KHR(F11_KEY), LYK_DO_NOTHING}, +#ifdef DJGPP_KEYHANDLER + {302, LYK_ABORT}, +#endif /* DJGPP_KEYHANDLER */ +#if (defined(_WINDOWS) || defined(__DJGPP__) || defined(__CYGWIN__)) && !defined(USE_SLANG) /* PDCurses */ + {441, LYK_ABORT}, /* ALT_X */ + {459, LYK_WHEREIS}, /* KP_SLASH */ + {464, LYK_IMAGE_TOGGLE}, /* KP_* */ + {465, LYK_PREV_PAGE}, /* KP_- */ + {466, LYK_NEXT_PAGE}, /* KP_+ */ +#endif + {657, LYK_CHANGE_LINK}, + {-1, LYE_UNKNOWN} +}; + +static LYEditConfig myKeymapData = +{ + "Key Map", initKeymapData, keymap +}; + +#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE) +/* + * This table is used to override the standard keyboard assignments + * when lynx_edit_mode is in effect and keyboard overrides have been + * allowed at compile time. + */ + +LYKeymap_t key_override[KEYMAP_SIZE]; + +static const LYEditInit initOverrideData[] = +{ + {22, LYK_NEXT_DOC}, /* ^V */ + {47, LYK_TAG_LINK}, /* . */ +#ifndef SUPPORT_CHDIR + {68, LYK_CREATE}, /* C */ +#else + {68, LYK_CHDIR}, /* C */ +#endif + {71, LYK_DIRED_MENU}, /* F */ + {78, LYK_MODIFY}, /* M */ + {83, LYK_REMOVE}, /* R */ + {85, LYK_TAG_LINK}, /* T */ + {86, LYK_UPLOAD}, /* U */ + {100, LYK_CREATE}, /* c */ + {103, LYK_DIRED_MENU}, /* f */ + {110, LYK_MODIFY}, /* m */ + {115, LYK_REMOVE}, /* r */ + {117, LYK_TAG_LINK}, /* t */ + {118, LYK_UPLOAD}, /* u */ + {271, LYK_DO_NOTHING}, /* DO_NOTHING */ + {-1, LYE_UNKNOWN} +}; + +static LYEditConfig myOverrideData = +{ + "Key Override", initOverrideData, key_override +}; +#endif /* DIRED_SUPPORT && OK_OVERRIDE */ + +#define DATA(code, name, doc) { code, name, doc } +/* The order of this array must match the LYKeymapCode enum in LYKeymap.h */ +static Kcmd revmap[] = +{ + DATA( + LYK_UNKNOWN, "UNMAPPED", + NULL), + DATA( + LYK_COMMAND, "COMMAND", + "prompt for, execute a command"), + DATA( + LYK_1, "1", + NULL), + DATA( + LYK_2, "2", + NULL), + DATA( + LYK_3, "3", + NULL), + DATA( + LYK_4, "4", + NULL), + DATA( + LYK_5, "5", + NULL), + DATA( + LYK_6, "6", + NULL), + DATA( + LYK_7, "7", + NULL), + DATA( + LYK_8, "8", + NULL), + DATA( + LYK_9, "9", + NULL), + DATA( + LYK_SOURCE, "SOURCE", + "toggle source/presentation for current document"), + DATA( + LYK_RELOAD, "RELOAD", + "reload the current document"), + DATA( + LYK_QUIT, "QUIT", + "quit the browser"), + DATA( + LYK_ABORT, "ABORT", + "quit the browser unconditionally"), + DATA( + LYK_NEXT_PAGE, "NEXT_PAGE", + "view the next page of the document"), + DATA( + LYK_PREV_PAGE, "PREV_PAGE", + "view the previous page of the document"), + DATA( + LYK_UP_TWO, "UP_TWO", + "go back two lines in the document"), + DATA( + LYK_DOWN_TWO, "DOWN_TWO", + "go forward two lines in the document"), + DATA( + LYK_UP_HALF, "UP_HALF", + "go back half a page in the document"), + DATA( + LYK_DOWN_HALF, "DOWN_HALF", + "go forward half a page in the document"), + DATA( + LYK_REFRESH, "REFRESH", + "refresh the screen to clear garbled text"), + DATA( + LYK_HOME, "HOME", + "go to the beginning of the current document"), + DATA( + LYK_END, "END", + "go to the end of the current document"), + DATA( + LYK_FIRST_LINK, "FIRST_LINK", + "make the first link on the line current"), + DATA( + LYK_LAST_LINK, "LAST_LINK", + "make the last link on the line current"), + DATA( + LYK_PREV_LINK, "PREV_LINK", + "make the previous link current"), + DATA( + LYK_NEXT_LINK, "NEXT_LINK", + "make the next link current"), + DATA( + LYK_LPOS_PREV_LINK, "LPOS_PREV_LINK", + "make previous link current, same column for input"), + DATA( + LYK_LPOS_NEXT_LINK, "LPOS_NEXT_LINK", + "make next link current, same column for input"), + DATA( + LYK_FASTBACKW_LINK, "FASTBACKW_LINK", + "previous link or text area, only stops on links"), + DATA( + LYK_FASTFORW_LINK, "FASTFORW_LINK", + "next link or text area, only stops on links"), + DATA( + LYK_UP_LINK, "UP_LINK", + "move up the page to a previous link"), + DATA( + LYK_DOWN_LINK, "DOWN_LINK", + "move down the page to another link"), + DATA( + LYK_RIGHT_LINK, "RIGHT_LINK", + "move right to another link"), + DATA( + LYK_LEFT_LINK, "LEFT_LINK", + "move left to a previous link"), + DATA( + LYK_HISTORY, "HISTORY", + "display stack of currently-suspended documents"), + DATA( + LYK_PREV_DOC, "PREV_DOC", + "go back to the previous document"), + DATA( + LYK_NEXT_DOC, "NEXT_DOC", + "undo going back to the previous document"), + DATA( + LYK_ACTIVATE, "ACTIVATE", + "go to the document given by the current link"), + DATA( + LYK_MOUSE_SUBMIT, "MOUSE_SUBMIT", + "DO NOT MAP: follow current link, submit"), + DATA( + LYK_SUBMIT, "SUBMIT", + "prompt and submit form"), + DATA( + LYK_RESET, "RESET", + "reset fields on current form"), + DATA( + LYK_GOTO, "GOTO", + "go to a document given as a URL"), + DATA( + LYK_ECGOTO, "ECGOTO", + "edit the current document's URL and go to it"), + DATA( + LYK_HELP, "HELP", + "display help on using the browser"), + DATA( + LYK_DWIMHELP, "DWIMHELP", + "display help page that may depend on context"), + DATA( + LYK_INDEX, "INDEX", + "display an index of potentially useful documents"), + DATA( + LYK_NOCACHE, "NOCACHE", + "force submission of form or link with no-cache"), + DATA( + LYK_INTERRUPT, "INTERRUPT", + "interrupt network connection or transmission"), + DATA( + LYK_MAIN_MENU, "MAIN_MENU", + "return to the first screen (home page)"), + DATA( + LYK_OPTIONS, "OPTIONS", + "display and change option settings"), + DATA( + LYK_INDEX_SEARCH, "INDEX_SEARCH", + "allow searching of an index"), + DATA( + LYK_WHEREIS, "WHEREIS", + "search within the current document"), + DATA( + LYK_PREV, "PREV", + "search for the previous occurrence"), + DATA( + LYK_NEXT, "NEXT", + "search for the next occurrence"), + DATA( + LYK_COMMENT, "COMMENT", + "send a comment to the author of the current document"), + DATA( + LYK_EDIT, "EDIT", + "edit the current document or a form's textarea"), + DATA( + LYK_INFO, "INFO", + "display information on the current document and link"), + DATA( + LYK_PRINT, "PRINT", + "display choices for printing the current document"), + DATA( + LYK_ADD_BOOKMARK, "ADD_BOOKMARK", + "add to your personal bookmark list"), + DATA( + LYK_DEL_BOOKMARK, "DEL_BOOKMARK", + "delete from your personal bookmark list"), + DATA( + LYK_VIEW_BOOKMARK, "VIEW_BOOKMARK", + "view your personal bookmark list"), + DATA( + LYK_VLINKS, "VLINKS", + "list links visited during the current Lynx session"), + DATA( + LYK_SHELL, "SHELL", + "escape from the browser to the system"), + DATA( + LYK_DOWNLOAD, "DOWNLOAD", + "download the current link to your computer"), + DATA( + LYK_TRACE_TOGGLE, "TRACE_TOGGLE", + "toggle tracing of browser operations"), + DATA( + LYK_TRACE_LOG, "TRACE_LOG", + "view trace log if started in the current session"), + DATA( + LYK_IMAGE_TOGGLE, "IMAGE_TOGGLE", + "toggle handling of all images as links"), + DATA( + LYK_INLINE_TOGGLE, "INLINE_TOGGLE", + "toggle pseudo-ALTs for inlines with no ALT string"), + DATA( + LYK_HEAD, "HEAD", + "send a HEAD request for the current document or link"), + DATA( + LYK_DO_NOTHING, "DO_NOTHING", + NULL), + DATA( + LYK_TOGGLE_HELP, "TOGGLE_HELP", + "show other commands in the novice help menu"), + DATA( + LYK_JUMP, "JUMP", + "go directly to a target document or action"), + DATA( + LYK_EDITMAP, "EDITMAP", + "display the current edit-key map"), + DATA( + LYK_KEYMAP, "KEYMAP", + "display the current key map"), + DATA( + LYK_LIST, "LIST", + "list the references (links) in the current document"), + DATA( + LYK_TOOLBAR, "TOOLBAR", + "go to Toolbar or Banner in the current document"), + DATA( + LYK_HISTORICAL, "HISTORICAL", + "toggle historical vs. valid/minimal comment parsing"), + DATA( + LYK_MINIMAL, "MINIMAL", + "toggle minimal vs. valid comment parsing"), + DATA( + LYK_SOFT_DQUOTES, "SOFT_DQUOTES", + "toggle valid vs. soft double-quote parsing"), + DATA( + LYK_RAW_TOGGLE, "RAW_TOGGLE", + "toggle raw 8-bit translations or CJK mode ON or OFF"), + DATA( + LYK_COOKIE_JAR, "COOKIE_JAR", + "examine the Cookie Jar"), + DATA( + LYK_F_LINK_NUM, "F_LINK_NUM", + "invoke the 'Follow link (or page) number:' prompt"), + DATA( + LYK_CLEAR_AUTH, "CLEAR_AUTH", + "clear all authorization info for this session"), + DATA( + LYK_SWITCH_DTD, "SWITCH_DTD", + "switch between two ways of parsing HTML"), + DATA( + LYK_ELGOTO, "ELGOTO", + "edit the current link's URL or ACTION and go to it"), + DATA( + LYK_CHANGE_LINK, "CHANGE_LINK", + "force reset of the current link on the page"), + DATA( + LYK_DWIMEDIT, "DWIMEDIT", + "use external editor for context-dependent purpose"), + DATA( + LYK_EDITTEXTAREA, "EDITTEXTAREA", + "use an external editor to edit a form's textarea"), + DATA( + LYK_GROWTEXTAREA, "GROWTEXTAREA", + "add 5 new blank lines to the bottom of a textarea"), + DATA( + LYK_INSERTFILE, "INSERTFILE", + "insert file into a textarea (just above cursorline)"), +#ifdef USE_ADDRLIST_PAGE + DATA( + LYK_ADDRLIST, "ADDRLIST", + "like LIST command, but always shows the links' URLs"), +#endif +#ifdef USE_EXTERNALS + DATA( + LYK_EXTERN_LINK, "EXTERN_LINK", + "run external program with current link"), + DATA( + LYK_EXTERN_PAGE, "EXTERN_PAGE", + "run external program with current page"), +#endif +#ifdef VMS + DATA( + LYK_DIRED_MENU, "DIRED_MENU", + "invoke File/Directory Manager, if available"), +#else +#ifdef DIRED_SUPPORT + DATA( + LYK_DIRED_MENU, "DIRED_MENU", + "display a full menu of file operations"), + DATA( + LYK_CREATE, "CREATE", + "create a new file or directory"), + DATA( + LYK_REMOVE, "REMOVE", + "remove a file or directory"), + DATA( + LYK_MODIFY, "MODIFY", + "modify the name or location of a file or directory"), + DATA( + LYK_TAG_LINK, "TAG_LINK", + "tag a file or directory for later action"), + DATA( + LYK_UPLOAD, "UPLOAD", + "upload from your computer to the current directory"), + DATA( + LYK_INSTALL, "INSTALL", + "install file or tagged files into a system area"), +#endif /* DIRED_SUPPORT */ + DATA( + LYK_CHANGE_CENTER, "CHANGE_CENTER", + "toggle center alignment in HTML TABLE"), +#ifdef KANJI_CODE_OVERRIDE + DATA( + LYK_CHANGE_KCODE, "CHANGE_KCODE", + "Change Kanji code"), +#endif +#endif /* VMS */ +#ifdef SUPPORT_CHDIR + DATA( + LYK_CHDIR, "CHDIR", + "change current directory"), + DATA( + LYK_PWD, "PWD", + "print current directory"), +#endif +#ifdef USE_CURSES_PADS + DATA( + LYK_SHIFT_LEFT, "SHIFT_LEFT", + "shift the screen left"), + DATA( + LYK_SHIFT_RIGHT, "SHIFT_RIGHT", + "shift the screen right"), + DATA( + LYK_LINEWRAP_TOGGLE, "LINEWRAP_TOGGLE", + "toggle linewrap on/off"), +#endif +#ifdef CAN_CUT_AND_PASTE + DATA( + LYK_PASTE_URL, "PASTE_URL", + "Goto the URL in the clipboard"), + DATA( + LYK_TO_CLIPBOARD, "TO_CLIPBOARD", + "link's URL to Clip Board"), +#endif +#ifdef EXP_NESTED_TABLES + DATA( + LYK_NESTED_TABLES, "NESTED_TABLES", + "toggle nested-table parsing on/off"), +#endif +#ifdef USE_CACHEJAR + DATA( + LYK_CACHE_JAR, "CACHE_JAR", + "examine list of cached documents"), +#endif +#ifdef USE_MAXSCREEN_TOGGLE + DATA( + LYK_MAXSCREEN_TOGGLE, "MAXSCREEN_TOGGLE", + "toggle max screen and normal"), +#endif + DATA( + LYK_UNKNOWN, NULL, + "") +}; + + +#undef DATA +/* *INDENT-OFF* */ +static const struct { + int key; + const char *name; +} named_keys[] = { + { '\t', "<tab>" }, + { '\r', "<return>" }, + { CH_ESC, "ESC" }, + { ' ', "<space>" }, + { '<', "<" }, + { '>', ">" }, + /* LYExtraKeys */ + { CH_DEL, "<delete>" }, + { UPARROW_KEY, "Up Arrow" }, + { DNARROW_KEY, "Down Arrow" }, + { RTARROW_KEY, "Right Arrow" }, + { LTARROW_KEY, "Left Arrow" }, + { PGDOWN_KEY, "Page Down" }, + { PGUP_KEY, "Page Up" }, + { HOME_KEY, "Home" }, + { END_KEY, "End" }, + { F1_KEY, "F1" }, + { F2_KEY, "F2" }, + { F3_KEY, "F3" }, + { F4_KEY, "F4" }, + { F5_KEY, "F5" }, + { F6_KEY, "F6" }, + { F7_KEY, "F7" }, + { F8_KEY, "F8" }, + { F9_KEY, "F9" }, + { F10_KEY, "F10" }, + { F11_KEY, "F11" }, + { F12_KEY, "F12" }, + { DO_KEY, "Do key" }, + { FIND_KEY, "Find key" }, + { SELECT_KEY, "Select key" }, + { INSERT_KEY, "Insert key" }, + { REMOVE_KEY, "Remove key" }, + { DO_NOTHING, "(DO_NOTHING)" }, + { BACKTAB_KEY, "Back Tab" }, + { MOUSE_KEY, "mouse pseudo key" }, +}; +/* *INDENT-ON* */ + +/* + * Build a list of Lynx's commands, for use in the tab-completion in LYgetstr. + */ +HTList *LYcommandList(void) +{ + static HTList *myList = NULL; + + if (myList == NULL) { + unsigned j; + + myList = HTList_new(); + for (j = 0; revmap[j].name != 0; j++) { + if (revmap[j].doc != 0) { + char *data = NULL; + + StrAllocCopy(data, revmap[j].name); + HTList_addObject(myList, data); + } + } + } + return myList; +} + +/* + * Find the given keycode. + */ +Kcmd *LYKeycodeToKcmd(LYKeymapCode code) +{ + unsigned j; + Kcmd *result = 0; + + if (code > LYK_UNKNOWN) { + for (j = 0; revmap[j].name != 0; j++) { + if (revmap[j].code == code) { + result = revmap + j; + break; + } + } + } + return result; +} + +/* + * Find the given command-name, accepting an abbreviation if it is unique. + */ +Kcmd *LYStringToKcmd(const char *name) +{ + size_t need = strlen(name); + size_t j; + BOOL exact = FALSE; + Kcmd *result = 0; + Kcmd *maybe = 0; + + if (non_empty(name)) { + for (j = 0; revmap[j].name != 0; j++) { + if (!strcasecomp(revmap[j].name, name)) { + result = revmap + j; + break; + } else if (!exact + && !strncasecomp(revmap[j].name, name, (int) need)) { + if (maybe == 0) { + maybe = revmap + j; + } else { + if (revmap[j].name[need] != 0 + && maybe->name[need] != 0) { + maybe = 0; + exact = TRUE; + } + } + } + } + } + return (result != 0) ? result : maybe; +} + +char *LYKeycodeToString(int c, + int upper8) +{ + static char buf[30]; + unsigned n; + BOOLEAN named = FALSE; + + for (n = 0; n < TABLESIZE(named_keys); n++) { + if (named_keys[n].key == c) { + named = TRUE; + LYStrNCpy(buf, named_keys[n].name, sizeof(buf) - 1); + break; + } + } + + if (!named) { + if (c <= 0377 + && TOASCII(c) > TOASCII(' ') + && TOASCII(c) < 0177) + sprintf(buf, "%c", c); + else if (upper8 + && TOASCII(c) > TOASCII(' ') + && c <= 0377 + && c <= LYlowest_eightbit[current_char_set]) + sprintf(buf, "%c", c); + else if (TOASCII(c) < TOASCII(' ')) + sprintf(buf, "^%c", FROMASCII(TOASCII(c) | 0100)); + else if (c >= 0400) + sprintf(buf, "key-0x%x", (unsigned) c); + else + sprintf(buf, "0x%x", (unsigned) c); + } + return buf; +} + +int LYStringToKeycode(char *src) +{ + unsigned n; + int key = -1; + int len = (int) strlen(src); + + if (len == 1) { + key = *src; + } else if (len == 2 && *src == '^') { + key = src[1] & 0x1f; + } else if (len > 2 && !strncasecomp(src, "0x", 2)) { + char *dst = 0; + + key = (int) strtol(src, &dst, 0); + if (non_empty(dst)) + key = -1; + } else if (len > 6 && !strncasecomp(src, "key-", 4)) { + char *dst = 0; + + key = (int) strtol(src + 4, &dst, 0); + if (isEmpty(dst)) + key = -1; + } + if (key < 0) { + for (n = 0; n < TABLESIZE(named_keys); n++) { + if (!strcasecomp(named_keys[n].name, src)) { + key = named_keys[n].key; + break; + } + } + } + return key; +} + +#define PRETTY_LEN 11 + +static char *pretty_html(int c) +{ + char *src = LYKeycodeToString(c, TRUE); + + if (src != 0) { + /* *INDENT-OFF* */ + static const struct { + int code; + const char *name; + } table[] = { + { '<', "<" }, + { '>', ">" }, + { '"', """ }, + { '&', "&" } + }; + /* *INDENT-ON* */ + + static char buf[30]; + char *dst = buf; + int adj = 0; + unsigned n; + BOOLEAN found; + + while ((c = *src++) != 0) { + found = FALSE; + for (n = 0; n < TABLESIZE(table); n++) { + if (c == table[n].code) { + found = TRUE; + LYStrNCpy(dst, + table[n].name, + sizeof(buf) - (size_t) ((dst - buf) - 1)); + adj += (int) strlen(dst) - 1; + dst += (int) strlen(dst); + break; + } + } + if (!found) { + *dst++ = (char) c; + } + } + adj -= (int) (dst - buf) - PRETTY_LEN; + while (adj-- > 0) + *dst++ = ' '; + *dst = 0; + return buf; + } + + return 0; +} + +static char *format_binding(LYKeymap_t *table, int i) +{ + LYKeymap_t the_key = table[i]; + char *buf = 0; + char *formatted; + Kcmd *rmap = LYKeycodeToKcmd((LYKeymapCode) the_key); + + if (rmap != 0 + && rmap->name != 0 + && rmap->doc != 0 + && (formatted = pretty_html(i - 1)) != 0) { + HTSprintf0(&buf, "%-*s %-13s %s\n", + PRETTY_LEN, formatted, + rmap->name, + rmap->doc); + return buf; + } + return 0; +} + +/* if both is true, produce an additional line for the corresponding + uppercase key if its binding is different. - kw */ +static void print_binding(HTStream *target, int i, int both) +{ + char *buf; + LYKeymap_t lac1 = LYK_UNKNOWN; /* 0 */ + +#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE) + if (prev_lynx_edit_mode && !no_dired_support && + (lac1 = key_override[i]) != LYK_UNKNOWN) { + if ((buf = format_binding(key_override, i)) != 0) { + PUTS(buf); + FREE(buf); + } + } else +#endif /* DIRED_SUPPORT && OK_OVERRIDE */ + if ((buf = format_binding(keymap, i)) != 0) { + lac1 = keymap[i]; + PUTS(buf); + FREE(buf); + } + + if (!both) + return; + i -= ' '; /* corresponding uppercase key */ + +#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE) + if (prev_lynx_edit_mode && !no_dired_support && key_override[i]) { + if (key_override[i] != lac1 && + (buf = format_binding(key_override, i)) != 0) { + PUTS(buf); + FREE(buf); + } + } else +#endif /* DIRED_SUPPORT && OK_OVERRIDE */ + if (keymap[i] != lac1 && (buf = format_binding(keymap, i)) != 0) { + PUTS(buf); + FREE(buf); + } +} + +/* + * Return lynxactioncode whose name is the string func. returns -1 if not + * found. - kw + */ +int lacname_to_lac(const char *func) +{ + Kcmd *mp = LYStringToKcmd(func); + + return (mp != 0) ? (int) mp->code : -1; +} + +/* + * Return lynxkeycode represented by string src. returns -1 if not valid. + * + * This is simpler than what map_string_to_keysym() does for USE_KEYMAP, but + * compatible with revmap() used for processing KEYMAP options in the + * configuration file. - kw + */ +int lkcstring_to_lkc(const char *src) +{ + int c = -1; + + if (strlen(src) == 1) { + c = *src; + } else if (strlen(src) == 2 && *src == '^') { + c = src[1] & 037; + } else if (strlen(src) >= 2 && isdigit(UCH(*src))) { + char *next = 0; + + c = (int) strtol(src, &next, 0); + if (next != 0 && *next != '\0') + c = (-1); +#ifdef USE_KEYMAPS + } else { + map_string_to_keysym(src, &c, TRUE); +#ifndef USE_SLANG + if (c >= 0) { + /* make curses-keys mapped from Keysym_Strings[] available here */ + if ((c & LKC_MASK) > 255) + c &= ~LKC_ISLKC; + } +#endif +#endif + } + + if (c == CH_ESC) { + escape_bound = 1; + } else if (c < -1) { + c = (-1); + } + + return c; +} + +static int LYLoadKeymap(const char *arg GCC_UNUSED, + HTParentAnchor *anAnchor, + HTFormat format_out, + HTStream *sink) +{ + HTFormat format_in = WWW_HTML; + HTStream *target; + char *buf = 0; + int i; + + /* + * Set up the stream. - FM + */ + target = HTStreamStack(format_in, format_out, sink, anAnchor); + if (target == NULL) { + HTSprintf0(&buf, CANNOT_CONVERT_I_TO_O, + HTAtom_name(format_in), HTAtom_name(format_out)); + HTAlert(buf); + FREE(buf); + return (HT_NOT_LOADED); + } + anAnchor->no_cache = TRUE; + + HTSprintf0(&buf, "<html>\n<head>\n<title>%s</title>\n</head>\n<body>\n", + CURRENT_KEYMAP_TITLE); + PUTS(buf); + HTSprintf0(&buf, "<pre>\n"); + PUTS(buf); + + for (i = 'a' + 1; i <= 'z' + 1; i++) { + print_binding(target, i, TRUE); + } + for (i = 1; i < KEYMAP_SIZE; i++) { + /* + * Don't show CHANGE_LINK if mouse not enabled. + */ + if ((i >= 0200 || i <= ' ' || !isalpha(i - 1)) && + (LYUseMouse || (keymap[i] != LYK_CHANGE_LINK))) { + print_binding(target, i, FALSE); + } + } + + HTSprintf0(&buf, "</pre>\n</body>\n</html>\n"); + PUTS(buf); + + (*target->isa->_free) (target); + FREE(buf); + return (HT_LOADED); +} + +#ifdef GLOBALDEF_IS_MACRO +#define _LYKEYMAP_C_GLOBALDEF_1_INIT { "LYNXKEYMAP", LYLoadKeymap, 0} +GLOBALDEF(HTProtocol, LYLynxKeymap, _LYKEYMAP_C_GLOBALDEF_1_INIT); +#else +GLOBALDEF HTProtocol LYLynxKeymap = +{"LYNXKEYMAP", LYLoadKeymap, 0}; +#endif /* GLOBALDEF_IS_MACRO */ + +/* + * Install func as the mapping for key. + * If for_dired is TRUE, install it in the key_override[] table + * for Dired mode, otherwise in the general keymap[] table. + * If DIRED_SUPPORT or OK_OVERRIDE is not defined, don't do anything + * when for_dired is requested. + * returns lynxkeycode value != 0 if the mapping was made, 0 if not. + */ +int remap(char *key, + const char *func, + int for_dired) +{ + Kcmd *mp; + int c; + int result = 0; + +#if !defined(DIRED_SUPPORT) || !defined(OK_OVERRIDE) + if (for_dired) { + return result; + } +#endif + if (func != NULL) { + c = lkcstring_to_lkc(key); + if ((c >= 0) && (c < KEYMAP_SIZE)) { + /* Remapping of key actions is supported only for basic + * lynxkeycodes, without modifiers etc.! If we get somehow + * called for an invalid lynxkeycode, fail or silently ignore + * modifiers -KW + */ + if (!(c & (LKC_ISLECLAC | LKC_ISLAC))) { + c &= LKC_MASK; + if ((mp = LYStringToKcmd(func)) != 0) { +#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE) + if (for_dired) + key_override[c + 1] = mp->code; + else +#endif + keymap[c + 1] = (LYKeymap_t) mp->code; + /* don't return 0, successful */ + result = (c ? c : (int) LAC_TO_LKC0(mp->code)); + } + } + } + } + return result; +} + +typedef struct { + int code; + LYKeymap_t map; + LYKeymap_t save; +} ANY_KEYS; + +/* + * Save the given keys in the table, setting them to the map'd value. + */ +static void set_any_keys(ANY_KEYS * table, size_t size) +{ + size_t j, k; + + for (j = 0; j < size; ++j) { + k = (size_t) (table[j].code + 1); + table[j].save = keymap[k]; + keymap[k] = table[j].map; + } +} + +/* + * Restore the given keys from the table. + */ +static void reset_any_keys(ANY_KEYS * table, size_t size) +{ + size_t j, k; + + for (j = 0; j < size; ++j) { + k = (size_t) (table[j].code + 1); + keymap[k] = table[j].save; + } +} + +static ANY_KEYS vms_keys_table[] = +{ + {26, LYK_ABORT, 0}, /* control-Z */ + {'$', LYK_SHELL, 0}, +}; + +void set_vms_keys(void) +{ + set_any_keys(vms_keys_table, TABLESIZE(vms_keys_table)); +} + +static ANY_KEYS vi_keys_table[] = +{ + {'h', LYK_PREV_DOC, 0}, + {'j', LYK_NEXT_LINK, 0}, + {'k', LYK_PREV_LINK, 0}, + {'l', LYK_ACTIVATE, 0}, +}; + +static BOOLEAN did_vi_keys; + +void set_vi_keys(void) +{ + set_any_keys(vi_keys_table, TABLESIZE(vi_keys_table)); + did_vi_keys = TRUE; +} + +void reset_vi_keys(void) +{ + if (did_vi_keys) { + reset_any_keys(vi_keys_table, TABLESIZE(vi_keys_table)); + did_vi_keys = FALSE; + } +} + +static ANY_KEYS emacs_keys_table[] = +{ + {2, LYK_PREV_DOC, 0}, /* ^B */ + {14, LYK_NEXT_LINK, 0}, /* ^N */ + {16, LYK_PREV_LINK, 0}, /* ^P */ + {6, LYK_ACTIVATE, 0}, /* ^F */ +}; + +static BOOLEAN did_emacs_keys; + +void set_emacs_keys(void) +{ + set_any_keys(emacs_keys_table, TABLESIZE(emacs_keys_table)); + did_emacs_keys = TRUE; +} + +void reset_emacs_keys(void) +{ + if (did_emacs_keys) { + reset_any_keys(emacs_keys_table, TABLESIZE(emacs_keys_table)); + did_emacs_keys = FALSE; + } +} + +/* + * Map numbers to functions as labeled on the IBM Enhanced keypad, and save + * their original mapping for reset_numbers_as_arrows(). - FM + */ +static ANY_KEYS number_keys_table[] = +{ + {'1', LYK_END, 0}, + {'2', LYK_NEXT_LINK, 0}, + {'3', LYK_NEXT_PAGE, 0}, + {'4', LYK_PREV_DOC, 0}, + {'5', LYK_DO_NOTHING, 0}, + {'6', LYK_ACTIVATE, 0}, + {'7', LYK_HOME, 0}, + {'8', LYK_PREV_LINK, 0}, + {'9', LYK_PREV_PAGE, 0}, +}; + +static BOOLEAN did_number_keys; + +void set_numbers_as_arrows(void) +{ + set_any_keys(number_keys_table, TABLESIZE(number_keys_table)); + did_number_keys = TRUE; +} + +void reset_numbers_as_arrows(void) +{ + if (did_number_keys) { + reset_any_keys(number_keys_table, TABLESIZE(number_keys_table)); + did_number_keys = FALSE; + } +} + +char *key_for_func(int func) +{ + static char *buf; + int i; + char *formatted; + + if ((i = LYReverseKeymap(func)) >= 0) { + formatted = LYKeycodeToString(i, TRUE); + StrAllocCopy(buf, formatted != 0 ? formatted : "?"); + } else if (buf == 0) { + StrAllocCopy(buf, ""); + } + return buf; +} + +/* + * Given one or two keys as lynxkeycodes, returns an allocated string + * representing the key(s) suitable for statusline messages, or NULL if no + * valid lynxkeycode is passed in (i.e., lkc_first < 0 or some other failure). + * The caller must free the string. - kw + */ +char *fmt_keys(int lkc_first, + int lkc_second) +{ + char *buf = NULL; + BOOLEAN quotes = FALSE; + char *fmt_first; + char *fmt_second; + + if (lkc_first < 0) + return NULL; + fmt_first = LYKeycodeToString(lkc_first, TRUE); + if (fmt_first && strlen(fmt_first) == 1 && *fmt_first != '\'') { + quotes = TRUE; + } + if (quotes) { + if (lkc_second < 0) { + HTSprintf0(&buf, "'%s'", fmt_first); + return buf; + } else { + HTSprintf0(&buf, "'%s", fmt_first); + } + } else { + StrAllocCopy(buf, fmt_first); + } + if (lkc_second >= 0) { + fmt_second = LYKeycodeToString(lkc_second, TRUE); + if (!fmt_second) { + FREE(buf); + return NULL; + } + HTSprintf(&buf, "%s%s%s", + (((strlen(fmt_second) > 2 && *fmt_second != '<') || + (strlen(buf) > 2 && buf[strlen(buf) - 1] != '>')) + ? " " + : ""), + fmt_second, quotes ? "'" : ""); + } + return buf; +} + +/* + * This function returns the (int)ch mapped to the LYK_foo value passed to it + * as an argument. It is like LYReverseKeymap, only the order of search is + * different; e.g., small ASCII letters will be returned in preference to + * capital ones. Cf. LYKeyForEditAction, LYEditKeyForAction in LYEditmap.c + * which use the same order to find a best key. In addition, this function + * takes the dired override map into account while LYReverseKeymap doesn't. + * The caller must free the returned string. - kw + */ +#define FIRST_I 97 +#define NEXT_I(i,imax) ((i==122) ? 32 : (i==96) ? 123 : (i==126) ? 0 :\ + (i==31) ? 256 : (i==imax) ? 127 :\ + (i==255) ? (-1) :i+1) +static int best_reverse_keymap(int lac) +{ + int i, c; + + for (i = FIRST_I; i >= 0; i = NEXT_I(i, KEYMAP_SIZE - 1)) { +#ifdef NOT_ASCII + if (i < 256) { + c = FROMASCII(i); + } else +#endif + c = i; +#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE) + if (lynx_edit_mode && !no_dired_support && lac && + LKC_TO_LAC(key_override, c) == lac) + return c; +#endif /* DIRED_SUPPORT && OK_OVERRIDE */ + if (LKC_TO_LAC(keymap, c) == lac) { + return c; + } + } + + return (-1); +} + +/* + * This function returns a string representing a key mapped to a LYK_foo + * function, or NULL if not found. The string may represent a pair of keys. + * if context_code is FOR_INPUT, an appropriate binding for use while in the + * (forms) line editor is sought. - kw + */ +char *key_for_func_ext(int lac, + int context_code) +{ + int lkc, modkey = -1; + + if (context_code == FOR_INPUT) { + lkc = LYEditKeyForAction(lac, &modkey); + if (lkc >= 0) { + if (lkc & (LKC_MOD1 | LKC_MOD2 | LKC_MOD3)) { + return fmt_keys(modkey, lkc & ~(LKC_MOD1 | LKC_MOD2 | LKC_MOD3)); + } else { + return fmt_keys(lkc, -1); + } + } + } + lkc = best_reverse_keymap(lac); + if (lkc < 0) + return NULL; + if (context_code == FOR_INPUT) { + modkey = LYKeyForEditAction(LYE_LKCMD); + if (modkey < 0) + return NULL; + return fmt_keys(modkey, lkc); + } else { + return fmt_keys(lkc, -1); + } +} + +/* + * This function returns TRUE if the ch is non-alphanumeric and maps to KeyName + * (LYK_foo in the keymap[] array). - FM + */ +BOOLEAN LYisNonAlnumKeyname(int ch, + int KeyName) +{ + BOOLEAN result = FALSE; + + if (ch >= 0 && (ch + 1) < KEYMAP_SIZE) { + if ((ch <= 0 + || StrChr("0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz", ch) == NULL) + && (keymap[ch + 1] == KeyName)) { + result = TRUE; + } + } + return result; +} + +/* + * This function returns the (int)ch mapped to the LYK_foo value passed to it + * as an argument. - FM + */ +int LYReverseKeymap(int KeyName) +{ + int i; + int result = -1; + + for (i = 1; i < KEYMAP_SIZE; i++) { + if (keymap[i] == KeyName) { + result = (i - 1); + break; + } + } + + return result; +} + +#ifdef EXP_KEYBOARD_LAYOUT +BOOLEAN LYSetKbLayout(char *layout_id) +{ + int i; + BOOLEAN result = FALSE; + + for (i = 0; i < (int) TABLESIZE(LYKbLayoutNames) - 1; i++) { + if (!strcasecomp(LYKbLayoutNames[i], layout_id)) { + current_layout = i; + result = TRUE; + break; + } + } + + return result; +} +#endif + +#if 0 +/* + * This function was useful in converting the hand-crafted key-bindings to + * their reusable form in 2.8.8 -TD + */ +static void checkKeyMap(LYEditConfig * table) +{ + unsigned j, k; + char comment[80]; + int first = TRUE; + + for (j = 0; table->init[j].code >= 0; ++j) { + int code = table->init[j].code; + + if (table->init[j].edit != table->used[code]) { + if (first) { + printf("TABLE %s\n", table->name); + first = FALSE; + } + printf("%u: init %d vs used %d\n", + j, + table->init[j].edit, + table->used[code]); + } + } + for (j = 0; j < KEYMAP_SIZE; ++j) { + int code = (int) j; + BOOL found = FALSE; + + for (k = 0; table->init[k].code >= 0; ++k) { + if (code == table->init[k].code) { + found = TRUE; + break; + } + } + if (!found) { + if (table->used[j] != 0) { + unsigned used = (j - 1); + int edit = table->used[j]; + const char *prefix = "LYK_"; + const char *name = 0; + Kcmd *cmd = LYKeycodeToKcmd(edit + 0); + + if (cmd != 0) { + name = cmd->name; + } + + if (used < 32) { + char temp[80]; + const char *what = 0; + + switch (used) { + case 0: + what = "nul"; + break; + case 17: + what = "XON"; + break; + case 19: + what = "XOFF"; + break; + default: + sprintf(temp, "^%c", used + 'A'); + what = temp; + break; + } + sprintf(comment, "\t/* %s */", what); + } else if (used < 127) { + sprintf(comment, "\t/* %c */", used); + } else if (used == 127) { + strcpy(comment, "\t/* DEL */"); + } else { + const char *what = LYextraKeysToName(used); + + if (non_empty(what)) { + sprintf(comment, "\t/* %s%s */", what, + ((StrChr(what, '_') != 0) + ? "" + : "_KEY")); + } else { + strcpy(comment, ""); + } + } + if (name == 0) { + name = "XXX"; + } + if (first) { + printf("TABLE %s\n", table->name); + first = FALSE; + } + printf("\t{ %d, %s%s },%s\n", code, prefix, name, comment); + } + } + } +} + +#else +#define checkKeyMap(table) /* nothing */ +#endif + +static void initKeyMap(LYEditConfig * table) +{ + unsigned k; + LYEditCode *used = table->used; + const LYEditInit *init = table->init; + + memset(used, 0, sizeof(LYEditCode) * KEYMAP_SIZE); + + for (k = 0; init[k].code >= 0; ++k) { + int code = init[k].code; + + used[code] = init[k].edit; + } + checkKeyMap(table); +} + +/* + * Reset the key bindings to their default values. + */ +void LYinitKeymap(void) +{ + CTRACE((tfp, "LYinitKeymap\n")); + initKeyMap(&myKeymapData); +#if defined(DIRED_SUPPORT) && defined(OK_OVERRIDE) + initKeyMap(&myOverrideData); +#endif +} |