From f388f14c01eeec551a3cdd705c9fa680048cb758 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 30 Nov 2013 00:18:24 +0100 Subject: command: add a cycle_values input command --- DOCS/man/en/input.rst | 18 +++++++++++ mpvcore/input/input.c | 5 ++- mpvcore/input/input.h | 1 + mpvcore/player/command.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/DOCS/man/en/input.rst b/DOCS/man/en/input.rst index 0e05be2745..0763b1d1e1 100644 --- a/DOCS/man/en/input.rst +++ b/DOCS/man/en/input.rst @@ -326,6 +326,24 @@ Input Commands that are Possibly Subject to Change - ``b vf set ""`` remove all video filters on ``b`` - ``c vf toggle lavfi=gradfun`` toggle debanding on ``c`` +``cycle_values ["!reverse"] "" "" ...`` + Cycle through a list of values. Each invocation of the command will set the + given property to the next value in the list. The command maintains an + internal counter which value to pick next, and which is initially 0. It is + reset to 0 once the last value is reached. + + The internal counter is associated using the property name and the value + list. If multiple commands (bound to different keys) use the same name + and value list, they will share the internal counter. + + The special argument ``!reverse`` can be used to cycle the value list in + reverse. Compared with a command that just lists the value in reverse, this + command will actually share the internal counter with the forward-cycling + key binding. + + Note that there is a static limit of (as of this writing) 10 arguments + (this limit could be raised on demand). + ``enable_section "
" [default|exclusive]`` Enable all key bindings in the named input section. diff --git a/mpvcore/input/input.c b/mpvcore/input/input.c index 5d096fcd58..3e0313976a 100644 --- a/mpvcore/input/input.c +++ b/mpvcore/input/input.c @@ -228,7 +228,10 @@ static const struct mp_cmd_def mp_cmds[] = { .allow_auto_repeat = true }, { MP_CMD_MULTIPLY, "multiply", { ARG_STRING, ARG_DOUBLE }, - .allow_auto_repeat = true}, + .allow_auto_repeat = true}, + + { MP_CMD_CYCLE_VALUES, "cycle_values", { ARG_STRING, ARG_STRING, ARG_STRING }, + .vararg = true, .allow_auto_repeat = true}, { MP_CMD_ENABLE_INPUT_SECTION, "enable_section", { ARG_STRING, diff --git a/mpvcore/input/input.h b/mpvcore/input/input.h index a7ddaa7db1..27db11705e 100644 --- a/mpvcore/input/input.h +++ b/mpvcore/input/input.h @@ -65,6 +65,7 @@ enum mp_command_type { MP_CMD_ADD, MP_CMD_CYCLE, MP_CMD_MULTIPLY, + MP_CMD_CYCLE_VALUES, MP_CMD_RADIO_STEP_FREQ, MP_CMD_TV_STEP_FREQ, MP_CMD_TV_START_SCAN, diff --git a/mpvcore/player/command.c b/mpvcore/player/command.c index 3bd618da8e..d8a317413f 100644 --- a/mpvcore/player/command.c +++ b/mpvcore/player/command.c @@ -71,6 +71,9 @@ struct command_ctx { int events; + struct cycle_counter *cycle_counters; + int num_cycle_counters; + #define OVERLAY_MAX_ID 64 void *overlay_map[OVERLAY_MAX_ID]; }; @@ -2388,6 +2391,47 @@ static void overlay_uninit(struct MPContext *mpctx){} #endif +struct cycle_counter { + char **args; + int counter; +}; + +static bool stringlist_equals(char **l1, char **l2) +{ + assert(l1 && l2); + for (int i = 0; ; i++) { + if (!l1[i] && !l2[i]) + return true; + if (!l1[i] || !l2[i]) + return false; + if (strcmp(l1[i], l2[i]) != 0) + return false; + } +} + +static char **stringlist_dup(void *talloc_ctx, char **list) +{ + int num = 0; + char **res = NULL; + for (int i = 0; list && list[i]; i++) + MP_TARRAY_APPEND(talloc_ctx, res, num, talloc_strdup(talloc_ctx, list[i])); + MP_TARRAY_APPEND(talloc_ctx, res, num, NULL); + return res; +} + +static int *get_cmd_cycle_counter(struct MPContext *mpctx, char **args) +{ + struct command_ctx *cmd = mpctx->command_ctx; + for (int n = 0; n < cmd->num_cycle_counters; n++) { + struct cycle_counter *ctr = &cmd->cycle_counters[n]; + if (stringlist_equals(ctr->args, args)) + return &ctr->counter; + } + struct cycle_counter ctr = {stringlist_dup(cmd, args), 0}; + MP_TARRAY_APPEND(cmd, cmd->cycle_counters, cmd->num_cycle_counters, ctr); + return &cmd->cycle_counters[cmd->num_cycle_counters - 1].counter; +} + static int mp_property_multiply(char *property, double f, struct MPContext *mpctx) { union m_option_value val = {0}; @@ -2533,6 +2577,41 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) break; } + case MP_CMD_CYCLE_VALUES: { + char *args[MP_CMD_MAX_ARGS + 1] = {0}; + for (int n = 0; n < cmd->nargs; n++) + args[n] = cmd->args[n].v.s; + int first = 1, dir = 1; + if (strcmp(args[0], "!reverse") == 0) { + first += 1; + dir = -1; + } + int *ptr = get_cmd_cycle_counter(mpctx, &args[first - 1]); + int count = cmd->nargs - first; + if (ptr && count > 0) { + int next = *ptr; + *ptr += dir; + if (*ptr >= count) + *ptr = 0; + if (*ptr < 0) + *ptr = count - 1; + char *property = args[first - 1]; + char *value = args[first + next]; + int r = mp_property_do(property, M_PROPERTY_SET_STRING, value, mpctx); + if (r == M_PROPERTY_OK || r == M_PROPERTY_UNAVAILABLE) { + show_property_osd(mpctx, property, cmd->on_osd); + } else if (r == M_PROPERTY_UNKNOWN) { + set_osd_msg(mpctx, OSD_MSG_TEXT, osdl, osd_duration, + "Unknown property: '%s'", property); + } else if (r <= 0) { + set_osd_msg(mpctx, OSD_MSG_TEXT, osdl, osd_duration, + "Failed to set property '%s' to '%s'", + property, value); + } + } + break; + } + case MP_CMD_GET_PROPERTY: { char *tmp; int r = mp_property_do(cmd->args[0].v.s, M_PROPERTY_GET_STRING, -- cgit v1.2.3