Files
dttb 265d99b378 Mac dictation: Hammerspoon + Groq Whisper решение
- decisions/2026-05-05-mac-dictation-groq-hammerspoon.md: полный план,
  грабли с раскладкой, fallback на whisper-cpp, восстановление на новом Mac
- notes/ru-geoblocked-services.md: реестр CDN с RU-блоком
  (cdn.spokenly, dl.wisprflow и пр.) + принципы обхода
- snippets/mac-dictation/: рабочая версия скриптов и init.lua

Триггер — одиночный Fn, Groq cloud first → tiny local fallback,
вставка через hs.eventtap.event keycode 9 (минует ru-keymap warnings).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 16:27:17 +03:00

53 lines
2.0 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- Groq Dictate: trigger по одиночному нажатию Fn (Globe)
-- Fn нельзя биндить через hs.hotkey, поэтому слушаем flagsChanged
local SCRIPT = os.getenv("HOME") .. "/bin/groq-dictate.sh"
local function runScript()
hs.task.new("/bin/bash", function(exitCode, stdOut, stdErr)
local f = io.open("/tmp/groq-dictate.last", "r")
if f then
local text = f:read("*a")
f:close()
os.remove("/tmp/groq-dictate.last")
if text and #text > 0 then
hs.pasteboard.setContents(text)
-- keycode 9 = физическая V, в обход keymap lookup чтобы не спамить warnings на ru-раскладке
hs.eventtap.event.newKeyEvent({"cmd"}, 9, true):post()
hs.eventtap.event.newKeyEvent({"cmd"}, 9, false):post()
end
end
end, {SCRIPT}):start()
end
-- Отслеживаем Fn: keycode 63 — это physical Fn/Globe
-- Триггер по press (а не по release), чтобы было снапи
local fnPressed = false
local fnTime = 0
fnTap = hs.eventtap.new({hs.eventtap.event.types.flagsChanged}, function(event)
local kc = event:getKeyCode()
if kc ~= 63 then return false end -- 63 = Fn/Globe
local flags = event:getFlags()
local now = hs.timer.absoluteTime() / 1e6 -- ms
if flags.fn and not fnPressed then
-- Fn pressed
fnPressed = true
fnTime = now
elseif (not flags.fn) and fnPressed then
-- Fn released
fnPressed = false
local elapsed = now - fnTime
-- Только короткое нажатие (<400ms) триггерит — long-press для других целей
if elapsed < 400 then
runScript()
end
end
return false -- не блокировать event для других слушателей
end)
fnTap:start()
hs.alert.show("Groq Dictate: Fn (Globe) ready")