Search code examples
objective-cmacoscocoakeyboard-eventsnstextfield

Capture the space key in a window containing several NSTextFields


I have a large window with a number of NSTextField fields on it, and I would like to intercept the space bar even while any of the text fields have focus, so that pressing space at any time will cause a separate action.

Subclassing NSTextField and overriding -keyUp: allows me to detect the space key, but a blank is still inserted in the text field. -keyDown: does not fire at all.

For other keys like Return and the arrow keys, I could use the control:textView:doCommandBySelector: delegate method, but it does not fire with the space bar.

There's a lot of advice out there for NSTextView, but I have found none for NSTextField.


Solution

  • Have you experimented with adding an event monitor? You create them via the NSEvent class method addLocalMonitorForEventsMatchingMask(_:handler:) and they give you first dibs on the events you specify. In your case you'd add a monitor for keyDown events, then in the associated block you decide what to do with them. At the end of the block you can return the event just as it arrived, in which case it will behave normally, you can swallow the event (return nil), or you can modify the event by creating a new event object and returning that instead. Here's an example:

    // You can add monitors anywhere - I've chosen the AppDelegate for
    // this simple example.
    - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
        [NSEvent addLocalMonitorForEventsMatchingMask:NSKeyDownMask
                                              handler:^NSEvent * (NSEvent * theEvent) {
    
              if (theEvent.keyCode == 49) {
                  NSLog(@"swallowing spacebar");
                  theEvent = nil;
    
              }
    
              return theEvent;
        }];
    }