diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/command.c | 49 | ||||
-rw-r--r-- | core/command.h | 2 | ||||
-rw-r--r-- | core/input/input.c | 319 | ||||
-rw-r--r-- | core/input/input.h | 60 | ||||
-rw-r--r-- | core/input/keycodes.h | 31 | ||||
-rw-r--r-- | core/mplayer.c | 12 |
6 files changed, 328 insertions, 145 deletions
diff --git a/core/command.c b/core/command.c index 828bf21a08..9e77436a95 100644 --- a/core/command.c +++ b/core/command.c @@ -84,37 +84,17 @@ static char *format_delay(double time) return talloc_asprintf(NULL, "%d ms", ROUND(time * 1000)); } -static void rescale_input_coordinates(struct MPContext *mpctx, int ix, int iy, - double *dx, double *dy) +// Get current mouse position in OSD coordinate space. +void mp_get_osd_mouse_pos(struct MPContext *mpctx, float *x, float *y) { - struct MPOpts *opts = &mpctx->opts; - struct vo *vo = mpctx->video_out; - //remove the borders, if any, and rescale to the range [0,1],[0,1] - if (opts->vo.fs) { //we are in full-screen mode - if (opts->vo.screenwidth > vo->dwidth) - // there are borders along the x axis - ix -= (opts->vo.screenwidth - vo->dwidth) / 2; - if (opts->vo.screenheight > vo->dheight) - // there are borders along the y axis (usual way) - iy -= (opts->vo.screenheight - vo->dheight) / 2; - - if (ix < 0 || ix > vo->dwidth) { - *dx = *dy = -1.0; - return; - } //we are on one of the borders - if (iy < 0 || iy > vo->dheight) { - *dx = *dy = -1.0; - return; - } //we are on one of the borders - } - - *dx = (double) ix / (double) vo->dwidth; - *dy = (double) iy / (double) vo->dheight; - - mp_msg(MSGT_CPLAYER, MSGL_V, - "\r\nrescaled coordinates: %.3f, %.3f, screen (%d x %d), vodisplay: (%d, %d), fullscreen: %d\r\n", - *dx, *dy, opts->vo.screenwidth, opts->vo.screenheight, vo->dwidth, - vo->dheight, opts->vo.fs); + int wx, wy; + mp_input_get_mouse_pos(mpctx->input, &wx, &wy); + float p[2] = {wx, wy}; + // Raw window coordinates (VO mouse events) to OSD resolution. + if (mpctx->video_out) + vo_control(mpctx->video_out, VOCTRL_WINDOW_TO_OSD_COORDS, p); + *x = p[0]; + *y = p[1]; } // Property-option bridge. @@ -2432,15 +2412,6 @@ void run_command(MPContext *mpctx, mp_cmd_t *cmd) mplayer_put_key(mpctx->key_fifo, cmd->args[0].v.i); break; - case MP_CMD_SET_MOUSE_POS: { - int pointer_x, pointer_y; - double dx, dy; - pointer_x = cmd->args[0].v.i; - pointer_y = cmd->args[1].v.i; - rescale_input_coordinates(mpctx, pointer_x, pointer_y, &dx, &dy); - break; - } - case MP_CMD_VO_CMDLINE: if (mpctx->video_out) { char *s = cmd->args[0].v.s; diff --git a/core/command.h b/core/command.h index 2c2de03585..dbe1f638e2 100644 --- a/core/command.h +++ b/core/command.h @@ -22,6 +22,8 @@ struct MPContext; struct mp_cmd; +void mp_get_osd_mouse_pos(struct MPContext *mpctx, float *x, float *y); + void run_command(struct MPContext *mpctx, struct mp_cmd *cmd); char *mp_property_expand_string(struct MPContext *mpctx, char *str); void property_print_help(void); diff --git a/core/input/input.c b/core/input/input.c index dfa7d1e5b4..b883974409 100644 --- a/core/input/input.c +++ b/core/input/input.c @@ -194,8 +194,6 @@ static const mp_cmd_t mp_cmds[] = { .v.f = 1 }, }}, - { MP_CMD_SET_MOUSE_POS, "set_mouse_pos", { ARG_INT, ARG_INT } }, - { MP_CMD_AF_SWITCH, "af_switch", { ARG_STRING } }, { MP_CMD_AF_ADD, "af_add", { ARG_STRING } }, { MP_CMD_AF_DEL, "af_del", { ARG_STRING } }, @@ -433,7 +431,8 @@ static const struct key_name key_names[] = { { MP_KEY_PREV, "XF86_PREV" }, { MP_KEY_NEXT, "XF86_NEXT" }, - { MP_KEY_CLOSE_WIN, "CLOSE_WIN" }, + { MP_KEY_CLOSE_WIN, "CLOSE_WIN" }, + { MP_KEY_MOUSE_MOVE, "MOUSE_MOVE" }, { 0, NULL } }; @@ -476,9 +475,18 @@ struct cmd_bind_section { struct cmd_bind *cmd_binds; bool is_builtin; char *section; + struct mp_rect mouse_area; // set at runtime, if at all + bool mouse_area_set; // mouse_area is valid and should be tested struct cmd_bind_section *next; }; +#define MAX_ACTIVE_SECTIONS 5 + +struct active_section { + char *name; + int flags; +}; + struct cmd_queue { struct mp_cmd *first; }; @@ -486,7 +494,6 @@ struct cmd_queue { struct input_ctx { // Autorepeat stuff short ar_state; - mp_cmd_t *ar_cmd; int64_t last_ar; // Autorepeat config unsigned int ar_delay; @@ -499,16 +506,24 @@ struct input_ctx { int key_down[MP_MAX_KEY_DOWN]; unsigned int num_key_down; int64_t last_key_down; + struct mp_cmd *current_down_cmd; + + // Mouse position on the consumer side (as command.c sees it) + int mouse_x, mouse_y; + + // Mouse position on the producer side (as the VO sees it) + // Unlike mouse_x/y, this can be used to resolve mouse click bindings. + int mouse_vo_x, mouse_vo_y; bool test; bool default_bindings; // List of command binding sections struct cmd_bind_section *cmd_bind_sections; - // Name of currently used command section - char *section; - // Bitfield of mp_input_section_flags - int section_flags; + + // List currently active command sections + struct active_section active_sections[MAX_ACTIVE_SECTIONS]; + int num_active_sections; // Used to track whether we managed to read something while checking // events sources. If yes, the sources may have more queued. @@ -568,6 +583,11 @@ static const char builtin_input_conf[] = #include "core/input/input_conf.h" ; +static bool test_rect(struct mp_rect *rc, int x, int y) +{ + return x >= rc->x0 && y >= rc->y0 && x < rc->x1 && y < rc->y1; +} + static char *get_key_name(int key, char *ret) { for (int i = 0; modifier_names[i].name; i++) { @@ -1081,11 +1101,10 @@ static void append_bind_info(char **pmsg, struct cmd_bind *bind) 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); - } + msg = talloc_asprintf_append(msg, " in %s", bind->location); + if (bind->owner->is_builtin) + msg = talloc_asprintf_append(msg, " (default)"); + talloc_free(cmd); *pmsg = msg; } @@ -1100,7 +1119,7 @@ static mp_cmd_t *handle_test(struct input_ctx *ictx, int n, int *keys) 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++) { + for (struct cmd_bind *bind = bs->cmd_binds; bind && bind->cmd; bind++) { if (bind_matches_key(bind, n, keys)) { count++; msg = talloc_asprintf_append(msg, "%d. ", count); @@ -1113,6 +1132,8 @@ static mp_cmd_t *handle_test(struct input_ctx *ictx, int n, int *keys) if (!count) msg = talloc_asprintf_append(msg, "(nothing)"); + mp_msg(MSGT_INPUT, MSGL_V, "[input] %s\n", msg); + mp_cmd_t *res = mp_input_parse_cmd(bstr0("show_text \"\""), ""); res->args[0].v.s = talloc_steal(res, msg); return res; @@ -1135,7 +1156,7 @@ static struct cmd_bind *find_bind_for_key(struct cmd_bind *binds, int n, { int j; - if (n <= 0) + if (n <= 0 || !binds) return NULL; for (j = 0; binds[j].cmd != NULL; j++) { if (bind_matches_key(&binds[j], n, keys)) @@ -1166,36 +1187,39 @@ static struct cmd_bind_section *get_bind_section(struct input_ctx *ictx, ictx->cmd_bind_sections = talloc_ptrtype(ictx, ictx->cmd_bind_sections); bind_section = ictx->cmd_bind_sections; } - bind_section->cmd_binds = NULL; - bind_section->section = bstrdup0(bind_section, section); - bind_section->is_builtin = builtin; - bind_section->next = NULL; + *bind_section = (struct cmd_bind_section) { + .section = bstrdup0(bind_section, section), + .is_builtin = builtin, + }; return bind_section; } -static struct cmd_bind *section_find_bind_for_key(struct input_ctx *ictx, - bool builtin, char *section, - int n, int *keys) -{ - struct cmd_bind_section *bs = get_bind_section(ictx, builtin, - bstr0(section)); - return bs->cmd_binds ? find_bind_for_key(bs->cmd_binds, n, keys) : NULL; -} - static struct cmd_bind *find_any_bind_for_key(struct input_ctx *ictx, int n, int *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)) { - if (cmd == NULL) - cmd = section_find_bind_for_key(ictx, false, "default", n, keys); - if (ictx->default_bindings && cmd == NULL) - cmd = section_find_bind_for_key(ictx, true, "default", n, keys); + for (int i = ictx->num_active_sections - 1; i >= 0; i--) { + struct active_section *as = &ictx->active_sections[i]; + bstr name = bstr0(as->name); + for (int b = 0; b < 2; b++) { + bool builtin = !!b; + struct cmd_bind_section *bs = get_bind_section(ictx, builtin, name); + for (int i = 0; i < n; i++) { + if (MP_KEY_DEPENDS_ON_MOUSE_POS(keys[i]) && + bs->mouse_area_set && + !test_rect(&bs->mouse_area, + ictx->mouse_vo_x, + ictx->mouse_vo_y)) + goto skip; + } + struct cmd_bind *cmd = find_bind_for_key(bs->cmd_binds, n, keys); + if (cmd) + return cmd; + skip: ; + } + if (as->flags & MP_INPUT_EXCLUSIVE) + break; } - return cmd; + return NULL; } static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys) @@ -1227,12 +1251,27 @@ static mp_cmd_t *get_cmd_from_keys(struct input_ctx *ictx, int n, int *keys) return ret; } +static void release_down_cmd(struct input_ctx *ictx) +{ + if (ictx->current_down_cmd && ictx->current_down_cmd->key_up_follows) { + ictx->current_down_cmd->key_up_follows = false; + queue_add(&ictx->key_cmd_queue, ictx->current_down_cmd, false); + } else { + talloc_free(ictx->current_down_cmd); + } + ictx->current_down_cmd = NULL; + ictx->last_key_down = 0; + ictx->ar_state = -1; +} static mp_cmd_t *interpret_key(struct input_ctx *ictx, int code) { unsigned int j; mp_cmd_t *ret; + if (code == MP_KEY_MOUSE_MOVE) + return get_cmd_from_keys(ictx, 1, (int[]){code}); + /* 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 @@ -1256,21 +1295,23 @@ static mp_cmd_t *interpret_key(struct input_ctx *ictx, int code) } if (j != ictx->num_key_down) return NULL; + release_down_cmd(ictx); ictx->key_down[ictx->num_key_down] = code; ictx->num_key_down++; ictx->last_key_down = mp_time_us(); ictx->ar_state = 0; - ret = NULL; - if (!(code & MP_NO_REPEAT_KEY)) - ret = get_cmd_from_keys(ictx, ictx->num_key_down, ictx->key_down); - return ret; + ictx->current_down_cmd = get_cmd_from_keys(ictx, ictx->num_key_down, + ictx->key_down); + if (ictx->current_down_cmd && (code & MP_KEY_EMIT_ON_UP)) + ictx->current_down_cmd->key_up_follows = true; + return mp_cmd_clone(ictx->current_down_cmd); } // button released or press of key with no separate down/up events for (j = 0; j < ictx->num_key_down; j++) { if (ictx->key_down[j] == code) break; } - bool doubleclick = code >= MP_MOUSE_BTN0_DBL && code < MP_MOUSE_BTN_DBL_END; + bool doubleclick = MP_KEY_IS_MOUSE_BTN_DBL(code); if (doubleclick) { int btn = code - MP_MOUSE_BTN0_DBL + MP_MOUSE_BTN0; if (!ictx->num_key_down @@ -1279,7 +1320,7 @@ static mp_cmd_t *interpret_key(struct input_ctx *ictx, int code) j = ictx->num_key_down - 1; ictx->key_down[j] = code; } - bool emit_key = ictx->last_key_down && (code & MP_NO_REPEAT_KEY); + bool emit_key = ictx->last_key_down; if (j == ictx->num_key_down) { // was not already down; add temporarily if (ictx->num_key_down > MP_MAX_KEY_DOWN) { mp_tmsg(MSGT_INPUT, MSGL_ERR, "Too many key down events " @@ -1290,6 +1331,9 @@ static mp_cmd_t *interpret_key(struct input_ctx *ictx, int code) ictx->num_key_down++; emit_key = true; } + // This is a key up event, but the key up command is added by + // release_down_cmd(), not by this code. + emit_key &= !(code & MP_KEY_EMIT_ON_UP); // Interpret only maximal point of multibutton event ret = NULL; if (emit_key) @@ -1303,10 +1347,7 @@ static mp_cmd_t *interpret_key(struct input_ctx *ictx, int code) memmove(&ictx->key_down[j], &ictx->key_down[j + 1], (ictx->num_key_down - (j + 1)) * sizeof(int)); ictx->num_key_down--; - ictx->last_key_down = 0; - ictx->ar_state = -1; - mp_cmd_free(ictx->ar_cmd); - ictx->ar_cmd = NULL; + release_down_cmd(ictx); return ret; } @@ -1322,51 +1363,83 @@ static mp_cmd_t *check_autorepeat(struct input_ctx *ictx) if (ictx->ar_state == 0 && (t - ictx->last_key_down) >= ictx->ar_delay * 1000) { - talloc_free(ictx->ar_cmd); - ictx->ar_cmd = get_cmd_from_keys(ictx, ictx->num_key_down, - ictx->key_down); - if (!ictx->ar_cmd) { + if (!ictx->current_down_cmd) { ictx->ar_state = -1; return NULL; } ictx->ar_state = 1; ictx->last_ar = ictx->last_key_down + ictx->ar_delay * 1000; - return mp_cmd_clone(ictx->ar_cmd); + return mp_cmd_clone(ictx->current_down_cmd); // Then send rate / sec event } else if (ictx->ar_state == 1 && (t - ictx->last_ar) >= 1000000 / ictx->ar_rate) { ictx->last_ar += 1000000 / ictx->ar_rate; - return mp_cmd_clone(ictx->ar_cmd); + return mp_cmd_clone(ictx->current_down_cmd); } } return NULL; } +static void add_key_cmd(struct input_ctx *ictx, struct mp_cmd *cmd) +{ + struct cmd_queue *queue = &ictx->key_cmd_queue; + if (queue_count_cmds(queue) >= ictx->key_fifo_size && + (!mp_input_is_abort_cmd(cmd->id) || queue_has_abort_cmds(queue))) + { + talloc_free(cmd); + return; + } + queue_add(queue, cmd, false); +} + +// Whether a command can deal with redundant key up events. +static bool key_updown_ok(enum mp_command_type cmd) +{ + switch (cmd) { + default: + return false; + } +} + void mp_input_feed_key(struct input_ctx *ictx, int code) { ictx->got_new_events = true; int unmod = code & ~(MP_KEY_MODIFIER_MASK | MP_KEY_STATE_DOWN); - if (unmod >= MP_MOUSE_BASE && unmod <= MP_MOUSE_BTN_END) + if (MP_KEY_DEPENDS_ON_MOUSE_POS(unmod)) ictx->mouse_event_counter++; if (code == MP_INPUT_RELEASE_ALL) { mp_msg(MSGT_INPUT, MSGL_V, "input: release all\n"); memset(ictx->key_down, 0, sizeof(ictx->key_down)); ictx->num_key_down = 0; - ictx->last_key_down = 0; + release_down_cmd(ictx); return; } mp_msg(MSGT_INPUT, MSGL_V, "input: key code=%#x\n", code); struct mp_cmd *cmd = interpret_key(ictx, code); if (!cmd) return; - struct cmd_queue *queue = &ictx->key_cmd_queue; - if (queue_count_cmds(queue) >= ictx->key_fifo_size && - (!mp_input_is_abort_cmd(cmd->id) || queue_has_abort_cmds(queue))) - { + // Prevent redundant key-down events from being added to the queue. In some + // cases (like MP_CMD_SEEK commands), duplicated events might severely + // confuse the frontend. + if (cmd->key_up_follows && !key_updown_ok(cmd->id)) { talloc_free(cmd); return; } - queue_add(queue, cmd, false); + add_key_cmd(ictx, cmd); +} + +void mp_input_set_mouse_pos(struct input_ctx *ictx, int x, int y) +{ + ictx->mouse_event_counter++; + ictx->mouse_vo_x = x; + ictx->mouse_vo_y = y; + struct mp_cmd *cmd = interpret_key(ictx, MP_KEY_MOUSE_MOVE); + if (!cmd) + return; + cmd->mouse_move = true; + cmd->mouse_x = x; + cmd->mouse_y = y; + add_key_cmd(ictx, cmd); } static void read_cmd_fd(struct input_ctx *ictx, struct input_fd *cmd_fd) @@ -1513,8 +1586,6 @@ int mp_input_queue_cmd(struct input_ctx *ictx, mp_cmd_t *cmd) ictx->got_new_events = true; if (!cmd) return 0; - if (cmd->id == MP_CMD_SET_MOUSE_POS) - ictx->mouse_event_counter++; queue_add(&ictx->control_cmd_queue, cmd, false); return 1; } @@ -1545,12 +1616,23 @@ mp_cmd_t *mp_input_get_cmd(struct input_ctx *ictx, int time, int peek_only) if (!ret) return NULL; - if (!peek_only) + if (!peek_only) { queue_remove(queue, ret); + if (ret->mouse_move) { + ictx->mouse_x = ret->mouse_x; + ictx->mouse_y = ret->mouse_y; + } + } return ret; } +void mp_input_get_mouse_pos(struct input_ctx *ictx, int *x, int *y) +{ + *x = ictx->mouse_x; + *y = ictx->mouse_y; +} + void mp_cmd_free(mp_cmd_t *cmd) { talloc_free(cmd); @@ -1561,6 +1643,9 @@ mp_cmd_t *mp_cmd_clone(mp_cmd_t *cmd) mp_cmd_t *ret; int i; + if (!cmd) + return NULL; + ret = talloc_memdup(NULL, cmd, sizeof(mp_cmd_t)); ret->name = talloc_strdup(ret, cmd->name); for (i = 0; i < MP_CMD_MAX_ARGS; i++) { @@ -1668,8 +1753,10 @@ static void bind_keys(struct input_ctx *ictx, bool builtin, bstr section, memcpy(bind->input, keys, (MP_MAX_KEY_DOWN + 1) * sizeof(int)); } +// restrict_section: every entry is forced to this section name +// if NULL, load normally and allow any sections static int parse_config(struct input_ctx *ictx, bool builtin, bstr data, - const char *location) + const char *location, const char *restrict_section) { int n_binds = 0, keys[MP_MAX_KEY_DOWN + 1]; int line_no = 0; @@ -1704,12 +1791,14 @@ static int parse_config(struct input_ctx *ictx, bool builtin, bstr data, } talloc_free(name); - bstr section = {0}; - if (bstr_startswith0(command, "{")) { - int p = bstrchr(command, '}'); - if (p != -1) { - section = bstr_strip(bstr_splice(command, 1, p)); - command = bstr_lstrip(bstr_cut(command, p + 1)); + bstr section = bstr0(restrict_section); + if (!section.len) { + if (bstr_startswith0(command, "{")) { + int p = bstrchr(command, '}'); + if (p != -1) { + section = bstr_strip(bstr_splice(command, 1, p)); + command = bstr_lstrip(bstr_cut(command, p + 1)); + } } } @@ -1740,23 +1829,91 @@ static int parse_config_file(struct input_ctx *ictx, char *file, bool warn) bstr res = stream_read_complete(s, NULL, 1000000); free_stream(s); mp_msg(MSGT_INPUT, MSGL_V, "Parsing input config file %s\n", file); - int n_binds = parse_config(ictx, false, res, file); + int n_binds = parse_config(ictx, false, res, file, NULL); talloc_free(res.start); mp_msg(MSGT_INPUT, MSGL_V, "Input config file %s parsed: %d binds\n", file, n_binds); return 1; } -void mp_input_set_section(struct input_ctx *ictx, char *name, int flags) +void mp_input_disable_section(struct input_ctx *ictx, char *name) +{ + struct cmd_bind_section *s = get_bind_section(ictx, false, bstr0(name)); + name = s->section; // get allocated name, reduce NULL to "default" + + // Remove old section, or make sure it's on top if re-enabled + for (int i = ictx->num_active_sections - 1; i >= 0; i--) { + struct active_section *as = &ictx->active_sections[i]; + if (strcmp(as->name, name) == 0) { + for (int x = i; i < ictx->num_active_sections - 1; i++) + ictx->active_sections[x] = ictx->active_sections[x + 1]; + ictx->num_active_sections--; + } + } +} + +void mp_input_enable_section(struct input_ctx *ictx, char *name, int flags) +{ + struct cmd_bind_section *s = get_bind_section(ictx, false, bstr0(name)); + name = s->section; // get allocated name, reduce NULL to "default" + + mp_input_disable_section(ictx, name); + + if (ictx->num_active_sections < MAX_ACTIVE_SECTIONS) { + ictx->active_sections[ictx->num_active_sections++] = + (struct active_section) {name, flags}; + } +} + +void mp_input_disable_all_sections(struct input_ctx *ictx) +{ + ictx->num_active_sections = 0; +} + +void mp_input_set_section_mouse_area(struct input_ctx *ictx, char *name, + int x0, int y0, int x1, int y1) { - talloc_free(ictx->section); - ictx->section = talloc_strdup(ictx, name ? name : "default"); - ictx->section_flags = flags; + for (int b = 0; b < 2; b++) { + struct cmd_bind_section *s = get_bind_section(ictx, !!b, bstr0(name)); + s->mouse_area = (struct mp_rect){x0, y0, x1, y1}; + s->mouse_area_set = x0 != x1 && y0 != y1; + } +} + +bool mp_input_test_mouse_active(struct input_ctx *ictx, int x, int y) +{ + for (int i = 0; i < ictx->num_active_sections; i++) { + char *name = ictx->active_sections[i].name; + for (int b = 0; b < 2; b++) { + struct cmd_bind_section *s = get_bind_section(ictx, !!b, bstr0(name)); + if (s->mouse_area_set && test_rect(&s->mouse_area, x, y)) + return true; + } + } + return false; +} + +bool mp_input_test_dragging(struct input_ctx *ictx, int x, int y) +{ + return mp_input_test_mouse_active(ictx, x, y); } -char *mp_input_get_section(struct input_ctx *ictx) +void mp_input_define_section(struct input_ctx *ictx, char *name, char *location, + char *contents, bool builtin) { - return ictx->section; + if (!name || !name[0]) + return; // parse_config() changes semantics with restrict_section==empty + if (contents) { + parse_config(ictx, builtin, bstr0(contents), location, name); + } else { + // Disable: + mp_input_disable_section(ictx, name); + // Delete: + struct cmd_bind_section *s = get_bind_section(ictx, builtin, bstr0(name)); + talloc_free(s->cmd_binds); + s->cmd_binds = NULL; + // Could remove the section itself too, but that's not really necessary. + } } struct input_ctx *mp_input_init(struct input_conf *input_conf, @@ -1772,9 +1929,9 @@ struct input_ctx *mp_input_init(struct input_conf *input_conf, .test = input_conf->test, .wakeup_pipe = {-1, -1}, }; - ictx->section = talloc_strdup(ictx, "default"); + mp_input_enable_section(ictx, NULL, 0); - parse_config(ictx, true, bstr0(builtin_input_conf), "<default>"); + parse_config(ictx, true, bstr0(builtin_input_conf), "<builtin>", NULL); #ifndef __MINGW32__ long ret = pipe(ictx->wakeup_pipe); @@ -1904,7 +2061,7 @@ void mp_input_uninit(struct input_ctx *ictx, struct input_conf *input_conf) } clear_queue(&ictx->key_cmd_queue); clear_queue(&ictx->control_cmd_queue); - talloc_free(ictx->ar_cmd); + talloc_free(ictx->current_down_cmd); talloc_free(ictx); } diff --git a/core/input/input.h b/core/input/input.h index b9bc295646..26b529bfb9 100644 --- a/core/input/input.h +++ b/core/input/input.h @@ -60,7 +60,6 @@ enum mp_command_type { MP_CMD_RADIO_STEP_CHANNEL, MP_CMD_RADIO_SET_CHANNEL, MP_CMD_RADIO_SET_FREQ, - MP_CMD_SET_MOUSE_POS, MP_CMD_ADD, MP_CMD_CYCLE, MP_CMD_RADIO_STEP_FREQ, @@ -108,10 +107,10 @@ enum mp_on_osd { }; enum mp_input_section_flags { - // If a key binding is not defined in the current section, search the - // default section for it ("default" refers to bindings with no section - // specified, not to the default input.conf aka builtin key bindings) - MP_INPUT_NO_DEFAULT_SECTION = 1, + // If a key binding is not defined in the current section, do not search the + // other sections for it (like the default section). Instead, an unbound + // key warning will be printed. + MP_INPUT_EXCLUSIVE = 1, }; struct input_ctx; @@ -136,6 +135,9 @@ typedef struct mp_cmd { bool raw_args; enum mp_on_osd on_osd; bstr original; + bool key_up_follows; + bool mouse_move; + int mouse_x, mouse_y; struct mp_cmd *queue_next; } mp_cmd_t; @@ -170,6 +172,11 @@ int mp_input_add_key_fd(struct input_ctx *ictx, int fd, int select, // Feed a keypress (alternative to being returned from read_func above) void mp_input_feed_key(struct input_ctx *ictx, int code); +// Update mouse position (in window coordinates). +void mp_input_set_mouse_pos(struct input_ctx *ictx, int x, int y); + +void mp_input_get_mouse_pos(struct input_ctx *ictx, int *x, int *y); + // As for the cmd one you usually don't need this function. void mp_input_rm_key_fd(struct input_ctx *ictx, int fd); @@ -197,16 +204,49 @@ void mp_cmd_free(struct mp_cmd *cmd); // This creates a copy of a command (used by the auto repeat stuff). struct mp_cmd *mp_cmd_clone(struct mp_cmd *cmd); -// Set current input section +// Set current input section. The section is appended on top of the list of +// active sections, so its bindings are considered first. If the section was +// already active, it's moved to the top as well. +// name==NULL will behave as if name=="default" // flags is a bitfield of enum mp_input_section_flags values -void mp_input_set_section(struct input_ctx *ictx, char *name, int flags); - -// Get current input section -char *mp_input_get_section(struct input_ctx *ictx); +void mp_input_enable_section(struct input_ctx *ictx, char *name, int flags); + +// Undo mp_input_enable_section(). +// name==NULL will behave as if name=="default" +void mp_input_disable_section(struct input_ctx *ictx, char *name); + +// Like mp_input_set_section(ictx, ..., 0) for all sections. +void mp_input_disable_all_sections(struct input_ctx *ictx); + +// Set the contents of an input section. +// name: name of the section, for mp_input_set_section() etc. +// location: location string (like filename) for error reporting +// contents: list of keybindings, like input.conf +// a value of NULL deletes the section +// builtin: create as builtin section; this means if the user defines bindings +// using "{name}", they won't be ignored or overwritten - instead, +// they are preferred to the bindings defined with this call +// If the section already exists, its bindings are removed and replaced. +void mp_input_define_section(struct input_ctx *ictx, char *name, char *location, + char *contents, bool builtin); + +// Define where on the screen the named input section should receive. +// Setting a rectangle of size 0 unsets the mouse area. +// A rectangle with negative size disables mouse input for this section. +void mp_input_set_section_mouse_area(struct input_ctx *ictx, char *name, + int x0, int y0, int x1, int y1); // Used to detect mouse movement. unsigned int mp_input_get_mouse_event_counter(struct input_ctx *ictx); +// Test whether there is any input section which wants to receive events. +// Note that the mouse event is always delivered, even if this returns false. +bool mp_input_test_mouse_active(struct input_ctx *ictx, int x, int y); + +// Whether input.c wants mouse drag events at this mouse position. If this +// returns false, some VOs will initiate window dragging. +bool mp_input_test_dragging(struct input_ctx *ictx, int x, int y); + // Initialize the input system struct input_conf; struct input_ctx *mp_input_init(struct input_conf *input_conf, diff --git a/core/input/keycodes.h b/core/input/keycodes.h index 92608aa6fa..b086d82809 100644 --- a/core/input/keycodes.h +++ b/core/input/keycodes.h @@ -126,7 +126,7 @@ // Mouse events from VOs -#define MP_MOUSE_BASE ((MP_KEY_BASE+0xA0)|MP_NO_REPEAT_KEY) +#define MP_MOUSE_BASE ((MP_KEY_BASE+0xA0)|MP_NO_REPEAT_KEY|MP_KEY_EMIT_ON_UP) #define MP_MOUSE_BTN0 (MP_MOUSE_BASE+0) #define MP_MOUSE_BTN1 (MP_MOUSE_BASE+1) #define MP_MOUSE_BTN2 (MP_MOUSE_BASE+2) @@ -149,6 +149,9 @@ #define MP_MOUSE_BTN19 (MP_MOUSE_BASE+19) #define MP_MOUSE_BTN_END (MP_MOUSE_BASE+20) +#define MP_KEY_IS_MOUSE_BTN_SINGLE(code) \ + ((code) >= MP_MOUSE_BASE && (code) < MP_MOUSE_BTN_END) + #define MP_MOUSE_BASE_DBL ((MP_KEY_BASE+0xC0)|MP_NO_REPEAT_KEY) #define MP_MOUSE_BTN0_DBL (MP_MOUSE_BASE_DBL+0) #define MP_MOUSE_BTN1_DBL (MP_MOUSE_BASE_DBL+1) @@ -172,6 +175,9 @@ #define MP_MOUSE_BTN19_DBL (MP_MOUSE_BASE_DBL+19) #define MP_MOUSE_BTN_DBL_END (MP_MOUSE_BASE_DBL+20) +#define MP_KEY_IS_MOUSE_BTN_DBL(code) \ + ((code) >= MP_MOUSE_BTN0_DBL && (code) < MP_MOUSE_BTN_DBL_END) + // Apple Remote input module #define MP_AR_BASE (MP_KEY_BASE+0xE0) #define MP_AR_PLAY (MP_AR_BASE + 0) @@ -198,6 +204,13 @@ /* Special keys */ #define MP_KEY_INTERN (MP_KEY_BASE+0x1000) #define MP_KEY_CLOSE_WIN (MP_KEY_INTERN+0) +// Generated by input.c (VOs use mp_input_set_mouse_pos()) +#define MP_KEY_MOUSE_MOVE ((MP_KEY_INTERN+1)|MP_NO_REPEAT_KEY) + + +#define MP_KEY_DEPENDS_ON_MOUSE_POS(code) \ + (MP_KEY_IS_MOUSE_BTN_SINGLE(code) || MP_KEY_IS_MOUSE_BTN_DBL(code) || \ + (code) == MP_KEY_MOUSE_MOVE) /* Modifiers added to individual keys */ #define MP_KEY_MODIFIER_SHIFT (1<<22) @@ -208,13 +221,19 @@ #define MP_KEY_MODIFIER_MASK (MP_KEY_MODIFIER_SHIFT | MP_KEY_MODIFIER_CTRL | \ MP_KEY_MODIFIER_ALT | MP_KEY_MODIFIER_META) -// Use this when the key shouldn't be auto-repeated (like mouse buttons) -// This is not a modifier, but is part of the keycode itself. -#define MP_NO_REPEAT_KEY (1<<28) - // Flag for key events. Multiple down events are idempotent. Release keys by // sending the key code without this flag, or by sending MP_INPUT_RELEASE_ALL // as key code. -#define MP_KEY_STATE_DOWN (1<<29) +#define MP_KEY_STATE_DOWN (1<<26) + +// The following flags are not modifiers, but are part of the keycode itself. + +// Emit a command even on key-up (normally key-up is ignored). The command +// handling code has to ignore unwanted commands specifically. +#define MP_KEY_EMIT_ON_UP (1<<27) + +// Use this when the key shouldn't be auto-repeated (like mouse buttons) +// Also means both key-down key-up events produce emit bound commands. +#define MP_NO_REPEAT_KEY (1<<28) #endif /* MPLAYER_KEYCODES_H */ diff --git a/core/mplayer.c b/core/mplayer.c index f12560b589..567e38e285 100644 --- a/core/mplayer.c +++ b/core/mplayer.c @@ -4333,13 +4333,6 @@ goto_reopen_demuxer: ; mpctx->sh_video->fps, mpctx->sh_video->frametime); } - mp_input_set_section(mpctx->input, NULL, 0); - //TODO: add desired (stream-based) sections here - if (mpctx->master_demuxer->type == DEMUXER_TYPE_TV) - mp_input_set_section(mpctx->input, "tv", 0); - if (mpctx->encode_lavc_ctx) - mp_input_set_section(mpctx->input, "encode", MP_INPUT_NO_DEFAULT_SECTION); - //==================== START PLAYING ======================= if (!mpctx->sh_video && !mpctx->sh_audio) { @@ -4702,6 +4695,8 @@ static int mpv_main(int argc, char *argv[]) set_priority(); #endif + init_input(mpctx); + #ifdef CONFIG_ENCODING if (opts->encode_output.file && *opts->encode_output.file) { mpctx->encode_lavc_ctx = encode_lavc_init(&opts->encode_output); @@ -4713,6 +4708,7 @@ static int mpv_main(int argc, char *argv[]) m_config_set_option0(mpctx->mconfig, "ao", "lavc"); m_config_set_option0(mpctx->mconfig, "fixed-vo", "yes"); m_config_set_option0(mpctx->mconfig, "gapless-audio", "yes"); + mp_input_enable_section(mpctx->input, "encode", MP_INPUT_EXCLUSIVE); } #endif @@ -4722,8 +4718,6 @@ static int mpv_main(int argc, char *argv[]) mpctx->osd = osd_create(opts, mpctx->ass_library); - init_input(mpctx); - mpctx->playlist->current = mpctx->playlist->first; play_files(mpctx); |