Merge Irssi 0.8.16-rc1
[silc.git] / apps / irssi / src / fe-common / core / keyboard.c
index ac68200196baec1863f5a8dd99f239613724a528..49bcd399694c83902da7a303965372121c4b2753 100644 (file)
@@ -13,9 +13,9 @@
     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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+    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 "module.h"
@@ -44,7 +44,7 @@ static char used_keys[256];
 static GTree *key_states;
 static int key_config_frozen;
 
-struct KEYBOARD_REC {
+struct _KEYBOARD_REC {
        char *key_state; /* the ongoing key combo */
         void *gui_data; /* GUI specific data sent in "key pressed" signal */
 };
@@ -193,7 +193,7 @@ static int expand_combo(const char *start, const char *end, GSList **out)
         KEY_REC *rec;
        KEYINFO_REC *info;
         GSList *tmp, *tmp2, *list, *copy, *newout;
-       char *str;
+       char *str, *p;
 
        if (start == end) {
                /* single key */
@@ -214,14 +214,21 @@ static int expand_combo(const char *start, const char *end, GSList **out)
                if (strcmp(rec->data, str) == 0)
                         list = g_slist_append(list, rec);
        }
-       g_free(str);
 
-       if (list == NULL)
-               return FALSE;
+       if (list == NULL) {
+               /* unknown keycombo - add it as-is, maybe the GUI will
+                  feed it to us as such */
+               for (p = str; *p != '\0'; p++)
+                       expand_out_char(*out, *p);
+               g_free(str);
+               return TRUE;
+       }
+       g_free(str);
 
        if (list->next == NULL) {
                 /* only one way to generate the combo, good */
                 rec = list->data;
+               g_slist_free(list);
                return expand_key(rec->key, out);
        }
 
@@ -246,6 +253,7 @@ static int expand_combo(const char *start, const char *end, GSList **out)
        }
 
         rec = list->data;
+       g_slist_free(list);
        if (!expand_key(rec->key, out)) {
                /* illegal key combo, remove from list */
                expand_out_free(*out);
@@ -292,7 +300,7 @@ static int expand_key(const char *key, GSList **out)
                        expand_out_char(*out, *key);
                        expand_out_char(*out, '-');
                         last_hyphen = FALSE; /* optional */
-               } else if (last_hyphen && i_isalnum(*key) && !i_isdigit(*key)) {
+               } else if (last_hyphen && i_isalpha(*key)) {
                         /* possibly beginning of keycombo */
                        start = key;
                         last_hyphen = FALSE;
@@ -382,6 +390,8 @@ static void key_configure_destroy(KEY_REC *rec)
        rec->info->keys = g_slist_remove(rec->info->keys, rec);
        g_hash_table_remove(keys, rec->key);
 
+       signal_emit("key destroyed", 1, rec);
+
        if (!key_config_frozen)
                 key_states_rescan();
 
@@ -415,6 +425,8 @@ static void key_configure_create(const char *id, const char *key,
        info->keys = g_slist_append(info->keys, rec);
        g_hash_table_insert(keys, rec->key, rec);
 
+       signal_emit("key created", 1, rec);
+
        if (!key_config_frozen)
                 key_states_rescan();
 }
@@ -541,8 +553,6 @@ static int key_states_search(const unsigned char *combo,
         return 0;
 }
 
-/* Returns TRUE if key press was consumed. Control characters should be sent
-   as "^@" .. "^_" instead of #0..#31 chars, #127 should be sent as ^? */
 int key_pressed(KEYBOARD_REC *keyboard, const char *key)
 {
        KEY_REC *rec;
@@ -555,7 +565,7 @@ int key_pressed(KEYBOARD_REC *keyboard, const char *key)
        if (keyboard->key_state == NULL && key[1] == '\0' &&
            !used_keys[(int) (unsigned char) key[0]]) {
                /* fast check - key not used */
-               return FALSE;
+               return -1;
        }
 
         first_key = keyboard->key_state == NULL;
@@ -564,19 +574,19 @@ int key_pressed(KEYBOARD_REC *keyboard, const char *key)
        g_free_and_null(keyboard->key_state);
 
        rec = g_tree_search(key_states,
-                           (GSearchFunc) key_states_search,
+                           (GCompareFunc) key_states_search,
                            combo);
        if (rec == NULL) {
                /* unknown key combo, eat the invalid key
                   unless it was the first key pressed */
                 g_free(combo);
-               return !first_key;
+               return first_key ? -1 : 1;
        }
 
        if (g_tree_lookup(key_states, combo) != rec) {
                /* key combo continues.. */
                keyboard->key_state = combo;
-                return TRUE;
+                return 0;
        }
 
         /* finished key combo, execute */
@@ -584,7 +594,7 @@ int key_pressed(KEYBOARD_REC *keyboard, const char *key)
        consumed = key_emit_signal(keyboard, rec);
 
        /* never consume non-control characters */
-       return consumed;
+       return consumed ? 1 : -1;
 }
 
 void keyboard_entry_redirect(SIGNAL_FUNC func, const char *entry,
@@ -633,11 +643,17 @@ static void sig_multi(const char *data, void *gui_data)
         g_strfreev(list);
 }
 
+static void sig_nothing(const char *data)
+{
+}
+
 static void cmd_show_keys(const char *searchkey, int full)
 {
        GSList *info, *key;
         int len;
 
+       printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_BIND_HEADER);
+
        len = searchkey == NULL ? 0 : strlen(searchkey);
        for (info = keyinfos; info != NULL; info = info->next) {
                KEYINFO_REC *rec = info->data;
@@ -647,14 +663,16 @@ static void cmd_show_keys(const char *searchkey, int full)
 
                        if ((len == 0 || g_strncasecmp(rec->key, searchkey, len) == 0) &&
                            (!full || rec->key[len] == '\0')) {
-                               printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_BIND_KEY,
+                               printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_BIND_LIST,
                                            rec->key, rec->info->id, rec->data == NULL ? "" : rec->data);
                        }
                }
        }
