Unwanted beep when a key is hit
Asked Answered
C

2

6

I have a custom view that accepts key input, its inside a NSScrollView. I have set the acceptsFirstResponder to yes and it is accepting the keyDown successfully. But every time I hit a key, I hear a beep. I'm sure that there something else needed but can't remember what.. Please help.

-(void)keyUp:(NSEvent *)theEvent{

NSLog(@"is first responder %i", self.window.firstResponder == self);

switch (theEvent.keyCode) {
    case KeyCodeEnumBackspace:
    case KeyCodeEnumDelete:
    {
        if (self.scheduleControl.selectedEvent) {
            [self.scheduleControl deleteEvent:self.scheduleControl.selectedEvent];
        }
    }
        break;

    default:
        break;
}
   }
Colonel answered 17/8, 2012 at 17:51 Comment(2)
Did you call [self becomeFirstResponder] in the initialization code of your NSView ?Universe
No, when I click the control it becomes first responder. But just to be sure I checked with the code above if it was a first responder. It is.Colonel
C
9

Got it. The beep occurs at keyDown, not at KeyUp. To remove the beep, I need to handle it, and an empty implementation will suffice. The key is not to pass it to super

- (void)keyDown:(NSEvent *)theEvent {

}

- (void)keyUp:(NSEvent *)theEvent {
    switch (theEvent.keyCode) {
        case KeyCodeEnumBackspace:
        case KeyCodeEnumDelete:
            if (self.scheduleControl.selectedEvent) {
                [self.scheduleControl deleteEvent:self.scheduleControl.selectedEvent];
            }
            break;
        default:
            break;
    }
}
Colonel answered 18/8, 2012 at 19:2 Comment(0)
A
2

Here is my solution as in my case:

STEP 1. Subclass NSViewController and override -performKeyEquivalent(with:) method:

    extension MyViewController {

        override func performKeyEquivalent(with event: NSEvent) -> Bool {
            switch event.modifierFlags.intersection(NSEvent.ModifierFlags.deviceIndependentFlagsMask) {
            case [.command] where event.characters == "\r":
                // do something, and....
                // return a flag that we have handled this key-stroke combination
                return true
            default:
                // otherwise unhandled (by return `false`)
                return false
            }
        }
    }

STEP 2. Setup your controller to observe local events:

    class MyViewController: NSViewController {

        // ...
        // properties and methods...
        // ...

        override func viewDidLoad() {
            super.viewDidLoad()

            _ = NSEvent.addLocalMonitorForEvents(matching: .keyDown) { (event) -> NSEvent? in

                // process the event and get the handled/unhandled flag;
                let isHandled = self.performKeyEquivalent(with: event)

                // stop dispatching this event if handled, or...
                // dispatch it forward to next receiver if unhandled
                return isHandled ? nil : event
            }
        }

        // ...   
    }

What I found is that the error beep is triggered by one of subsequent calls after you dispatched the event in the block. So, to mute the beep, just stop dispatching it by return nil.

Documentation for reference:

Use +addLocal to install an event monitor that receives events before they are dispatched by -[NSApplication sendEvent:]. In this case, your block should either return a valid NSEvent (which may be the same as the incoming NSEvent, or may be a newly created NSEvent) to cause the event to be dispatched, or it may return nil to stop dispatching of the event. Note that your handler will not be called for events that are consumed by nested event-tracking loops such as control tracking, menu tracking, or window dragging; only events that are dispatched through -[NSApplication sendEvent:] will be passed to your handler.

Agglutinin answered 16/9, 2019 at 8:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.