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
Далее: синтаксис отправки клавиш, рецепты или расположение журналов.