mirror of
https://github.com/mpv-player/mpv
synced 2025-04-07 10:02:50 +00:00
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.
This commit is contained in:
parent
b4564c2d4f
commit
67fd58d6f0
@ -10,6 +10,10 @@
|
|||||||
## If you wish to unbind a key, use key ignore.
|
## If you wish to unbind a key, use key ignore.
|
||||||
## e.g. ENTER ignore
|
## e.g. ENTER ignore
|
||||||
##
|
##
|
||||||
|
## You can use modifier-key combinations like Shift+Left or Ctrl+Alt+x with
|
||||||
|
## modifiers Shift, Ctrl, Alt and Meta, but note that currently reading
|
||||||
|
## key combinations is only supported through the video windows of X-based
|
||||||
|
## output drivers (not in output windows of other drivers or in a terminal).
|
||||||
|
|
||||||
RIGHT seek +10
|
RIGHT seek +10
|
||||||
LEFT seek -10
|
LEFT seek -10
|
||||||
|
127
input/input.c
127
input/input.c
@ -45,6 +45,7 @@
|
|||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "talloc.h"
|
#include "talloc.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
#include "bstr.h"
|
||||||
|
|
||||||
#include "joystick.h"
|
#include "joystick.h"
|
||||||
|
|
||||||
@ -361,6 +362,16 @@ static const mp_key_name_t key_names[] = {
|
|||||||
{ 0, NULL }
|
{ 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.
|
// This is the default binding. The content of input.conf overrides these.
|
||||||
// The first arg is a null terminated array of key codes.
|
// The first arg is a null terminated array of key codes.
|
||||||
// The second is the command
|
// 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 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,
|
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)
|
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;
|
char* cmd = NULL;
|
||||||
mp_cmd_t* ret;
|
mp_cmd_t* ret;
|
||||||
char key_buf[12];
|
|
||||||
|
|
||||||
if (ictx->cmd_binds)
|
if (ictx->cmd_binds)
|
||||||
cmd = find_bind_for_key(ictx->cmd_binds, n, keys);
|
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);
|
cmd = find_bind_for_key(def_cmd_binds,n,keys);
|
||||||
|
|
||||||
if(cmd == NULL) {
|
if(cmd == NULL) {
|
||||||
mp_tmsg(MSGT_INPUT,MSGL_WARN,"No bind found for key '%s'.", get_key_name(keys[0],
|
char *key_buf = get_key_name(keys[0]);
|
||||||
key_buf));
|
mp_tmsg(MSGT_INPUT,MSGL_WARN,"No bind found for key '%s'.", key_buf);
|
||||||
|
talloc_free(key_buf);
|
||||||
if(n > 1) {
|
if(n > 1) {
|
||||||
int s;
|
int s;
|
||||||
for(s=1; s < n; s++)
|
for(s=1; s < n; s++) {
|
||||||
mp_msg(MSGT_INPUT,MSGL_WARN,"-%s", get_key_name(keys[s], key_buf));
|
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");
|
mp_msg(MSGT_INPUT,MSGL_WARN," \n");
|
||||||
return NULL;
|
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;
|
if (strcmp(cmd, "ignore") == 0) return NULL;
|
||||||
ret = mp_input_parse_cmd(cmd);
|
ret = mp_input_parse_cmd(cmd);
|
||||||
if(!ret) {
|
if(!ret) {
|
||||||
mp_tmsg(MSGT_INPUT,MSGL_ERR,"Invalid command for bound key %s",
|
char *key_buf = get_key_name(ictx->key_down[0]);
|
||||||
get_key_name(ictx->key_down[0], key_buf));
|
mp_tmsg(MSGT_INPUT,MSGL_ERR,"Invalid command for bound key %s", key_buf);
|
||||||
|
talloc_free(key_buf);
|
||||||
if (ictx->num_key_down > 1) {
|
if (ictx->num_key_down > 1) {
|
||||||
unsigned int s;
|
unsigned int s;
|
||||||
for(s=1; s < ictx->num_key_down; s++)
|
for(s=1; s < ictx->num_key_down; s++) {
|
||||||
mp_msg(MSGT_INPUT,MSGL_ERR,"-%s", get_key_name(ictx->key_down[s],
|
char *key_buf = get_key_name(ictx->key_down[s]);
|
||||||
key_buf));
|
mp_msg(MSGT_INPUT,MSGL_ERR,"-%s", key_buf);
|
||||||
|
talloc_free(key_buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mp_msg(MSGT_INPUT,MSGL_ERR," : %s \n",cmd);
|
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;
|
unsigned int j;
|
||||||
mp_cmd_t* ret;
|
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(mp_input_key_cb) {
|
||||||
if (code & MP_KEY_DOWN)
|
if (code & MP_KEY_DOWN)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -1371,38 +1415,31 @@ mp_cmd_clone(mp_cmd_t* cmd) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *get_key_name(int key, char buffer[12])
|
int mp_input_get_key_from_name(const char *name)
|
||||||
{
|
{
|
||||||
int i;
|
int modifiers = 0;
|
||||||
|
const char *p;
|
||||||
for(i = 0; key_names[i].name != NULL; i++) {
|
while (p = strchr(name, '+')) {
|
||||||
if(key_names[i].key == key)
|
for (struct mp_key_name *m = modifier_names; m->name; m++)
|
||||||
return key_names[i].name;
|
if (!bstrcasecmp(BSTR(m->name), (struct bstr){name, p - name})) {
|
||||||
|
modifiers |= m->key;
|
||||||
|
goto found;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(name, "+"))
|
||||||
if(isascii(key)) {
|
return '+' + modifiers;
|
||||||
snprintf(buffer, 12, "%c",(char)key);
|
return -1;
|
||||||
return buffer;
|
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;
|
||||||
|
|
||||||
// Print the hex key code
|
for (int i = 0; key_names[i].name != NULL; i++) {
|
||||||
snprintf(buffer, 12, "%#-8x",key);
|
if (strcasecmp(key_names[i].name, name) == 0)
|
||||||
return buffer;
|
return key_names[i].key + modifiers;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@ -1595,10 +1632,14 @@ static int parse_config(struct input_ctx *ictx, char *file)
|
|||||||
// Found new line
|
// Found new line
|
||||||
if(iter[0] == '\n' || iter[0] == '\r') {
|
if(iter[0] == '\n' || iter[0] == '\r') {
|
||||||
int i;
|
int i;
|
||||||
char key_buf[12];
|
char *key_buf = get_key_name(keys[0]);
|
||||||
mp_tmsg(MSGT_INPUT,MSGL_ERR,"No command found for key %s", get_key_name(keys[0], key_buf));
|
mp_tmsg(MSGT_INPUT,MSGL_ERR,"No command found for key %s", key_buf);
|
||||||
for(i = 1; keys[i] != 0 ; i++)
|
talloc_free(key_buf);
|
||||||
mp_msg(MSGT_INPUT,MSGL_ERR,"-%s", get_key_name(keys[i], 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");
|
mp_msg(MSGT_INPUT,MSGL_ERR,"\n");
|
||||||
keys[0] = 0;
|
keys[0] = 0;
|
||||||
if(iter > buffer) {
|
if(iter > buffer) {
|
||||||
|
@ -540,12 +540,12 @@ static const struct mp_keymap keysym_map[] = {
|
|||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void vo_x11_putkey_ext(struct vo *vo, int keysym)
|
static void vo_x11_putkey_ext(struct vo *vo, int keysym, int modifiers)
|
||||||
{
|
{
|
||||||
struct mp_fifo *f = vo->key_fifo;
|
struct mp_fifo *f = vo->key_fifo;
|
||||||
int mpkey = lookup_keymap_table(keysym_map, keysym);
|
int mpkey = lookup_keymap_table(keysym_map, keysym);
|
||||||
if (mpkey)
|
if (mpkey)
|
||||||
mplayer_put_key(f, mpkey);
|
mplayer_put_key(f, mpkey + modifiers);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -584,7 +584,7 @@ static const struct mp_keymap keymap[] = {
|
|||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
void vo_x11_putkey(struct vo *vo, int key)
|
static void vo_x11_putkey(struct vo *vo, int key, int modifiers)
|
||||||
{
|
{
|
||||||
static const char *passthrough_keys = " -+*/<>`~!@#$%^&()_{}:;\"\',.?\\|=[]";
|
static const char *passthrough_keys = " -+*/<>`~!@#$%^&()_{}:;\"\',.?\\|=[]";
|
||||||
int mpkey = 0;
|
int mpkey = 0;
|
||||||
@ -598,7 +598,7 @@ void vo_x11_putkey(struct vo *vo, int key)
|
|||||||
mpkey = lookup_keymap_table(keymap, key);
|
mpkey = lookup_keymap_table(keymap, key);
|
||||||
|
|
||||||
if (mpkey)
|
if (mpkey)
|
||||||
mplayer_put_key(vo->key_fifo, mpkey);
|
mplayer_put_key(vo->key_fifo, mpkey + modifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -814,13 +814,22 @@ int vo_x11_check_events(struct vo *vo)
|
|||||||
|
|
||||||
XLookupString(&Event.xkey, buf, sizeof(buf), &keySym,
|
XLookupString(&Event.xkey, buf, sizeof(buf), &keySym,
|
||||||
&x11->compose_status);
|
&x11->compose_status);
|
||||||
|
int modifiers = 0;
|
||||||
|
if (Event.xkey.state & ShiftMask)
|
||||||
|
modifiers |= KEY_MODIFIER_SHIFT;
|
||||||
|
if (Event.xkey.state & ControlMask)
|
||||||
|
modifiers |= KEY_MODIFIER_CTRL;
|
||||||
|
if (Event.xkey.state & Mod1Mask)
|
||||||
|
modifiers |= KEY_MODIFIER_ALT;
|
||||||
|
if (Event.xkey.state & Mod4Mask)
|
||||||
|
modifiers |= KEY_MODIFIER_META;
|
||||||
#ifdef XF86XK_AudioPause
|
#ifdef XF86XK_AudioPause
|
||||||
vo_x11_putkey_ext(vo, keySym);
|
vo_x11_putkey_ext(vo, keySym, modifiers);
|
||||||
#endif
|
#endif
|
||||||
key =
|
key =
|
||||||
((keySym & 0xff00) !=
|
((keySym & 0xff00) !=
|
||||||
0 ? ((keySym & 0x00ff) + 256) : (keySym));
|
0 ? ((keySym & 0x00ff) + 256) : (keySym));
|
||||||
vo_x11_putkey(vo, key);
|
vo_x11_putkey(vo, key, modifiers);
|
||||||
ret |= VO_EVENT_KEYPRESS;
|
ret |= VO_EVENT_KEYPRESS;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -170,8 +170,6 @@ void xv_setup_colorkeyhandling(struct vo *vo, const char *ck_method_str, const c
|
|||||||
int xv_test_ck( void * arg );
|
int xv_test_ck( void * arg );
|
||||||
int xv_test_ckm( void * arg );
|
int xv_test_ckm( void * arg );
|
||||||
|
|
||||||
void vo_x11_putkey(struct vo *vo, int key);
|
|
||||||
|
|
||||||
#ifdef CONFIG_XF86VM
|
#ifdef CONFIG_XF86VM
|
||||||
void vo_vm_switch(struct vo *vo);
|
void vo_vm_switch(struct vo *vo);
|
||||||
void vo_vm_close(struct vo *vo);
|
void vo_vm_close(struct vo *vo);
|
||||||
|
@ -94,4 +94,10 @@
|
|||||||
#define KEY_INTERN (0x1000)
|
#define KEY_INTERN (0x1000)
|
||||||
#define KEY_CLOSE_WIN (KEY_INTERN+0)
|
#define KEY_CLOSE_WIN (KEY_INTERN+0)
|
||||||
|
|
||||||
|
/* Modifiers added to individual keys */
|
||||||
|
#define KEY_MODIFIER_SHIFT 0x2000
|
||||||
|
#define KEY_MODIFIER_CTRL 0x4000
|
||||||
|
#define KEY_MODIFIER_ALT 0x8000
|
||||||
|
#define KEY_MODIFIER_META 0x10000
|
||||||
|
|
||||||
#endif /* MPLAYER_KEYCODES_H */
|
#endif /* MPLAYER_KEYCODES_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user