Repository navigation
Хоткей коррекции на одиночное нажатие модификатора (например, Control) #16
Copy link
Copy link
Open
Description
Что хочется
Сделать возможным хоткей коррекции из одиночного нажатия модификатора, в первую очередь Control: нажал и отпустил, без других клавиш между ними. Сочетания вроде Ctrl+C и Ctrl+Space должны работать как раньше.
Зачем
- Одна клавиша под мизинцем — самый быстрый способ «исправить последнее слово». Так привыкли пользователи Punto Switcher и Caramba Switcher.
- Комбинации с пробелом печатают символ. Event tap работает в
.listenOnlyи не может проглотить нажатие. Например, Option+Space на macOS вставляет неразрывный пробел. SwitchFix стирает N символов, но первым под удаление попадает этот пробел, и первая буква слова остаётся:ghbdtn→gпривет. Одиночный модификатор ничего не печатает, так что такой проблемы у него нет. - Сейчас так настроить нельзя. Окно настроек не принимает модификатор без основной клавиши, а
KeyboardMonitor.classifyобрабатываетflagsChangedтолько для CapsLock (хоткей отмены).
Как это может работать
- На
flagsChangedлевого или правого Control (keyCode 59/62) с установленным.maskControlи без других модификаторов — «взвести» тап. - Любое другое событие (
keyDown, другой модификатор, клик мышью) — снять взвод. - На отпускании Control: если тап взведён — вернуть
.hotkey.
Прототип, который работает у меня локально. Он включается, когда hotkeyKeyCode == 59, а hotkeyModifiers == 0, и значения выставляются через defaults write, потому что UI их не умеет:
+ // Tap-callback-thread confined: a lone Control press awaiting its release.
+ private var controlTapArmed = false
...
+ private static let leftControlKeyCode: UInt16 = 59
+ private static let rightControlKeyCode: UInt16 = 62
...
) -> CapturedInput.Kind? {
+ let hotkeys = captureState.hotkeyConfiguration()
+ let isControlKey = type == .flagsChanged &&
+ (keyCode == KeyboardMonitor.leftControlKeyCode || keyCode == KeyboardMonitor.rightControlKeyCode)
+ if !isControlKey {
+ controlTapArmed = false
+ }
+ // Hotkey key code = Control: fire on a lone Control tap (press + release with
+ // nothing else in between), so Ctrl+<key> combos keep working as usual.
+ if isControlKey, hotkeys.hotkeyKeyCode == KeyboardMonitor.leftControlKeyCode {
+ if flags.contains(.maskControl) {
+ controlTapArmed = flags.intersection([.maskCommand, .maskAlternate, .maskShift]).isEmpty
+ return nil
+ }
+ let fire = controlTapArmed
+ controlTapArmed = false
+ return fire ? .hotkey : nil
+ }
+
if type == .leftMouseDown || type == .rightMouseDown || type == .otherMouseDown {
return .focusMayChange
}defaults write com.switchfix.app SwitchFix_hotkeyKeyCode -int 59
defaults write com.switchfix.app SwitchFix_hotkeyModifiers -int 0Для полноценной фичи нужно ещё:
- научить окно настроек записывать одиночный модификатор, лучше сразу Control / Option / Shift / Command, с выбором левого, правого или любого;
- отображать такой хоткей в UI, сейчас он показывается некорректно;
- возможно, добавить таймаут: не срабатывать, если Control держали дольше ~0,5 с.
Окружение
SwitchFix v0.0.9 (d31f7b6), macOS 27.0, Apple Silicon, Swift 6.4.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels
Activity
Hantok commentedon Oct 20, 2026
Pre-merge audit against released v0.0.11 and PR #22 (commit 68873cc): not implemented. No fixed release yet.
KeyboardMonitor.classifystill handles modifierflagsChangedevents only for the Caps Lock revert shortcut. The settings recorder also passes through other modifier transitions, so a lone Control/Option/Shift/Command cannot be recorded or triggered.Proposed implementation:
Leaving open. This needs a separate feature change; PR #22 does not address it.