mirror of https://github.com/mpv-player/mpv
input: add input test mode
In input test mode, key bindings won't be executed, but are shown on the OSD. The OSD includes various information, such as the name of the key, the command itself, whether it's builtin, and the config file location it was defined. The input test mode can be enabled with "--input=test". No effort is spent trying to react to key bindings that normally exit the player; they are treated just like any other binding.
This commit is contained in:
parent
ad5bc380e2
commit
187cbd7aa7
|
@ -935,6 +935,13 @@
|
|||
can do several `echo "seek 10" > mp_pipe` and the pipe will stay
|
||||
valid.
|
||||
|
||||
test
|
||||
Input test mode. Instead of executing commands on key presses, mpv
|
||||
will show the keys and the bound commands on the OSD. Has to be used
|
||||
with a dummy video, and the normal ways to quit the player will not
|
||||
work (key bindings that normally quit will be shown on OSD only, just
|
||||
like any other binding).
|
||||
|
||||
--ipv4-only-proxy
|
||||
Skip any HTTP proxy for IPv6 addresses. It will still be used for IPv4
|
||||
connections.
|
||||
|
|
|
@ -2,10 +2,13 @@
|
|||
#
|
||||
# You are able to redefine default keyboard/joystick/mouse/LIRC bindings, or
|
||||
# add new ones here.
|
||||
# See DOCS/tech/slave.txt for possible commands that can be bound.
|
||||
# Also see mpv -input cmdlist for other possible options.
|
||||
# See DOCS/man/en/input.rst for possible commands that can be bound.
|
||||
# Also see mpv --input=cmdlist for other possible options.
|
||||
# The file should be placed in the $HOME/.mpv directory.
|
||||
#
|
||||
# mpv --input=test --pause dummy.mkv can be used to test which commands keys are
|
||||
# bound to.
|
||||
#
|
||||
# If you wish to unbind a key, use key ignore.
|
||||
# e.g. ENTER ignore
|
||||
#
|
||||
|
|
|
@ -485,6 +485,8 @@ struct input_ctx {
|
|||
unsigned int num_key_down;
|
||||
unsigned int last_key_down;
|
||||
|
||||
bool test;
|
||||
|
||||
bool default_bindings;
|
||||
// List of command binding sections
|
||||
struct cmd_bind_section *cmd_bind_sections;
|
||||
|
@ -526,6 +528,7 @@ static const m_option_t input_conf[] = {
|
|||
OPT_STRING("ar-dev", input.ar_dev, CONF_GLOBAL),
|
||||
OPT_STRING("file", input.in_file, CONF_GLOBAL),
|
||||
OPT_MAKE_FLAGS("default-bindings", input.default_bindings, CONF_GLOBAL),
|
||||
OPT_MAKE_FLAGS("test", input.test, CONF_GLOBAL),
|
||||
{ NULL, NULL, 0, 0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
|
@ -854,6 +857,7 @@ mp_cmd_t *mp_input_parse_cmd(bstr str, const char *loc)
|
|||
int pausing = 0;
|
||||
int on_osd = MP_ON_OSD_AUTO;
|
||||
struct mp_cmd *cmd = NULL;
|
||||
bstr start = str;
|
||||
void *tmp = talloc_new(NULL);
|
||||
|
||||
if (eat_token(&str, "pausing")) {
|
||||
|
@ -877,6 +881,7 @@ mp_cmd_t *mp_input_parse_cmd(bstr str, const char *loc)
|
|||
entry->old, entry->new, loc);
|
||||
bstr s = bstr_cut(str, old_len);
|
||||
str = bstr0(talloc_asprintf(tmp, "%s%.*s", entry->new, BSTR_P(s)));
|
||||
start = str;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -971,6 +976,9 @@ mp_cmd_t *mp_input_parse_cmd(bstr str, const char *loc)
|
|||
goto error;
|
||||
}
|
||||
|
||||
bstr orig = (bstr) {start.start, str.start - start.start};
|
||||
cmd->original = bstrdup(cmd, bstr_strip(orig));
|
||||
|
||||
talloc_free(tmp);
|
||||
return cmd;
|
||||
|
||||
|
@ -1090,6 +1098,67 @@ static int read_wakeup(void *ctx, int fd)
|
|||
return MP_INPUT_NOTHING;
|
||||
}
|
||||
|
||||
static bool bind_matches_key(struct cmd_bind *bind, int n, int *keys);
|
||||
|
||||
static void append_bind_info(char **pmsg, struct cmd_bind *bind)
|
||||
{
|
||||
char *msg = *pmsg;
|
||||
struct mp_cmd *cmd = mp_input_parse_cmd(bstr0(bind->cmd), bind->location);
|
||||
bstr stripped = cmd ? cmd->original : bstr0(bind->cmd);
|
||||
msg = talloc_asprintf_append(msg, " '%.*s'", BSTR_P(stripped));
|
||||
if (!cmd)
|
||||
msg = talloc_asprintf_append(msg, " (invalid)");
|
||||
if (strcmp(bind->owner->section, "default") != 0)
|
||||
msg = talloc_asprintf_append(msg, " in section {%s}",
|
||||
bind->owner->section);
|
||||
if (bind->owner->is_builtin) {
|
||||
msg = talloc_asprintf_append(msg, " (default binding)");
|
||||
} else {
|
||||
msg = talloc_asprintf_append(msg, " in %s", bind->location);
|
||||
}
|
||||
*pmsg = msg;
|
||||
}
|
||||
|
||||
static mp_cmd_t *handle_test(struct input_ctx *ictx, int n, int *keys)
|
||||
{
|
||||
char *key_buf = get_key_combo_name(keys, n);
|
||||
// "$>" to disable property substitution when invoking "show_text"
|
||||
char *msg = talloc_asprintf(NULL, "$>Key %s is bound to:\n", key_buf);
|
||||
talloc_free(key_buf);
|
||||
|
||||
int count = 0;
|
||||
for (struct cmd_bind_section *bs = ictx->cmd_bind_sections;
|
||||
bs; bs = bs->next)
|
||||
{
|
||||
for (struct cmd_bind *bind = bs->cmd_binds; bind->cmd; bind++) {
|
||||
if (bind_matches_key(bind, n, keys)) {
|
||||
count++;
|
||||
msg = talloc_asprintf_append(msg, "%d. ", count);
|
||||
append_bind_info(&msg, bind);
|
||||
msg = talloc_asprintf_append(msg, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!count)
|
||||
msg = talloc_asprintf_append(msg, "(nothing)");
|
||||
|
||||
mp_cmd_t *res = mp_input_parse_cmd(bstr0("show_text \"\""), "");
|
||||
res->args[0].v.s = talloc_steal(res, msg);
|
||||
return res;
|
||||
}
|
||||
|
||||
static bool bind_matches_key(struct cmd_bind *bind, int n, int *keys)
|
||||
{
|
||||
int found = 1, s;
|
||||
for (s = 0; s < n && bind->input[s] != 0; s++) {
|
||||
if (bind->input[s] != keys[s]) {
|
||||
found = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return found && bind->input[s] == 0 && s == n;
|
||||
}
|
||||
|
||||
static struct cmd_bind *find_bind_for_key(struct cmd_bind *binds, int n,
|
||||
int *keys)
|
||||
|
@ -1099,14 +1168,7 @@ static struct cmd_bind *find_bind_for_key(struct cmd_bind *binds, int n,
|
|||
if (n <= 0)
|
||||
return NULL;
|
||||
for (j = 0; binds[j].cmd != NULL; j++) {
|
||||
int found = 1, s;
|
||||
for (s = 0; s < n && binds[j].input[s] != 0; s++) {
|
||||
if (binds[j].input[s] != keys[s]) {
|
||||
found = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found && binds[j].input[s] == 0 && s == n)
|
||||
if (bind_matches_key(&binds[j], n, keys))
|
||||
break;
|
||||
}
|
||||
return binds[j].cmd ? &binds[j] : NULL;
|
||||
|
@ -1152,10 +1214,11 @@ static struct cmd_bind *section_find_bind_for_key(struct input_ctx *ictx,
|
|||
|
||||
static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys)
|
||||
{
|
||||
struct cmd_bind *cmd = NULL;
|
||||
mp_cmd_t *ret;
|
||||
if (ictx->test)
|
||||
return handle_test(ictx, n, keys);
|
||||
|
||||
cmd = section_find_bind_for_key(ictx, false, ictx->section, n, keys);
|
||||
struct cmd_bind *cmd
|
||||
= section_find_bind_for_key(ictx, false, ictx->section, n, keys);
|
||||
if (ictx->default_bindings && cmd == NULL)
|
||||
cmd = section_find_bind_for_key(ictx, true, ictx->section, n, keys);
|
||||
if (!(ictx->section_flags & MP_INPUT_NO_DEFAULT_SECTION)) {
|
||||
|
@ -1172,7 +1235,7 @@ static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys)
|
|||
talloc_free(key_buf);
|
||||
return NULL;
|
||||
}
|
||||
ret = mp_input_parse_cmd(bstr0(cmd->cmd), cmd->location);
|
||||
mp_cmd_t *ret = mp_input_parse_cmd(bstr0(cmd->cmd), cmd->location);
|
||||
if (!ret) {
|
||||
char *key_buf = get_key_combo_name(keys, n);
|
||||
mp_tmsg(MSGT_INPUT, MSGL_ERR,
|
||||
|
@ -1697,6 +1760,7 @@ struct input_ctx *mp_input_init(struct input_conf *input_conf)
|
|||
.ar_delay = input_conf->ar_delay,
|
||||
.ar_rate = input_conf->ar_rate,
|
||||
.default_bindings = input_conf->default_bindings,
|
||||
.test = input_conf->test,
|
||||
.wakeup_pipe = {-1, -1},
|
||||
};
|
||||
ictx->section = talloc_strdup(ictx, "default");
|
||||
|
|
|
@ -130,6 +130,7 @@ typedef struct mp_cmd {
|
|||
int nargs;
|
||||
int pausing;
|
||||
enum mp_on_osd on_osd;
|
||||
bstr original;
|
||||
struct mp_cmd *queue_next;
|
||||
} mp_cmd_t;
|
||||
|
||||
|
|
Loading…
Reference in New Issue