Mousetroke GitHub
Русский ▾
Содержание руководства

Lua API#

Это все функции, которые общая среда выполнения регистрирует в ms. Примеры — операторы для размещения внутри ms_action, где доступны pos, wid, pid, exe, title и mode. Полный скрипт см. в основах Lua, готовые действия — в рецептах.

Соглашения#

Версия Lua: 5.4 (mlua с lua54 и vendored). nil означает отсутствие значения; ? отмечает необязательный параметр. Функции без возвращаемых значений показаны как -> nil. Опущенный необязательный аргумент эквивалентен nil. Для логических аргументов передавайте настоящие логические значения. Целочисленные параметры отсекают конечные дроби к нулю и отвергают значения вне своего базового целочисленного диапазона; в скриптах используйте целые.

Таблицы позиций используют именованные поля {x=..., y=...}, а не элементы массива. Неподдерживаемые вызовы Mac обычно пишут в журнал один раз на функцию на процесс; геттеры возвращают nil, сеттеры ничего не делают. Сеттер без значения — не проверка успеха. Строки Lua API не получают подстановку переменных действия.

Поток выполнения и обратная связь#

ms.log#

ms.log(...) -> nil

Принимает любые значения Lua. При строке формата и дополнительных аргументах поддерживает %s, %d, %f, %q и %%; иначе соединяет значения пробелами. %q не добавляет кавычки Lua. Пишет строку Lua: в журнал среды выполнения на обеих платформах. Не возвращает значения.

ms.log("pid=%d app=%s", pid, exe)

ms.sleep#

ms.sleep(milliseconds: integer) -> nil

Ждёт неотрицательное число миллисекунд (беззнаковое 64-битное). Блокирует рабочий поток этого скрипта на обеих платформах; движок жестов/главный поток продолжает работу. Нет возвращаемого значения и не устанавливается таймаут скрипта.

ms.sleep(100)

ms.is_paused#

ms.is_paused() -> boolean

Без параметров. Возвращает флаг ручной паузы движка на обеих платформах. Не сообщает об автоматическом подавлении полноэкранного режима или исключении программы.

ms.log(ms.is_paused())

ms.set_paused#

ms.set_paused(paused: boolean) -> nil

true ставит на паузу; false возобновляет. Нет возвращаемого значения. Поддерживается на обеих платформах. Windows отправляет команду в поток области уведомлений, поэтому немедленный is_paused() ещё может видеть старое значение. Mac применяет через мост главного потока.

ms.set_paused(true)

ms.show_settings#

ms.show_settings() -> nil

Без параметров и возвращаемого значения. Открывает или выводит на передний план настройки на обеих платформах.

ms.show_settings()

ms.show_toast#

ms.show_toast(message: string, duration_ms?: integer) -> nil

message — отображаемый текст. Необязательная неотрицательная длительность в миллисекундах, по умолчанию 1200. Показывает сообщение-оверлей на обеих платформах; не возвращает значения.

ms.show_toast("Done", 1500)

Клавиатурный ввод#

ms.keys#

ms.keys(sequence: string, text_by_default?: boolean) -> nil

Разбирает и посылает последовательность клавиш; текстовый режим по умолчанию false. Возвращается после отправки; неверный синтаксис вызывает ошибку Lua. Обе платформы поддерживают обычный клавиатурный/текстовый ввод. Mac пропускает неподдерживаемые клавиши, действия мыши и колеса и применяет свои пределы очереди/текста. Он ждёт свою очередь ввода главного потока, в которой могут быть и другие последовательности.

ms.keys("Hello", true)

ms.keys_down#

ms.keys_down(sequence: string) -> nil

Только Windows: разбирает в режиме клавиш и нажимает клавиши/модификаторы без отпускания. Повторы в этой фазе не повторяются; действия колеса срабатывают один раз. Неверный синтаксис вызывает ошибку Lua. Для отпускания сочетайте с keys_up. Mac пишет в журнал «не поддерживается» и ничего не делает. Нет возвращаемого значения.

ms.keys_down("^a")
ms.sleep(50)
ms.keys_up("^a")

ms.keys_up#

ms.keys_up(sequence: string) -> nil

