MASShortcut

repository·master·Indexed 23 days ago

https://github.com/cocoabits/masshortcut

A modern macOS framework for recording, storing, and executing system-wide keyboard shortcuts. It provides a user interface via MASShortcutView for defining shortcuts and an API via MASShortcutBinder to trigger actions. Supports installation via Swift Package Manager, CocoaPods, and Carthage, with compatibility options for the legacy Shortcut Recorder.

Tokens
2.1K
Snippets
7
Records
9
Agent score
32%

What's inside MASShortcut

  1. Identify shortcuts by key code and modifiers instead of strings

    master

    When working with MASShortcut, do not rely on the keyCodeString property to uniquely identify a shortcut. The keyCodeString is sensitive to the user's current keyboard layout and will change if the layout is switched (e.g., a shortcut might return ^2 on a US layout but on a Czech layout).

    To ensure a shortcut's identity remains consistent across different keyboard layouts, you must identify it using its key code and modifiers (e.g., combining a specific key code like kVK_ANSI_2 with a modifier mask like NSControlKeyMask).

  2. Shortcut Recording Rules and Constraints

    master

    When recording shortcuts using the library, the following validation rules apply to ensure compatibility and prevent system conflicts:

    Rejected Shortcuts

    • No Modifiers: Shortcuts consisting of a single key without modifiers (e.g., A, Shift-A) are rejected, unless they are function keys (F1–F20).
    • Esc: A plain Esc keypress without modifiers is rejected and cancels the current recording session.
    • Backspace/Delete: Plain Backspace or Delete keys are rejected, clear any currently recorded shortcut, and cancel the recording.
    • System Conflicts: Shortcuts already reserved by the system (e.g., Cmd-S, Cmd-N) must be rejected.

    Special Handling

    • App/Window Management: Pressing Cmd-W or Cmd-Q cancels the recording and passes the keypress through to the system (to close the window or quit the app).

    Accepted Shortcuts

    • All other combinations are accepted, including function keys (e.g., F16) and combinations like Ctrl-Esc or Cmd-Delete.
  3. Enable Shortcut Recorder compatibility

    master

    By default, MASShortcut uses a storage format incompatible with the legacy Shortcut Recorder. To maintain compatibility and avoid migrating existing shortcuts, follow these two steps:

    1. In Interface Builder: For the MASShortcutView (recorder control) bound to User Defaults, set the Value Transformer field to MASDictionaryTransformer.
    2. In Code: When using MASShortcutBinder to load shortcuts, set the bindingOptions to include the MASDictionaryTransformerName.

    This ensures shortcuts are written and read in the Shortcut Recorder format.

    [[MASShortcutBinder sharedBinder] setBindingOptions:@{NSValueTransformerNameBindingOption:MASDictionaryTransformerName}];
  4. Install MASShortcut via Carthage or Git Submodule

    master
    You can install via Carthage or use Git submodules and link against the MASShortcut framework manually. To build the framework from the command line, use the make release command. The framework will be created in a temporary directory.
    make release
  5. Use MASShortcut in Swift projects

    master

    If using Swift Package Manager, simply use import MASShortcut.

    If using CocoaPods or other methods, you must use a bridging header containing the following imports:

    #import <Cocoa/Cocoa.h>
    #import <MASShortcut/Shortcut.h>
    import MASShortcut
  6. Observe shortcut changes via KVO

    master

    You can react to user shortcut changes by registering for KVO notifications from NSUserDefaultsController. Use the key path format values.[your_preference_key] to observe the specific preference key associated with your shortcut.

    // Declare an ivar for key path in the user defaults controller
    NSString *_observableKeyPath;
        
    // Make a global context reference
    void *kGlobalShortcutContext = &kGlobalShortcutContext;
        
    // Implement when loading view
    _observableKeyPath = [@"values." stringByAppendingString:kPreferenceGlobalShortcut];
    [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:_observableKeyPath
                                                                 options:NSKeyValueObservingOptionInitial
                                                                 context:kGlobalShortcutContext];
    
    // Capture the KVO change and do something
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)obj
                            change:(NSDictionary *)change context:(void *)ctx
    {
        if (ctx == kGlobalShortcutContext) {
            NSLog(@"Shortcut has changed");
        }
        else {
            [super observeValueForKeyPath:keyPath ofObject:obj change:change context:ctx];
        }
    }
    
    // Do not forget to remove the observer
    [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self
                                                                 forKeyPath:_observableKeyPath
                                                                    context:kGlobalShortcutContext];
  7. Use MASShortcut to record and bind shortcuts

    master

    To implement shortcut recording in an Objective-C project:

    1. Add a MASShortcutView to your XIB. Set its class to MASShortcutView and its height to 19 (or check MASShortcutView.h for other appearance styles).
    2. Associate the view with a NSUserDefaults key.
    3. Use MASShortcutBinder to bind that key to a specific action.

    Note: If you installed via methods other than Swift Package Manager, use #import <MASShortcut/Shortcut.h> instead of #import <Shortcut.h>.

    #import <Shortcut.h>
    
    // Drop a custom view into XIB, set its class to MASShortcutView
    // and its height to 19. If you select another appearance style, 
    // look up the correct height values in MASShortcutView.h.
    @property (nonatomic, weak) IBOutlet MASShortcutView *shortcutView;
    
    // Pick a preference key to store the shortcut between launches
    static NSString *const kPreferenceGlobalShortcut = @"GlobalShortcut";
    
    // Associate the shortcut view with user defaults
    self.shortcutView.associatedUserDefaultsKey = kPreferenceGlobalShortcut;
    
    // Associate the preference key with an action
    [[MASShortcutBinder sharedBinder]
        bindShortcutWithDefaultsKey:kPreferenceGlobalShortcut
        toAction:^{
        // Action to execute when shortcut is triggered
    }];