diff options
author | Johannes Hofmann <Johannes.Hofmann@gmx.de> | 2010-08-20 23:24:19 +0200 |
---|---|---|
committer | Johannes Hofmann <Johannes.Hofmann@gmx.de> | 2010-08-20 23:24:19 +0200 |
commit | f5c598b518d1f906148534d015f50075d3e8242d (patch) | |
tree | 21dd70add5b366c3dd80641b77f6b18e0baa009e /src/keys.cc | |
parent | e98d02a01ffeb18ede86af025e51ae1ec011c75a (diff) | |
parent | 5f0fc0e48b8cbee7e1795935da0abff6627fd498 (diff) |
merge
Diffstat (limited to 'src/keys.cc')
-rw-r--r-- | src/keys.cc | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/src/keys.cc b/src/keys.cc new file mode 100644 index 00000000..1a39f4c8 --- /dev/null +++ b/src/keys.cc @@ -0,0 +1,363 @@ +/* + * Key parser + * + * Copyright (C) 2009 Jorge Arellano Cid <jcid@dillo.org> + * + * 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 3 of the License, or + * (at your option) any later version. + */ + +#include <fltk/events.h> +#include <stdio.h> +#include <stdlib.h> /* strtol */ +#include <string.h> +#include <ctype.h> + +#include "dlib/dlib.h" +#include "keys.hh" +#include "msg.h" + +/* + * Local data types + */ +typedef struct { + const char *name; + KeysCommand_t cmd; + int modifier, key; +} KeyBinding_t; + +typedef struct { + const char *name; + const int value; +} Mapping_t; + + +/* + * Local data + */ +static const Mapping_t keyNames[] = { + { "Backspace", fltk::BackSpaceKey }, + { "Delete", fltk::DeleteKey }, + { "Down", fltk::DownKey }, + { "End", fltk::EndKey }, + { "Esc", fltk::EscapeKey }, + { "F1", fltk::F1Key }, + { "F2", fltk::F2Key }, + { "F3", fltk::F3Key }, + { "F4", fltk::F4Key }, + { "F5", fltk::F5Key }, + { "F6", fltk::F6Key }, + { "F7", fltk::F7Key }, + { "F8", fltk::F8Key }, + { "F9", fltk::F9Key }, + { "F10", fltk::F10Key }, + { "F11", fltk::F11Key }, + { "F12", fltk::F12Key }, + { "Home", fltk::HomeKey }, + { "Insert", fltk::InsertKey }, + { "Left", fltk::LeftKey }, + { "PageDown", fltk::PageDownKey }, + { "PageUp", fltk::PageUpKey }, + { "Print", fltk::PrintKey }, + { "Return", fltk::ReturnKey }, + { "Right", fltk::RightKey }, + { "Space", fltk::SpaceKey }, + { "Tab", fltk::TabKey }, + { "Up", fltk::UpKey } +}; + +static const Mapping_t modifierNames[] = { + { "Shift", fltk::SHIFT }, + { "Ctrl", fltk::CTRL }, + { "Alt", fltk::ALT }, + { "Meta", fltk::META }, + { "Button1", fltk::BUTTON1 }, + { "Button2", fltk::BUTTON2 }, + { "Button3", fltk::BUTTON3 } +}; + +static const KeyBinding_t default_keys[] = { + { "nop" , KEYS_NOP , 0 , 0 }, + { "open" , KEYS_OPEN , fltk::CTRL , 'o' }, + { "new-window" , KEYS_NEW_WINDOW , fltk::CTRL , 'n' }, + { "new-tab" , KEYS_NEW_TAB , fltk::CTRL , 't' }, + { "left-tab" , KEYS_LEFT_TAB , fltk::SHIFT , fltk::TabKey }, + { "right-tab" , KEYS_RIGHT_TAB , fltk::CTRL , fltk::TabKey }, + { "close-tab" , KEYS_CLOSE_TAB , fltk::CTRL , 'q' }, + { "find" , KEYS_FIND , fltk::CTRL , 'f' }, + { "websearch" , KEYS_WEBSEARCH , fltk::CTRL , 's' }, + { "bookmarks" , KEYS_BOOKMARKS , fltk::CTRL , 'b' }, + { "fullscreen" , KEYS_FULLSCREEN , fltk::CTRL , fltk::SpaceKey }, + { "reload" , KEYS_RELOAD , fltk::CTRL , 'r' }, + { "stop" , KEYS_STOP , 0 , 0 }, + { "save" , KEYS_SAVE , 0 , 0 }, + { "hide-panels" , KEYS_HIDE_PANELS , 0 , fltk::EscapeKey }, + { "file-menu" , KEYS_FILE_MENU , fltk::ALT , 'f' }, + { "close-all" , KEYS_CLOSE_ALL , fltk::ALT , 'q' }, + { "back" , KEYS_BACK , 0 , fltk::BackSpaceKey }, + { "back" , KEYS_BACK , 0 , ',' }, + { "forward" , KEYS_FORWARD , fltk::SHIFT , fltk::BackSpaceKey }, + { "forward" , KEYS_FORWARD , 0 , '.' }, + { "goto" , KEYS_GOTO , fltk::CTRL , 'l' }, + { "home" , KEYS_HOME , fltk::CTRL , 'h' }, + { "screen-up" , KEYS_SCREEN_UP , 0 , fltk::PageUpKey }, + { "screen-up" , KEYS_SCREEN_UP , 0 , 'b' }, + { "screen-down" , KEYS_SCREEN_DOWN , 0 , fltk::PageDownKey }, + { "screen-down" , KEYS_SCREEN_DOWN , 0 , fltk::SpaceKey }, + { "line-up" , KEYS_LINE_UP , 0 , fltk::UpKey }, + { "line-down" , KEYS_LINE_DOWN , 0 , fltk::DownKey }, + { "left" , KEYS_LEFT , 0 , fltk::LeftKey }, + { "right" , KEYS_RIGHT , 0 , fltk::RightKey }, + { "top" , KEYS_TOP , 0 , fltk::HomeKey }, + { "bottom" , KEYS_BOTTOM , 0 , fltk::EndKey }, +}; + +static Dlist *bindings; + + + +/* + * Initialize the bindings list + */ +void Keys::init() +{ + KeyBinding_t *node; + + // Fill our key bindings list + bindings = dList_new(32); + for (uint_t i = 0; i < sizeof(default_keys) / sizeof(KeyBinding_t); i++) { + if (default_keys[i].key) { + node = dNew(KeyBinding_t, 1); + node->name = dStrdup(default_keys[i].name); + node->cmd = default_keys[i].cmd; + node->modifier = default_keys[i].modifier; + node->key = default_keys[i].key; + dList_insert_sorted(bindings, node, nodeByKeyCmp); + } + } +} + +/* + * Free data + */ +void Keys::free() +{ + KeyBinding_t *node; + + while ((node = (KeyBinding_t*)dList_nth_data(bindings, 0))) { + dFree((char*)node->name); + dList_remove_fast(bindings, node); + dFree(node); + } + dList_free(bindings); +} + +/* + * Compare function by {key,modifier} pairs. + */ +int Keys::nodeByKeyCmp(const void *node, const void *key) +{ + KeyBinding_t *n = (KeyBinding_t*)node, *k = (KeyBinding_t*)key; + _MSG("Keys::nodeByKeyCmp modifier=%d\n", k->modifier); + return (n->key != k->key) ? (n->key - k->key) : (n->modifier - k->modifier); +} + +/* + * Look if the just pressed key is bound to a command. + * Return value: The command if found, KEYS_NOP otherwise. + */ +KeysCommand_t Keys::getKeyCmd() +{ + KeysCommand_t ret = KEYS_NOP; + KeyBinding_t keyNode; + // We're only interested in some flags + keyNode.modifier = fltk::event_state() & + (fltk::SHIFT | fltk::CTRL | fltk::ALT | fltk::META); + + if (keyNode.modifier == fltk::SHIFT && + ispunct(fltk::event_text()[0])) { + // Get key code for a shifted character + keyNode.key = fltk::event_text()[0]; + keyNode.modifier = 0; + } else { + keyNode.key = fltk::event_key(); + } + + _MSG("getKeyCmd: key=%d, mod=%d\n", keyNode.key, keyNode.modifier); + void *data = dList_find_sorted(bindings, &keyNode, nodeByKeyCmp); + if (data) + ret = ((KeyBinding_t*)data)->cmd; + return ret; +} + +/* + * Remove a key binding from the table. + */ +void Keys::delKeyCmd(int key, int mod) +{ + KeyBinding_t keyNode, *node; + keyNode.key = key; + keyNode.modifier = mod; + + node = (KeyBinding_t*) dList_find_sorted(bindings, &keyNode, nodeByKeyCmp); + if (node) { + dList_remove(bindings, node); + dFree((char*)node->name); + dFree(node); + } +} + +/* + * Takes a key name and looks it up in the mapping table. If + * found, its key code is returned. Otherwise -1 is given + * back. + */ +int Keys::getKeyCode(char *keyName) +{ + uint_t i; + for (i = 0; i < sizeof(keyNames) / sizeof(Mapping_t); i++) { + if (!dStrcasecmp(keyNames[i].name, keyName)) { + return keyNames[i].value; + } + } + + return -1; +} + +/* + * Takes a command name and searches it in the mapping table. + * Return value: command code if found, -1 otherwise + */ +KeysCommand_t Keys::getCmdCode(const char *commandName) +{ + uint_t i; + + for (i = 0; i < sizeof(default_keys) / sizeof(KeyBinding_t); i++) { + if (!dStrcasecmp(default_keys[i].name, commandName)) + return default_keys[i].cmd; + } + return KEYS_INVALID; +} + +/* + * Takes a modifier name and looks it up in the mapping table. If + * found, its key code is returned. Otherwise -1 is given back. + */ +int Keys::getModifier(char *modifierName) +{ + uint_t i; + for (i = 0; i < sizeof(modifierNames) / sizeof(Mapping_t); i++) { + if (!dStrcasecmp(modifierNames[i].name, modifierName)) { + return modifierNames[i].value; + } + } + + return -1; +} + +/* + * Given a keys command, return a shortcut for it, or 0 if there is none + * (e.g., for KEYS_NEW_WINDOW, return CTRL+'n'). + */ +int Keys::getShortcut(KeysCommand_t cmd) +{ + int len = dList_length(bindings); + + for (int i = 0; i < len; i++) { + KeyBinding_t *node = (KeyBinding_t*)dList_nth_data(bindings, i); + if (cmd == node->cmd) + return node->modifier + node->key; + } + return 0; +} + +/* + * Parse a key-combination/command-name pair, and + * insert it into the bindings list. + */ +void Keys::parseKey(char *key, char *commandName) +{ + char *p, *modstr, *keystr; + KeysCommand_t symcode; + int st, keymod = 0, keycode = 0; + + _MSG("Keys::parseKey key='%s' commandName='%s'\n", key, commandName); + + // Get command code + if ((symcode = getCmdCode(commandName)) == KEYS_INVALID) { + MSG("Keys::parseKey: Invalid command name: '%s'\n", commandName); + return; + } + + // Skip space + for ( ; isspace(*key); ++key) ; + // Get modifiers + while(*key == '<' && (p = strchr(key, '>'))) { + ++key; + modstr = dStrndup(key, p - key); + if ((st = getModifier(modstr)) == -1) { + MSG("Keys::parseKey unknown modifier: %s\n", modstr); + } else { + keymod |= st; + } + dFree(modstr); + key = p + 1; + } + // Allow trailing space after keyname + keystr = (*key && (p = strchr(key + 1, ' '))) ? dStrndup(key, p - key - 1) : + dStrdup(key); + // Get key code + if (!key[1]) { + keycode = *key; + } else if (key[0] == '0' && key[1] == 'x') { + /* keysym. For details on values reported, see fltk's fltk/events.h */ + keycode = strtol(key, NULL, 0x10); + } else if ((st = getKeyCode(keystr)) == -1) { + MSG("Keys::parseKey unknown keyname: %s\n", keystr); + } else { + keycode = st; + } + dFree(keystr); + + // Set binding + if (keycode) { + delKeyCmd(keycode, keymod); + if (symcode != KEYS_NOP) { + KeyBinding_t *node = dNew(KeyBinding_t, 1); + node->name = dStrdup(commandName); + node->cmd = symcode; + node->modifier = keymod; + node->key = keycode; + dList_insert_sorted(bindings, node, nodeByKeyCmp); + _MSG("parseKey: Adding key=%d, mod=%d\n", node->key, node->modifier); + } + } +} + +/* + * Parse the keysrc. + */ +void Keys::parse(FILE *fp) +{ + char *line, *keycomb, *command; + int st, lineno = 1; + + // scan the file line by line + while ((line = dGetline(fp)) != NULL) { + st = dParser_parse_rc_line(&line, &keycomb, &command); + + if (st == 0) { + _MSG("Keys::parse: keycomb=%s, command=%s\n", keycomb, command); + parseKey(keycomb, command); + } else if (st < 0) { + MSG("Keys::parse: Syntax error in keysrc line %d: " + "keycomb=\"%s\" command=\"%s\"\n", lineno, keycomb, command); + } + + dFree(line); + ++lineno; + } + fclose(fp); +} |