How to Handle Shortcut Conflicts in OpenSuperWhisper: Priority System and Resolution

OpenSuperWhisper resolves shortcut conflicts through a strict priority hierarchy where mouse-button hotkeys take precedence over modifier-only keys, which in turn override regular keyboard shortcuts, enforced by mutual exclusion in ShortcutManager.swift.

OpenSuperWhisper, the open-source macOS dictation tool by Starmel, allows users to trigger recordings through three distinct input mechanisms. When multiple hotkey types are configured, the application must prevent simultaneous activation to avoid duplicate recordings or conflicting states. The conflict resolution system is centralized in ShortcutManager.swift, which implements a priority-based mutex ensuring only one recording trigger remains active at any time.

Understanding the Three Hotkey Modes

OpenSuperWhisper supports three activation methods, each managed by separate monitoring components. The application handles shortcut conflicts by strictly prioritizing these modes to prevent overlapping triggers.

Regular Keyboard Shortcuts

The default activation method uses the KeyboardShortcuts library with the identifier KeyboardShortcuts.Name.toggleRecord. Typically bound to ⌥ + \, this mode relies on standard key press and release combinations. When either a modifier-only or mouse-button hotkey is active, this regular shortcut is automatically disabled to prevent conflicts.

Modifier-Only Hotkeys

Users can configure modifier-only hotkeys (such as Left ⌘ or Right ⌥) through the custom ModifierKeyMonitor class. These triggers activate when a specific modifier key is pressed and released without accompanying character keys. This mode takes precedence over regular keyboard shortcuts but yields to mouse-button hotkeys when both are configured.

Mouse-Button Hotkeys

Mouse-button hotkeys provide the highest priority activation method, monitored by MouseButtonMonitor. When configured (for example, Right-click or Middle-click), this mode automatically disables both the regular keyboard shortcut and any modifier-only hotkeys. This ensures that deliberate mouse-based triggering isn't interrupted by accidental keyboard modifier presses.

Conflict Resolution Logic in ShortcutManager.swift

The core conflict resolution implementation resides in OpenSuperWhisper/ShortcutManager.swift. The manager evaluates user preferences and enforces mutual exclusion whenever hotkey settings change.

Preference Lookup and Monitoring

The manager first reads the current configuration from AppPreferences to determine which modes should be active. According to lines 75-77 of ShortcutManager.swift, the initialization checks both modifier and mouse button settings:

let modifierKey = ModifierKey(rawValue: AppPreferences.shared.modifierOnlyHotkey) ?? .none
let mouseButton = MouseButton(rawValue: AppPreferences.shared.mouseButtonHotkey) ?? .none

The setupRecordingTrigger() method (lines 84-119) then evaluates these values to determine which monitoring system to activate.

Mutual Exclusion Enforcement

Before enabling any hotkey mode, the manager explicitly stops all other monitors to guarantee single-mode operation. As implemented in lines 78-83, the system tears down existing monitors before initializing new ones:

ModifierKeyMonitor.shared.stop()
MouseButtonMonitor.shared.stop()

This teardown prevents race conditions where a modifier key release might trigger a recording while a mouse button hotkey is being configured.

Priority Order Handling

The decision hierarchy in setupRecordingTrigger() follows strict precedence rules:

  1. Mouse-button hotkey – If mouseButton != .none, the manager installs the mouse monitor, disables the regular shortcut, and logs the configuration change.
  2. Modifier-only hotkey – If no mouse button is selected but a modifier key is configured, the manager starts ModifierKeyMonitor and disables the regular shortcut.
  3. Regular shortcut – Only when both specialized modes are set to "none" does the KeyboardShortcuts library handle the default toggle.

Both handleKeyDown() and handleKeyUp() methods maintain consistent recording logic regardless of which trigger system is active, ensuring uniform behavior across all input modes.

Dynamic Reconfiguration