Только Windows: отпускает разобранную последовательность в обратном порядке действий, модификаторы отпускаются последними. Шаги ожидания по-прежнему ждут. Ошибки синтаксиса вызывают ошибку Lua. Mac пишет в журнал «не поддерживается» и ничего не делает. Нет возвращаемого значения.

ms.keys_down("{SHIFT}")
ms.keys_up("{SHIFT}")

ms.is_keys_pressed#

ms.is_keys_pressed(sequence: string) -> boolean | nil

Обе платформы проверяют каждую клавишу и её префиксные модификаторы: "^a" требует Control и A. Любая сторона удовлетворяет префиксу; явные имена вроде {RCTRL} требуют именно эту сторону. На Mac ^ = Control, % = Option, + = Shift и # = Command. Несколько шагов означают, что все перечисленные клавиши/модификаторы должны быть нажаты вместе, а не то, что их нажимали по порядку; повторы ничего не добавляют. Действия мыши/колеса, ожидания или текста делают проверку ложной; пустая последовательность возвращает true. Неверный синтаксис возвращает false. Mac читает объединённое состояние сеанса и без разрешения универсального доступа возвращает false, записав в журнал один раз.

if ms.is_keys_pressed("^a") then
  ms.show_toast("Ctrl and A are down")
end

Буфер обмена и файлы#

ms.get_clipboard_text#

ms.get_clipboard_text() -> string | nil

Без параметров. Возвращает текст буфера обмена или nil, если текст недоступен. Поддерживается на обеих платформах; выделение при этом автоматически не забирается.

local text = ms.get_clipboard_text()
ms.log(text or "No text")

ms.set_clipboard_text#

ms.set_clipboard_text(text: string) -> nil

Заменяет содержимое буфера обмена текстом на обеих платформах; нет возвращаемого значения и флага успеха. Другие форматы буфера обмена не сохраняются. См. рецепты буфера обмена.

ms.set_clipboard_text("Hello from Mousetroke")

ms.read_text#

ms.read_text(path: string) -> string | nil

Читает весь файл как UTF-8 на обеих платформах. Возвращает nil при ошибке чтения или декодирования UTF-8. Относительные пути используют рабочий каталог процесса, а не документированную папку скриптов. Прочитанное учитывается в доступной памяти.

