diff options
Diffstat (limited to 'input')
-rw-r--r-- | input/cmd.c | 44 | ||||
-rw-r--r-- | input/cmd.h | 6 | ||||
-rw-r--r-- | input/event.c | 15 | ||||
-rw-r--r-- | input/event.h | 5 | ||||
-rw-r--r-- | input/input.c | 388 | ||||
-rw-r--r-- | input/input.h | 21 | ||||
-rw-r--r-- | input/ipc-dummy.c | 6 | ||||
-rw-r--r-- | input/ipc-unix.c | 151 | ||||
-rw-r--r-- | input/ipc-win.c | 38 | ||||
-rw-r--r-- | input/ipc.c | 205 | ||||
-rw-r--r-- | input/keycodes.c | 35 | ||||
-rw-r--r-- | input/keycodes.h | 14 | ||||
-rw-r--r-- | input/meson.build | 20 | ||||
-rw-r--r-- | input/pipe-win32.c | 110 | ||||
-rw-r--r-- | input/sdl_gamepad.c | 14 |
15 files changed, 561 insertions, 511 deletions
diff --git a/input/cmd.c b/input/cmd.c index 5a073d9fec..64232143f7 100644 --- a/input/cmd.c +++ b/input/cmd.c @@ -336,11 +336,34 @@ static int pctx_read_token(struct parse_ctx *ctx, bstr *out) return -1; } if (!bstr_eatstart0(&ctx->str, "\"")) { - MP_ERR(ctx, "Unterminated quotes: ...>%.*s<.\n", BSTR_P(start)); + MP_ERR(ctx, "Unterminated double quote: ...>%.*s<.\n", BSTR_P(start)); return -1; } return 1; } + if (bstr_eatstart0(&ctx->str, "'")) { + int next = bstrchr(ctx->str, '\''); + if (next < 0) { + MP_ERR(ctx, "Unterminated single quote: ...>%.*s<.\n", BSTR_P(start)); + return -1; + } + *out = bstr_splice(ctx->str, 0, next); + ctx->str = bstr_cut(ctx->str, next+1); + return 1; + } + if (ctx->start.len > 1 && bstr_eatstart0(&ctx->str, "`")) { + char endquote[2] = {ctx->str.start[0], '`'}; + ctx->str = bstr_cut(ctx->str, 1); + int next = bstr_find(ctx->str, (bstr){endquote, 2}); + if (next < 0) { + MP_ERR(ctx, "Unterminated custom quote: ...>%.*s<.\n", BSTR_P(start)); + return -1; + } + *out = bstr_splice(ctx->str, 0, next); + ctx->str = bstr_cut(ctx->str, next+2); + return 1; + } + return read_token(ctx->str, &ctx->str, out) ? 1 : 0; } @@ -544,6 +567,15 @@ mp_cmd_t *mp_cmd_clone(mp_cmd_t *cmd) return ret; } +static int get_arg_count(const struct mp_cmd_def *cmd) +{ + for (int i = MP_CMD_DEF_MAX_ARGS - 1; i >= 0; i--) { + if (cmd->args[i].type) + return i + 1; + } + return 0; +} + void mp_cmd_dump(struct mp_log *log, int msgl, char *header, struct mp_cmd *cmd) { if (!mp_msg_test(log, msgl)) @@ -555,7 +587,9 @@ void mp_cmd_dump(struct mp_log *log, int msgl, char *header, struct mp_cmd *cmd) return; } mp_msg(log, msgl, "%s, flags=%d, args=[", cmd->name, cmd->flags); + int argc = get_arg_count(cmd->def); for (int n = 0; n < cmd->nargs; n++) { + const char *argname = cmd->def->args[MPMIN(n, argc - 1)].name; char *s = m_option_print(cmd->args[n].type, &cmd->args[n].v); if (n) mp_msg(log, msgl, ", "); @@ -565,7 +599,7 @@ void mp_cmd_dump(struct mp_log *log, int msgl, char *header, struct mp_cmd *cmd) }; char *esc = NULL; json_write(&esc, &node); - mp_msg(log, msgl, "%s", esc ? esc : "<error>"); + mp_msg(log, msgl, "%s=%s", argname, esc ? esc : "<error>"); talloc_free(esc); talloc_free(s); } @@ -574,8 +608,10 @@ void mp_cmd_dump(struct mp_log *log, int msgl, char *header, struct mp_cmd *cmd) bool mp_input_is_repeatable_cmd(struct mp_cmd *cmd) { - return (cmd->def->allow_auto_repeat) || cmd->def == &mp_cmd_list || - (cmd->flags & MP_ALLOW_REPEAT); + if (cmd->def == &mp_cmd_list && cmd->args[0].v.p) + cmd = cmd->args[0].v.p; // list - only 1st cmd is considered + + return (cmd->def->allow_auto_repeat) || (cmd->flags & MP_ALLOW_REPEAT); } bool mp_input_is_scalable_cmd(struct mp_cmd *cmd) diff --git a/input/cmd.h b/input/cmd.h index c22672b9d3..3d4b15fcc3 100644 --- a/input/cmd.h +++ b/input/cmd.h @@ -23,7 +23,7 @@ #include "misc/bstr.h" #include "options/m_option.h" -#define MP_CMD_DEF_MAX_ARGS 9 +#define MP_CMD_DEF_MAX_ARGS 11 #define MP_CMD_OPT_ARG M_OPT_OPTIONAL_PARAM struct mp_log; @@ -85,6 +85,7 @@ enum mp_cmd_flags { struct mp_cmd_arg { const struct m_option *type; union { + bool b; int i; int64_t i64; float f; @@ -152,7 +153,4 @@ struct mp_cmd *mp_cmd_clone(struct mp_cmd *cmd); extern const struct m_option_type m_option_type_cycle_dir; -#define OPT_CYCLEDIR(...) \ - OPT_GENERAL(double, __VA_ARGS__, .type = &m_option_type_cycle_dir) - #endif diff --git a/input/event.c b/input/event.c index 266e0294e2..6c1e00409a 100644 --- a/input/event.c +++ b/input/event.c @@ -37,6 +37,21 @@ void mp_event_drop_files(struct input_ctx *ictx, int num_files, char **files, }; mp_input_run_cmd(ictx, cmd); } + } else if (action == DND_INSERT_NEXT) { + /* To insert the entries in the correct order, we iterate over them + backwards */ + for (int i = num_files - 1; i >= 0; i--) { + const char *cmd[] = { + "osd-auto", + "loadfile", + files[i], + /* Since we're inserting in reverse, wait til the final item + is added to start playing */ + (i > 0) ? "insert-next" : "insert-next-play", + NULL + }; + mp_input_run_cmd(ictx, cmd); + } } else { for (int i = 0; i < num_files; i++) { const char *cmd[] = { diff --git a/input/event.h b/input/event.h index 1e2149bb89..5f48bee00e 100644 --- a/input/event.h +++ b/input/event.h @@ -24,16 +24,17 @@ struct input_ctx; enum mp_dnd_action { DND_REPLACE, DND_APPEND, + DND_INSERT_NEXT, }; // Enqueue files for playback after drag and drop void mp_event_drop_files(struct input_ctx *ictx, int num_files, char **files, - enum mp_dnd_action append); + enum mp_dnd_action action); // Drop data in a specific format (identified by the mimetype). // Returns <0 on error, ==0 if data was ok but empty, >0 on success. int mp_event_drop_mime_data(struct input_ctx *ictx, const char *mime_type, - bstr data, enum mp_dnd_action append); + bstr data, enum mp_dnd_action action); // Many drag & drop APIs support multiple mime types, and this function returns // whether a type is preferred (higher integer score), or supported (scores diff --git a/input/input.c b/input/input.c index f9475648b0..b24e82fe50 100644 --- a/input/input.c +++ b/input/input.c @@ -28,7 +28,6 @@ #include <sys/stat.h> #include <sys/time.h> #include <fcntl.h> -#include <pthread.h> #include <assert.h> #include "osdep/io.h" @@ -51,13 +50,13 @@ #include "common/common.h" #if HAVE_COCOA -#include "osdep/macosx_events.h" +#include "osdep/mac/app_bridge.h" #endif -#define input_lock(ictx) pthread_mutex_lock(&ictx->mutex) -#define input_unlock(ictx) pthread_mutex_unlock(&ictx->mutex) +#define input_lock(ictx) mp_mutex_lock(&ictx->mutex) +#define input_unlock(ictx) mp_mutex_unlock(&ictx->mutex) -#define MP_MAX_KEY_DOWN 4 +#define MP_MAX_KEY_DOWN 16 struct cmd_bind { int keys[MP_MAX_KEY_DOWN]; @@ -80,8 +79,6 @@ struct cmd_bind_section { #define MP_MAX_SOURCES 10 -#define MAX_ACTIVE_SECTIONS 50 - struct active_section { char *name; int flags; @@ -97,7 +94,7 @@ struct wheel_state { }; struct input_ctx { - pthread_mutex_t mutex; + mp_mutex mutex; struct mp_log *log; struct mpv_global *global; struct m_config_cache *opts_cache; @@ -122,6 +119,7 @@ struct input_ctx { // Mouse position on the consumer side (as command.c sees it) int mouse_x, mouse_y; + int mouse_hover; // updated on mouse-enter/leave char *mouse_section; // last section to receive mouse event // Mouse position on the producer side (as the VO sees it) @@ -142,7 +140,7 @@ struct input_ctx { int num_sections; // List currently active command sections - struct active_section active_sections[MAX_ACTIVE_SECTIONS]; + struct active_section *active_sections; int num_active_sections; unsigned int mouse_event_counter; @@ -170,40 +168,40 @@ struct input_opts { // Autorepeat config (be aware of mp_input_set_repeat_info()) int ar_delay; int ar_rate; - int use_alt_gr; - int use_appleremote; - int use_gamepad; - int use_media_keys; - int default_bindings; - int enable_mouse_movements; - int vo_key_input; - int test; - int allow_win_drag; + bool use_alt_gr; + bool use_gamepad; + bool use_media_keys; + bool default_bindings; + bool builtin_bindings; + bool enable_mouse_movements; + bool vo_key_input; + bool test; + bool allow_win_drag; + bool preprocess_wheel; }; const struct m_sub_options input_config = { .opts = (const m_option_t[]) { - OPT_STRING("input-conf", config_file, M_OPT_FILE), - OPT_INT("input-ar-delay", ar_delay, 0), - OPT_INT("input-ar-rate", ar_rate, 0), - OPT_PRINT("input-keylist", mp_print_key_list), - OPT_PRINT("input-cmdlist", mp_print_cmd_list), - OPT_FLAG("input-default-bindings", default_bindings, 0), - OPT_FLAG("input-test", test, 0), - OPT_INTRANGE("input-doubleclick-time", doubleclick_time, 0, 0, 1000), - OPT_FLAG("input-right-alt-gr", use_alt_gr, 0), - OPT_INTRANGE("input-key-fifo-size", key_fifo_size, 0, 2, 65000), - OPT_FLAG("input-cursor", enable_mouse_movements, 0), - OPT_FLAG("input-vo-keyboard", vo_key_input, 0), - OPT_FLAG("input-media-keys", use_media_keys, 0), + {"input-conf", OPT_STRING(config_file), .flags = M_OPT_FILE}, + {"input-ar-delay", OPT_INT(ar_delay)}, + {"input-ar-rate", OPT_INT(ar_rate)}, + {"input-keylist", OPT_PRINT(mp_print_key_list)}, + {"input-cmdlist", OPT_PRINT(mp_print_cmd_list)}, + {"input-default-bindings", OPT_BOOL(default_bindings)}, + {"input-builtin-bindings", OPT_BOOL(builtin_bindings)}, + {"input-test", OPT_BOOL(test)}, + {"input-doubleclick-time", OPT_INT(doubleclick_time), + M_RANGE(0, 1000)}, + {"input-right-alt-gr", OPT_BOOL(use_alt_gr)}, + {"input-key-fifo-size", OPT_INT(key_fifo_size), M_RANGE(2, 65000)}, + {"input-cursor", OPT_BOOL(enable_mouse_movements)}, + {"input-vo-keyboard", OPT_BOOL(vo_key_input)}, + {"input-media-keys", OPT_BOOL(use_media_keys)}, + {"input-preprocess-wheel", OPT_BOOL(preprocess_wheel)}, #if HAVE_SDL2_GAMEPAD - OPT_FLAG("input-gamepad", use_gamepad, 0), -#endif - OPT_FLAG("window-dragging", allow_win_drag, 0), - OPT_REPLACED("input-x11-keyboard", "input-vo-keyboard"), -#if HAVE_COCOA - OPT_REMOVED("input-appleremote", "replaced by MediaPlayer support"), + {"input-gamepad", OPT_BOOL(use_gamepad)}, #endif + {"window-dragging", OPT_BOOL(allow_win_drag)}, {0} }, .size = sizeof(struct input_opts), @@ -212,18 +210,20 @@ const struct m_sub_options input_config = { .doubleclick_time = 300, .ar_delay = 200, .ar_rate = 40, - .use_alt_gr = 1, - .enable_mouse_movements = 1, - .use_media_keys = 1, - .default_bindings = 1, - .vo_key_input = 1, - .allow_win_drag = 1, + .use_alt_gr = true, + .enable_mouse_movements = true, + .use_media_keys = true, + .default_bindings = true, + .builtin_bindings = true, + .vo_key_input = true, + .allow_win_drag = true, + .preprocess_wheel = true, }, .change_flags = UPDATE_INPUT, }; static const char builtin_input_conf[] = -#include "input/input_conf.h" +#include "etc/input.conf.inc" ; static bool test_rect(struct mp_rect *rc, int x, int y) @@ -275,6 +275,14 @@ static struct mp_cmd *queue_peek_tail(struct cmd_queue *queue) return cur; } +static void queue_cmd(struct input_ctx *ictx, mp_cmd_t *cmd) +{ + if (!cmd) + return; + queue_add_tail(&ictx->cmd_queue, cmd); + mp_input_wakeup(ictx); +} + static void append_bind_info(struct input_ctx *ictx, char **pmsg, struct cmd_bind *bind) { @@ -508,7 +516,7 @@ static void update_mouse_section(struct input_ctx *ictx) if (strcmp(old, ictx->mouse_section) != 0) { MP_TRACE(ictx, "input: switch section %s -> %s\n", old, ictx->mouse_section); - mp_input_queue_cmd(ictx, get_cmd_from_keys(ictx, old, MP_KEY_MOUSE_LEAVE)); + queue_cmd(ictx, get_cmd_from_keys(ictx, old, MP_KEY_MOUSE_LEAVE)); } } @@ -526,7 +534,7 @@ static void release_down_cmd(struct input_ctx *ictx, bool drop_current) { memset(ictx->key_history, 0, sizeof(ictx->key_history)); ictx->current_down_cmd->is_up = true; - mp_input_queue_cmd(ictx, ictx->current_down_cmd); + queue_cmd(ictx, ictx->current_down_cmd); } else { talloc_free(ictx->current_down_cmd); } @@ -590,7 +598,7 @@ static void interpret_key(struct input_ctx *ictx, int code, double scale, ictx->current_down_cmd = mp_cmd_clone(cmd); } ictx->last_key_down = code; - ictx->last_key_down_time = mp_time_us(); + ictx->last_key_down_time = mp_time_ns(); ictx->ar_state = 0; mp_input_wakeup(ictx); // possibly start timer for autorepeat } else if (state == MP_KEY_STATE_UP) { @@ -622,7 +630,7 @@ static void interpret_key(struct input_ctx *ictx, int code, double scale, if (mp_input_is_scalable_cmd(cmd)) { cmd->scale = scale; cmd->scale_units = scale_units; - mp_input_queue_cmd(ictx, cmd); + queue_cmd(ictx, cmd); } else { // Non-scalable commands won't understand cmd->scale, so synthesize // multiple commands with cmd->scale = 1 @@ -631,9 +639,9 @@ static void interpret_key(struct input_ctx *ictx, int code, double scale, // Avoid spamming the player with too many commands scale_units = MPMIN(scale_units, 20); for (int i = 0; i < scale_units - 1; i++) - mp_input_queue_cmd(ictx, mp_cmd_clone(cmd)); + queue_cmd(ictx, mp_cmd_clone(cmd)); if (scale_units) - mp_input_queue_cmd(ictx, cmd); + queue_cmd(ictx, cmd); } } @@ -703,7 +711,7 @@ static bool process_wheel(struct input_ctx *ictx, int code, double *scale, return true; } -static void mp_input_feed_key(struct input_ctx *ictx, int code, double scale, +static void feed_key(struct input_ctx *ictx, int code, double scale, bool force_mouse) { struct input_opts *opts = ictx->opts; @@ -718,8 +726,13 @@ static void mp_input_feed_key(struct input_ctx *ictx, int code, double scale, if (!opts->enable_mouse_movements && MP_KEY_IS_MOUSE(unmod) && !force_mouse) return; if (unmod == MP_KEY_MOUSE_LEAVE || unmod == MP_KEY_MOUSE_ENTER) { + ictx->mouse_hover = unmod == MP_KEY_MOUSE_ENTER; update_mouse_section(ictx); - mp_input_queue_cmd(ictx, get_cmd_from_keys(ictx, NULL, code)); + + mp_cmd_t *cmd = get_cmd_from_keys(ictx, NULL, code); + if (!cmd) // queue dummy cmd so that mouse-pos can notify observers + cmd = mp_input_parse_cmd(ictx, bstr0("ignore"), "<internal>"); + queue_cmd(ictx, cmd); return; } double now = mp_time_sec(); @@ -727,18 +740,23 @@ static void mp_input_feed_key(struct input_ctx *ictx, int code, double scale, if (!force_mouse && opts->doubleclick_time && MP_KEY_IS_MOUSE_BTN_DBL(unmod)) return; int units = 1; - if (MP_KEY_IS_WHEEL(unmod) && !process_wheel(ictx, unmod, &scale, &units)) + if (MP_KEY_IS_WHEEL(unmod) && opts->preprocess_wheel && !process_wheel(ictx, unmod, &scale, &units)) return; interpret_key(ictx, code, scale, units); if (code & MP_KEY_STATE_DOWN) { code &= ~MP_KEY_STATE_DOWN; if (ictx->last_doubleclick_key_down == code && - now - ictx->last_doubleclick_time < opts->doubleclick_time / 1000.0) + now - ictx->last_doubleclick_time < opts->doubleclick_time / 1000.0 && + code >= MP_MBTN_LEFT && code <= MP_MBTN_RIGHT) { - if (code >= MP_MBTN_LEFT && code <= MP_MBTN_RIGHT) { - interpret_key(ictx, code - MP_MBTN_BASE + MP_MBTN_DBL_BASE, - 1, 1); - } + now = 0; + interpret_key(ictx, code - MP_MBTN_BASE + MP_MBTN_DBL_BASE, + 1, 1); + } else if (code == MP_MBTN_LEFT) { + // This is a mouse left botton down event which isn't part of a doubleclick. + // Initialize vo dragging in this case. + mp_cmd_t *cmd = mp_input_parse_cmd(ictx, bstr0("begin-vo-dragging"), "<internal>"); + queue_cmd(ictx, cmd); } ictx->last_doubleclick_key_down = code; ictx->last_doubleclick_time = now; @@ -748,25 +766,31 @@ static void mp_input_feed_key(struct input_ctx *ictx, int code, double scale, void mp_input_put_key(struct input_ctx *ictx, int code) { input_lock(ictx); - mp_input_feed_key(ictx, code, 1, false); + feed_key(ictx, code, 1, false); input_unlock(ictx); } -void mp_input_put_key_artificial(struct input_ctx *ictx, int code) +void mp_input_put_key_artificial(struct input_ctx *ictx, int code, double value) { + if (value == 0.0) + return; input_lock(ictx); - mp_input_feed_key(ictx, code, 1, true); + feed_key(ictx, code, value, true); input_unlock(ictx); } void mp_input_put_key_utf8(struct input_ctx *ictx, int mods, struct bstr t) { + if (!t.len) + return; + input_lock(ictx); while (t.len) { int code = bstr_decode_utf8(t, &t); if (code < 0) break; - mp_input_put_key(ictx, code | mods); + feed_key(ictx, code | mods, 1, false); } + input_unlock(ictx); } void mp_input_put_wheel(struct input_ctx *ictx, int direction, double value) @@ -774,7 +798,7 @@ void mp_input_put_wheel(struct input_ctx *ictx, int direction, double value) if (value == 0.0) return; input_lock(ictx); - mp_input_feed_key(ictx, direction, value, false); + feed_key(ictx, direction, value, false); input_unlock(ictx); } @@ -808,21 +832,11 @@ bool mp_input_vo_keyboard_enabled(struct input_ctx *ictx) return r; } -void mp_input_set_mouse_pos(struct input_ctx *ictx, int x, int y) +static void set_mouse_pos(struct input_ctx *ictx, int x, int y) { - input_lock(ictx); - if (ictx->opts->enable_mouse_movements) - mp_input_set_mouse_pos_artificial(ictx, x, y); - input_unlock(ictx); -} - -void mp_input_set_mouse_pos_artificial(struct input_ctx *ictx, int x, int y) -{ - input_lock(ictx); MP_TRACE(ictx, "mouse move %d/%d\n", x, y); if (ictx->mouse_vo_x == x && ictx->mouse_vo_y == y) { - input_unlock(ictx); return; } @@ -860,10 +874,62 @@ void mp_input_set_mouse_pos_artificial(struct input_ctx *ictx, int x, int y) queue_remove(&ictx->cmd_queue, tail); talloc_free(tail); } - mp_input_queue_cmd(ictx, cmd); + queue_cmd(ictx, cmd); + } + } +} + +void mp_input_set_mouse_pos_artificial(struct input_ctx *ictx, int x, int y) +{ + input_lock(ictx); + set_mouse_pos(ictx, x, y); + input_unlock(ictx); +} + +void mp_input_set_mouse_pos(struct input_ctx *ictx, int x, int y) +{ + input_lock(ictx); + if (ictx->opts->enable_mouse_movements) + set_mouse_pos(ictx, x, y); + input_unlock(ictx); +} + +static bool test_mouse(struct input_ctx *ictx, int x, int y, int rej_flags) +{ + bool res = false; + for (int i = 0; i < ictx->num_active_sections; i++) { + struct active_section *as = &ictx->active_sections[i]; + if (as->flags & rej_flags) + continue; + struct cmd_bind_section *s = get_bind_section(ictx, bstr0(as->name)); + if (s->mouse_area_set && test_rect(&s->mouse_area, x, y)) { + res = true; + break; } } + return res; +} + +static bool test_mouse_active(struct input_ctx *ictx, int x, int y) +{ + return test_mouse(ictx, x, y, MP_INPUT_ALLOW_HIDE_CURSOR); +} + +bool mp_input_test_mouse_active(struct input_ctx *ictx, int x, int y) +{ + input_lock(ictx); + bool res = test_mouse_active(ictx, x, y); input_unlock(ictx); + return res; +} + +bool mp_input_test_dragging(struct input_ctx *ictx, int x, int y) +{ + input_lock(ictx); + bool r = !ictx->opts->allow_win_drag || + test_mouse(ictx, x, y, MP_INPUT_ALLOW_VO_DRAGGING); + input_unlock(ictx); + return r; } unsigned int mp_input_get_mouse_event_counter(struct input_ctx *ictx) @@ -871,7 +937,7 @@ unsigned int mp_input_get_mouse_event_counter(struct input_ctx *ictx) // Make the frontend always display the mouse cursor (as long as it's not // forced invisible) if mouse input is desired. input_lock(ictx); - if (mp_input_test_mouse_active(ictx, ictx->mouse_x, ictx->mouse_y)) + if (test_mouse_active(ictx, ictx->mouse_x, ictx->mouse_y)) ictx->mouse_event_counter++; int ret = ictx->mouse_event_counter; input_unlock(ictx); @@ -890,11 +956,10 @@ static void adjust_max_wait_time(struct input_ctx *ictx, double *time) int mp_input_queue_cmd(struct input_ctx *ictx, mp_cmd_t *cmd) { + if (!cmd) + return 0; input_lock(ictx); - if (cmd) { - queue_add_tail(&ictx->cmd_queue, cmd); - mp_input_wakeup(ictx); - } + queue_cmd(ictx, cmd); input_unlock(ictx); return 1; } @@ -910,19 +975,19 @@ static mp_cmd_t *check_autorepeat(struct input_ctx *ictx) ictx->ar_state = -1; // disable if (ictx->ar_state >= 0) { - int64_t t = mp_time_us(); - if (ictx->last_ar + 2000000 < t) + int64_t t = mp_time_ns(); + if (ictx->last_ar + MP_TIME_S_TO_NS(2) < t) ictx->last_ar = t; // First time : wait delay if (ictx->ar_state == 0 - && (t - ictx->last_key_down_time) >= opts->ar_delay * 1000) + && (t - ictx->last_key_down_time) >= MP_TIME_MS_TO_NS(opts->ar_delay)) { ictx->ar_state = 1; - ictx->last_ar = ictx->last_key_down_time + opts->ar_delay * 1000; + ictx->last_ar = ictx->last_key_down_time + MP_TIME_MS_TO_NS(opts->ar_delay); // Then send rate / sec event } else if (ictx->ar_state == 1 - && (t - ictx->last_ar) >= 1000000 / opts->ar_rate) { - ictx->last_ar += 1000000 / opts->ar_rate; + && (t - ictx->last_ar) >= 1e9 / opts->ar_rate) { + ictx->last_ar += 1e9 / opts->ar_rate; } else { return NULL; } @@ -961,11 +1026,12 @@ mp_cmd_t *mp_input_read_cmd(struct input_ctx *ictx) return ret; } -void mp_input_get_mouse_pos(struct input_ctx *ictx, int *x, int *y) +void mp_input_get_mouse_pos(struct input_ctx *ictx, int *x, int *y, int *hover) { input_lock(ictx); *x = ictx->mouse_x; *y = ictx->mouse_y; + *hover = ictx->mouse_hover; input_unlock(ictx); } @@ -977,9 +1043,8 @@ static char *normalize_section(struct input_ctx *ictx, char *name) return get_bind_section(ictx, bstr0(name))->section; } -void mp_input_disable_section(struct input_ctx *ictx, char *name) +static void disable_section(struct input_ctx *ictx, char *name) { - input_lock(ictx); name = normalize_section(ictx, name); // Remove old section, or make sure it's on top if re-enabled @@ -990,6 +1055,12 @@ void mp_input_disable_section(struct input_ctx *ictx, char *name) ictx->num_active_sections, i); } } +} + +void mp_input_disable_section(struct input_ctx *ictx, char *name) +{ + input_lock(ictx); + disable_section(ictx, name); input_unlock(ictx); } @@ -998,24 +1069,20 @@ void mp_input_enable_section(struct input_ctx *ictx, char *name, int flags) input_lock(ictx); name = normalize_section(ictx, name); - mp_input_disable_section(ictx, name); + disable_section(ictx, name); MP_TRACE(ictx, "enable section '%s'\n", name); - if (ictx->num_active_sections < MAX_ACTIVE_SECTIONS) { - int top = ictx->num_active_sections; - if (!(flags & MP_INPUT_ON_TOP)) { - // insert before the first top entry - for (top = 0; top < ictx->num_active_sections; top++) { - if (ictx->active_sections[top].flags & MP_INPUT_ON_TOP) - break; - } - for (int n = ictx->num_active_sections; n > top; n--) - ictx->active_sections[n] = ictx->active_sections[n - 1]; + int top = ictx->num_active_sections; + if (!(flags & MP_INPUT_ON_TOP)) { + // insert before the first top entry + for (top = 0; top < ictx->num_active_sections; top++) { + if (ictx->active_sections[top].flags & MP_INPUT_ON_TOP) + break; } - ictx->active_sections[top] = (struct active_section){name, flags}; - ictx->num_active_sections++; } + MP_TARRAY_INSERT_AT(ictx, ictx->active_sections, ictx->num_active_sections, + top, (struct active_section){name, flags}); MP_TRACE(ictx, "active section stack:\n"); for (int n = 0; n < ictx->num_active_sections; n++) { @@ -1043,38 +1110,6 @@ void mp_input_set_section_mouse_area(struct input_ctx *ictx, char *name, input_unlock(ictx); } -static bool test_mouse(struct input_ctx *ictx, int x, int y, int rej_flags) -{ - input_lock(ictx); - bool res = false; - for (int i = 0; i < ictx->num_active_sections; i++) { - struct active_section *as = &ictx->active_sections[i]; - if (as->flags & rej_flags) - continue; - struct cmd_bind_section *s = get_bind_section(ictx, bstr0(as->name)); - if (s->mouse_area_set && test_rect(&s->mouse_area, x, y)) { - res = true; - break; - } - } - input_unlock(ictx); - return res; -} - -bool mp_input_test_mouse_active(struct input_ctx *ictx, int x, int y) -{ - return test_mouse(ictx, x, y, MP_INPUT_ALLOW_HIDE_CURSOR); -} - -bool mp_input_test_dragging(struct input_ctx *ictx, int x, int y) -{ - input_lock(ictx); - bool r = !ictx->opts->allow_win_drag || - test_mouse(ictx, x, y, MP_INPUT_ALLOW_VO_DRAGGING); - input_unlock(ictx); - return r; -} - static void bind_dealloc(struct cmd_bind *bind) { talloc_free(bind->cmd); @@ -1115,7 +1150,7 @@ void mp_input_define_section(struct input_ctx *ictx, char *name, char *location, parse_config(ictx, builtin, bstr0(contents), location, name); } else { // Disable: - mp_input_disable_section(ictx, name); + disable_section(ictx, name); } input_unlock(ictx); } @@ -1126,7 +1161,7 @@ void mp_input_remove_sections_by_owner(struct input_ctx *ictx, char *owner) for (int n = 0; n < ictx->num_sections; n++) { struct cmd_bind_section *bs = ictx->sections[n]; if (bs->owner && owner && strcmp(bs->owner, owner) == 0) { - mp_input_disable_section(ictx, bs->section); + disable_section(ictx, bs->section); remove_binds(bs, false); remove_binds(bs, true); } @@ -1268,9 +1303,9 @@ static int parse_config(struct input_ctx *ictx, bool builtin, bstr data, return n_binds; } -static int parse_config_file(struct input_ctx *ictx, char *file, bool warn) +static bool parse_config_file(struct input_ctx *ictx, char *file) { - int r = 0; + bool r = false; void *tmp = talloc_new(NULL); stream_t *s = NULL; @@ -1287,7 +1322,7 @@ static int parse_config_file(struct input_ctx *ictx, char *file, bool warn) MP_VERBOSE(ictx, "Parsing input config file %s\n", file); int num = parse_config(ictx, false, data, file, NULL); MP_VERBOSE(ictx, "Input config file %s parsed: %d binds\n", file, num); - r = 1; + r = true; } else { MP_ERR(ictx, "Error reading input config file %s\n", file); } @@ -1312,11 +1347,12 @@ struct input_ctx *mp_input_init(struct mpv_global *global, .opts_cache = m_config_cache_alloc(ictx, global, &input_config), .wakeup_cb = wakeup_cb, .wakeup_ctx = wakeup_ctx, + .active_sections = talloc_array(ictx, struct active_section, 0), }; ictx->opts = ictx->opts_cache->opts; - mpthread_mutex_init_recursive(&ictx->mutex); + mp_mutex_init(&ictx->mutex); // Setup default section, so that it does nothing. mp_input_enable_section(ictx, NULL, MP_INPUT_ALLOW_VO_DRAGGING | @@ -1359,7 +1395,7 @@ void mp_input_load_config(struct input_ctx *ictx) // "Uncomment" the default key bindings in etc/input.conf and add them. // All lines that do not start with '# ' are parsed. bstr builtin = bstr0(builtin_input_conf); - while (builtin.len) { + while (ictx->opts->builtin_bindings && builtin.len) { bstr line = bstr_getline(builtin, &builtin); bstr_eatstart0(&line, "#"); if (!bstr_startswith0(line, " ")) @@ -1368,31 +1404,33 @@ void mp_input_load_config(struct input_ctx *ictx) bool config_ok = false; if (ictx->opts->config_file && ictx->opts->config_file[0]) - config_ok = parse_config_file(ictx, ictx->opts->config_file, true); + config_ok = parse_config_file(ictx, ictx->opts->config_file); if (!config_ok) { // Try global conf dir void *tmp = talloc_new(NULL); char **files = mp_find_all_config_files(tmp, ictx->global, "input.conf"); for (int n = 0; files && files[n]; n++) - parse_config_file(ictx, files[n], false); + parse_config_file(ictx, files[n]); talloc_free(tmp); } -#if HAVE_WIN32_PIPES - char *ifile; - mp_read_option_raw(ictx->global, "input-file", &m_option_type_string, &ifile); - if (ifile && ifile[0]) - mp_input_pipe_add(ictx, ifile); - talloc_free(ifile); -#endif + bool use_gamepad = ictx->opts->use_gamepad; + input_unlock(ictx); #if HAVE_SDL2_GAMEPAD - if (ictx->opts->use_gamepad) { + if (use_gamepad) mp_input_sdl_gamepad_add(ictx); - } +#else + (void)use_gamepad; #endif +} +bool mp_input_load_config_file(struct input_ctx *ictx, char *file) +{ + input_lock(ictx); + bool result = parse_config_file(ictx, file); input_unlock(ictx); + return result; } static void clear_queue(struct cmd_queue *queue) @@ -1416,7 +1454,7 @@ void mp_input_uninit(struct input_ctx *ictx) close_input_sources(ictx); clear_queue(&ictx->cmd_queue); talloc_free(ictx->current_down_cmd); - pthread_mutex_destroy(&ictx->mutex); + mp_mutex_destroy(&ictx->mutex); talloc_free(ictx); } @@ -1444,11 +1482,14 @@ struct mp_cmd *mp_input_parse_cmd(struct input_ctx *ictx, bstr str, void mp_input_run_cmd(struct input_ctx *ictx, const char **cmd) { - mp_input_queue_cmd(ictx, mp_input_parse_cmd_strv(ictx->log, cmd)); + input_lock(ictx); + queue_cmd(ictx, mp_input_parse_cmd_strv(ictx->log, cmd)); + input_unlock(ictx); } void mp_input_bind_key(struct input_ctx *ictx, int key, bstr command) { + input_lock(ictx); struct cmd_bind_section *bs = get_bind_section(ictx, (bstr){0}); struct cmd_bind *bind = NULL; @@ -1483,6 +1524,7 @@ void mp_input_bind_key(struct input_ctx *ictx, int key, bstr command) bind->cmd, bind->location); talloc_free(s); } + input_unlock(ictx); } struct mpv_node mp_input_get_bindings(struct input_ctx *ictx) @@ -1536,7 +1578,7 @@ struct mpv_node mp_input_get_bindings(struct input_ctx *ictx) } struct mp_input_src_internal { - pthread_t thread; + mp_thread thread; bool thread_running; bool init_done; @@ -1545,7 +1587,7 @@ struct mp_input_src_internal { bool drop; }; -static struct mp_input_src *mp_input_add_src(struct input_ctx *ictx) +static struct mp_input_src *input_add_src(struct input_ctx *ictx) { input_lock(ictx); if (ictx->num_sources == MP_MAX_SOURCES) { @@ -1569,7 +1611,7 @@ static struct mp_input_src *mp_input_add_src(struct input_ctx *ictx) return src; } -static void mp_inp |