This document describes how keyboard events are handled on OS X. Some of this is common for all three platforms, some of it is specific to OS X.
The central principles behind all design decisions are
Copy all links from my notes, have a version of Apple's diagram with annotations where we intercept and redispatch what.
Cocoa sends all events to -[NSApplication sendEvent:]. The standard implementation of this checks if cmd or ctrl are pressed (of if the key is an arrow key), and if so sends the event via -performKeyEquivalent: down to the window, which does a pre-order traversal of all views in the window and calls -performKeyEquivalent: on every view until a view handles the event. The responder chain is not used during key equivalent processing. If no view handles the event, it is next sent to the menu, then to the key view loop, and if it is not handled by those, down the regular path of key events.
For normal key events, -[NSWindow sendEvent:] is called, which sends -keyDown: to the window's first responder. The first responder either handles the event or forwards it to the next responder in the responder chain.
FOO about pKE being a problem and keyDown: being good.
The first approach I tried was to have -[RenderWidgetHostViewMac performKeyEquivalent:] always return YES for key events that would be handled by the menu (by checking if cmd is down) and then ipc the event that was passed in to the renderers. Other key events would make it through to -keyDown: and be processed correctly through the flow there. If the key comes back unprocessed from the renderer, I passed it to -[NSMenu performKeyEquivalent:] so that it would trigger a menu item. There were several problems: Some keys didn't make it through to -keyDown: (notably, ctrl-tab, which Cocoa swallowed for use in the view loop), and some keys that Cocoa should handle get dropped (for example, cmd-`, which is not handled by the main menu).
The next approach was that -[CrApplication sendEvent:] asks the window if it wants to shortcircuit the event. The window checks if its first responder is a RenderWidgetHostViewMac and if so, sends the key over ipc and tells the application to drop the key. If the key comes back unhandled from the renderer, it is sent to -[NSApp sendEvent:] again (with a flag set that the shortcircuiting mechanism should not be used this time). This will then let cocoa give the key to the menu and handle keyboard shortcuts like cmd-`. (TODO(thakis): Mention that original key events are kept in a queue on the browser side and the original object is used during redispatch).
The current approach is based on -performKeyEquivalent: again, as the sendEvent-based approach disabled input menu toggling if the web page swallowed the key press for that. To work around the problems this approach had on the first try, the event redispatch is kept from the old approach (that maked cmd-` work), and we use an SPI to make sure ctrl-tab is not swallowed by the key view loop handling. (TODO(thakis): Probably, nobody cares about the history? Remove the old two approaches, at least from the main text)
FIXME(thakis): Explain how the shortcut blacklist (cmd-w etc) works.
FIXME(thakis): Explain what isSystemKey keys are.
FIXME(thakis): Explain why there are window-level and browser-level equivalent shortcuts. Talk about global_keyboard_shortcuts_mac, but also about how this being keycode-based sucks.
FIXME(thakis): Explain how keys are IPCd.
FIXME(thakis): Explain why the key needs to go to the menu before going go g_k_s_m and _then_ to [NSApp sendEvent:].
FIXME(thakis): Explain how IME works.
FIXME(thakis): Explain how emacs key bindings are implemented.
TODO(thakis): Split this up into several sections. Possible sections: "Big picture" with subsections Key event interception, IPC, Redispatch. "Gory details" with all the FIXMEs above?
To guard against regressions, the keyboard handling code should be thoroughly unit-tested. As of now, it is not very tested. This section contains a list of interesting keyboard handling bugs, as a list of things to think of when changing the keyboard handling code. I will write tests for all of these once in-process browser tests work.