From e5abd5d4be60c95beefba5ebeb2054a8dd03b7c8 Mon Sep 17 00:00:00 2001 From: Daniel Carl Date: Sat, 21 Sep 2013 01:38:00 +0200 Subject: [PATCH] Allow to bind also function keys. --- src/ex.c | 2 - src/hints.c | 2 - src/input.c | 4 +- src/main.c | 1 + src/main.h | 3 +- src/map.c | 179 ++++++++++++++++++++++++++++++++++++++++----------- src/map.h | 1 + src/mode.c | 1 + src/normal.c | 8 +-- src/pass.c | 2 +- 10 files changed, 150 insertions(+), 53 deletions(-) diff --git a/src/ex.c b/src/ex.c index 3ea60e6..c1cd120 100644 --- a/src/ex.c +++ b/src/ex.c @@ -193,12 +193,10 @@ VbResult ex_keypress(unsigned int key) /* delegate call to the submode if hinting is active */ if (vb.mode->flags & FLAG_HINTING) { if (RESULT_COMPLETE == hints_keypress(key)) { - vb.state.processed_key = true; return RESULT_COMPLETE; } } - vb.state.processed_key = true; switch (key) { case CTRL('I'): /* Tab */ /* mode will be set in completion_complete */ diff --git a/src/hints.c b/src/hints.c index b0a4cd4..7831e38 100644 --- a/src/hints.c +++ b/src/hints.c @@ -51,7 +51,6 @@ void hints_init(WebKitWebFrame *frame) VbResult hints_keypress(unsigned int key) { - vb.state.processed_key = true; if (key == '\n') { hints_fire(); @@ -85,7 +84,6 @@ VbResult hints_keypress(unsigned int key) return RESULT_COMPLETE; } - vb.state.processed_key = false; return RESULT_ERROR; } diff --git a/src/input.c b/src/input.c index b967cd6..ac4a7f3 100644 --- a/src/input.c +++ b/src/input.c @@ -59,19 +59,17 @@ VbResult input_keypress(unsigned int key) { switch (key) { case CTRL('['): /* esc */ - vb.state.processed_key = true; mode_enter('n'); return RESULT_COMPLETE; case CTRL('T'): - vb.state.processed_key = true; return input_open_editor(); case CTRL('Z'): - vb.state.processed_key = true; mode_enter('p'); return RESULT_COMPLETE; } + vb.state.processed_key = false; return RESULT_ERROR; } diff --git a/src/main.c b/src/main.c index 6176509..e0837b2 100644 --- a/src/main.c +++ b/src/main.c @@ -731,6 +731,7 @@ static void init_core(void) mode_add('p', pass_enter, pass_leave, pass_keypress, NULL); mode_enter('n'); + map_init(); init_files(); session_init(); setting_init(); diff --git a/src/main.h b/src/main.h index 153f7e1..a924aab 100644 --- a/src/main.h +++ b/src/main.h @@ -41,12 +41,13 @@ /* this macro converts a non-'g' ascii command into a 'g' command by setting * the 8th bit for the char */ -/* TODO maybe these macros are only used in keybind.c or mode.c */ #define G_CMD(x) ((x) | 0x80) #define UNG_CMD(x) ((x) & ~0x80) #define CTRL(x) ((x) ^ 0x40) /* check if the char x is a char with CTRL like ^C */ #define IS_CTRL(x) (((unsigned char)x) <= 32) +#define CSI 0x9b /* Control Sequence Introducer */ +#define CSI_STR "\233" #ifdef DEBUG #define PRINT_DEBUG(...) { \ diff --git a/src/map.c b/src/map.c index a016c98..c6a893f 100644 --- a/src/map.c +++ b/src/map.c @@ -49,6 +49,16 @@ static void showcmd(char *keys, int keylen, gboolean append); static void free_map(Map *map); +void map_init(void) +{ + /* bind cursor keys to ^P and ^N but only in command mode else down would + * trigger the queue pop */ + map_insert("", "\x10", 'c'); + map_insert("", "\x0e", 'c'); + map_insert("", "k", 'n'); + map_insert("", "j", 'n'); +} + void map_cleanup(void) { if (map.list) { @@ -63,46 +73,90 @@ void map_cleanup(void) gboolean map_keypress(GtkWidget *widget, GdkEventKey* event, gpointer data) { unsigned int key = 0; - if ((event->state & GDK_CONTROL_MASK) == 0 - && event->keyval > 0 - && event->keyval < 0xff - ) { - key = event->keyval; - } else { - /* convert chars A-Za-z with ctrl flag or -> \001 - * and -> \032 like vi */ - if (event->keyval == GDK_Escape) { - key = CTRL('['); - } else if (event->keyval == GDK_Tab) { - key = CTRL('I'); - } else if (event->keyval == GDK_ISO_Left_Tab) { - key = CTRL('O'); - } else if (event->keyval == GDK_Return) { - key = '\n'; - } else if (event->keyval == GDK_BackSpace) { - /* FIXME how to handle to remove selected Numbers in - * hint mode */ - key = CTRL('H'); /* 0x08 */ - } else if (event->keyval == GDK_Up) { - key = CTRL('P'); /* or ^Ok instead? */ - } else if (event->keyval == GDK_Down) { - key = CTRL('N'); - } else if (event->keyval >= 0x41 && event->keyval <= 0x5d) {/* chars A-] */ - key = event->keyval - 0x40; - } else if (event->keyval >= 0x61 && event->keyval <= 0x7a) {/* chars a-z */ - key = event->keyval - 0x60; - } - } + static struct { + guint keyval; + int ctrl; /* -1 = indifferent, 1 = ctrl, 0 = no ctrl */ + char *ch; + int chlen; + } keys[] = { + {GDK_Escape, -1, "\x1b", 1}, /* ^[ */ + {GDK_Tab, -1, "\x09", 1}, /* ^I */ + {GDK_ISO_Left_Tab, -1, "\x0f", 1}, /* ^O */ + {GDK_Return, -1, "\x0a", 1}, + {GDK_KP_Enter, -1, "\x0a", 1}, + {GDK_BackSpace, -1, "\x08", 1}, /* ^H */ + {GDK_Up, -1, CSI_STR "ku", 3}, + {GDK_Down, -1, CSI_STR "kd", 3}, + {GDK_Left, -1, CSI_STR "kl", 3}, + {GDK_Right, -1, CSI_STR "kr", 3}, + /* function keys are prefixed by gEsc like in vim the CSI Control + * Sequence Introducer \233 */ + /* TODO calculate this automatic */ + {GDK_KEY_F1, 1, CSI_STR "\x01", 2}, + {GDK_KEY_F2, 1, CSI_STR "\x02", 2}, + {GDK_KEY_F3, 1, CSI_STR "\x03", 2}, + {GDK_KEY_F4, 1, CSI_STR "\x04", 2}, + {GDK_KEY_F5, 1, CSI_STR "\x05", 2}, + {GDK_KEY_F6, 1, CSI_STR "\x06", 2}, + {GDK_KEY_F7, 1, CSI_STR "\x07", 2}, + {GDK_KEY_F8, 1, CSI_STR "\x08", 2}, + {GDK_KEY_F9, 1, CSI_STR "\x09", 2}, + {GDK_KEY_F10, 1, CSI_STR "\x0a", 2}, + {GDK_KEY_F11, 1, CSI_STR "\x0b", 2}, + {GDK_KEY_F12, 1, CSI_STR "\x0c", 2}, + {GDK_KEY_F1, 0, CSI_STR "\x0d", 2}, + {GDK_KEY_F2, 0, CSI_STR "\x0e", 2}, + {GDK_KEY_F3, 0, CSI_STR "\x0f", 2}, + {GDK_KEY_F4, 0, CSI_STR "\x10", 2}, + {GDK_KEY_F5, 0, CSI_STR "\x11", 2}, + {GDK_KEY_F6, 0, CSI_STR "\x12", 2}, + {GDK_KEY_F7, 0, CSI_STR "\x13", 2}, + {GDK_KEY_F8, 0, CSI_STR "\x14", 2}, + {GDK_KEY_F9, 0, CSI_STR "\x15", 2}, + {GDK_KEY_F10, 0, CSI_STR "\x16", 2}, + {GDK_KEY_F11, 0, CSI_STR "\x17", 2}, + {GDK_KEY_F12, 0, CSI_STR "\x18", 2}, + }; + + int ctrl = (event->state & GDK_CONTROL_MASK) != 0; /* set initial value for the flag that should be changed in the modes key * handler functions */ - vb.state.processed_key = false; - if (key) { + vb.state.processed_key = true; + if (!ctrl && event->keyval > 0 && event->keyval < 0xff) { + map_handle_keys((char*)(&event->keyval), 1); + + return vb.state.processed_key; + } + + /* convert chars A-]a-z with ctrl flag or -> \001 + * and -> \032 like vi */ + if (event->keyval >= 0x41 && event->keyval <= 0x5d) {/* chars A-] */ + key = event->keyval - 0x40; + map_handle_keys((char*)(&key), 1); + + return vb.state.processed_key; + } else if (event->keyval >= 0x61 && event->keyval <= 0x7a) {/* chars a-z */ + key = event->keyval - 0x60; map_handle_keys((char*)(&key), 1); + + return vb.state.processed_key; + } + + for (int i = 0; i < LENGTH(keys); i++) { + if (keys[i].keyval == event->keyval + && (keys[i].ctrl == ctrl ||keys[i].ctrl == -1) + ) { + map_handle_keys(keys[i].ch, keys[i].chlen); + + return vb.state.processed_key; + } } - return vb.state.processed_key; -} + /* mark all unknown key events as unhandled to not break some gtk features + * like to copy clipboard content into inputbox */ + return false; +} /** * Added the given key sequence ot the key queue and precesses the mapping of @@ -134,6 +188,7 @@ MapState map_handle_keys(const char *keys, int keylen) /* try to resolve keys against the map */ while (true) { /* send any resolved key to the parser */ + static int csi = 0; while (map.resolved > 0) { /* pop the next char from queue */ map.resolved--; @@ -146,6 +201,23 @@ MapState map_handle_keys(const char *keys, int keylen) map.queue[i] = map.queue[i + 1]; } + /* skip csi indicator and the next 2 chars - if the csi sequence + * isn't part of a mapped command we let gtk handle the key - this + * is required allo to move cursor in inputbox with and + * keys */ + /* TODO make it simplier to skip the special keys here */ + if ((qk & 0xff) == CSI) { + csi = 2; + vb.state.processed_key = false; + continue; + } + if (csi > 0) { + csi--; + vb.state.processed_key = false; + showcmd(NULL, 0, false); + continue; + } + /* remove the nomap flag */ vb.mode->flags &= ~FLAG_NOMAP; @@ -357,9 +429,40 @@ static char *map_convert_keylabel(char *in, int inlen, int *len) char *ch; int chlen; } keys[] = { - {"", 4, "\n", 1}, - {"", 5, "\t", 1}, - {"", 5, "\x1b", 1} + {"", 4, "\n", 1}, + {"", 5, "\t", 1}, + {"", 5, "\x1b", 1}, + {"", 4, CSI_STR "ku", 3}, + {"", 6, CSI_STR "kd", 3}, + {"", 6, CSI_STR "kl", 3}, + {"", 7, CSI_STR "kr", 3}, + /* convert function keys to gEsc+num */ + /* TODO allow to calculate the ch programmatic instead of mapping the + * function keys here */ + {"", 6, CSI_STR "\x01", 2}, + {"", 6, CSI_STR "\x02", 2}, + {"", 6, CSI_STR "\x03", 2}, + {"", 6, CSI_STR "\x04", 2}, + {"", 6, CSI_STR "\x05", 2}, + {"", 6, CSI_STR "\x06", 2}, + {"", 6, CSI_STR "\x07", 2}, + {"", 6, CSI_STR "\x08", 2}, + {"", 6, CSI_STR "\x09", 2}, + {"", 7, CSI_STR "\x0a", 2}, + {"", 7, CSI_STR "\x0b", 2}, + {"", 7, CSI_STR "\x0c", 2}, + {"", 4, CSI_STR "\x0d", 2}, + {"", 4, CSI_STR "\x0e", 2}, + {"", 4, CSI_STR "\x0f", 2}, + {"", 4, CSI_STR "\x10", 2}, + {"", 4, CSI_STR "\x11", 2}, + {"", 4, CSI_STR "\x12", 2}, + {"", 4, CSI_STR "\x13", 2}, + {"", 4, CSI_STR "\x14", 2}, + {"", 4, CSI_STR "\x15", 2}, + {"", 5, CSI_STR "\x16", 2}, + {"", 5, CSI_STR "\x17", 2}, + {"", 5, CSI_STR "\x18", 2}, }; for (int i = 0; i < LENGTH(keys); i++) { @@ -409,6 +512,8 @@ static void showcmd(char *keys, int keylen, gboolean append) if (IS_CTRL(key)) { map.showbuf[map.slen++] = '^'; map.showbuf[map.slen++] = CTRL(key); + } else if ((key & 0xff) == CSI) { + map.showbuf[map.slen++] = '@'; } else { map.showbuf[map.slen++] = key; } diff --git a/src/map.h b/src/map.h index 26d66df..03b360d 100644 --- a/src/map.h +++ b/src/map.h @@ -32,6 +32,7 @@ typedef enum { MAP_NOMATCH } MapState; +void map_init(void); void map_cleanup(void); gboolean map_keypress(GtkWidget *widget, GdkEventKey* event, gpointer data); MapState map_handle_keys(const char *keys, int keylen); diff --git a/src/mode.c b/src/mode.c index e36e9df..ab86172 100644 --- a/src/mode.c +++ b/src/mode.c @@ -96,6 +96,7 @@ VbResult mode_handle_key(unsigned int key) { VbResult res; if (vb.mode && vb.mode->keypress) { + key &= 0xff; int flags = vb.mode->flags; int id = vb.mode->id; res = vb.mode->keypress(key); diff --git a/src/normal.c b/src/normal.c index b951e09..324b6e1 100644 --- a/src/normal.c +++ b/src/normal.c @@ -223,7 +223,7 @@ static struct { /* g^X */ {NULL}, /* g^Y */ {NULL}, /* g^Z */ {NULL}, -/* gESC */ {NULL}, +/* gESC */ {NULL}, /* used as Control Sequence Introducer */ /* g^\ */ {NULL}, /* g^] */ {NULL}, /* g^^ */ {NULL}, @@ -355,7 +355,6 @@ void normal_leave(void) VbResult normal_keypress(unsigned int key) { State *s = &vb.state; - s->processed_key = true; VbResult res; if (info.phase == PHASE_START && key == 'g') { info.phase = PHASE_AFTERG; @@ -488,9 +487,6 @@ static VbResult normal_ex(const NormalCmdInfo *info) { char prompt[2] = {0}; - /* avoid to print the char that called this function into the input box */ - vb.state.processed_key = true; - /* Handle some hardwired mapping here instead of using map_insert. This * makes the binding imutable and we can simply use f, F, o and t in * mapped keys too */ @@ -549,8 +545,6 @@ static VbResult normal_hint(const NormalCmdInfo *info) /* check if this is a valid hint mode */ if (!info->arg || !strchr(allowed, info->arg)) { - vb.state.processed_key = true; - return RESULT_ERROR; } diff --git a/src/pass.c b/src/pass.c index b23110f..b835d96 100644 --- a/src/pass.c +++ b/src/pass.c @@ -48,8 +48,8 @@ void pass_leave(void) VbResult pass_keypress(unsigned int key) { if (key == CTRL('[')) { /* esc */ - vb.state.processed_key = true; mode_enter('n'); } + vb.state.processed_key = false; return RESULT_COMPLETE; } -- 2.20.1