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:
wm4 2012-10-13 21:10:20 +02:00
parent ad5bc380e2
commit 187cbd7aa7
5 changed files with 90 additions and 14 deletions

View File

@ -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.

View File

@ -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
#

View File

@ -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");

View File

@ -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;

View File

@ -160,6 +160,7 @@ typedef struct MPOpts {
int use_lircc;
int use_ar; // apple remote
int default_bindings;
int test;
} input;
struct encode_output_conf {