Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Java dispatch KeyEvents?

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.processKeyEvent() 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.)

like image 230
Geoffrey Zheng Avatar asked Oct 14 '10 03:10

Geoffrey Zheng


1 Answers

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:

  1. Set timestamp and modifiers of current event.; Pre-dispatchers. Do any necessary retargeting/reordering here before we notify AWTEventListeners.
  2. Allow the Toolkit to pass this event to AWTEventListeners.
  3. If no one has consumed a key event, allow the KeyboardFocusManager to process it.
  4. Allow input methods to process the event
  5. Pre-process any special events before delivery
  6. Deliver event for normal processing
  7. Special handling for 4061116 : Hook for browser to close modal dialogs.:)
  8. 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.

like image 175
Suraj Chandran Avatar answered Sep 19 '22 15:09

Suraj Chandran