Преминете към основното съдържание

Горещи клавиши

Модулът hotkeys/ имплементира глобално прихващане на клавишни комбинации за управление на диктовката. Използва GetAsyncKeyState polling вместо RegisterHotKey или low-level keyboard hooks за по-надеждна работа с elevated приложения.

Архитектура

HotkeyEvent enum

pub enum HotkeyEvent {
DictationStart, // Hold mode: натискане
DictationStop, // Hold mode: пускане
DictationToggle, // Toggle mode: натискане
TranslateStart, // Hold mode: натискане (translate hotkey)
TranslateStop, // Hold mode: пускане
TranslateToggle, // Toggle mode: натискане
Quit, // Ctrl+Shift+Q (hardcoded)
}

Режими на диктовка

РежимПоведение
Hold (по подразбиране)Задръж клавишите за запис, пусни за спиране. Изпраща DictationStart при натискане и DictationStop при пускане.
ToggleНатисни веднъж за старт, натисни отново за стоп. Изпраща DictationToggle.

Polling механизъм

Защо polling вместо hooks

  • RegisterHotKey: Не работи когато целевото приложение е elevated (admin)
  • Low-level keyboard hooks (WH_KEYBOARD_LL): Сложна имплементация, изисква message pump
  • GetAsyncKeyState polling: Работи независимо от привилегиите на приложенията, прост за имплементация

Edge detection

Polling-ът отчита промяна на състоянието (edge), не просто натиснато (level):

if pressed && !was_pressed {
// Rising edge: клавишът току-що е натиснат
tx.send(DictationStart);
} else if !pressed && was_pressed && mode == Hold {
// Falling edge: клавишът е пуснат
tx.send(DictationStop);
}
was_pressed = pressed;

HotkeyConfig

pub struct HotkeyConfig {
pub required_modifiers: Vec<Modifier>, // Ctrl, Shift, Alt, Win
pub main_key: MainKey, // Keyboard(vk) или Mouse(btn)
pub mode: DictationMode, // Hold или Toggle
}

Конфигурацията се споделя между main thread и hotkey thread чрез Arc<Mutex<HotkeyConfig>>. Всеки 20ms hotkey thread-ът заключва mutex-а за кратко четене.

Формат на hotkey string

Hotkey комбинациите се записват като +-разделени стрингове:

ctrl+shift+r        // Ctrl+Shift+R
alt+mouse4 // Alt+Mouse4 (back button)
mouse5 // Mouse5 (forward button, без modifier)
win+space // Win+Space
ctrl+shift+alt+f12 // Ctrl+Shift+Alt+F12

Парсване

parse_hotkey("ctrl+shift+r") връща:

  • modifiers: [Ctrl, Shift]
  • main_key: Keyboard(0x52) (VK_R)

Поддържани модификатори: ctrl/control, shift, alt, win/super/meta.

Поддържани главни клавиши:

  • Букви a-z
  • Цифри 0-9
  • F1-F12
  • Специални: space, enter, escape, tab, backspace, insert, delete, home, end, pageup, pagedown, arrows
  • OEM: grave, minus, equals, brackets, backslash, semicolon, quote, comma, period, slash
  • Lock клавиши: capslock, numlock, scrolllock
  • Mouse бутони: mouse1-mouse5

Форматиране

Модификаторите се извеждат в стабилен ред: ctrl, shift, alt, win. Roundtrip parse -> format -> parse е гарантиран.

Virtual Key Mapping

Модулът vk_map.rs предоставя двупосочно преобразуване между Win32 virtual key codes и display стрингове:

  • vk_to_string(0x52) -> "r"
  • str_to_vk("space") -> Some(0x20)
  • vk_to_modifier(0xA0) -> Some(Modifier::Shift) (VK_LSHIFT)

HotkeyRecorder

Механизъм за записване на нова hotkey комбинация от потребителя в Settings панела:

500ms debounce: След натискане на "Record" бутона, системата игнорира входа за 500ms за да не залови самото натискане на бутона.

scan_pressed_key: Сканира всички VK codes (0x08 до 0xFE) и mouse бутони, пропускайки modifier-ите. Първият намерен натиснат клавиш се комбинира с текущите модификатори.

macOS (TODO)

macOS имплементацията е stub. Планирана е чрез rdev crate за CGEvent tap-based глобално прихващане на входа. Изисква Accessibility/Input Monitoring permission.