From 5ae3a2bbe8f8db8a708317eed3b77d86390d9baa Mon Sep 17 00:00:00 2001 From: dyphire Date: Tue, 6 Feb 2024 17:30:42 +0800 Subject: [PATCH] =?UTF-8?q?=E9=85=8D=E7=BD=AE=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- archive/scripts/open_dialog.lua | 21 ++- scripts/subtitle-lines.lua | 3 +- scripts/uosc/elements/Button.lua | 4 +- scripts/uosc/elements/Speed.lua | 2 +- scripts/uosc/elements/TopBar.lua | 43 ++++-- scripts/uosc/elements/Updater.lua | 2 +- scripts/uosc/elements/Volume.lua | 4 +- scripts/uosc/lib/cursor.lua | 246 ++++++++++++++++++++---------- scripts/uosc/lib/utils.lua | 14 +- scripts/uosc/main.lua | 19 ++- 10 files changed, 240 insertions(+), 118 deletions(-) diff --git a/archive/scripts/open_dialog.lua b/archive/scripts/open_dialog.lua index 8d194251..d5180474 100644 --- a/archive/scripts/open_dialog.lua +++ b/archive/scripts/open_dialog.lua @@ -253,18 +253,23 @@ end -- open for clipboard local function import_clipboard(type) - local clip = get_clipboard() - local meta = utils.file_info(clip) + local clip = get_clipboard():gsub("^[\'\"]", ""):gsub("[\'\"]$", "") if clip ~= '' then if clip:find('^%a[%w.+-]-://') then mp.commandv('loadfile', clip) - elseif meta.is_dir then - open_folder(clip) - elseif meta.is_file then - open_files(clip, type, 1, true) else - mp.osd_message('Clipboard is not a valid URL or file path') - msg.warn('Clipboard is not a valid URL or file path') + local meta = utils.file_info(clip) + if not meta then + mp.osd_message('Clipboard is not a valid URL or file path') + msg.warn('Clipboard is not a valid URL or file path') + elseif meta.is_dir then + open_folder(clip) + elseif meta.is_file then + open_files(clip, type, 1, true) + else + mp.osd_message('Clipboard is not a valid URL or file path') + msg.warn('Clipboard is not a valid URL or file path') + end end else mp.osd_message('Clipboard is empty') diff --git a/scripts/subtitle-lines.lua b/scripts/subtitle-lines.lua index 53f5296e..f0c96783 100644 --- a/scripts/subtitle-lines.lua +++ b/scripts/subtitle-lines.lua @@ -1,4 +1,4 @@ --- subtitle-lines 1.0.0 - 2023-Oct-22 +-- subtitle-lines 1.1.0 - 2024-Feb-02 -- https://github.com/christoph-heinrich/mpv-subtitle-lines -- -- List and search subtitle lines of the selected subtitle track. @@ -6,6 +6,7 @@ -- Usage: -- add bindings to input.conf: -- Ctrl+f script-binding subtitle_lines/list_subtitles +-- Ctrl+F script-binding subtitle_lines/list_secondary_subtitles local mp = require 'mp' local utils = require 'mp.utils' diff --git a/scripts/uosc/elements/Button.lua b/scripts/uosc/elements/Button.lua index 73d32b8d..b0d29f04 100644 --- a/scripts/uosc/elements/Button.lua +++ b/scripts/uosc/elements/Button.lua @@ -23,7 +23,7 @@ function Button:init(id, props) end function Button:on_coordinates() self.font_size = round((self.by - self.ay) * 0.7) end -function Button:handle_cursor_down() +function Button:handle_cursor_click() -- We delay the callback to next tick, otherwise we are risking race -- conditions as we are in the middle of event dispatching. -- For example, handler might add a menu to the end of the element stack, and that @@ -34,7 +34,7 @@ end function Button:render() local visibility = self:get_visibility() if visibility <= 0 then return end - cursor:zone('primary_down', self, function() self:handle_cursor_down() end) + cursor:zone('primary_click', self, function() self:handle_cursor_click() end) local ass = assdraw.ass_new() local is_hover = self.proximity_raw == 0 diff --git a/scripts/uosc/elements/Speed.lua b/scripts/uosc/elements/Speed.lua index e6bc2efb..216d0d69 100644 --- a/scripts/uosc/elements/Speed.lua +++ b/scripts/uosc/elements/Speed.lua @@ -109,7 +109,7 @@ function Speed:render() self:handle_cursor_down() cursor:once('primary_up', function() self:handle_cursor_up() end) end) - cursor:zone('secondary_down', self, function() mp.set_property_native('speed', 1) end) + cursor:zone('secondary_click', self, function() mp.set_property_native('speed', 1) end) cursor:zone('wheel_down', self, function() self:handle_wheel_down() end) cursor:zone('wheel_up', self, function() self:handle_wheel_up() end) diff --git a/scripts/uosc/elements/TopBar.lua b/scripts/uosc/elements/TopBar.lua index 1a430e7d..25a685be 100644 --- a/scripts/uosc/elements/TopBar.lua +++ b/scripts/uosc/elements/TopBar.lua @@ -16,7 +16,7 @@ function TopBarButton:init(id, props) self.command = props.command end -function TopBarButton:handle_cursor_down() +function TopBarButton:handle_click() mp.command(type(self.command) == 'function' and self.command() or self.command) end @@ -29,7 +29,7 @@ function TopBarButton:render() if self.proximity_raw == 0 then ass:rect(self.ax, self.ay, self.bx, self.by, {color = self.background, opacity = visibility}) end - cursor:zone('primary_down', self, function() self:handle_cursor_down() end) + cursor:zone('primary_click', self, function() self:handle_click() end) local width, height = self.bx - self.ax, self.by - self.ay local icon_size = math.min(width, height) * 0.5 @@ -199,6 +199,7 @@ function TopBar:render() if state.title or state.has_playlist then local bg_margin = math.floor((self.size - self.font_size) / 4) local padding = self.font_size / 2 + local spacing = 1 local title_ax = self.ax + bg_margin local title_ay = self.ay + bg_margin local max_bx = self.title_bx - self.spacing @@ -226,7 +227,7 @@ function TopBar:render() title_ax = rect.bx + bg_margin -- Click action - cursor:zone('primary_down', rect, function() mp.command('script-binding uosc/playlist') end) + cursor:zone('primary_click', rect, function() mp.command('script-binding uosc/playlist') end) end -- Skip rendering titles if there's not enough horizontal space @@ -248,14 +249,14 @@ function TopBar:render() local title_rect = {ax = title_ax, ay = title_ay, bx = bx, by = by} if options.top_bar_alt_title_place == 'toggle' then - cursor:zone('primary_down', title_rect, function() self:toggle_title() end) + cursor:zone('primary_click', title_rect, function() self:toggle_title() end) end ass:rect(title_rect.ax, title_rect.ay, title_rect.bx, title_rect.by, { color = bg, opacity = visibility * config.opacity.title, radius = state.radius, }) ass:txt(title_ax + padding, self.ay + (self.size / 2), 4, main_title, opts) - title_ay = by + 1 + title_ay = by + spacing end -- Alt title @@ -277,14 +278,19 @@ function TopBar:render() color = bg, opacity = visibility * config.opacity.title, radius = state.radius, }) ass:txt(title_ax + padding, title_ay + height / 2, 4, self.alt_title, opts) - title_ay = by + 1 + title_ay = by + spacing end - -- Subtitle: current chapter + -- Current chapter if state.current_chapter then + local padding_half = round(padding / 2) local font_size = self.font_size * 0.8 local height = font_size * 1.3 local text = '└ ' .. state.current_chapter.index .. ': ' .. state.current_chapter.title + local next_chapter = state.chapters[state.current_chapter.index + 1] + local chapter_end = next_chapter and next_chapter.time or state.duration or 0 + local remaining_time = (state.time and state.time or 0) - chapter_end + local remaining_human = format_time(remaining_time, math.abs(remaining_time)) local opts = { size = font_size, italic = true, @@ -294,10 +300,17 @@ function TopBar:render() border_color = bg, opacity = visibility * 0.8, } + local remaining_width = timestamp_width(remaining_human, opts) + local remaining_box_width = remaining_width + padding_half * 2 + + -- Title local rect = { ax = title_ax, ay = title_ay, - bx = round(math.min(max_bx, title_ax + text_width(text, opts) + padding * 2)), + bx = round(math.min( + max_bx - remaining_box_width - spacing, + title_ax + text_width(text, opts) + padding * 2 + )), by = title_ay + height, } opts.clip = string.format('\\clip(%d, %d, %d, %d)', title_ax, title_ay, rect.bx, rect.by) @@ -305,10 +318,20 @@ function TopBar:render() color = bg, opacity = visibility * config.opacity.title, radius = state.radius, }) ass:txt(rect.ax + padding, rect.ay + height / 2, 4, text, opts) - title_ay = rect.by + 1 -- Click action - cursor:zone('primary_down', rect, function() mp.command('script-binding uosc/chapters') end) + cursor:zone('primary_click', rect, function() mp.command('script-binding uosc/chapters') end) + + -- Time + rect.ax = rect.bx + spacing + rect.bx = rect.ax + remaining_box_width + opts.clip = nil + ass:rect(rect.ax, rect.ay, rect.bx, rect.by, { + color = bg, opacity = visibility * config.opacity.title, radius = state.radius, + }) + ass:txt(rect.ax + padding_half, rect.ay + height / 2, 4, remaining_human, opts) + + title_ay = rect.by + spacing end end self.title_by = title_ay - 1 diff --git a/scripts/uosc/elements/Updater.lua b/scripts/uosc/elements/Updater.lua index 651c664d..f09389c4 100644 --- a/scripts/uosc/elements/Updater.lua +++ b/scripts/uosc/elements/Updater.lua @@ -161,7 +161,7 @@ function Updater:render() local y = round(button_rect.ay + (button_rect.by - button_rect.ay) / 2) ass:icon(x, y, icon_size * 0.8, 'close', {color = bg}) - cursor:zone('primary_down', button_rect, function() self:destroy() end) + cursor:zone('primary_click', button_rect, function() self:destroy() end) end return ass diff --git a/scripts/uosc/elements/Volume.lua b/scripts/uosc/elements/Volume.lua index ff65f4cd..03870194 100644 --- a/scripts/uosc/elements/Volume.lua +++ b/scripts/uosc/elements/Volume.lua @@ -249,14 +249,14 @@ function Volume:render() if visibility <= 0 then return end -- Reset volume on secondary click - cursor:zone('secondary_down', self, function() + cursor:zone('secondary_click', self, function() mp.set_property_native('mute', false) mp.set_property_native('volume', 100) end) -- Mute button local mute_rect = {ax = self.ax, ay = self.mute_ay, bx = self.bx, by = self.by} - cursor:zone('primary_down', mute_rect, function() mp.commandv('cycle', 'mute') end) + cursor:zone('primary_click', mute_rect, function() mp.commandv('cycle', 'mute') end) local ass = assdraw.ass_new() local width_half = (mute_rect.bx - mute_rect.ax) / 2 local height_half = (mute_rect.by - mute_rect.ay) / 2 diff --git a/scripts/uosc/lib/cursor.lua b/scripts/uosc/lib/cursor.lua index c1600ed5..0bd3e02a 100644 --- a/scripts/uosc/lib/cursor.lua +++ b/scripts/uosc/lib/cursor.lua @@ -3,19 +3,9 @@ local cursor = { y = math.huge, hidden = true, hover_raw = false, - -- Event handlers that are only fired on cursor, bound during render loop. Guidelines: - -- - element activations (clicks) go to `primary_down` handler - -- - `primary_up` is only for clearing dragging/swiping, and prevents autohide when bound - ---@type {[string]: {hitbox: Rect|{point: Point, r: number}; handler: fun(...)}[]} - zone_handlers = { - primary_down = {}, - primary_up = {}, - secondary_down = {}, - secondary_up = {}, - wheel_down = {}, - wheel_up = {}, - move = {}, - }, + -- Event handlers that are only fired on zones defined during render loop. + ---@type {event: string, hitbox: Hitbox; handler: fun(...)}[] + zones = {}, handlers = { primary_down = {}, primary_up = {}, @@ -27,12 +17,49 @@ local cursor = { }, first_real_mouse_move_received = false, history = CircularBuffer:new(10), - -- Enables pointer key group captures needed by handlers (called at the end of each render) - mbtn_left_enabled = nil, - mbtn_left_dbl_enabled = nil, - mbtn_right_enabled = nil, - wheel_enabled = nil, autohide_fs_only = nil, + -- Tracks current key binding levels for each event. 0: disabled, 1: enabled, 2: enabled + window dragging prevented + binding_levels = { + mbtn_left = 0, + mbtn_left_dbl = 0, + mbtn_right = 0, + wheel = 0, + }, + is_dragging_prevented = false, + event_forward_map = { + primary_down = 'MBTN_LEFT', + primary_up = 'MBTN_LEFT', + secondary_down = 'MBTN_RIGHT', + secondary_up = 'MBTN_RIGHT', + wheel_down = 'WHEEL_DOWN', + wheel_up = 'WHEEL_UP', + }, + event_binding_map = { + primary_down = 'mbtn_left', + primary_up = 'mbtn_left', + primary_click = 'mbtn_left', + secondary_down = 'mbtn_right', + secondary_up = 'mbtn_right', + secondary_click = 'mbtn_right', + wheel_down = 'wheel', + wheel_up = 'wheel', + }, + window_dragging_blockers = create_set({'primary_click', 'primary_down'}), + event_propagation_blockers = { + primary_down = 'primary_click', + primary_click = 'primary_down', + secondary_down = 'secondary_click', + secondary_click = 'secondary_down', + }, + event_parent_map = { + primary_down = {is_start = true, trigger_event = 'primary_click'}, + primary_up = {is_end = true, start_event = 'primary_down', trigger_event = 'primary_click'}, + secondary_down = {is_start = true, trigger_event = 'secondary_click'}, + secondary_up = {is_end = true, start_event = 'secondary_down', trigger_event = 'secondary_click'}, + }, + -- Holds positions of last events. + ---@type {[string]: {x: number, y: number, time: number}} + last_event = {}, } cursor.autohide_timer = mp.add_timeout(1, function() cursor:autohide() end) @@ -43,30 +70,48 @@ end) -- Called at the beginning of each render function cursor:clear_zones() - for _, handlers in pairs(self.zone_handlers) do - itable_clear(handlers) - end + itable_clear(self.zones) +end + +---@param hitbox Hitbox +function cursor:collides_with(hitbox) + return point_collides_with(self, hitbox) end +-- Returns zone for event at current cursor position. ---@param event string -function cursor:find_zone_handler(event) - local zone_handlers = self.zone_handlers[event] - for i = #zone_handlers, 1, -1 do - local zone_handler = zone_handlers[i] - local hitbox = zone_handler.hitbox - if (hitbox.r and get_point_to_point_proximity(self, hitbox.point) <= hitbox.r) or - (not hitbox.r and get_point_to_rectangle_proximity(self, hitbox) == 0) then - return zone_handler.handler +function cursor:find_zone(event) + -- Premature optimization to ignore a high frequency event that is not needed as a zone atm. + if event == 'move' then return end + + for i = #self.zones, 1, -1 do + local zone = self.zones[i] + local is_blocking_only = zone.event == self.event_propagation_blockers[event] + if (zone.event == event or is_blocking_only) and self:collides_with(zone.hitbox) then + return not is_blocking_only and zone or nil end end end +-- Defines an event zone for a hitbox on currently rendered screen. Available events: +-- - primary_down, primary_up, primary_click, secondary_down, secondary_up, secondary_click, wheel_down, wheel_up +-- +-- Notes: +-- - Zones are cleared on beginning of every `render()`, and need to be rebound. +-- - One event type per zone: only the last bound zone per event gets triggered. +-- - In current implementation, you have to choose between `_click` or `_down`. Binding both makes only the last bound fire. +-- - Primary `_down` and `_click` disable dragging. Define `window_drag = true` on hitbox to re-enable. +-- - Anything that disables dragging also implicitly disables cursor autohide. +-- - `move` event zones are ignored due to it being a high frequency event that is currently not needed as a zone. +---@param event string +---@param hitbox Hitbox +---@param callback fun(...) function cursor:zone(event, hitbox, callback) - local area_handlers = self.zone_handlers[event] - area_handlers[#area_handlers + 1] = {hitbox = hitbox, handler = callback} + self.zones[#self.zones + 1] = {event = event, hitbox = hitbox, handler = callback} end --- Binds a cursor event handler. +-- Binds a permanent cursor event handler active until manually unbound using `cursor:off()`. +-- `_click` events are not available as permanent global events, only as zones. ---@param event string ---@return fun() disposer Unbinds the event. function cursor:on(event, callback) @@ -102,68 +147,101 @@ end -- Trigger the event. ---@param event string function cursor:trigger(event, ...) - local zone_handler = self:find_zone_handler(event) + local forward = true + + -- Call raw event handlers. + local zone = self:find_zone(event) local callbacks = self.handlers[event] - if zone_handler or #callbacks > 0 then - call_maybe(zone_handler, ...) + if zone or #callbacks > 0 then + forward = false + if zone then zone.handler(...) end for _, callback in ipairs(callbacks) do callback(...) end - elseif (event == 'primary_down' or event == 'primary_up') then - -- forward mbtn_left events if there was no handler - local active = find_active_keybindings('MBTN_LEFT') - if active then - if active.owner then - -- binding belongs to other script, so make it look like regular key event - -- mouse bindings are simple, other keys would require repeat and pressed handling - -- which can't be done with mp.set_key_bindings(), but is possible with mp.add_key_binding() - local state = event == 'primary_up' and 'um' or 'dm' - local name = active.cmd:sub(active.cmd:find('/') + 1, -1) - mp.commandv('script-message-to', active.owner, 'key-binding', name, state, 'MBTN_LEFT') - elseif event == 'primary_down' then - -- input.conf binding - mp.command(active.cmd) + end + + -- Call compound/parent (click) event handlers if both start and end events are within `parent_zone.hitbox`. + local parent = self.event_parent_map[event] + if parent then + local parent_zone = self:find_zone(parent.trigger_event) + if parent_zone then + forward = false -- Canceled here so we don't forward down events if they can lead to a click. + if parent.is_end then + local last_start_event = self.last_event[parent.start_event] + if last_start_event and point_collides_with(last_start_event, parent_zone.hitbox) then + parent_zone.handler(...) + end end end end - self:queue_autohide() -- refresh cursor autohide timer -end ----Checks if there are any handlers for the current cursor position ----@param name string -function cursor:has_handler(name) - return self:find_zone_handler(name) ~= nil or #self.handlers[name] > 0 -end + -- Forward unhandled events. + if forward then + local forward_name = self.event_forward_map[event] + if forward_name then + -- Forward events if there was no handler. + local active = find_active_keybindings(forward_name) + if active then + local is_wheel = event:find('wheel', 1, true) + local is_up = event:sub(-3) == '_up' + if active.owner then + -- Binding belongs to other script, so make it look like regular key event. + -- Mouse bindings are simple, other keys would require repeat and pressed handling, + -- which can't be done with mp.set_key_bindings(), but is possible with mp.add_key_binding(). + local state = is_wheel and 'pm' or is_up and 'um' or 'dm' + local name = active.cmd:sub(active.cmd:find('/') + 1, -1) + mp.commandv('script-message-to', active.owner, 'key-binding', name, state, forward_name) + elseif is_wheel or is_up then + -- input.conf binding, react to button release for mouse buttons + mp.command(active.cmd) + end + end + end + end + + -- Update last event position. + local last = self.last_event[event] or {} + last.x, last.y, last.time = self.x, self.y, mp.get_time() + self.last_event[event] = last ----Checks if there are any handlers at all ----@param name string -function cursor:has_any_handler(name) - return #self.zone_handlers[name] > 0 or #self.handlers[name] > 0 + -- Refresh cursor autohide timer. + self:queue_autohide() end -- Enables or disables keybinding groups based on what event listeners are bound. function cursor:decide_keybinds() - local enable_mbtn_left = self:has_any_handler('primary_down') or self:has_any_handler('primary_up') - local enable_mbtn_left_dbl = self:has_handler('primary_down') or self:has_handler('primary_up') - local enable_mbtn_right = self:has_handler('secondary_down') or self:has_handler('secondary_up') - local enable_wheel = self:has_handler('wheel_down') or self:has_handler('wheel_up') - if enable_mbtn_left ~= self.mbtn_left_enabled then - local flags = 'allow-vo-dragging+allow-hide-cursor' - mp[(enable_mbtn_left and 'enable' or 'disable') .. '_key_bindings']('mbtn_left', flags) - self.mbtn_left_enabled = enable_mbtn_left - end - if enable_mbtn_left_dbl ~= self.mbtn_left_dbl_enabled then - mp[(enable_mbtn_left_dbl and 'enable' or 'disable') .. '_key_bindings']('mbtn_left_dbl') - self.mbtn_left_dbl_enabled = enable_mbtn_left_dbl - self:queue_autohide() + local new_levels = {mbtn_left = 0, mbtn_right = 0, wheel = 0} + self.is_dragging_prevented = false + + -- Check global events. + for name, handlers in ipairs(self.handlers) do + local binding = self.event_binding_map[name] + if binding then + new_levels[binding] = #handlers > 0 and 1 or 0 + end end - if enable_mbtn_right ~= self.mbtn_right_enabled then - mp[(enable_mbtn_right and 'enable' or 'disable') .. '_key_bindings']('mbtn_right') - self.mbtn_right_enabled = enable_mbtn_right - self:queue_autohide() + + -- Check zones. + for _, zone in ipairs(self.zones) do + local binding = self.event_binding_map[zone.event] + if binding and cursor:collides_with(zone.hitbox) then + local new_level = (self.window_dragging_blockers[zone.event] and zone.hitbox.window_drag ~= true) and 2 + or math.max(new_levels[binding], zone.hitbox.window_drag == false and 2 or 1) + new_levels[binding] = new_level + if new_level > 1 then + self.is_dragging_prevented = true + end + end end - if enable_wheel ~= self.wheel_enabled then - mp[(enable_wheel and 'enable' or 'disable') .. '_key_bindings']('wheel') - self.wheel_enabled = enable_wheel - self:queue_autohide() + + -- Window dragging only gets prevented when on top of an element, which is when double clicks should be ignored. + new_levels.mbtn_left_dbl = new_levels.mbtn_left == 2 and 2 or 0 + + for name, level in pairs(new_levels) do + if level ~= self.binding_levels[name] then + local flags = level == 1 and 'allow-vo-dragging+allow-hide-cursor' or '' + mp[(level == 0 and 'disable' or 'enable') .. '_key_bindings'](name, flags) + self.binding_levels[name] = level + self:queue_autohide() + end end end @@ -258,9 +336,9 @@ end function cursor:leave() self:move(math.huge, math.huge) end function cursor:is_autohide_allowed() - return options.autohide and (not self.autohide_fs_only or state.fullscreen) and - not (self.mbtn_left_dbl_enabled or self.mbtn_right_enabled or self.wheel_enabled) and - not Menu:is_open() + return options.autohide and (not self.autohide_fs_only or state.fullscreen) + and not self.is_dragging_prevented + and not Menu:is_open() end mp.observe_property('cursor-autohide-fs-only', 'bool', function(_, val) cursor.autohide_fs_only = val end) diff --git a/scripts/uosc/lib/utils.lua b/scripts/uosc/lib/utils.lua index 975af585..41999123 100644 --- a/scripts/uosc/lib/utils.lua +++ b/scripts/uosc/lib/utils.lua @@ -1,7 +1,9 @@ --[[ UI specific utilities that might or might not depend on its state or options ]] ---@alias Point {x: number; y: number} ----@alias Rect {ax: number, ay: number, bx: number, by: number} +---@alias Rect {ax: number, ay: number, bx: number, by: number, window_drag?: boolean} +---@alias Circle {point: Point, r: number, window_drag?: boolean} +---@alias Hitbox Rect|Circle --- In place sorting of filenames ---@param filenames string[] @@ -145,6 +147,13 @@ function get_point_to_point_proximity(point_a, point_b) return math.sqrt(dx * dx + dy * dy) end +---@param point Point +---@param hitbox Hitbox +function point_collides_with(point, hitbox) + return (hitbox.r and get_point_to_point_proximity(point, hitbox.point) <= hitbox.r) or + (not hitbox.r and get_point_to_rectangle_proximity(point, hitbox --[[@as Rect]]) == 0) +end + ---@param lax number ---@param lay number ---@param lbx number @@ -831,6 +840,9 @@ function render() cursor:clear_zones() + -- Click on empty area detection + if setup_click_detection then setup_click_detection() end + -- Actual rendering local ass = assdraw.ass_new() diff --git a/scripts/uosc/main.lua b/scripts/uosc/main.lua index 2f568945..f43aaaba 100644 --- a/scripts/uosc/main.lua +++ b/scripts/uosc/main.lua @@ -593,14 +593,17 @@ if options.click_threshold > 0 then if delta > 0 and delta < click_time and delta > 0.02 then mp.command(options.click_command) end end) click_timer:kill() - mp.set_key_bindings({{'mbtn_left', - function() last_up = mp.get_time() end, - function() - last_down = mp.get_time() - if click_timer:is_enabled() then click_timer:kill() else click_timer:resume() end - end, - }}, 'mouse_movement', 'force') - mp.enable_key_bindings('mouse_movement', 'allow-vo-dragging+allow-hide-cursor') + local function handle_up() last_up = mp.get_time() end + local function handle_down() + last_down = mp.get_time() + if click_timer:is_enabled() then click_timer:kill() else click_timer:resume() end + end + -- If this function exists, it'll be called at the beginning of render(). + function setup_click_detection() + local hitbox = {ax = 0, ay = 0, bx = display.width, by = display.height, window_drag = true} + cursor:zone('primary_down', hitbox, handle_down) + cursor:zone('primary_up', hitbox, handle_up) + end end mp.observe_property('osc', 'bool', function(name, value) if value == true then mp.set_property('osc', 'no') end end)