summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.lua239
1 files changed, 124 insertions, 115 deletions
diff --git a/main.lua b/main.lua
index f57cd85..89e3586 100644
--- a/main.lua
+++ b/main.lua
@@ -16,7 +16,9 @@ local script_name = mp.get_script_name()
local script_dir = mp.get_script_directory()
local state = _state.new()
+local binding_state = {mappings = {}, active = {}}
local click_state = {}
+local osc_visibility
local downloader = _downloader.new({limit = 5})
local xc = _xc.new({
@@ -58,9 +60,6 @@ local osd = _osd.new({
end,
})
-local key_bindings = {}
-local osc_visibility
-
local function update_osd()
osd:redraw(state)
end
@@ -69,6 +68,10 @@ local function osd_menu_lines()
return osd:menu_lines(state)
end
+local function set_key_mapping(m)
+ binding_state.active = binding_state.mappings[m]
+end
+
local function load_data()
local arr = {
{id = 'live', name = 'Live TV', type = 'live'},
@@ -812,17 +815,17 @@ local function search_menu_options(options)
return ret
end
-local function search_input_char(event)
- if event.event ~= 'down' and event.event ~= 'repeat' then
+local function search_input_char(ev)
+ if ev.event ~= 'down' and ev.event ~= 'repeat' then
return
end
local menu = state:menu()
menu:set_search_text(
menu.search_text:sub(1, menu.search_cursor - 1) ..
- event.key_text ..
+ ev.key_text ..
menu.search_text:sub(menu.search_cursor))
- menu:set_search_cursor(menu.search_cursor + #event.key_text)
+ menu:set_search_cursor(menu.search_cursor + #ev.key_text)
update_osd()
end
@@ -879,9 +882,6 @@ local function search_cursor_end()
set_search_cursor(#state:menu().search_text + 1)
end
-local bind_search_keys
-local bind_menu_keys
-
local function start_search()
local menu = state:menu()
local title = 'Searching: <text_with_cursor>' ..
@@ -907,7 +907,7 @@ local function start_search()
end
update_osd()
- bind_search_keys()
+ set_key_mapping('SEARCH')
end
local function end_search()
@@ -916,7 +916,7 @@ local function end_search()
menu.title = 'Search results: <text>' ..
' <colours.info>(<num_matches>/<num_total>)'
update_osd()
- bind_menu_keys()
+ set_key_mapping('MENU')
end
local function cancel_search()
@@ -934,7 +934,7 @@ local function cancel_search()
menu.search_active = false
state.depth = state.depth - 1
update_osd()
- bind_menu_keys()
+ set_key_mapping('MENU')
end
local function toggle_menu_sort()
@@ -1080,115 +1080,125 @@ local function mouse_click_right(ev)
open_option_info(menu.options[pos])
end
-local function bind_key(key, func, opts)
- -- unique name is needed for removal
- local i = #key_bindings+1
- local name = 'key' .. i
- key_bindings[i] = name
- mp.add_forced_key_binding(key, name, func, opts)
-end
-
-local function unbind_keys()
- for _, key in ipairs(key_bindings) do
- mp.remove_key_binding(key)
- end
- key_bindings = {}
-end
-
-function bind_search_keys()
- unbind_keys()
-
- local c = {complex = true}
- local r = {repeatable = true}
-
- bind_key('ANY_UNICODE', search_input_char, c)
- bind_key('BS', search_input_bs, r)
- bind_key('DEL', search_input_del, r)
-
- bind_key('ENTER', end_search)
- bind_key('ESC', cancel_search)
- bind_key('Ctrl+c', cancel_search)
-
- bind_key('LEFT', search_cursor_left, r)
- bind_key('RIGHT', search_cursor_right, r)
- bind_key('Ctrl+a', search_cursor_start)
- bind_key('Ctrl+e', search_cursor_end)
-end
-
-function bind_menu_keys()
- unbind_keys()
-
- local c = {complex = true}
- local r = {repeatable = true}
-
- bind_key('BS', prev_menu)
- bind_key('/', start_search)
- bind_key('Ctrl+s', toggle_menu_sort)
-
- bind_key('ENTER', select_option)
- bind_key('Ctrl+f', favourite_option)
- bind_key('g', goto_option)
- bind_key('i', open_option_info)
- bind_key('?', open_option_info)
- bind_key('Ctrl+p', goto_playing)
-
- bind_key('MBTN_LEFT', mouse_click_left, c)
- bind_key('MBTN_RIGHT', mouse_click_right, c)
- bind_key('MBTN_LEFT_DBL')
- bind_key('MBTN_RIGHT_DBL')
-
- bind_key('k', cursor_up, r)
- bind_key('j', cursor_down, r)
- bind_key('K', cursor_page_up, r)
- bind_key('J', cursor_page_down, r)
- bind_key('UP', cursor_up, r)
- bind_key('DOWN', cursor_down, r)
- bind_key('Shift+UP', cursor_page_up, r)
- bind_key('Shift+DOWN', cursor_page_down, r)
- bind_key('PGUP', cursor_page_up, r)
- bind_key('PGDWN', cursor_page_down, r)
- bind_key('HOME', cursor_start)
- bind_key('END', cursor_end)
- bind_key('WHEEL_UP', cursor_up, r)
- bind_key('WHEEL_DOWN', cursor_down, r)
- bind_key('Shift+WHEEL_UP', cursor_page_up, r)
- bind_key('Shift+WHEEL_DOWN', cursor_page_down, r)
-
- bind_key('Alt+k', move_option_up, r)
- bind_key('Alt+j', move_option_down, r)
- bind_key('Alt+K', move_option_page_up, r)
- bind_key('Alt+J', move_option_page_down, r)
- bind_key('Alt+UP', move_option_up, r)
- bind_key('Alt+DOWN', move_option_down, r)
- bind_key('Alt+Shift+UP', move_option_page_up, r)
- bind_key('Alt+Shift+DOWN', move_option_page_down, r)
- bind_key('Alt+PGUP', move_option_page_up, r)
- bind_key('Alt+PGDWN', move_option_page_down, r)
- bind_key('Alt+HOME', move_option_start)
- bind_key('Alt+END', move_option_end)
- bind_key('Alt+WHEEL_UP', move_option_up, r)
- bind_key('Alt+WHEEL_DOWN', move_option_down, r)
- bind_key('Alt+Shift+WHEEL_UP', move_option_page_up, r)
- bind_key('Alt+Shift+WHEEL_DOWN', move_option_page_down, r)
+binding_state.mappings.MENU = {
+ ['BS'] = {prev_menu},
+ ['/'] = {start_search},
+ ['Ctrl+s'] = {toggle_menu_sort},
+
+ ['ENTER'] = {select_option},
+ ['Ctrl+f'] = {favourite_option},
+ ['g'] = {goto_option},
+ ['i'] = {open_option_info},
+ ['?'] = {open_option_info},
+ ['Ctrl+p'] = {goto_playing},
+
+ ['MBTN_LEFT'] = {mouse_click_left, 'complex'},
+ ['MBTN_RIGHT'] = {mouse_click_right, 'complex'},
+
+ ['k'] = {cursor_up, 'repeat'},
+ ['j'] = {cursor_down, 'repeat'},
+ ['K'] = {cursor_page_up, 'repeat'},
+ ['J'] = {cursor_page_down, 'repeat'},
+ ['UP'] = {cursor_up, 'repeat'},
+ ['DOWN'] = {cursor_down, 'repeat'},
+ ['Shift+UP'] = {cursor_page_up, 'repeat'},
+ ['Shift+DOWN'] = {cursor_page_down, 'repeat'},
+ ['PGUP'] = {cursor_page_up, 'repeat'},
+ ['PGDWN'] = {cursor_page_down, 'repeat'},
+ ['HOME'] = {cursor_start},
+ ['END'] = {cursor_end},
+ ['WHEEL_UP'] = {cursor_up, 'repeat'},
+ ['WHEEL_DOWN'] = {cursor_down, 'repeat'},
+ ['Shift+WHEEL_UP'] = {cursor_page_up, 'repeat'},
+ ['Shift+WHEEL_DOWN'] = {cursor_page_down, 'repeat'},
+
+ ['Alt+k'] = {move_option_up, 'repeat'},
+ ['Alt+j'] = {move_option_down, 'repeat'},
+ ['Alt+K'] = {move_option_page_up, 'repeat'},
+ ['Alt+J'] = {move_option_page_down, 'repeat'},
+ ['Alt+UP'] = {move_option_up, 'repeat'},
+ ['Alt+DOWN'] = {move_option_down, 'repeat'},
+ ['Shift+Alt+UP'] = {move_option_page_up, 'repeat'},
+ ['Shift+Alt+DOWN'] = {move_option_page_down, 'repeat'},
+ ['Alt+PGUP'] = {move_option_page_up, 'repeat'},
+ ['Alt+PGDWN'] = {move_option_page_down, 'repeat'},
+ ['Alt+HOME'] = {move_option_start},
+ ['Alt+END'] = {move_option_end},
+ ['Alt+WHEEL_UP'] = {move_option_up, 'repeat'},
+ ['Alt+WHEEL_DOWN'] = {move_option_down, 'repeat'},
+ ['Shift+Alt+WHEEL_UP'] = {move_option_page_up, 'repeat'},
+ ['Shift+Alt+WHEEL_DOWN'] = {move_option_page_down, 'repeat'},
+}
+
+binding_state.mappings.SEARCH = {
+ ['ANY_UNICODE'] = {search_input_char, 'complex'},
+ ['BS'] = {search_input_bs, 'repeat'},
+ ['DEL'] = {search_input_del, 'repeat'},
+
+ ['ENTER'] = {end_search},
+ ['ESC'] = {cancel_search},
+ ['Ctrl+c'] = {cancel_search},
+
+ ['LEFT'] = {search_cursor_left, 'repeat'},
+ ['RIGHT'] = {search_cursor_right, 'repeat'},
+ ['Ctrl+a'] = {search_cursor_start},
+ ['Ctrl+e'] = {search_cursor_end},
+}
+
+-- mpv does not process key-binding changes requested by script functions until
+-- those functions return. in the meantime, while the function is running, mpv
+-- discards any key presses for keys that were not already bound prior to the
+-- start of function execution. similarly, any pending key presses (for keys
+-- that were bound) are discarded if the binding changes during function
+-- execution.
+--
+-- in other words, we get an inconsistent result where pressing a key while a
+-- function is running triggers the bound function upon completion if that
+-- binding remains the same, but ignores such key presses when our function
+-- changes the corresponding binding or adds a new one. we can avoid this by
+-- leaving our keys bound to a common function and building our own logic to
+-- route keys per the current state.
+local function handle_key(ev)
+ t = binding_state.active[ev.key_name]
+ if not t and ev.key_text then
+ t = binding_state.active['ANY_UNICODE']
+ end
+
+ f = t and t[1]
+ if not f then
+ return
+ end
+
+ flag = t[2]
+ if flag == 'complex' then
+ f(ev)
+ elseif ev.event == 'down' or
+ (ev.event == 'repeat' and flag == 'repeat') then
+ f()
+ end
end
-- uses enable-section and disable-section to disable builtin key bindings
-- while the OSD is visible. these commands are technically deprecated for
-- non-internal use, but they still work, and there doesn't appear to be
-- another way apart from setting an override for each individual key.
---
--- might eventually change this to a selective override, since some of these
--- builtin keys could still be useful while the menus are open.
local function set_key_bindings()
if osd:is_hidden() then
- unbind_keys()
- mp.command_native({'enable-section', 'default'})
- elseif state:menu().search_active then
- bind_search_keys()
- mp.command_native({'disable-section', 'default'})
- else
- bind_menu_keys()
+ if binding_state.bound then
+ mp.remove_key_binding('mouse_move')
+ mp.remove_key_binding('unmapped')
+ mp.command_native({'enable-section', 'default'})
+ binding_state.bound = false
+ end
+ return
+ end
+
+ if not binding_state.bound then
mp.command_native({'disable-section', 'default'})
+ mp.add_forced_key_binding('MOUSE_MOVE', 'mouse_move') -- noisy
+ mp.add_forced_key_binding(
+ 'UNMAPPED', 'unmapped', handle_key, {complex = true})
+ binding_state.bound = true
end
end
@@ -1234,7 +1244,6 @@ push_group_menu(catalogue:get('root'))
osc_visibility = mp.get_property_native('user-data/osc/visibility', 'auto')
set_osc_visibility()
--- keys added via bind_key() are unbound when the OSD is closed, but we want
--- toggle-menu to work regardless of setting.
mp.add_forced_key_binding('TAB', 'toggle-menu', toggle_menu)
+set_key_mapping('MENU')
set_key_bindings()