+
+       printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_BIND_FOOTER);
 }
 
-/* SYNTAX: BIND [-delete] [<key> [<command> [<data>]]] */
+/* SYNTAX: BIND [-list] [-delete] [<key> [<command> [<data>]]] */
 static void cmd_bind(const char *data)
 {
        GHashTable *optlist;
@@ -666,6 +684,19 @@ static void cmd_bind(const char *data)
                            "bind", &optlist, &key, &id, &keydata))
                return;
 
+       if (g_hash_table_lookup(optlist, "list")) {
+               GSList *tmp;
+
+               for (tmp = keyinfos; tmp != NULL; tmp = tmp->next) {
+                       KEYINFO_REC *rec = tmp->data;
+
+                       printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_BIND_COMMAND_LIST,
+                                   rec->id, rec->description ? rec->description : "");
+               }
+               cmd_params_free(free_arg);
+               return;
+       }
+
        if (*key != '\0' && g_hash_table_lookup(optlist, "delete")) {
                 /* delete key */
                key_configure_remove(key);
@@ -683,7 +714,7 @@ static void cmd_bind(const char *data)
        command_id = strchr(settings_get_str("cmdchars"), *id) != NULL;
        if (command_id) {
                /* using shortcut to command id */
-               keydata = g_strconcat(id, " ", keydata, NULL);
+               keydata = g_strconcat(id+1, " ", keydata, NULL);
                id = "command";
        }
 
@@ -813,9 +844,10 @@ void keyboard_init(void)
         key_config_frozen = 0;
        memset(used_keys, 0, sizeof(used_keys));
 
-       key_bind("command", "Run any IRC command", NULL, NULL, (SIGNAL_FUNC) sig_command);
+       key_bind("command", "Run any command", NULL, NULL, (SIGNAL_FUNC) sig_command);
        key_bind("key", "Specify name for key binding", NULL, NULL, (SIGNAL_FUNC) sig_key);
        key_bind("multi", "Run multiple commands", NULL, NULL, (SIGNAL_FUNC) sig_multi);
+       key_bind("nothing", "Do nothing", NULL, NULL, (SIGNAL_FUNC) sig_nothing);
 
        /* read the keyboard config when all key binds are known */
        signal_add("irssi init read settings", (SIGNAL_FUNC) read_keyboard_config);
@@ -823,11 +855,16 @@ void keyboard_init(void)
        signal_add("complete command bind", (SIGNAL_FUNC) sig_complete_bind);
 
        command_bind("bind", NULL, (SIGNAL_FUNC) cmd_bind);
-       command_set_options("bind", "delete");
+       command_set_options("bind", "delete list");
 }
 
 void keyboard_deinit(void)
 {
+       key_unbind("command", (SIGNAL_FUNC) sig_command);
+       key_unbind("key", (SIGNAL_FUNC) sig_key);
+       key_unbind("multi", (SIGNAL_FUNC) sig_multi);
+       key_unbind("nothing", (SIGNAL_FUNC) sig_nothing);
+
        while (keyinfos != NULL)
                keyinfo_remove(keyinfos->data);
        g_hash_table_destroy(keys);