From ae5df9be98e4193342321f30285655fcf88e7e63 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 23 Nov 2014 15:08:49 +0100 Subject: input, lua: redo input handling Much of it is the same, but now there's the possibility to distinguish key down/up events in the Lua API. --- player/lua/defaults.lua | 132 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 98 insertions(+), 34 deletions(-) (limited to 'player/lua/defaults.lua') diff --git a/player/lua/defaults.lua b/player/lua/defaults.lua index 4b3be12ac9..812bb71afe 100644 --- a/player/lua/defaults.lua +++ b/player/lua/defaults.lua @@ -22,7 +22,27 @@ function mp.get_opt(key, def) return val end -local callbacks = {} +-- For dispatching script_binding. This is sent as: +-- script_message_to $script_name $binding_name $keystate +-- The array is indexed by $binding_name, and has functions like this as value: +-- fn($binding_name, $keystate) +local dispatch_key_bindings = {} + +local message_id = 0 +local function reserve_binding() + message_id = message_id + 1 + return "__keybinding" .. tostring(message_id) +end + +local function dispatch_key_binding(name, state) + local fn = dispatch_key_bindings[name] + if fn then + fn(name, state) + end +end + +-- "Old", deprecated API + -- each script has its own section, so that they don't conflict local default_section = "input_dispatch_" .. mp.script_name @@ -34,13 +54,8 @@ local default_section = "input_dispatch_" .. mp.script_name -- Note: the bindings are not active by default. Use enable_key_bindings(). -- -- list is an array of key bindings, where each entry is an array as follow: --- {key, callback} --- {key, callback, callback_down} +-- {key, callback_press, callback_down, callback_up} -- key is the key string as used in input.conf, like "ctrl+a" --- callback is a Lua function that is called when the key binding is used. --- callback_down can be given too, and is called when a mouse button is pressed --- if the key is a mouse button. (The normal callback will be for mouse button --- down.) -- -- callback can be a string too, in which case the following will be added like -- an input.conf line: key .. " " .. callback @@ -52,10 +67,29 @@ function mp.set_key_bindings(list, section, flags) local key = entry[1] local cb = entry[2] local cb_down = entry[3] - if type(cb) == "function" then - callbacks[#callbacks + 1] = {press=cb, before_press=cb_down} - cfg = cfg .. key .. " script_dispatch " .. mp.script_name - .. " " .. #callbacks .. "\n" + local cb_up = entry[4] + if type(cb) ~= "string" then + local mangle = reserve_binding() + dispatch_key_bindings[mangle] = function(name, state) + local event = state:sub(1, 1) + local is_mouse = state:sub(2, 2) == "m" + local def = (is_mouse and "u") or "d" + if event == "r" then + event = "d" + end + if event == "p" and cb then + cb() + elseif event == "d" and cb_down then + cb_down() + elseif event == "u" and cb_up then + cb_up() + elseif event == def and cb then + print("whooo") + cb() + end + end + cfg = cfg .. key .. " script_binding " .. + mp.script_name .. "/" .. mangle .. "\n" else cfg = cfg .. key .. " " .. cb .. "\n" end @@ -75,21 +109,9 @@ function mp.set_mouse_area(x0, y0, x1, y1, section) mp.input_set_section_mouse_area(section or default_section, x0, y0, x1, y1) end -local function script_dispatch(event) - local cb = callbacks[event.arg0] - if cb then - if event.type == "press" and cb.press then - cb.press() - elseif event.type == "keyup_follows" and cb.before_press then - cb.before_press() - end - end -end - -- "Newer" and more convenient API local key_bindings = {} -local message_id = 1 local function update_key_bindings() for i = 1, 2 do @@ -105,9 +127,7 @@ local function update_key_bindings() local cfg = "" for k, v in pairs(key_bindings) do if v.forced ~= def then - local flags = (v.repeatable and " repeatable") or "" - cfg = cfg .. v.key .. " " .. flags .. " script_message_to " - .. mp.script_name .. " " .. v.name .. "\n" + cfg = cfg .. v.bind .. "\n" end end mp.input_define_section(section, cfg, flags) @@ -117,19 +137,61 @@ local function update_key_bindings() end local function add_binding(attrs, key, name, fn, rp) + rp = rp or "" if (type(name) ~= "string") and (not fn) then fn = name - name = "message" .. tostring(message_id) - message_id = message_id + 1 + name = reserve_binding() + end + local bind = key + if rp == "repeatable" or rp["repeatable"] then + bind = bind .. " repeatable" + end + if rp["forced"] then + attrs.forced = true + end + local key_cb, msg_cb + if not fn then + fn = function() end + end + if rp["complex"] then + local key_states = { + ["u"] = "up", + ["d"] = "down", + ["r"] = "repeat", + ["p"] = "press", + } + key_cb = function(name, state) + fn({ + event = key_states[state:sub(1, 1)] or "unknown", + is_mouse = state:sub(2, 2) == "m" + }) + end + msg_cb = function() + fn({event = "press", is_mouse = false}) + end + else + key_cb = function(name, state) + -- Emulate the same semantics as input.c uses for most bindings: + -- For keyboard, "down" runs the command, "up" does nothing; + -- for mouse, "down" does nothing, "up" runs the command. + -- Also, key repeat triggers the binding again. + local event = state:sub(1, 1) + local is_mouse = state:sub(2, 2) == "m" + if is_mouse and event == "u" then + fn() + elseif (not is_mouse) and (event == "d" or event == "r") then + fn() + end + end + msg_cb = fn end - attrs.repeatable = rp == "repeatable" - attrs.key = key + attrs.bind = bind .. " script_binding " .. mp.script_name .. "/" .. name attrs.name = name key_bindings[name] = attrs update_key_bindings() - if fn then - mp.register_script_message(name, fn) - end + dispatch_key_bindings[name] = key_cb + mp.unregister_script_message(name) + mp.register_script_message(name, msg_cb) end function mp.add_key_binding(...) @@ -322,10 +384,12 @@ end -- default handlers mp.register_event("shutdown", function() mp.keep_running = false end) -mp.register_event("script-input-dispatch", script_dispatch) mp.register_event("client-message", message_dispatch) mp.register_event("property-change", property_change) +-- sent by "script_binding" +mp.register_script_message("key-binding", dispatch_key_binding) + mp.msg = { log = mp.log, fatal = function(...) return mp.log("fatal", ...) end, -- cgit v1.2.3