From 67fd58d6f01ad84387421e2fc861c28dcf5c4f3c Mon Sep 17 00:00:00 2001 From: Uoti Urpala Date: Sun, 19 Dec 2010 12:12:20 +0200 Subject: input: support bindings with modifier keys for X input Add support for binding commands to modifier+key combinations like "Shift+Left" or "Ctrl+Alt+x", and support reading such combinations from the output window of X VOs. The recognized modifier names are Shift, Ctrl, Alt and Meta. Any combination of those and then a non-modifier key name, separated by '+', is accepted as a key name in input.conf. For non-special keys that produce characters shift is ignored as a modifier. For example "A" is handled as a key without modifiers even if you use shift to write the capital letter; 'a' vs 'A' already distinguishes the combinations with a normal keymap, and having separate 'a', 'Shift+A' and 'A' (written with caps lock for example) would bring more confusion than benefit. Currently reading the modifier+key combinations is only supported in the output window of those VOs that use x11_common.c event handling. It's not possible to input the key combinations in other VOs or in a terminal window. --- input/input.c | 137 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 89 insertions(+), 48 deletions(-) (limited to 'input') diff --git a/input/input.c b/input/input.c index 72725a5409..7df91a6922 100644 --- a/input/input.c +++ b/input/input.c @@ -45,6 +45,7 @@ #include "path.h" #include "talloc.h" #include "options.h" +#include "bstr.h" #include "joystick.h" @@ -361,6 +362,16 @@ static const mp_key_name_t key_names[] = { { 0, NULL } }; +struct mp_key_name modifier_names[] = { + { KEY_MODIFIER_SHIFT, "Shift" }, + { KEY_MODIFIER_CTRL, "Ctrl" }, + { KEY_MODIFIER_ALT, "Alt" }, + { KEY_MODIFIER_META, "Meta" }, + { 0 } +}; + +#define KEY_MODIFIER_MASK (KEY_MODIFIER_SHIFT | KEY_MODIFIER_CTRL | KEY_MODIFIER_ALT | KEY_MODIFIER_META) + // This is the default binding. The content of input.conf overrides these. // The first arg is a null terminated array of key codes. // The second is the command @@ -620,8 +631,27 @@ static const m_option_t mp_input_opts[] = { static int default_cmd_func(int fd,char* buf, int l); -static char *get_key_name(int key, char buffer[12]); +static char *get_key_name(int key) +{ + char *ret = talloc_strdup(NULL, ""); + for (int i = 0; modifier_names[i].name; i++) { + if (modifier_names[i].key & key) { + ret = talloc_asprintf_append_buffer(ret, "%s+", + modifier_names[i].name); + key -= modifier_names[i].key; + } + } + for (int i = 0; key_names[i].name != NULL; i++) { + if (key_names[i].key == key) + return talloc_asprintf_append_buffer(ret, "%s", key_names[i].name); + } + + if (isascii(key)) + return talloc_asprintf_append_buffer(ret, "%c", key); + // Print the hex key code + return talloc_asprintf_append_buffer(ret, "%#-8x", key); +} int mp_input_add_cmd_fd(struct input_ctx *ictx, int fd, int select, mp_cmd_func_t read_func, mp_close_func_t close_func) @@ -1034,7 +1064,6 @@ static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys) { char* cmd = NULL; mp_cmd_t* ret; - char key_buf[12]; if (ictx->cmd_binds) cmd = find_bind_for_key(ictx->cmd_binds, n, keys); @@ -1044,12 +1073,16 @@ static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys) cmd = find_bind_for_key(def_cmd_binds,n,keys); if(cmd == NULL) { - mp_tmsg(MSGT_INPUT,MSGL_WARN,"No bind found for key '%s'.", get_key_name(keys[0], - key_buf)); + char *key_buf = get_key_name(keys[0]); + mp_tmsg(MSGT_INPUT,MSGL_WARN,"No bind found for key '%s'.", key_buf); + talloc_free(key_buf); if(n > 1) { int s; - for(s=1; s < n; s++) - mp_msg(MSGT_INPUT,MSGL_WARN,"-%s", get_key_name(keys[s], key_buf)); + for(s=1; s < n; s++) { + key_buf = get_key_name(keys[s]); + mp_msg(MSGT_INPUT,MSGL_WARN,"-%s", key_buf); + talloc_free(key_buf); + } } mp_msg(MSGT_INPUT,MSGL_WARN," \n"); return NULL; @@ -1057,13 +1090,16 @@ static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys) if (strcmp(cmd, "ignore") == 0) return NULL; ret = mp_input_parse_cmd(cmd); if(!ret) { - mp_tmsg(MSGT_INPUT,MSGL_ERR,"Invalid command for bound key %s", - get_key_name(ictx->key_down[0], key_buf)); + char *key_buf = get_key_name(ictx->key_down[0]); + mp_tmsg(MSGT_INPUT,MSGL_ERR,"Invalid command for bound key %s", key_buf); + talloc_free(key_buf); if (ictx->num_key_down > 1) { unsigned int s; - for(s=1; s < ictx->num_key_down; s++) - mp_msg(MSGT_INPUT,MSGL_ERR,"-%s", get_key_name(ictx->key_down[s], - key_buf)); + for(s=1; s < ictx->num_key_down; s++) { + char *key_buf = get_key_name(ictx->key_down[s]); + mp_msg(MSGT_INPUT,MSGL_ERR,"-%s", key_buf); + talloc_free(key_buf); + } } mp_msg(MSGT_INPUT,MSGL_ERR," : %s \n",cmd); } @@ -1076,6 +1112,14 @@ static mp_cmd_t* interpret_key(struct input_ctx *ictx, int code) unsigned int j; mp_cmd_t* ret; + /* On normal keyboards shift changes the character code of non-special + * keys, so don't count the modifier separately for those. In other words + * we want to have "a" and "A" instead of "a" and "Shift+A"; but a separate + * shift modifier is still kept for special keys like arrow keys. + */ + if ((code & ~KEY_MODIFIER_MASK) < 256) + code &= ~KEY_MODIFIER_SHIFT; + if(mp_input_key_cb) { if (code & MP_KEY_DOWN) return NULL; @@ -1371,41 +1415,34 @@ mp_cmd_clone(mp_cmd_t* cmd) { return ret; } -static char *get_key_name(int key, char buffer[12]) +int mp_input_get_key_from_name(const char *name) { - int i; - - for(i = 0; key_names[i].name != NULL; i++) { - if(key_names[i].key == key) - return key_names[i].name; - } - - if(isascii(key)) { - snprintf(buffer, 12, "%c",(char)key); - return buffer; - } - - // Print the hex key code - snprintf(buffer, 12, "%#-8x",key); - return buffer; - -} - -int -mp_input_get_key_from_name(const char *name) { - int i,ret = 0,len = strlen(name); - if(len == 1) { // Direct key code - ret = (unsigned char)name[0]; - return ret; - } else if(len > 2 && strncasecmp("0x",name,2) == 0) - return strtol(name,NULL,16); - - for(i = 0; key_names[i].name != NULL; i++) { - if(strcasecmp(key_names[i].name,name) == 0) - return key_names[i].key; - } + int modifiers = 0; + const char *p; + while (p = strchr(name, '+')) { + for (struct mp_key_name *m = modifier_names; m->name; m++) + if (!bstrcasecmp(BSTR(m->name), (struct bstr){name, p - name})) { + modifiers |= m->key; + goto found; + } + if (!strcmp(name, "+")) + return '+' + modifiers; + return -1; + found: + name = p + 1; + } + int len = strlen(name); + if (len == 1) // Direct key code + return (unsigned char)name[0] + modifiers; + else if (len > 2 && strncasecmp("0x", name, 2) == 0) + return strtol(name, NULL, 16) + modifiers; + + for (int i = 0; key_names[i].name != NULL; i++) { + if (strcasecmp(key_names[i].name, name) == 0) + return key_names[i].key + modifiers; + } - return -1; + return -1; } static int get_input_from_name(char* name,int* keys) { @@ -1595,10 +1632,14 @@ static int parse_config(struct input_ctx *ictx, char *file) // Found new line if(iter[0] == '\n' || iter[0] == '\r') { int i; - char key_buf[12]; - mp_tmsg(MSGT_INPUT,MSGL_ERR,"No command found for key %s", get_key_name(keys[0], key_buf)); - for(i = 1; keys[i] != 0 ; i++) - mp_msg(MSGT_INPUT,MSGL_ERR,"-%s", get_key_name(keys[i], key_buf)); + char *key_buf = get_key_name(keys[0]); + mp_tmsg(MSGT_INPUT,MSGL_ERR,"No command found for key %s", key_buf); + talloc_free(key_buf); + for(i = 1; keys[i] != 0 ; i++) { + char *key_buf = get_key_name(keys[i]); + mp_msg(MSGT_INPUT,MSGL_ERR,"-%s", key_buf); + talloc_free(key_buf); + } mp_msg(MSGT_INPUT,MSGL_ERR,"\n"); keys[0] = 0; if(iter > buffer) { -- cgit v1.2.3