💾 Archived View for ait.place › dot › mpv › .config › mpv › scripts › zones.lua.txt captured on 2022-06-11 at 21:18:39.

View Raw

More Information

⬅️ Previous capture (2021-12-03)

-=-=-=-=-=-=-

--  zones.lua: mpv script for handling commands depending on where the mouse pointer is at,
--             mostly for mouse wheel handling, by configuring it via input.conf, e.g.:
--
--  Ported from avih's ( https://github.com/avih ) zones.js
--
--  Vertical positions can be top, middle, bottom or "*" to represent the whole column.
--  Horizontal positions can be left, middle, bottom or "*" to represent the whole row.
--  If you only use one position, it'll only represent the middle slot of that position.
--    ex: "top" == "top-middle", "right" == "middle-right", "middle" == "middle-middle"
--  "default" will be the fallback command to be used if no command is assigned to that area.
--  "" (empty), "*-*" and "*" are synonyms for "default"
--
--  # input.conf example of use:
--  #    wheel up/down with mouse
-- MOUSE_BTN3 script_message_to zones commands "top-right: add brightness  1" "top: add contrast  1" "*-left: add volume  5" "default: seek  10"
-- MOUSE_BTN4 script_message_to zones commands "top-right: add brightness -1" "top: add contrast -1" "*-left: add volume -5" "default: seek -10"
--
--  # There's no way to get the info directly from each of the keys, so you can use:
-- Ctrl+Alt+Z script_message_to zones info "middle-right: wheel up/down to change brightness" "*-left: wheel up/down to change volume" "default: wheel to seek"
--  # to provide some free-text info which the script can display on hover.
--  # This complicated key combination is suggested so it's not accidentaly pressed.
--  # You can use a simpler input as shortcut:
-- Z  keypress Ctrl+Alt+Z
--  # Or even a zones command in the same way:
--  # e.g. right-click is pause, but let's use top-left to toggle hover-info:
-- MOUSE_BTN2 script_message_to zones commands "default: cycle pause" "top-left: keypress Ctrl+Alt+Z"
--
--  # You can change the two settings below to choose whether the info is shown by default and
--  # which key combination contains the zones info.

local _show_zones_info_by_default = false;
local _zones_key = ""

local ZONE_THRESH_PERCENTAGE = 20;
-- -- sides get 20% each, mid gets 60%, same vertically
local VERT = {'top', 'middle', 'bottom'}
local HORZ = {'left', 'middle', 'right'}

local msg = mp.msg

function getMouseZone()
    -- returns the mouse zone as two strings [top/middle/bottom], [left/middle/right], e.g. "middle", "right"

    local screenW, screenH = mp.get_osd_size()
    local mouseX, mouseY   = mp.get_mouse_pos()

    local threshY = screenH * ZONE_THRESH_PERCENTAGE / 100
    local threshX = screenW * ZONE_THRESH_PERCENTAGE / 100

    local yZone = (mouseY < threshY) and VERT[1] or (mouseY < (screenH - threshY)) and VERT[2] or VERT[3]
    local xZone = (mouseX < threshX) and HORZ[1] or (mouseX < (screenW - threshX)) and HORZ[2] or HORZ[3]

    return yZone, xZone
end

function string:split(sep)
    local sep, key, cmd = sep or ":", nil, nil
    local sep = self:find(sep)
    if sep ~= nil then
        key = self:sub(0,sep-1):gsub("^%s*(.-)%s*$","%1")
        cmd = self:sub(sep+1,-1):gsub("^%s*(.-)%s*$","%1")
    else
        key = self
        cmd = nil
    end
    return key, cmd
end

function getZonesData(list)
    local data = {}
    for _, v in ipairs(list) do
        local sep = v:find(":")
        if sep < 1 or sep == nil then
            msg.warn("Invalid zone description: " .. v)
            msg.warn("Expected: {default|{top|middle|bottom|left|right|*}[-{left|middle|right|*}}]: <command>")
            msg.warn("E.g. \"default: seek 10\" or \"middle-right: add volume 5\"")
        else
            local pos, cmd = v:split()
            posY, posX = pos:split('-')
            if posX == nil and posY ~= "default" and posY ~= "*" and posY ~= "" then
                for _, x in pairs(HORZ) do
                    if posY == x and data['middle-'..x] == nil then
                        data['middle-'..x] = cmd
                    end
                end
                for _, y in pairs(VERT) do
                    if posY == y and data[y..'-middle'] == nil then
                        data[y..'-middle'] = cmd
                    end
                end
            elseif posX == "*" and (posY ~= "*" or posY ~= "") then
                for _, x in pairs(HORZ) do
                    if data[posY..'-'..x] == nil then
                        data[posY..'-'..x] = cmd
                    end
                end
            elseif posY == "*" and (posX ~= "*" or posX ~= "") then
                for _, y in pairs(VERT) do
                    if data[y..'-'..posX] == nil then
                        data[y..'-'..posX] = cmd
                    end
                end
            elseif posX == nil and (posY == "default" or posY == "*" or posY == "") then
                data["default"] = cmd
            else
                data[pos] = cmd
            end
        end
    end
    return data
end

mp.register_script_message("commands", function (...)
    local arg={...}
    msg.debug('commands: \n\t'..table.concat(arg,'\n\t'))

    local keyY, keyX = getMouseZone()
    msg.debug(string.format("mouse at: %s-%s", keyY, keyX))

    local cmd = nil
    local commands = getZonesData(arg)
    local precise = commands[keyY..'-'..keyX]
    local default = commands['default']
    cmd = ( precise ~= nil ) and precise or default

    if cmd ~= nil then
        msg.verbose("running cmd: "..cmd)
        mp.command(cmd)
    else
        msg.debug("no command assigned for "..keyY .. '-' .. keyX)
    end
end)

local timeoutId, lastZone = nil, nil
mp.register_script_message("info", function (...)
    local arg={...}
    local info = {}
    local disp = ''
    if timeoutId == nil then
        timeoutId = mp.add_periodic_timer(0.1, function()
            local keyY, keyX = getMouseZone()
            local zone = keyY..'-'..keyX
            disp = info[zone] or info['default'] or ''
            if zone ~= lastZone then
                mp.osd_message(disp, 3)
            end
            lastZone = zone
        end)
    else
        timeoutId:kill()
        timeoutId = nil
    end
    info = getZonesData(arg)
    local status = (timeoutId ~= nil) and "on" or "off"
    mp.osd_message("zones info: "..status)
end)

if _show_zones_info_by_default then
    mp.command("keypress ".._zones_key)
end