NSTextView Bypasses performKeyEquivalent Check for Backspace and Option-Backspace
Here’s an AppKit quirk I found out this week.
Usually, the NSStandardKeyBindingResponding
protocol declares standard text movement and editing functions like selectWord
or moveToBeginningOfParagraph
or deleteWordForward
. While text view subclasses can just override these to modify the behavior, you can get the same key event handling from any NSResponder
: call interpretKeyEvents(_:)
in its keyDown
implementation, and you’re set.
There’s a dispatcher function, NSStandardKeyBindingResponding.doCommand(by:)
, that is called for all the methods from the protocol. It’s a bottleneck that you can also hook into to pre- or post-process handling these events.
Before you get there, though, the window needs to forward the event to your view, first.
Check out “The Path of Key Events” in Event Architecture, Cocoa Event Handling Guide from the legacy docs, and you’ll see a diagram stating that key equivalents are processed by performKeyEquivalent(_:)
, where a view can state that it wants to do something in response to the event. This is the ‘raw’ key event, way before it’s being processed into e.g. NSStandardKeyBindingResponding
selectors.
In my observation, ⌫ (Backspace) and ⌥+⌫ (Option+Backspace) bypass this in NSTextView
s.
When you hit any of these ‘key equivalents’, you can observe these functions being called in sequence:
doCommand(by:)
deleteBackward(_:)
anddeleteWordBackward(_:)
, respectively.
It’s different for ⌘+⌫ (Command+Backspace), so Backspace being involved is not the problem. Like most key equivalents, it’s processed like this:
performKeyEquivalent(_:)
doCommand(by:)
deleteToBeginningOfLine(_:)
I tried a couple of other NSStandardKeyBindingResponding
shortcuts and all of them are funneled through performKeyEquivalent(_:)
. I haven’t tested all of the methods from this protocol, though.
I have no clue why deleting a character and word with backspace behave this way, but now you know in case you want to bind a menu item to ⌫ or ⌥+⌫ and run into funny behavior.