diff options
Diffstat (limited to 'input')
-rw-r--r-- | input/cmd.c | 31 | ||||
-rw-r--r-- | input/cmd.h | 3 | ||||
-rw-r--r-- | input/event.c | 15 | ||||
-rw-r--r-- | input/event.h | 5 | ||||
-rw-r--r-- | input/input.c | 367 | ||||
-rw-r--r-- | input/input.h | 9 | ||||
-rw-r--r-- | input/ipc-unix.c | 30 | ||||
-rw-r--r-- | input/ipc-win.c | 32 | ||||
-rw-r--r-- | input/ipc.c | 4 | ||||
-rw-r--r-- | input/keycodes.c | 25 | ||||
-rw-r--r-- | input/keycodes.h | 13 | ||||
-rw-r--r-- | input/meson.build | 20 | ||||
-rw-r--r-- | input/sdl_gamepad.c | 14 |
13 files changed, 363 insertions, 205 deletions
diff --git a/input/cmd.c b/input/cmd.c index 692b9f5ad5..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; } @@ -585,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 3ed07e8028..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; 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 1d0c60569c..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,15 +168,16 @@ 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 = { @@ -188,23 +187,21 @@ const struct m_sub_options input_config = { {"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_FLAG(default_bindings)}, - {"input-test", OPT_FLAG(test)}, + {"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_FLAG(use_alt_gr)}, + {"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_FLAG(enable_mouse_movements)}, - {"input-vo-keyboard", OPT_FLAG(vo_key_input)}, - {"input-media-keys", OPT_FLAG(use_media_keys)}, + {"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 - {"input-gamepad", OPT_FLAG(use_gamepad)}, -#endif - {"window-dragging", OPT_FLAG(allow_win_drag)}, - {"input-x11-keyboard", OPT_REPLACED("input-vo-keyboard")}, -#if HAVE_COCOA - {"input-appleremote", OPT_REMOVED("replaced by MediaPlayer support")}, + {"input-gamepad", OPT_BOOL(use_gamepad)}, #endif + {"window-dragging", OPT_BOOL(allow_win_drag)}, {0} }, .size = sizeof(struct input_opts), @@ -213,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 "generated/etc/input.conf.inc" +#include "etc/input.conf.inc" ; static bool test_rect(struct mp_rect *rc, int x, int y) @@ -276,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) { @@ -509,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)); } } @@ -527,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); } @@ -591,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) { @@ -623,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 @@ -632,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); } } @@ -704,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; @@ -719,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(); @@ -728,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; @@ -749,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) @@ -775,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); } @@ -809,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; } @@ -861,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) @@ -872,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); @@ -891,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; } @@ -911,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; } @@ -962,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); } @@ -978,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 @@ -991,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); } @@ -999,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++) { @@ -1044,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); @@ -1116,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); } @@ -1127,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); } @@ -1269,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; @@ -1288,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); } @@ -1313,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 | @@ -1360,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, " ")) @@ -1369,23 +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); } + 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) @@ -1409,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); } @@ -1437,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; @@ -1476,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) @@ -1529,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; @@ -1538,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) { @@ -1562,7 +1611,7 @@ static struct mp_input_src *mp_input_add_src(struct input_ctx *ictx) return src; } -static void mp_input_src_kill(struct mp_input_src *src); +static void input_src_kill(struct mp_input_src *src); static void close_input_sources(struct input_ctx *ictx) { @@ -1574,11 +1623,11 @@ static void close_input_sources(struct input_ctx *ictx) input_unlock(ictx); if (!src) break; - mp_input_src_kill(src); + input_src_kill(src); } } -static void mp_input_src_kill(struct mp_input_src *src) +static void input_src_kill(struct mp_input_src *src) { if (!src) return; @@ -1591,33 +1640,33 @@ static void mp_input_src_kill(struct mp_input_src *src) if (src->cancel) src->cancel(src); if (src->in->thread_running) - pthread_join(src->in->thread, NULL); + mp_thread_join(src->in->thread); if (src->uninit) src->uninit(src); talloc_free(src); return; } } - abort(); + MP_ASSERT_UNREACHABLE(); } void mp_input_src_init_done(struct mp_input_src *src) { assert(!src->in->init_done); assert(src->in->thread_running); - assert(pthread_equal(src->in->thread, pthread_self())); + assert(mp_thread_id_equal(mp_thread_get_id(src->in->thread), mp_thread_current_id())); src->in->init_done = true; mp_rendezvous(&src->in->init_done, 0); } -static void *input_src_thread(void *ptr) +static MP_THREAD_VOID input_src_thread(void *ptr) { void **args = ptr; struct mp_input_src *src = args[0]; void (*loop_fn)(struct mp_input_src *src, void *ctx) = args[1]; void *ctx = args[2]; - mpthread_set_name("input source"); + mp_thread_set_name("input"); src->in->thread_running = true; @@ -1626,23 +1675,23 @@ static void *input_src_thread(void *ptr) if (!src->in->init_done) mp_rendezvous(&src->in->init_done, -1); - return NULL; + MP_THREAD_RETURN(); } int mp_input_add_thread_src(struct input_ctx *ictx, void *ctx, void (*loop_fn)(struct mp_input_src *src, void *ctx)) { - struct mp_input_src *src = mp_input_add_src(ictx); + struct mp_input_src *src = input_add_src(ictx); if (!src) return -1; void *args[] = {src, loop_fn, ctx}; - if (pthread_create(&src->in->thread, NULL, input_src_thread, args)) { - mp_input_src_kill(src); + if (mp_thread_create(&src->in->thread, input_src_thread, args)) { + input_src_kill(src); return -1; } if (mp_re |