local text = ms.read_text("config.json")
ms.log(text and #text or 0)

Окна#

ms.find_win_by_class#

ms.find_win_by_class(pattern: string) -> table | nil

Ищет видимые окна верхнего уровня по регулярному выражению Rust: в Windows по именам классов, на Mac по ID пакетов приложений (например ^com\\.apple\\.Safari$ в строке Lua). Возвращает до 32 записей в массиве с индексом с 1: {text=title, hwnd=window_id}; нет совпадения или неверное регулярное выражение даёт пустую таблицу. Сопоставление чувствительно к регистру, если шаблон не использует флаг вроде (?i); это не шаблоны Lua. Mac читает заголовки через универсальный доступ, без разрешения возвращает nil и пишет в журнал один раз. Его hwnd — это CGWindowID, принимаемый focus_win и API состояния окна. На Mac ищутся только окна, сейчас находящиеся на экране.

local wins = ms.find_win_by_class("^Notepad$")
if wins and wins[1] then ms.focus_win(wins[1].hwnd) end

ms.find_win_by_title#

ms.find_win_by_title(pattern: string) -> table | nil

Ищет заголовки окон на обеих платформах по регулярному выражению Rust, возвращая те же записи {text, hwnd} с индексом с 1, что и find_win_by_class, не более 32. Неверное регулярное выражение даёт пустую таблицу. Mac использует заголовки окон AX, требует разрешение универсального доступа и ищет только окна, сейчас находящиеся на экране.

local wins = ms.find_win_by_title("(?i)notepad")
if wins then ms.log(#wins) end

ms.focus_win#

ms.focus_win(wid: integer) -> nil

Активирует окно/приложение; нет возвращаемого значения и флага успеха. Windows принимает HWND. Mac принимает цель жеста или найденный CGWindowID, разворачивает свёрнутое и поднимает его AX-окно, затем активирует владеющее приложение через мост главного потока. Вызовы AX на Mac выполняются в рабочем потоке скрипта, повторно используют встроенный поиск окна по PID/границам и требуют разрешение универсального доступа; устаревшие ID или недоступные AX-окна игнорируются. Приложения с одинаковыми перекрывающимися границами окон могут быть неоднозначны.

if wid ~= 0 then ms.focus_win(wid) end

ms.set_win_state#

ms.set_win_state(wid: integer, state: string) -> nil

Windows: "min" сворачивает, "max" разворачивает; любая другая строка восстанавливает, включая "normal" и "norm". Mac: "min" использует AXMinimized; "max" разворачивает/выходит из полноэкранного режима и нажимает тот же AXZoomButton, что и встроенное действие, если окно не заполняет рабочую область своего экрана. "normal", "norm" и "restore" разворачивают/выходят из полноэкранного режима и отменяют масштаб рабочей области. Mac также принимает "fullscreen" через AXFullScreen, если приложение это поддерживает; любое другое имя игнорируется и один раз пишется в журнал. Значения чувствительны к регистру. Нет возвращаемого значения. Mac требует разрешение универсального доступа; AX выполняется в рабочем потоке, геометрия экрана приходит через мост главного потока. Переходы могут быть асинхронными.

Масштаб Mac определяется приложением: масштаб по размеру содержимого может по-прежнему сообщать "normal" и его нельзя надёжно восстановить этим API; повторные запросы "max" могут его переключать. Для таких программ используйте встроенный переключатель Развернуть / восстановить. Универсального публичного флага состояния масштаба AX нет.

if wid ~= 0 then ms.set_win_state(wid, "max") end

ms.get_win_state#

ms.get_win_state(wid: integer) -> string | nil

Windows возвращает "min", "max" или "normal". Это не запрос режима поверх всех и не проверяет устаревший дескриптор; неверный дескриптор может выглядеть как normal. Mac возвращает "min", "fullscreen", "max" (рамка совпадает с рабочей областью экрана в пределах 2 логических точек) или "normal". У Mac нет универсального публичного геттера состояния масштаба AX, поэтому масштаб по размеру содержимого сообщает normal. Возвращает nil при отсутствии разрешения, недоступном AX-окне/состоянии или устаревшем ID; отказ в разрешении пишется в журнал один раз.

if wid ~= 0 then ms.log(ms.get_win_state(wid)) end

ms.set_win_top#

ms.set_win_top(wid: integer, top: boolean) -> nil

Windows устанавливает (true) или снимает (false) режим поверх всех, не перемещая и не меняя размер окна; нет возвращаемого значения. Это задаёт состояние, не переключает его и не возвращает предыдущее. Mac ничего не делает и пишет в журнал один раз: у macOS нет публичного API для закрепления окна другого приложения, и встроенное действие поверх всех также не поддерживается. Для переключения выберите Действия с окном → Поверх всех / отменить в редакторе Windows.

if wid ~= 0 then ms.set_win_top(wid, true) end

Мышь и экран#

ms.get_mouse_pos#

ms.get_mouse_pos() -> table

Без параметров. Обе платформы возвращают {x=integer, y=integer} для текущей позиции курсора, которая может отличаться от входного pos. Windows использует пиксели экрана; Mac использует глобальные логические точки Quartz, Y растёт вниз. Mac возвращает {x=0,y=0}, если запрос курсора не удался.

local p = ms.get_mouse_pos()
ms.log("%d,%d", p.x, p.y)

ms.set_mouse_pos#

ms.set_mouse_pos(x: integer, y: integer) -> nil

Перемещает указатель в глобальные экранные координаты на обеих платформах; нет возвращаемого значения. Координаты могут быть отрицательными. Mac публикует помеченное событие перемещения, чтобы не начать другой жест.

local p = ms.get_mouse_pos()
ms.set_mouse_pos(p.x + 20, p.y)

ms.get_screen#

ms.get_screen(x: integer, y: integer) -> table | nil

Возвращает полный прямоугольник экрана {left, top, right, bottom} как целочисленные глобальные координаты, а не используемую рабочую область. Ширина — right-left; высота — bottom-top. Windows выбирает ближайший монитор, если точка вне всех мониторов. Mac выбирает содержащий дисплей или откатывается к первому кэшированному; может вернуть nil, если нет результата экрана/моста. Обе платформы поддерживают этот вызов.

local p = ms.get_mouse_pos()
local s = ms.get_screen(p.x, p.y)
if s then ms.log(s.right - s.left, s.bottom - s.top) end

ms.get_brightness#

ms.get_brightness(pos?: table) -> integer | nil

Необязательное {x=integer,y=integer} выбирает экран; опущенное/nil или неполная позиция откатывается к текущему курсору. Возвращает 0–100 процентов при успехе, nil при неудаче на любой платформе. Windows использует DDC/CI с запасным путём WMI. WMI использует своё первое устройство яркости, а не монитор, сопоставленный с курсором. Mac сейчас возвращает nil и пишет в журнал один раз: существующий модуль яркости только посылает события клавиш яркости встроенного дисплея, по которым нельзя прочитать процент. Внешний DDC не поддерживается. Только устаревшая обёртка Windows WG.GetBrightness сохраняет -1 при неудаче.

local value = ms.get_brightness()
if value ~= nil then ms.show_toast(tostring(value)) end

ms.set_brightness#

ms.set_brightness(pos: table | nil, delta: integer) -> integer | nil

Несмотря на имя, это изменяет яркость на delta процентных пунктов; абсолютный процент не задаётся. Передайте именованную таблицу {x=...,y=...} или nil как первый аргумент, чтобы использовать курсор. Успех возвращает новый процент 0–100, ограниченный этим диапазоном; неудача возвращает nil на обеих платформах. Windows использует тот же выбор DDC/CI и WMI, что и get_brightness. Только устаревшая обёртка Windows WG.SetBrightness сохраняет -1 при неудаче. Mac возвращает nil и пишет в журнал один раз: существующий модуль «Медиа и система» только посылает клавиши яркости встроенного дисплея, без числового считывания и управления процентными пунктами. Этот вызов Lua яркость не меняет; для клавиш яркости используйте эти встроенные действия. Внешний DDC по-прежнему не поддерживается.

local value = ms.set_brightness(nil, 5)
ms.log(value)

URL и процессы#

ms.open#

ms.open(url: string) -> nil

Открывает URL обработчиком по умолчанию; нет возвращаемого значения и флага успеха. Windows использует shell open и также принимает путь к файлу/папке. Mac ожидает URL; для файла используйте правильно закодированный URL file:// или ms.cmd, чтобы вызвать /usr/bin/open для пути. Подстановка переменных не выполняется.

ms.open("https://mousetroke.com/")

ms.run#

ms.run(file: string, args?: string) -> nil

Запускает с необязательной строкой аргументов, а не массивом Lua; не возвращает значения и PID. Windows использует обычный запуск без повышения прав с поведением RunAgain. Mac принимает ID пакета, путь к приложению или абсолютный путь к исполняемому файлу; аргументы разделяются с учётом кавычек. Запуск исполняемого файла может откатиться к фоновому процессу, если LaunchServices его отклоняет. Запрашивается новый экземпляр. Раскрытия переменных нет; используйте конкатенацию Lua. Вывод процесса не возвращается.

if package.config:sub(1, 1) == "\\" then
  ms.run("cmd.exe", "/K echo Hello")
else
  ms.run("/usr/bin/say", '"Hello from Mousetroke"')
end

ms.cmd#

ms.cmd(command: string) -> nil

Выполняет код оболочки через скрытый cmd.exe /C в Windows или /bin/zsh -c на Mac. Не возвращает значения, вывода и кода выхода и не ждёт завершения процесса. Mac ограничивает одновременно управляемые фоновые процессы 16 и пишет в журнал о завершении. Строки выполняются как переданы; подстановки %MS_*% этим Lua API не раскрываются. Кавычки для аргументов оболочки расставляйте сами.

if package.config:sub(1, 1) == "\\" then
  ms.cmd("taskmgr.exe")
else
  ms.cmd('/usr/bin/open -a "Activity Monitor"')
end

Далее: синтаксис отправки клавиш, рецепты или расположение журналов.

Начните с одного повседневного жеста

Скачайте Mousetroke бесплатно и настройте свой первый жест. Доступны версия для Windows и бета-версия для Mac.