From 103df928adcdbc3eaeae3c789322fd4979b234a3 Mon Sep 17 00:00:00 2001 From: CogentRedTester Date: Sun, 11 Jan 2026 11:12:27 +1030 Subject: [PATCH] mp.input: use unique event handlers for input.get requests This makes changes to mp.input and console.lua so that every input.get request uses a unique script-message to handle input events. Previously, making new input.get requests shortly after the termination of a previous request made by the same script could cause a race condition where the input handler was closed but the new request was still being drawn in the UI. This was caused by the `closed` event for the previous request being received only after the new request was registered, hence closing the event handler for the new request instead. In addition, this commit makes the behaviour of calling input.get while another request is active more consistent. When a new request is received it overwrites the in-progress request, sending a `closed` event. However, previously, the `closed` event could not be sent if both requests came from the same script, as the new request would have overwritten the event handler. Now, the `closed` event is called regardless of where the new request comes from. --- player/javascript/defaults.js | 20 +++++++++++++------- player/lua/console.lua | 24 +++++++++++++++--------- player/lua/input.lua | 15 ++++++++++----- 3 files changed, 38 insertions(+), 21 deletions(-) diff --git a/player/javascript/defaults.js b/player/javascript/defaults.js index ae687febe1014..f338efe946b09 100644 --- a/player/javascript/defaults.js +++ b/player/javascript/defaults.js @@ -653,8 +653,13 @@ mp.options = { read_options: read_options }; /********************************************************************** * input *********************************************************************/ +var input_handle_counter = 1; + function register_event_handler(t) { - mp.register_script_message("input-event", function (type, args) { + var handler_id = "input-event/" + input_handle_counter; + input_handle_counter += 1; + + mp.register_script_message(handler_id, function (type, args) { if (t[type]) { args = args ? JSON.parse(args) : []; var result = t[type].apply(null, args); @@ -666,18 +671,19 @@ function register_event_handler(t) { } if (type == "closed") - mp.unregister_script_message("input-event"); + mp.unregister_script_message(handler_id); }) + + return handler_id; } mp.input = { get: function(t) { - t.has_completions = t.complete !== undefined - - mp.commandv("script-message-to", "console", "get-input", mp.script_name, - JSON.stringify(t)); + t.has_completions = t.complete !== undefined; + var handler_id = register_event_handler(t); - register_event_handler(t) + mp.commandv("script-message-to", "console", "get-input", + mp.script_name, handler_id, JSON.stringify(t)); }, terminate: function () { mp.commandv("script-message-to", "console", "disable"); diff --git a/player/lua/console.lua b/player/lua/console.lua index 27ab10c974dd0..8da871906704d 100644 --- a/player/lua/console.lua +++ b/player/lua/console.lua @@ -96,6 +96,7 @@ local key_bindings = {} local dont_bind_up_down = false local global_margins = { t = 0, b = 0 } local input_caller +local input_caller_handler local keep_open = false local completion_buffer = {} @@ -949,7 +950,7 @@ end local function handle_edit() if not selectable_items then handle_cursor_move() - mp.commandv("script-message-to", input_caller, "input-event", "edited", + mp.commandv("script-message-to", input_caller, input_caller_handler, "edited", utils.format_json({line})) return end @@ -1070,7 +1071,7 @@ local function submit() if selectable_items then if #matches > 0 then - mp.commandv("script-message-to", input_caller, "input-event", "submit", + mp.commandv("script-message-to", input_caller, input_caller_handler, "submit", utils.format_json({matches[focused_match].index})) end else @@ -1079,7 +1080,7 @@ local function submit() cycle_through_completions() end - mp.commandv("script-message-to", input_caller, "input-event", "submit", + mp.commandv("script-message-to", input_caller, input_caller_handler, "submit", utils.format_json({line})) history_add(line) @@ -1481,7 +1482,7 @@ end complete = function () completion_old_line = line completion_old_cursor = cursor - mp.commandv("script-message-to", input_caller, "input-event", + mp.commandv("script-message-to", input_caller, input_caller_handler, "complete", utils.format_json({line:sub(1, cursor - 1)})) render() end @@ -1651,7 +1652,7 @@ set_active = function (active) unbind_mouse() mp.set_property_bool("user-data/mpv/console/open", false) mp.set_property_bool("input-ime", ime_active) - mp.commandv("script-message-to", input_caller, "input-event", + mp.commandv("script-message-to", input_caller, input_caller_handler, "closed", utils.format_json({line, cursor})) collectgarbage() end @@ -1662,13 +1663,14 @@ mp.register_script_message("disable", function() set_active(false) end) -mp.register_script_message("get-input", function (script_name, args) - if open and script_name ~= input_caller then - mp.commandv("script-message-to", input_caller, "input-event", +mp.register_script_message("get-input", function (script_name, handler_id, args) + if open then + mp.commandv("script-message-to", input_caller, input_caller_handler, "closed", utils.format_json({line, cursor})) end input_caller = script_name + input_caller_handler = handler_id args = utils.parse_json(args) prompt = args.prompt or "" line = args.default_text or "" @@ -1721,11 +1723,15 @@ mp.register_script_message("get-input", function (script_name, args) if line ~= "" then complete() + elseif open then + -- This is needed to update the prompt if a new request is + -- received while another is still active. + render() end end set_active(true) - mp.commandv("script-message-to", input_caller, "input-event", "opened") + mp.commandv("script-message-to", input_caller, input_caller_handler, "opened") end) -- Add a line to the log buffer diff --git a/player/lua/input.lua b/player/lua/input.lua index 3dded33dd744c..4fdab4c6ea7f0 100644 --- a/player/lua/input.lua +++ b/player/lua/input.lua @@ -17,6 +17,7 @@ License along with mpv. If not, see . local utils = require "mp.utils" local input = {} +local handle_counter = 1 local function get_non_callbacks(t) local non_callbacks = {} @@ -31,7 +32,10 @@ local function get_non_callbacks(t) end local function register_event_handler(t) - mp.register_script_message("input-event", function (type, args) + local handler_id = "input-event/"..handle_counter + handle_counter = handle_counter + 1 + + mp.register_script_message(handler_id, function (type, args) if t[type] then local completions, completion_pos, completion_append = t[type](unpack(utils.parse_json(args or "") or {})) @@ -44,18 +48,19 @@ local function register_event_handler(t) end if type == "closed" then - mp.unregister_script_message("input-event") + mp.unregister_script_message(handler_id) end end) + + return handler_id end function input.get(t) t.has_completions = t.complete ~= nil + local handler_id = register_event_handler(t) mp.commandv("script-message-to", "console", "get-input", - mp.get_script_name(), utils.format_json(get_non_callbacks(t))) - - register_event_handler(t) + mp.get_script_name(), handler_id, utils.format_json(get_non_callbacks(t))) end input.select = input.get