aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJorge Arellano Cid <jcid@dillo.org>2009-05-03 11:49:26 -0400
committerJorge Arellano Cid <jcid@dillo.org>2009-05-03 11:49:26 -0400
commit90b7c1ea18d41ffb3f57ec4a7048faa3b9737249 (patch)
treea53584a701eee42da52b8a412e652de319889c16 /src
parent58cc9f9f90ed1d86705db9ae3f3863af7230ac5a (diff)
parent54f8f849e170b7e8da8722b3912e544fca14e483 (diff)
merge
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/dillo.cc8
-rw-r--r--src/keys.cc309
-rw-r--r--src/keys.hh55
-rw-r--r--src/ui.cc113
5 files changed, 431 insertions, 56 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 0e050486..c8fc1db6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -41,6 +41,8 @@ dillo_SOURCES = \
prefs.h \
prefsparser.cc \
prefsparser.hh \
+ keys.cc \
+ keys.hh \
msg.h \
list.h \
url.c \
diff --git a/src/dillo.cc b/src/dillo.cc
index ef902bd6..9ed4578b 100644
--- a/src/dillo.cc
+++ b/src/dillo.cc
@@ -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 @@ int main(int argc, char **argv)
// 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 @@ int main(int argc, char **argv)
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();
diff --git a/src/keys.cc b/src/keys.cc
new file mode 100644
index 00000000..93bec708
--- /dev/null
+++ b/src/keys.cc
@@ -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);
+}
diff --git a/src/keys.hh b/src/keys.hh
new file mode 100644
index 00000000..9c47a635
--- /dev/null
+++ b/src/keys.hh
@@ -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__ */
diff --git a/src/ui.cc b/src/ui.cc
index e6dbb8f6..0b30034e 100644
--- a/src/ui.cc
+++ b/src/ui.cc
@@ -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 @@ int UI::handle(int event)
_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 @@ int UI::handle(int event)
}
}
- if (!ret)
+ if (!ret) {
ret = Group::handle(event);
+ }
+
return ret;
}