Skip to main content
HopTab’s app switcher lets you quickly cycle through your pinned apps using a global keyboard shortcut. Instead of cycling through every open window like macOS’s Cmd+Tab, you only switch between the apps you’ve pinned.

How it works

The app switcher uses a release to activate pattern. When you press the shortcut, an overlay appears showing your pinned apps. Continue holding the modifier key and press the trigger key to cycle through apps. When you release the modifier, the selected app activates.
1

Trigger the switcher

Press your configured shortcut (default: Option + Tab) to show the switcher overlay
2

Cycle through apps

While holding the modifier key, press the trigger key again to move forward through your pinned apps
3

Activate the selected app

Release the modifier key to switch to the currently selected app

Keyboard controls

ActionShortcut
Show switcher & cycle forwardOption + Tab (default)
Cycle backwardShift + Option + Tab
Activate selected appRelease Option
Cancel without switchingEscape

Cycling direction

The app switcher supports bidirectional cycling:
  • Forward: Press the trigger key (e.g., Tab) while holding the modifier
  • Backward: Add Shift to reverse direction (e.g., Shift + Option + Tab)
This is implemented in HotkeyService.swift:196-207:
if isModifierHeld && keyCode == triggerKeyCode {
    let shiftHeld = flags.contains(.maskShift)

    if !isSwitcherActive {
        isSwitcherActive = true
        onSwitcherActivated?()
    } else if shiftHeld {
        onCycleBackward?()
    } else {
        onCycleForward?()
    }
    return nil
}

App activation behavior

When you release the modifier key, HopTab activates the selected app using an aggressive activation strategy to ensure windows come to the front reliably.

Activation sequence

HopTab performs three steps to activate an app (AppSwitcherService.swift:15-31):
1

Unhide the app

If the app is hidden, unhide it first. Hidden apps won’t come to the front otherwise.
2

Activate with ignore other apps

Use activate(options: .activateIgnoringOtherApps) to bring the app forward
3

Raise windows via Accessibility API

Force-raise all windows using AXUIElementPerformAction(window, kAXRaiseAction) to ensure windows appear on top
private static func activateRunning(_ app: NSRunningApplication) {
    // 1. Unhide first — hidden apps won't come to front otherwise
    if app.isHidden {
        app.unhide()
    }

    // 2. Use the older, more aggressive activate API
    app.activate(options: .activateIgnoringOtherApps)

    // 3. Raise the frontmost window via Accessibility API as a fallback
    raiseWindows(of: app)
}
The three-step activation process fixes issues with stubborn apps like Simulator, Terminal, and other utilities that don’t always raise their windows on macOS 14+.

Canceling the switcher

You can cancel the switcher without switching apps:
  • Press Escape while the switcher is visible
  • The overlay closes and focus returns to your current app
Implemented in HotkeyService.swift:226-239:
if keyCode == kVK_Escape {
    if isSwitcherActive {
        isSwitcherActive = false
        isModifierHeld = false
        onSwitcherCancelled?()
        return nil
    }
}

Recent app first (optional)

By default, the switcher starts at the second app in your list when you first trigger it. You can enable recent app first mode to automatically move the last-activated app to the front of the list. When enabled (AppState.swift:264-266):
if recentAppFirst {
    store.moveToFront(bundleIdentifier: selectedApp.bundleIdentifier)
}
This creates an Alt+Tab-style “toggle between last two apps” behavior when you only tap the shortcut once.

Profiles

Create different app sets for different workflows

Keyboard shortcuts

Customize your app switcher shortcut

Build docs developers (and LLMs) love