makgunay/claude-swift-skills

global-hotkeys

System-wide keyboard shortcut registration on macOS using NSEvent monitoring (simple, app-level) and Carbon EventHotKey API (reliable, system-wide). Covers NSEvent.addGlobalMonitorForEvents and addLocalMonitorForEvents, CGEvent tap for keystroke simulation, Carbon RegisterEventHotKey for system-wide hotkeys, modifier flag handling (.deviceIndependentFlagsMask), common key code mappings, debouncing, Accessibility permission requirements (AXIsProcessTrusted), and SwiftUI .onKeyPress for in-app sh…

First seen Feb 14, 2026

Installation

$ npx skills add makgunay/claude-swift-skills --skill global-hotkeys

Summary

  • System-wide keyboard shortcut registration on macOS using NSEvent monitoring (simple, app-level) and Carbon EventHotKey API (reliable, system-wide).
  • Covers NSEvent.addGlobalMonitorForEvents and addLocalMonitorForEvents, CGEvent tap for keystroke simulation, Carbon RegisterEventHotKey for system-wide hotkeys, modifier flag handling (.deviceIndependentFlagsMask), common key code mappings, debouncing, Accessibility permission requirements (AXIsProcessTrusted), and SwiftUI .onKeyPress for in-app shortcuts.
  • Use when implementing global keyboard shortcuts, hotkey-triggered panels, or system-wide key event monitoring.

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from makgunay/claude-swift-skills · top by installs.

npx skills add makgunay/claude-swift-skills

Browse all from makgunay/claude-swift-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 1
License LICENSE
Default branch main
Open issues 0
Status Active

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 5,833 B
  • docs SUMMARY.md 640 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 15 installs

SKILL.md

Global Hotkeys — System-Wide Keyboard Shortcuts

Critical Constraints

  • ❌ DO NOT use only addGlobalMonitorForEvents → ✅ Also add addLocalMonitorForEvents (global doesn't fire when YOUR app is focused)
  • ❌ DO NOT forget Accessibility permission → ✅ Global event monitoring requires AXIsProcessTrusted()
  • ❌ DO NOT compare raw modifierFlags → ✅ Mask with .deviceIndependentFlagsMask first
  • ❌ DO NOT use NSEvent for system-wide hotkeys in sandboxed apps → ✅ Use Carbon RegisterEventHotKey for reliability

Decision Tree

In-app shortcut only?
└── SwiftUI .onKeyPress or .keyboardShortcut

System-wide, non-sandboxed?
├── Simple → NSEvent global + local monitors
└── Reliable → Carbon RegisterEventHotKey

System-wide, sandboxed (App Store)?
└── Carbon RegisterEventHotKey + Accessibility entitlement

Method 1: NSEvent Monitors (Simple)

import AppKit

class HotkeyManager {
    private var globalMonitor: Any?
    private var localMonitor: Any?
    var onHotkey: (() -> Void)?
    var modifiers: NSEvent.ModifierFlags = [.command, .shift]
    var keyCode: UInt16 = 49  // Space

    func start() {
        globalMonitor = NSEvent.addGlobalMonitorForEvents(matching: .keyDown) { [weak self] event in
            self?.handleEvent(event)
        }
        localMonitor = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { [weak self] event in
            self?.handleEvent(event)
            return event
        }
    }

    func stop() {
        if let m = globalMonitor { NSEvent.removeMonitor(m) }
        if let m = localMonitor { NSEvent.removeMonitor(m) }
    }

    private func handleEvent(_ event: NSEvent) {
        let flags = event.modifierFlags.intersection(.deviceIndependentFlagsMask)
        if flags == modifiers && event.keyCode == keyCode {
            DispatchQueue.main.async { self.onHotkey?() }
        }
    }
}

Method 2: Carbon API (Reliable, System-Wide)

import Carbon

class CarbonHotkeyManager {
    private var hotkeyRef: EventHotKeyRef?
    private var eventHandler: EventHandlerRef?
    var onHotkey: (() -> Void)?

    func register(keyCode: UInt32, modifiers: UInt32) {
        unregister()
        var hotkeyID = EventHotKeyID()
        hotkeyID.signature = OSType("HTKY".fourCharCodeValue)
        hotkeyID.id = 1

        var eventType = EventTypeSpec(
            eventClass: OSType(kEventClassKeyboard),
            eventKind: UInt32(kEventHotKeyPressed)
        )

        let handler: EventHandlerUPP = { _, event, userData in
            let mgr = Unmanaged<CarbonHotkeyManager>.fromOpaque(userData!).takeUnretainedValue()
            mgr.onHotkey?()
            return noErr
        }

        InstallEventHandler(GetApplicationEventTarget(), handler, 1, &eventType,
                           Unmanaged.passUnretained(self).toOpaque(), &eventHandler)
        RegisterEventHotKey(keyCode, modifiers, hotkeyID,
                           GetApplicationEventTarget(), 0, &hotkeyRef)
    }

    func unregister() {
        if let ref = hotkeyRef { UnregisterEventHotKey(ref) }
        if let h = eventHandler { RemoveEventHandler(h) }
    }
}

extension String {
    var fourCharCodeValue: FourCharCode {
        utf8.reduce(0) { ($0 << 8) + FourCharCode($1) }
    }
}

Carbon Modifier Constants

// Carbon modifier flags for RegisterEventHotKey
let cmdKey: UInt32    = UInt32(cmdKey)      // 256
let shiftKey: UInt32  = UInt32(shiftKey)    // 512
let optionKey: UInt32 = UInt32(optionKey)   // 2048
let controlKey: UInt32 = UInt32(controlKey) // 4096

// Example: Cmd+Shift+Space
register(keyCode: 49, modifiers: UInt32(cmdKey) | UInt32(shiftKey))

Common Key Codes

Key Code Key Code Key Code
Space 49 Return 36 Escape 53
Tab 48 Delete 51 A 0
S 1 D 2 F 3
J 38 K 40 L 37

SwiftUI In-App Shortcuts

// Keyboard shortcut on button
Button("Save") { save() }
    .keyboardShortcut("s", modifiers: .command)

// Raw key press handler
.onKeyPress(.escape) { dismiss(); return .handled }
.onKeyPress(.upArrow) { moveUp(); return .handled }
.onKeyPress(.downArrow) { moveDown(); return .handled }

Accessibility Permission Check

func checkAccessibilityPermissions() -> Bool {
    let options = [kAXTrustedCheckOptionPrompt.takeRetainedValue() as String: true]
    return AXIsProcessTrustedWithOptions(options as CFDictionary)
}

// Non-prompting check
func isAccessibilityGranted() -> Bool {
    AXIsProcessTrusted()
}

Common Mistakes & Fixes

Mistake Fix
Hotkey works everywhere except own app Add local monitor alongside global monitor
Modifier comparison fails Mask with .deviceIndependentFlagsMask
Hotkey fires twice Debounce with timestamp check (0.3s threshold)
Doesn't work on first launch Check/request Accessibility permission

References