Mercurial > dillo_port1.3
changeset 1064:485acc9e60e2
Added configurable keybindings! (in ~/.dillo/keysrc) # part1
author | Jorge Arellano Cid <jcid@dillo.org> |
---|---|
date | Sun, 03 May 2009 11:48:45 -0400 |
parents | 6fcb2fa90e23 |
children | 88765afb7d65 |
files | ChangeLog src/Makefile.am src/dillo.cc src/keys.cc src/keys.hh src/ui.cc |
diffstat | 6 files changed, 433 insertions(+), 56 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Tue Apr 28 08:45:47 2009 -0400 +++ b/ChangeLog Sun May 03 11:48:45 2009 -0400 @@ -87,6 +87,8 @@ Patch: João Ricardo Lourenço, Jorge Arellano Cid +- Added the "middle_click_drags_page" dillorc option. Patch: Jorge Arellano Cid, Thomas Orgis ++- Added configurable keybindings! (in ~/.dillo/keysrc) + Patch: Jorge Arellano Cid, Tim Nieradzik +- Set the File menu label to hide when the File menu-button is shown. - Set a new iconv() test in configure.in. - Allowed the rc parser to skip whitespace around the equal sign.
--- a/src/Makefile.am Tue Apr 28 08:45:47 2009 -0400 +++ b/src/Makefile.am Sun May 03 11:48:45 2009 -0400 @@ -41,6 +41,8 @@ prefs.h \ prefsparser.cc \ prefsparser.hh \ + keys.cc \ + keys.hh \ msg.h \ list.h \ url.c \
--- a/src/dillo.cc Tue Apr 28 08:45:47 2009 -0400 +++ b/src/dillo.cc Sun May 03 11:48:45 2009 -0400 @@ -34,6 +34,7 @@ #include "prefs.h" #include "prefsparser.hh" +#include "keys.hh" #include "bw.h" #include "misc.h" #include "nav.h" @@ -261,6 +262,9 @@ // create ~/.dillo if not present Paths::init(); + // initialize default key bindings + Keys::init(); + // set the default values for the preferences a_Prefs_init(); @@ -268,6 +272,10 @@ if ((fp = Paths::getPrefsFP(PATHS_RC_PREFS))) { PrefsParser::parse(fp); } + // parse keysrc + if ((fp = Paths::getPrefsFP(PATHS_RC_KEYS))) { + Keys::parse(fp); + } // initialize internal modules a_Dpi_init();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/keys.cc Sun May 03 11:48:45 2009 -0400 @@ -0,0 +1,309 @@ +/* + * 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 <string.h> +#include <ctype.h> + +#include "dlib/dlib.h" +#include "keys.hh" +#include "msg.h" + +/* + * Local data types + */ +typedef struct { + const char *name; + int cmd, 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 KeyBinding_t default_keys[] = { + { "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' }, + { "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' } +}; + +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++) { + 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_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. + */ +int Keys::getKeyCmd() +{ + int ret = KEYS_NOP; + KeyBinding_t keyNode; + keyNode.key = fltk::event_key(); + keyNode.modifier = fltk::event_state(); + + void *data = dList_find_sorted(bindings, &keyNode, + (dCompareFunc)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; + keyNode.key = key; + keyNode.modifier = mod; + + void *data = dList_find_sorted(bindings, &keyNode, + (dCompareFunc)nodeByKeyCmp); + if (data) + dList_remove(bindings, data); +} + +/* + * 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 (!strcasecmp(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 + */ +int Keys::getCmdCode(const char *commandName) +{ + uint_t i; + + for (i = 0; i < sizeof(default_keys) / sizeof(KeyBinding_t); i++) { + if (!strcasecmp(default_keys[i].name, commandName)) + return default_keys[i].cmd; + } + return -1; +} + +/* + * 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 (!strcasecmp(modifierNames[i].name, modifierName)) { + return modifierNames[i].value; + } + } + + return -1; +} + +/* + * 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; + int st, symcode = 0, keymod = 0, keycode = 0; + + _MSG("Keys::parseKey key='%s' commandName='%s'\n", key, commandName); + + // Get command code + if ((st = getCmdCode(commandName)) == -1) { + MSG("Invalid command name: '%s'\n", commandName); + return; + } else + symcode = st; + + // Skip space + for ( ; isspace(*key); ++key) ; + // Get modifiers + while(*key == '<' && (p = strchr(++key, '>'))) { + modstr = strndup(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, ' '))) ? strndup(key, p - key - 1) : + dStrdup(key); + // Get key code + if (!key[1]) { + keycode = *key; + } 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); + } + } +} + +/* + * Parse the keysrc. + */ +void Keys::parse(FILE *fp) +{ + char *line, *keycomb, *command; + int st; + + // 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: " + "keycomb=\"%s\" command=\"%s\"\n", keycomb, command); + } + + dFree(line); + } + fclose(fp); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/keys.hh Sun May 03 11:48:45 2009 -0400 @@ -0,0 +1,55 @@ +/* + * 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. + */ + +#ifndef __KEYS_HH__ +#define __KEYS_HH__ + + +enum { + KEYS_NOP, /* No operation bound */ + KEYS_OPEN, + KEYS_NEW_WINDOW, + KEYS_NEW_TAB, + KEYS_LEFT_TAB, + KEYS_RIGHT_TAB, + KEYS_CLOSE_TAB, + KEYS_FIRST_TAB, + KEYS_LAST_TAB, + KEYS_FIND, + KEYS_WEBSEARCH, + KEYS_BOOKMARKS, + KEYS_FULLSCREEN, + KEYS_RELOAD, + KEYS_HIDE_PANELS, + KEYS_FILE_MENU, + KEYS_CLOSE_ALL, + KEYS_BACK, + KEYS_FORWARD, + KEYS_GOTO, + KEYS_HOME +}; + +class Keys { +public: + static void init(); + static void free(); + static int nodeByKeyCmp(const void *node, const void *key); + static int getKeyCmd(void); + static void delKeyCmd(int key, int mod); + static int getCmdCode(const char *symbolName); + static int getKeyCode(char *keyName); + static int getModifier(char *modifierName); + static void parseKey(char *key, char *symbol); + static void parse(FILE *fp); +}; + + +#endif /* __KEYS_HH__ */
--- a/src/ui.cc Tue Apr 28 08:45:47 2009 -0400 +++ b/src/ui.cc Sun May 03 11:48:45 2009 -0400 @@ -25,6 +25,7 @@ #include <fltk/Item.h> #include <fltk/Divider.h> +#include "keys.hh" #include "ui.hh" #include "msg.h" #include "timeout.hh" @@ -741,66 +742,64 @@ _MSG("UI::handle event=%d (%d,%d)\n", event, event_x(), event_y()); _MSG("Panel->h()=%d Main->h()=%d\n", Panel->h() , Main->h()); - int ret = 0, k = event_key(); - - // We're only interested in some flags - unsigned modifier = event_state() & (SHIFT | CTRL | ALT); + int ret = 0; if (event == KEY) { return 0; // Receive as shortcut - } else if (event == SHORTCUT) { - // Handle keyboard shortcuts here. - if (modifier == CTRL) { - if (k == 'b') { - a_UIcmd_book(a_UIcmd_get_bw_by_widget(this)); - ret = 1; - } else if (k == 'f') { - set_findbar_visibility(1); - ret = 1; - } else if (k == 'l') { - focus_location(); - ret = 1; - } else if (k == 'n') { - a_UIcmd_browser_window_new(w(),h(),a_UIcmd_get_bw_by_widget(this)); - ret = 1; - } else if (k == 'o') { - a_UIcmd_open_file(a_UIcmd_get_bw_by_widget(this)); - ret = 1; - } else if (k == 'q') { - a_UIcmd_close_bw(a_UIcmd_get_bw_by_widget(this)); - ret = 1; - } else if (k == 'r') { - a_UIcmd_reload(a_UIcmd_get_bw_by_widget(this)); - ret = 1; - } else if (k == 's') { - a_UIcmd_search_dialog(a_UIcmd_get_bw_by_widget(this)); - ret = 1; - } else if (k == 't') { - a_UIcmd_open_url_nt(a_UIcmd_get_bw_by_widget(this), NULL, 1); - ret = 1; - } else if (k == ' ') { - panelmode_cb_i(); - ret = 1; - } - } else if (modifier == ALT) { - if (k == 'f') { - a_UIcmd_file_popup(a_UIcmd_get_bw_by_widget(this), FileButton); - } else if (k == 'q' && event_key_state(LeftAltKey)) { - a_Timeout_add(0.0, a_UIcmd_close_all_bw, NULL); - } - } else { - // Back and Forward navigation shortcuts - if (modifier == 0 && (k == BackSpaceKey || k == ',')) { - a_UIcmd_back(a_UIcmd_get_bw_by_widget(this)); - ret = 1; - } else if ((modifier == 0 && k == '.') || - (modifier == SHIFT && k == BackSpaceKey)) { - a_UIcmd_forw(a_UIcmd_get_bw_by_widget(this)); - ret = 1; - } + int cmd = Keys::getKeyCmd(); + if (cmd == KEYS_NOP) { + // Do nothing + } else if (cmd == KEYS_BACK) { + a_UIcmd_back(a_UIcmd_get_bw_by_widget(this)); + ret = 1; + } else if (cmd == KEYS_FORWARD) { + a_UIcmd_forw(a_UIcmd_get_bw_by_widget(this)); + ret = 1; + } else if (cmd == KEYS_BOOKMARKS) { + a_UIcmd_book(a_UIcmd_get_bw_by_widget(this)); + ret = 1; + } else if (cmd == KEYS_FIND) { + set_findbar_visibility(1); + ret = 1; + } else if (cmd == KEYS_WEBSEARCH) { + a_UIcmd_search_dialog(a_UIcmd_get_bw_by_widget(this)); + ret = 1; + } else if (cmd == KEYS_GOTO) { + focus_location(); + ret = 1; + } else if (cmd == KEYS_NEW_TAB) { + a_UIcmd_open_url_nt(a_UIcmd_get_bw_by_widget(this), NULL, 1); + ret = 1; + } else if (cmd == KEYS_CLOSE_TAB) { + a_UIcmd_close_bw(a_UIcmd_get_bw_by_widget(this)); + ret = 1; + } else if (cmd == KEYS_HIDE_PANELS && + get_panelmode() == UI_TEMPORARILY_SHOW_PANELS) { + set_panelmode(UI_HIDDEN); + ret = 1; + } else if (cmd == KEYS_NEW_WINDOW) { + a_UIcmd_browser_window_new(w(),h(),a_UIcmd_get_bw_by_widget(this)); + ret = 1; + } else if (cmd == KEYS_OPEN) { + a_UIcmd_open_file(a_UIcmd_get_bw_by_widget(this)); + ret = 1; + } else if (cmd == KEYS_HOME) { + a_UIcmd_home(a_UIcmd_get_bw_by_widget(this)); + ret = 1; + } else if (cmd == KEYS_RELOAD) { + a_UIcmd_reload(a_UIcmd_get_bw_by_widget(this)); + ret = 1; + } else if (cmd == KEYS_FULLSCREEN) { + panelmode_cb_i(); + ret = 1; + } else if (cmd == KEYS_FILE_MENU) { + a_UIcmd_file_popup(a_UIcmd_get_bw_by_widget(this), FileButton); + ret = 1; + } else if (cmd == KEYS_CLOSE_ALL) { + a_Timeout_add(0.0, a_UIcmd_close_all_bw, NULL); + ret = 1; } - } else if (event == PUSH) { if (prefs.middle_click_drags_page == 0 && event_button() == MiddleButton && @@ -810,8 +809,10 @@ } } - if (!ret) + if (!ret) { ret = Group::handle(event); + } + return ret; }