The system supports live switching without application restarts. When users modify hotkey preferences in the Settings UI, ShortcutManager observes the .hotkeySettingsChanged notification (registered in lines 30-35) and re-runs setupRecordingTrigger() to re-evaluate the priority hierarchy immediately.

Configuring Hotkeys Without Conflicts

You can programmatically configure hotkey preferences while respecting the conflict resolution system. Changes automatically trigger the priority evaluation in ShortcutManager.

Enabling Mouse-Button Hotkeys

To set a mouse button as the primary trigger (which automatically disables other modes):

// In Settings.swift – when the user selects a mouse button
AppPreferences.shared.mouseButtonHotkey = MouseButton.right.rawValue   // “right” is defined in MouseButton enum
// ShortcutManager will automatically re‑configure on the next notification

Setting Modifier-Only Keys

To configure a modifier-only hotkey (which disables the regular shortcut but defers to mouse buttons):

// In Settings.swift – user selects Left ⌘ as the hot‑key
AppPreferences.shared.modifierOnlyHotkey = ModifierKey.leftCommand.rawValue
// ShortcutManager disables the regular shortcut and starts ModifierKeyMonitor

Resetting to Default Shortcuts

To restore the standard keyboard shortcut and disable specialized modes:

AppPreferences.shared.mouseButtonHotkey = "none"
AppPreferences.shared.modifierOnlyHotkey = "none"
// ShortcutManager falls back to KeyboardShortcuts.toggleRecord

Observing Configuration Changes

Internally, components listen for preference changes to update UI state accordingly:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(hotkeySettingsChanged),
    name: .hotkeySettingsChanged,
    object: nil)

This observer pattern ensures that ContentView.swift and other UI components reflect the current active trigger mode without requiring manual refresh.

Summary

  • Priority hierarchy: Mouse-button hotkeys take precedence over modifier-only keys, which override regular keyboard shortcuts.
  • Mutual exclusion: ShortcutManager.swift stops all monitors before activating a new mode to prevent double-triggering.
  • Dynamic updates: The system re-evaluates conflicts immediately when preferences change via .hotkeySettingsChanged notifications.
  • Consistent handling: handleKeyDown() and handleKeyUp() provide uniform recording logic regardless of the active input method.
  • Configuration storage: AppPreferences.swift persists settings for modifierOnlyHotkey and mouseButtonHotkey, which ShortcutManager reads to resolve conflicts.

Frequently Asked Questions

What happens if I configure both a mouse button and a modifier key shortcut?

The mouse-button hotkey takes absolute precedence. When AppPreferences.shared.mouseButtonHotkey is set to any value other than "none", ShortcutManager automatically disables both the regular keyboard shortcut and the modifier-only monitor. This prevents conflicts where pressing a mouse button might coincide with modifier key presses.

Why does my regular keyboard shortcut stop working when I enable a modifier-only hotkey?

This is the intended behavior according to the conflict resolution logic in ShortcutManager.swift. When a modifier-only hotkey is active, the system disables the standard KeyboardShortcuts.toggleRecord to prevent both triggers from firing simultaneously. The modifier-only key becomes the exclusive recording trigger until you either disable it or configure a mouse-button hotkey (which would then take precedence).

How do I switch back to the default keyboard shortcut after using specialized hotkeys?

Set both preference values to "none" to restore the default behavior:

AppPreferences.shared.mouseButtonHotkey = "none"
AppPreferences.shared.modifierOnlyHotkey = "none"

Once both are reset to "none", ShortcutManager re-enables the regular KeyboardShortcuts library handler for toggle recording.

Can I use multiple hotkeys simultaneously in OpenSuperWhisper?

No, the architecture specifically prevents simultaneous activation. The setupRecordingTrigger() method in ShortcutManager.swift enforces mutual exclusion by stopping all monitors before starting a new one. This design prevents race conditions and ensures that a single physical action cannot trigger multiple recording sessions.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →