diff options
| author | David Vazgenovich Shakaryan <dvshakaryan@gmail.com> | 2026-01-19 03:32:24 -0800 |
|---|---|---|
| committer | David Vazgenovich Shakaryan <dvshakaryan@gmail.com> | 2026-01-19 03:32:24 -0800 |
| commit | c4293c5c7c147c61e8104f33c83d1fb83af2fe8a (patch) | |
| tree | 1c84aecae9b66fc754c01526d8dc94370dd27928 | |
| parent | 3ad105d4d8b63fe34f8a1bd8d2d6b64924df831f (diff) | |
| download | mpv-iptv-menu-c4293c5c7c147c61e8104f33c83d1fb83af2fe8a.tar.gz mpv-iptv-menu-c4293c5c7c147c61e8104f33c83d1fb83af2fe8a.tar.xz | |
consolidate mouse-pos listeners
| -rw-r--r-- | main.lua | 127 |
1 files changed, 60 insertions, 67 deletions
@@ -16,7 +16,7 @@ local script_name = mp.get_script_name() local state = _state.new() local binding_state = {mappings = {}, active = {}} -local click_state = {} +local mouse_state = {click = {}} local osc_visibility local downloader = _downloader.new({limit = 5}) @@ -995,78 +995,61 @@ local function mouse_has_drifted(x1, y1, x2, y2) math.abs(y1 - y2) > config.click_max_drift end --- mpv normally sends a cancel event when the mouse drifts before a click is --- released, but only for a first click and not for the second click of what --- mpv internally considers a double-click. this replicates that drift --- detection behaviour, allowing for consistency on double-clicks. -local function handle_mouse_drift(_, mpos) - local s = click_state - if not mpos or not s.ct then - return - end - - if mouse_has_drifted(mpos.x, mpos.y, s.cx, s.cy) then - click_state = {} - mp.unobserve_property(handle_mouse_drift) - end -end - -- when mpv registers a double-click, the second click triggers both -- double-click and click events. instead of identifying and ignoring this -- second click event, we can implement double-click detection ourselves for -- more control and to bypass some mpv inconsistencies. -local function handle_mouse_click(ev, mpos, id) - mp.unobserve_property(handle_mouse_drift) +local function handle_mouse_click(ev, id) + local ms = mouse_state if ev.canceled then - click_state = {} + ms.click = {} return end - local s = click_state local time = mp.get_time() + local clk = ms.click + local mpos = ms.pos if ev.event == 'down' then - s.ct, s.ck = time, ev.key_name - s.cx, s.cy, s.ci = mpos.x, mpos.y, id - mp.observe_property('mouse-pos', 'native', handle_mouse_drift) + clk.ct, clk.ck = time, ev.key_name + clk.cx, clk.cy, clk.ci = mpos.x, mpos.y, id return end - if ev.event ~= 'up' or not s.ct then + if ev.event ~= 'up' or not clk.ct then return end - if time - s.ct > config.click_timeout or - s.ck ~= ev.key_name or s.ci ~= id or - mouse_has_drifted(mpos.x, mpos.y, s.cx, s.cy) then - click_state = {} + if time - clk.ct > config.click_timeout or + clk.ck ~= ev.key_name or clk.ci ~= id or + mouse_has_drifted(mpos.x, mpos.y, clk.cx, clk.cy) then + ms.click = {} return end - local dbl = s.pt and s.ct - s.pt <= config.click_dbl_time and - s.pk == ev.key_name and s.pi == id and - not mouse_has_drifted(s.cx, s.cy, s.px, s.py) - click_state = dbl and {} or + local dbl = clk.pt and clk.ct - clk.pt <= config.click_dbl_time and + clk.pk == ev.key_name and clk.pi == id and + not mouse_has_drifted(clk.cx, clk.cy, clk.px, clk.py) + ms.click = dbl and {} or { - pt = s.ct, pk = ev.key_name, - px = s.cx, py = s.cy, pi = id, + pt = clk.ct, pk = ev.key_name, + px = clk.cx, py = clk.cy, pi = id, } return ev.key_name, dbl end local function process_mouse_click(ev) - local mpos = mp.get_property_native('mouse-pos') - if not mpos then + if not mouse_state.pos then return end - local line = osd:get_mouse_line(mpos) + local line = osd:get_mouse_line(mouse_state.pos) if line then line = line - (osd.lines - osd:menu_lines(state)) end - local key, dbl = handle_mouse_click(ev, mpos, line) + local key, dbl = handle_mouse_click(ev, line) return key, dbl, line end @@ -1281,15 +1264,13 @@ mp.set_key_bindings({ {'MBTN_LEFT', toggle_menu}, {'MBTN_LEFT_DBL'}, }, 'menu_button', 'force') -local mouse_pos_time -local mouse_over_button_area = false -local mouse_over_menu_button = false -local mouse_timer; mouse_timer = mp.add_periodic_timer(0.1, function() - if mouse_pos_time and - mp.get_time() - mouse_pos_time > +local menu_button_timer +menu_button_timer = mp.add_periodic_timer(0.1, function() + if mouse_state.pos and + mp.get_time() - mouse_state.pos_time > config.menu_button_timeout then osd:show_menu_button(false) - mouse_timer:kill() + menu_button_timer:kill() end end, true) -- disabled mp.observe_property('mouse-pos', 'native', function(_, mpos) @@ -1297,36 +1278,49 @@ mp.observe_property('mouse-pos', 'native', function(_, mpos) return end + local ms = mouse_state + -- mpv sends (0, 0) on startup if the mouse hasn't moved yet. don't -- trigger display of the button until the mouse has actually moved. - if not mouse_pos_time and mpos.x == 0 and mpos.y == 0 then + if not ms.pos and mpos.x == 0 and mpos.y == 0 then return end - mouse_pos_time = mp.get_time() + ms.pos = mpos + ms.pos_time = mp.get_time() + + -- mpv normally sends a cancel event when the mouse drifts before a + -- click is released, but only for a first click and not for the second + -- click of what mpv internally considers a double-click. this + -- replicates that drift detection behaviour, allowing for consistency + -- on double-clicks. + local clk = ms.click + if clk.ct and mouse_has_drifted(mpos.x, mpos.y, clk.cx, clk.cy) then + ms.click = {} + end - local is_over = osd:mouse_over_button_area(mpos) - if is_over ~= mouse_over_button_area then - mouse_over_button_area = is_over - osd:show_menu_button(mouse_over_button_area) - elseif mouse_over_button_area and osd.menu_button.hidden then + local over_button_area = osd:mouse_over_button_area(mpos) + if not over_button_area ~= not ms.over_button_area then + ms.over_button_area = over_button_area + osd:show_menu_button(over_button_area) + elseif over_button_area and osd.menu_button.hidden then osd:show_menu_button(true) end - local is_over = osd:mouse_over_menu_button(mpos) - if is_over ~= mouse_over_menu_button then - mouse_over_menu_button = is_over - if mouse_over_menu_button then + local over_menu_button = osd:mouse_over_menu_button(mpos) + if not over_menu_button ~= not ms.over_menu_button then + ms.over_menu_button = over_menu_button + if over_menu_button then mp.enable_key_bindings('menu_button') else mp.disable_key_bindings('menu_button') end end - if mouse_over_button_area and not mouse_over_menu_button then - mouse_timer:resume() + if over_button_area and not over_menu_button then + menu_button_timer:resume() else - mouse_timer:kill() + menu_button_timer:kill() end end) @@ -1341,15 +1335,14 @@ mp.observe_property('osd-dimensions', 'native', function(_, val) osd:redraw(state) -- after a resize, mpv does not update the mouse coordinates until the - -- mouse is moved. if the mouse was previously over the button and we - -- do nothing, a click would trigger the button regardless of mouse - -- position. since we cannot get the new mouse position, we instead - -- treat all resizes as moving the mouse off the button. + -- mouse is moved. if the mouse was previously over a clickable element + -- and we do nothing, a click would trigger that element regardless of + -- mouse position. since we cannot get the new position, we instead + -- wipe mouse state on resize, clearing it until the next move. osd:show_menu_button(false) - mouse_over_button_area = false - mouse_over_menu_button = false + mouse_state = {click = {}} mp.disable_key_bindings('menu_button') - mouse_timer:kill() + menu_button_timer:kill() end) mp.register_event('start-file', function() |
