I've read the definite tutorial on key bindings a few times, but my brain cache doesn't seem large enough to hold the complicated processes.
I was debugging a key binding problem (turned out I was using the wrong JComponent.WHEN_*
condition), and I stumbled upon a concise and hilarious javadoc for the package private javax.swing.KeyboardManager
by an (unfortunately) anonymous Java engineer.
My question is this: except for KeyEventDispatcher
which is checked at the very beginning, does the description miss and/or mistake anything?
The KeyboardManager class is used to help dispatch keyboard actions for the WHEN_IN_FOCUSED_WINDOW style actions. Actions with other conditions are handled directly in JComponent.
Here's a description of the symantics [sic] of how keyboard dispatching should work atleast [sic] as I understand it.
KeyEvents are dispatched to the focused component. The focus manager gets first crack at processing this event. If the focus manager doesn't want it, then the JComponent calls super.proces开发者_如何学JAVAsKeyEvent() this allows listeners a chance to process the event.
If none of the listeners "consumes" the event then the keybindings get a shot. This is where things start to get interesting. First, KeyStokes [sic] defined with the WHEN_FOCUSED condition get a chance. If none of these want the event, then the component walks though it's [sic] parents looked for actions of type WHEN_ANCESTOR_OF_FOCUSED_COMPONENT.
If no one has taken it yet, then it winds up here. We then look for components registered for WHEN_IN_FOCUSED_WINDOW events and fire to them. Note that if none of those are found then we pass the event to the menubars and let them have a crack at it. They're handled differently.
Lastly, we check if we're looking at an internal frame. If we are and no one wanted the event then we move up to the InternalFrame's creator and see if anyone wants the event (and so on and so on).
(UPDATE) If you've ever wondered about this bold warning in the key bindings guide:
Because the order of searching the components is unpredictable, avoid duplicate WHEN_IN_FOCUSED_WINDOW bindings!
It's because of this segment in KeyboardManager#fireKeyboardAction
:
Object tmp = keyMap.get(ks);
if (tmp == null) {
// don't do anything
} else if ( tmp instanceof JComponent) {
...
} else if ( tmp instanceof Vector) { //more than one comp registered for this
Vector v = (Vector)tmp;
// There is no well defined order for WHEN_IN_FOCUSED_WINDOW
// bindings, but we give precedence to those bindings just
// added. This is done so that JMenus WHEN_IN_FOCUSED_WINDOW
// bindings are accessed before those of the JRootPane (they
// both have a WHEN_IN_FOCUSED_WINDOW binding for enter).
for (int counter = v.size() - 1; counter >= 0; counter--) {
JComponent c = (JComponent)v.elementAt(counter);
//System.out.println("Trying collision: " + c + " vector = "+ v.size());
if ( c.isShowing() && c.isEnabled() ) { // don't want to give these out
fireBinding(c, ks, e, pressed);
if (e.isConsumed())
return true;
}
}
So the order of searching is actually predictable, but obviously dependent on this particular implementation, so it's better not to rely on it at all. Keep it unpredictable.
(Javadoc and code is from jdk1.6.0_b105 on WinXP.)
We need to start debugging from Component.dispatchEventImpl.
Just reading through the source comments of the method should give you the perfect idea of how events flow in Swing(you can also start one level up from EventQueue.pumpEventsForHeirarchy).
For clarity just let me give an extract from the code:
- Set timestamp and modifiers of current event.; Pre-dispatchers. Do any necessary retargeting/reordering here before we notify AWTEventListeners.
- Allow the Toolkit to pass this event to AWTEventListeners.
- If no one has consumed a key event, allow the KeyboardFocusManager to process it.
- Allow input methods to process the event
- Pre-process any special events before delivery
- Deliver event for normal processing
- Special handling for 4061116 : Hook for browser to close modal dialogs.:)
- Allow the peer to process the event. Except KeyEvents, they will be processed by peer after all KeyEventPostProcessors (see DefaultKeyboardFocusManager.dispatchKeyEvent())
Now you can match the above flow with your description to determine whether its right or not. But the point is you should really not depend on javadocs of private classes, the reason being that the developers usually dont care to update the comments of private classes when code changes, so the docs may become obsolete.
精彩评论