Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unwanted beep when a key is hit

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;
}
   }
like image 597
the Reverend Avatar asked Aug 17 '12 17:08

the Reverend


2 Answers

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;
    }
}
like image 60
the Reverend Avatar answered Nov 18 '22 04:11

the Reverend


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.

like image 44
Ke Yang Avatar answered Nov 18 '22 03:11

Ke Yang