2 * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
27 import java.awt.event.FocusEvent;
28 import java.awt.event.KeyEvent;
29 import java.awt.event.WindowEvent;
30 import java.awt.peer.ComponentPeer;
31 import java.awt.peer.LightweightPeer;
32 import java.lang.ref.WeakReference;
33 import java.util.LinkedList;
34 import java.util.Iterator;
35 import java.util.ListIterator;
38 import sun.util.logging.PlatformLogger;
40 import sun.awt.AppContext;
41 import sun.awt.SunToolkit;
42 import sun.awt.CausedFocusEvent;
45 * The default KeyboardFocusManager for AWT applications. Focus traversal is
46 * done in response to a Component's focus traversal keys, and using a
47 * Container's FocusTraversalPolicy.
50 * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/focus.html">
51 * How to Use the Focus Subsystem</a>,
52 * a section in <em>The Java Tutorial</em>, and the
53 * <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
54 * for more information.
56 * @author David Mendenhall
58 * @see FocusTraversalPolicy
59 * @see Component#setFocusTraversalKeys
60 * @see Component#getFocusTraversalKeys
63 public class DefaultKeyboardFocusManager extends KeyboardFocusManager {
64 private static final PlatformLogger focusLog = PlatformLogger.getLogger("java.awt.focus.DefaultKeyboardFocusManager");
66 // null weak references to not create too many objects
67 private static final WeakReference<Window> NULL_WINDOW_WR =
68 new WeakReference<Window>(null);
69 private static final WeakReference<Component> NULL_COMPONENT_WR =
70 new WeakReference<Component>(null);
71 private WeakReference<Window> realOppositeWindowWR = NULL_WINDOW_WR;
72 private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR;
73 private int inSendMessage;
74 private LinkedList enqueuedKeyEvents = new LinkedList(),
75 typeAheadMarkers = new LinkedList();
76 private boolean consumeNextKeyTyped;
78 private static class TypeAheadMarker {
80 Component untilFocused;
82 TypeAheadMarker(long after, Component untilFocused) {
84 this.untilFocused = untilFocused;
87 * Returns string representation of the marker
89 public String toString() {
90 return ">>> Marker after " + after + " on " + untilFocused;
94 private Window getOwningFrameDialog(Window window) {
95 while (window != null && !(window instanceof Frame ||
96 window instanceof Dialog)) {
97 window = (Window)window.getParent();
103 * This series of restoreFocus methods is used for recovering from a
104 * rejected focus or activation change. Rejections typically occur when
105 * the user attempts to focus a non-focusable Component or Window.
107 private void restoreFocus(FocusEvent fe, Window newFocusedWindow) {
108 Component realOppositeComponent = this.realOppositeComponentWR.get();
109 Component vetoedComponent = fe.getComponent();
111 if (newFocusedWindow != null && restoreFocus(newFocusedWindow,
112 vetoedComponent, false))
114 } else if (realOppositeComponent != null &&
115 doRestoreFocus(realOppositeComponent, vetoedComponent, false)) {
116 } else if (fe.getOppositeComponent() != null &&
117 doRestoreFocus(fe.getOppositeComponent(), vetoedComponent, false)) {
119 clearGlobalFocusOwner();
122 private void restoreFocus(WindowEvent we) {
123 Window realOppositeWindow = this.realOppositeWindowWR.get();
124 if (realOppositeWindow != null
125 && restoreFocus(realOppositeWindow, null, false))
127 // do nothing, everything is done in restoreFocus()
128 } else if (we.getOppositeWindow() != null &&
129 restoreFocus(we.getOppositeWindow(), null, false))
131 // do nothing, everything is done in restoreFocus()
133 clearGlobalFocusOwner();
136 private boolean restoreFocus(Window aWindow, Component vetoedComponent,
137 boolean clearOnFailure) {
139 KeyboardFocusManager.getMostRecentFocusOwner(aWindow);
141 if (toFocus != null && toFocus != vetoedComponent && doRestoreFocus(toFocus, vetoedComponent, false)) {
143 } else if (clearOnFailure) {
144 clearGlobalFocusOwner();
150 private boolean restoreFocus(Component toFocus, boolean clearOnFailure) {
151 return doRestoreFocus(toFocus, null, clearOnFailure);
153 private boolean doRestoreFocus(Component toFocus, Component vetoedComponent,
154 boolean clearOnFailure)
156 if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.canBeFocusOwner() &&
157 toFocus.requestFocus(false, CausedFocusEvent.Cause.ROLLBACK))
161 Component nextFocus = toFocus.getNextFocusCandidate();
162 if (nextFocus != null && nextFocus != vetoedComponent &&
163 nextFocus.requestFocusInWindow(CausedFocusEvent.Cause.ROLLBACK))
166 } else if (clearOnFailure) {
167 clearGlobalFocusOwner();
176 * A special type of SentEvent which updates a counter in the target
177 * KeyboardFocusManager if it is an instance of
178 * DefaultKeyboardFocusManager.
180 private static class DefaultKeyboardFocusManagerSentEvent
186 private static final long serialVersionUID = -2924743257508701758L;
188 public DefaultKeyboardFocusManagerSentEvent(AWTEvent nested,
189 AppContext toNotify) {
190 super(nested, toNotify);
192 public final void dispatch() {
193 KeyboardFocusManager manager =
194 KeyboardFocusManager.getCurrentKeyboardFocusManager();
195 DefaultKeyboardFocusManager defaultManager =
196 (manager instanceof DefaultKeyboardFocusManager)
197 ? (DefaultKeyboardFocusManager)manager
200 if (defaultManager != null) {
201 synchronized (defaultManager) {
202 defaultManager.inSendMessage++;
208 if (defaultManager != null) {
209 synchronized (defaultManager) {
210 defaultManager.inSendMessage--;
217 * Sends a synthetic AWTEvent to a Component. If the Component is in
218 * the current AppContext, then the event is immediately dispatched.
219 * If the Component is in a different AppContext, then the event is
220 * posted to the other AppContext's EventQueue, and this method blocks
221 * until the event is handled or target AppContext is disposed.
222 * Returns true if successfuly dispatched event, false if failed
225 static boolean sendMessage(Component target, AWTEvent e) {
227 AppContext myAppContext = AppContext.getAppContext();
228 final AppContext targetAppContext = target.appContext;
230 new DefaultKeyboardFocusManagerSentEvent(e, myAppContext);
232 if (myAppContext == targetAppContext) {
235 if (targetAppContext.isDisposed()) {
238 SunToolkit.postEvent(targetAppContext, se);
239 if (EventQueue.isDispatchThread()) {
240 EventDispatchThread edt = EventDispatchThread.findCurrent();
241 edt.pumpEvents(SentEvent.ID, new Conditional() {
242 public boolean evaluate() {
243 return !se.dispatched && !targetAppContext.isDisposed();
248 while (!se.dispatched && !targetAppContext.isDisposed()) {
251 } catch (InterruptedException ie) {
258 return se.dispatched;
262 * This method is called by the AWT event dispatcher requesting that the
263 * current KeyboardFocusManager dispatch the specified event on its behalf.
264 * DefaultKeyboardFocusManagers dispatch all FocusEvents, all WindowEvents
265 * related to focus, and all KeyEvents. These events are dispatched based
266 * on the KeyboardFocusManager's notion of the focus owner and the focused
267 * and active Windows, sometimes overriding the source of the specified
268 * AWTEvent. If this method returns <code>false</code>, then the AWT event
269 * dispatcher will attempt to dispatch the event itself.
271 * @param e the AWTEvent to be dispatched
272 * @return <code>true</code> if this method dispatched the event;
273 * <code>false</code> otherwise
275 public boolean dispatchEvent(AWTEvent e) {
276 if (focusLog.isLoggable(PlatformLogger.FINE) && (e instanceof WindowEvent || e instanceof FocusEvent)) focusLog.fine("" + e);
278 case WindowEvent.WINDOW_GAINED_FOCUS: {
279 WindowEvent we = (WindowEvent)e;
280 Window oldFocusedWindow = getGlobalFocusedWindow();
281 Window newFocusedWindow = we.getWindow();
282 if (newFocusedWindow == oldFocusedWindow) {
286 if (!(newFocusedWindow.isFocusableWindow()
287 && newFocusedWindow.isVisible()
288 && newFocusedWindow.isDisplayable()))
290 // we can not accept focus on such window, so reject it.
294 // If there exists a current focused window, then notify it
295 // that it has lost focus.
296 if (oldFocusedWindow != null) {
297 boolean isEventDispatched =
298 sendMessage(oldFocusedWindow,
299 new WindowEvent(oldFocusedWindow,
300 WindowEvent.WINDOW_LOST_FOCUS,
302 // Failed to dispatch, clear by ourselfves
303 if (!isEventDispatched) {
304 setGlobalFocusOwner(null);
305 setGlobalFocusedWindow(null);
309 // Because the native libraries do not post WINDOW_ACTIVATED
310 // events, we need to synthesize one if the active Window
312 Window newActiveWindow =
313 getOwningFrameDialog(newFocusedWindow);
314 Window currentActiveWindow = getGlobalActiveWindow();
315 if (newActiveWindow != currentActiveWindow) {
316 sendMessage(newActiveWindow,
317 new WindowEvent(newActiveWindow,
318 WindowEvent.WINDOW_ACTIVATED,
319 currentActiveWindow));
320 if (newActiveWindow != getGlobalActiveWindow()) {
321 // Activation change was rejected. Unlikely, but
328 setGlobalFocusedWindow(newFocusedWindow);
330 if (newFocusedWindow != getGlobalFocusedWindow()) {
331 // Focus change was rejected. Will happen if
332 // newFocusedWindow is not a focusable Window.
337 // Restore focus to the Component which last held it. We do
338 // this here so that client code can override our choice in
339 // a WINDOW_GAINED_FOCUS handler.
341 // Make sure that the focus change request doesn't change the
342 // focused Window in case we are no longer the focused Window
343 // when the request is handled.
344 if (inSendMessage == 0) {
345 // Identify which Component should initially gain focus
348 // * If we're in SendMessage, then this is a synthetic
349 // WINDOW_GAINED_FOCUS message which was generated by a
350 // the FOCUS_GAINED handler. Allow the Component to
351 // which the FOCUS_GAINED message was targeted to
352 // receive the focus.
353 // * Otherwise, look up the correct Component here.
354 // We don't use Window.getMostRecentFocusOwner because
355 // window is focused now and 'null' will be returned
358 // Calculating of most recent focus owner and focus
359 // request should be synchronized on KeyboardFocusManager.class
360 // to prevent from thread race when user will request
361 // focus between calculation and our request.
362 // But if focus transfer is synchronous, this synchronization
363 // may cause deadlock, thus we don't synchronize this block.
364 Component toFocus = KeyboardFocusManager.
365 getMostRecentFocusOwner(newFocusedWindow);
366 if ((toFocus == null) &&
367 newFocusedWindow.isFocusableWindow())
369 toFocus = newFocusedWindow.getFocusTraversalPolicy().
370 getInitialComponent(newFocusedWindow);
372 Component tempLost = null;
373 synchronized(KeyboardFocusManager.class) {
374 tempLost = newFocusedWindow.setTemporaryLostComponent(null);
377 // The component which last has the focus when this window was focused
378 // should receive focus first
379 if (focusLog.isLoggable(PlatformLogger.FINER)) {
380 focusLog.finer("tempLost {0}, toFocus {1}",
383 if (tempLost != null) {
384 tempLost.requestFocusInWindow(CausedFocusEvent.Cause.ACTIVATION);
387 if (toFocus != null && toFocus != tempLost) {
388 // If there is a component which requested focus when this window
389 // was inactive it expects to receive focus after activation.
390 toFocus.requestFocusInWindow(CausedFocusEvent.Cause.ACTIVATION);
394 Window realOppositeWindow = this.realOppositeWindowWR.get();
395 if (realOppositeWindow != we.getOppositeWindow()) {
396 we = new WindowEvent(newFocusedWindow,
397 WindowEvent.WINDOW_GAINED_FOCUS,
400 return typeAheadAssertions(newFocusedWindow, we);
403 case WindowEvent.WINDOW_ACTIVATED: {
404 WindowEvent we = (WindowEvent)e;
405 Window oldActiveWindow = getGlobalActiveWindow();
406 Window newActiveWindow = we.getWindow();
407 if (oldActiveWindow == newActiveWindow) {
411 // If there exists a current active window, then notify it that
412 // it has lost activation.
413 if (oldActiveWindow != null) {
414 boolean isEventDispatched =
415 sendMessage(oldActiveWindow,
416 new WindowEvent(oldActiveWindow,
417 WindowEvent.WINDOW_DEACTIVATED,
419 // Failed to dispatch, clear by ourselfves
420 if (!isEventDispatched) {
421 setGlobalActiveWindow(null);
423 if (getGlobalActiveWindow() != null) {
424 // Activation change was rejected. Unlikely, but
430 setGlobalActiveWindow(newActiveWindow);
432 if (newActiveWindow != getGlobalActiveWindow()) {
433 // Activation change was rejected. Unlikely, but
438 return typeAheadAssertions(newActiveWindow, we);
441 case FocusEvent.FOCUS_GAINED: {
442 FocusEvent fe = (FocusEvent)e;
443 CausedFocusEvent.Cause cause = (fe instanceof CausedFocusEvent) ?
444 ((CausedFocusEvent)fe).getCause() : CausedFocusEvent.Cause.UNKNOWN;
445 Component oldFocusOwner = getGlobalFocusOwner();
446 Component newFocusOwner = fe.getComponent();
447 if (oldFocusOwner == newFocusOwner) {
448 if (focusLog.isLoggable(PlatformLogger.FINE)) {
449 focusLog.fine("Skipping {0} because focus owner is the same", e);
451 // We can't just drop the event - there could be
452 // type-ahead markers associated with it.
453 dequeueKeyEvents(-1, newFocusOwner);
457 // If there exists a current focus owner, then notify it that
458 // it has lost focus.
459 if (oldFocusOwner != null) {
460 boolean isEventDispatched =
461 sendMessage(oldFocusOwner,
462 new CausedFocusEvent(oldFocusOwner,
463 FocusEvent.FOCUS_LOST,
465 newFocusOwner, cause));
466 // Failed to dispatch, clear by ourselfves
467 if (!isEventDispatched) {
468 setGlobalFocusOwner(null);
469 if (!fe.isTemporary()) {
470 setGlobalPermanentFocusOwner(null);
475 // Because the native windowing system has a different notion
476 // of the current focus and activation states, it is possible
477 // that a Component outside of the focused Window receives a
478 // FOCUS_GAINED event. We synthesize a WINDOW_GAINED_FOCUS
479 // event in that case.
480 final Window newFocusedWindow = SunToolkit.getContainingWindow(newFocusOwner);
481 final Window currentFocusedWindow = getGlobalFocusedWindow();
482 if (newFocusedWindow != null &&
483 newFocusedWindow != currentFocusedWindow)
485 sendMessage(newFocusedWindow,
486 new WindowEvent(newFocusedWindow,
487 WindowEvent.WINDOW_GAINED_FOCUS,
488 currentFocusedWindow));
489 if (newFocusedWindow != getGlobalFocusedWindow()) {
490 // Focus change was rejected. Will happen if
491 // newFocusedWindow is not a focusable Window.
493 // Need to recover type-ahead, but don't bother
494 // restoring focus. That was done by the
495 // WINDOW_GAINED_FOCUS handler
496 dequeueKeyEvents(-1, newFocusOwner);
501 if (!(newFocusOwner.isFocusable() && newFocusOwner.isShowing() &&
502 // Refuse focus on a disabled component if the focus event
503 // isn't of UNKNOWN reason (i.e. not a result of a direct request
504 // but traversal, activation or system generated).
505 (newFocusOwner.isEnabled() || cause.equals(CausedFocusEvent.Cause.UNKNOWN))))
507 // we should not accept focus on such component, so reject it.
508 dequeueKeyEvents(-1, newFocusOwner);
509 if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
510 // If FOCUS_GAINED is for a disposed component (however
511 // it shouldn't happen) its toplevel parent is null. In this
512 // case we have to try to restore focus in the current focused
513 // window (for the details: 6607170).
514 if (newFocusedWindow == null) {
515 restoreFocus(fe, currentFocusedWindow);
517 restoreFocus(fe, newFocusedWindow);
523 setGlobalFocusOwner(newFocusOwner);
525 if (newFocusOwner != getGlobalFocusOwner()) {
526 // Focus change was rejected. Will happen if
527 // newFocusOwner is not focus traversable.
528 dequeueKeyEvents(-1, newFocusOwner);
529 if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
530 restoreFocus(fe, (Window)newFocusedWindow);
535 if (!fe.isTemporary()) {
536 setGlobalPermanentFocusOwner(newFocusOwner);
538 if (newFocusOwner != getGlobalPermanentFocusOwner()) {
539 // Focus change was rejected. Unlikely, but possible.
540 dequeueKeyEvents(-1, newFocusOwner);
541 if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
542 restoreFocus(fe, (Window)newFocusedWindow);
548 setNativeFocusOwner(getHeavyweight(newFocusOwner));
550 Component realOppositeComponent = this.realOppositeComponentWR.get();
551 if (realOppositeComponent != null &&
552 realOppositeComponent != fe.getOppositeComponent()) {
553 fe = new CausedFocusEvent(newFocusOwner,
554 FocusEvent.FOCUS_GAINED,
556 realOppositeComponent, cause);
557 ((AWTEvent) fe).isPosted = true;
559 return typeAheadAssertions(newFocusOwner, fe);
562 case FocusEvent.FOCUS_LOST: {
563 FocusEvent fe = (FocusEvent)e;
564 Component currentFocusOwner = getGlobalFocusOwner();
565 if (currentFocusOwner == null) {
566 if (focusLog.isLoggable(PlatformLogger.FINE))
567 focusLog.fine("Skipping {0} because focus owner is null", e);
570 // Ignore cases where a Component loses focus to itself.
571 // If we make a mistake because of retargeting, then the
572 // FOCUS_GAINED handler will correct it.
573 if (currentFocusOwner == fe.getOppositeComponent()) {
574 if (focusLog.isLoggable(PlatformLogger.FINE))
575 focusLog.fine("Skipping {0} because current focus owner is equal to opposite", e);
579 setGlobalFocusOwner(null);
581 if (getGlobalFocusOwner() != null) {
582 // Focus change was rejected. Unlikely, but possible.
583 restoreFocus(currentFocusOwner, true);
587 if (!fe.isTemporary()) {
588 setGlobalPermanentFocusOwner(null);
590 if (getGlobalPermanentFocusOwner() != null) {
591 // Focus change was rejected. Unlikely, but possible.
592 restoreFocus(currentFocusOwner, true);
596 Window owningWindow = currentFocusOwner.getContainingWindow();
597 if (owningWindow != null) {
598 owningWindow.setTemporaryLostComponent(currentFocusOwner);
602 setNativeFocusOwner(null);
604 fe.setSource(currentFocusOwner);
606 realOppositeComponentWR = (fe.getOppositeComponent() != null)
607 ? new WeakReference<Component>(currentFocusOwner)
610 return typeAheadAssertions(currentFocusOwner, fe);
613 case WindowEvent.WINDOW_DEACTIVATED: {
614 WindowEvent we = (WindowEvent)e;
615 Window currentActiveWindow = getGlobalActiveWindow();
616 if (currentActiveWindow == null) {
620 if (currentActiveWindow != e.getSource()) {
621 // The event is lost in time.
622 // Allow listeners to precess the event but do not
623 // change any global states
627 setGlobalActiveWindow(null);
628 if (getGlobalActiveWindow() != null) {
629 // Activation change was rejected. Unlikely, but possible.
633 we.setSource(currentActiveWindow);
634 return typeAheadAssertions(currentActiveWindow, we);
637 case WindowEvent.WINDOW_LOST_FOCUS: {
638 WindowEvent we = (WindowEvent)e;
639 Window currentFocusedWindow = getGlobalFocusedWindow();
640 Window losingFocusWindow = we.getWindow();
641 Window activeWindow = getGlobalActiveWindow();
642 Window oppositeWindow = we.getOppositeWindow();
643 if (focusLog.isLoggable(PlatformLogger.FINE))
644 focusLog.fine("Active {0}, Current focused {1}, losing focus {2} opposite {3}",
645 activeWindow, currentFocusedWindow,
646 losingFocusWindow, oppositeWindow);
647 if (currentFocusedWindow == null) {
651 // Special case -- if the native windowing system posts an
652 // event claiming that the active Window has lost focus to the
653 // focused Window, then discard the event. This is an artifact
654 // of the native windowing system not knowing which Window is
656 if (inSendMessage == 0 && losingFocusWindow == activeWindow &&
657 oppositeWindow == currentFocusedWindow)
662 Component currentFocusOwner = getGlobalFocusOwner();
663 if (currentFocusOwner != null) {
664 // The focus owner should always receive a FOCUS_LOST event
665 // before the Window is defocused.
666 Component oppositeComp = null;
667 if (oppositeWindow != null) {
668 oppositeComp = oppositeWindow.getTemporaryLostComponent();
669 if (oppositeComp == null) {
670 oppositeComp = oppositeWindow.getMostRecentFocusOwner();
673 if (oppositeComp == null) {
674 oppositeComp = oppositeWindow;
676 sendMessage(currentFocusOwner,
677 new CausedFocusEvent(currentFocusOwner,
678 FocusEvent.FOCUS_LOST,
680 oppositeComp, CausedFocusEvent.Cause.ACTIVATION));
683 setGlobalFocusedWindow(null);
684 if (getGlobalFocusedWindow() != null) {
685 // Focus change was rejected. Unlikely, but possible.
686 restoreFocus(currentFocusedWindow, null, true);
690 we.setSource(currentFocusedWindow);
691 realOppositeWindowWR = (oppositeWindow != null)
692 ? new WeakReference<Window>(currentFocusedWindow)
694 typeAheadAssertions(currentFocusedWindow, we);
696 if (oppositeWindow == null) {
697 // Then we need to deactive the active Window as well.
698 // No need to synthesize in other cases, because
699 // WINDOW_ACTIVATED will handle it if necessary.
700 sendMessage(activeWindow,
701 new WindowEvent(activeWindow,
702 WindowEvent.WINDOW_DEACTIVATED,
704 if (getGlobalActiveWindow() != null) {
705 // Activation change was rejected. Unlikely,
707 restoreFocus(currentFocusedWindow, null, true);
713 case KeyEvent.KEY_TYPED:
714 case KeyEvent.KEY_PRESSED:
715 case KeyEvent.KEY_RELEASED:
716 return typeAheadAssertions(null, e);
726 * Called by <code>dispatchEvent</code> if no other
727 * KeyEventDispatcher in the dispatcher chain dispatched the KeyEvent, or
728 * if no other KeyEventDispatchers are registered. If the event has not
729 * been consumed, its target is enabled, and the focus owner is not null,
730 * this method dispatches the event to its target. This method will also
731 * subsequently dispatch the event to all registered
732 * KeyEventPostProcessors. After all this operations are finished,
733 * the event is passed to peers for processing.
735 * In all cases, this method returns <code>true</code>, since
736 * DefaultKeyboardFocusManager is designed so that neither
737 * <code>dispatchEvent</code>, nor the AWT event dispatcher, should take
738 * further action on the event in any situation.
740 * @param e the KeyEvent to be dispatched
741 * @return <code>true</code>
742 * @see Component#dispatchEvent
744 public boolean dispatchKeyEvent(KeyEvent e) {
745 Component focusOwner = (((AWTEvent)e).isPosted) ? getFocusOwner() : e.getComponent();
747 if (focusOwner != null && focusOwner.isShowing() && focusOwner.canBeFocusOwner()) {
748 if (!e.isConsumed()) {
749 Component comp = e.getComponent();
750 if (comp != null && comp.isEnabled()) {
751 redispatchEvent(comp, e);
755 boolean stopPostProcessing = false;
756 java.util.List processors = getKeyEventPostProcessors();
757 if (processors != null) {
758 for (java.util.Iterator iter = processors.iterator();
759 !stopPostProcessing && iter.hasNext(); )
761 stopPostProcessing = (((KeyEventPostProcessor)(iter.next())).
762 postProcessKeyEvent(e));
765 if (!stopPostProcessing) {
766 postProcessKeyEvent(e);
769 // Allow the peer to process KeyEvent
770 Component source = e.getComponent();
771 ComponentPeer peer = source.getPeer();
773 if (peer == null || peer instanceof LightweightPeer) {
774 // if focus owner is lightweight then its native container
776 Container target = source.getNativeContainer();
777 if (target != null) {
778 peer = target.getPeer();
789 * This method will be called by <code>dispatchKeyEvent</code>. It will
790 * handle any unconsumed KeyEvents that map to an AWT
791 * <code>MenuShortcut</code> by consuming the event and activating the
794 * @param e the KeyEvent to post-process
795 * @return <code>true</code>
796 * @see #dispatchKeyEvent
799 public boolean postProcessKeyEvent(KeyEvent e) {
800 if (!e.isConsumed()) {
801 Component target = e.getComponent();
802 Container p = (Container)
803 (target instanceof Container ? target : target.getParent());
805 p.postProcessKeyEvent(e);
811 private void pumpApprovedKeyEvents() {
815 synchronized (this) {
816 if (enqueuedKeyEvents.size() != 0) {
817 ke = (KeyEvent)enqueuedKeyEvents.getFirst();
818 if (typeAheadMarkers.size() != 0) {
819 TypeAheadMarker marker = (TypeAheadMarker)
820 typeAheadMarkers.getFirst();
821 // Fixed 5064013: may appears that the events have the same time
822 // if (ke.getWhen() >= marker.after) {
823 // The fix is rolled out.
825 if (ke.getWhen() > marker.after) {
830 focusLog.finer("Pumping approved event {0}", ke);
831 enqueuedKeyEvents.removeFirst();
836 preDispatchKeyEvent(ke);
838 } while (ke != null);
842 * Dumps the list of type-ahead queue markers to stderr
845 if (focusLog.isLoggable(PlatformLogger.FINEST)) {
846 focusLog.finest(">>> Markers dump, time: {0}", System.currentTimeMillis());
847 synchronized (this) {
848 if (typeAheadMarkers.size() != 0) {
849 Iterator iter = typeAheadMarkers.iterator();
850 while (iter.hasNext()) {
851 TypeAheadMarker marker = (TypeAheadMarker)iter.next();
852 focusLog.finest(" {0}", marker);
859 private boolean typeAheadAssertions(Component target, AWTEvent e) {
861 // Clear any pending events here as well as in the FOCUS_GAINED
862 // handler. We need this call here in case a marker was removed in
863 // response to a call to dequeueKeyEvents.
864 pumpApprovedKeyEvents();
867 case KeyEvent.KEY_TYPED:
868 case KeyEvent.KEY_PRESSED:
869 case KeyEvent.KEY_RELEASED: {
870 KeyEvent ke = (KeyEvent)e;
871 synchronized (this) {
872 if (e.isPosted && typeAheadMarkers.size() != 0) {
873 TypeAheadMarker marker = (TypeAheadMarker)
874 typeAheadMarkers.getFirst();
875 // Fixed 5064013: may appears that the events have the same time
876 // if (ke.getWhen() >= marker.after) {
877 // The fix is rolled out.
879 if (ke.getWhen() > marker.after) {
880 focusLog.finer("Storing event {0} because of marker {1}", ke, marker);
881 enqueuedKeyEvents.addLast(ke);
887 // KeyEvent was posted before focus change request
888 return preDispatchKeyEvent(ke);
891 case FocusEvent.FOCUS_GAINED:
892 focusLog.finest("Markers before FOCUS_GAINED on {0}", target);
894 // Search the marker list for the first marker tied to
895 // the Component which just gained focus. Then remove
896 // that marker, any markers which immediately follow
897 // and are tied to the same component, and all markers
898 // that preceed it. This handles the case where
899 // multiple focus requests were made for the same
900 // Component in a row and when we lost some of the
901 // earlier requests. Since FOCUS_GAINED events will
902 // not be generated for these additional requests, we
903 // need to clear those markers too.
904 synchronized (this) {
905 boolean found = false;
906 if (hasMarker(target)) {
907 for (Iterator iter = typeAheadMarkers.iterator();
910 if (((TypeAheadMarker)iter.next()).untilFocused ==
920 // Exception condition - event without marker
921 focusLog.finer("Event without marker {0}", e);
924 focusLog.finest("Markers after FOCUS_GAINED");
927 redispatchEvent(target, e);
929 // Now, dispatch any pending KeyEvents which have been
930 // released because of the FOCUS_GAINED event so that we don't
931 // have to wait for another event to be posted to the queue.
932 pumpApprovedKeyEvents();
936 redispatchEvent(target, e);
942 * Returns true if there are some marker associated with component <code>comp</code>
943 * in a markers' queue
946 private boolean hasMarker(Component comp) {
947 for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
948 if (((TypeAheadMarker)iter.next()).untilFocused == comp) {
956 * Clears markers queue
959 void clearMarkers() {
961 typeAheadMarkers.clear();
965 private boolean preDispatchKeyEvent(KeyEvent ke) {
966 if (((AWTEvent) ke).isPosted) {
967 Component focusOwner = getFocusOwner();
968 ke.setSource(((focusOwner != null) ? focusOwner : getFocusedWindow()));
970 if (ke.getSource() == null) {
974 // Explicitly set the current event and most recent timestamp here in
975 // addition to the call in Component.dispatchEventImpl. Because
976 // KeyEvents can be delivered in response to a FOCUS_GAINED event, the
977 // current timestamp may be incorrect. We need to set it here so that
978 // KeyEventDispatchers will use the correct time.
979 EventQueue.setCurrentEventAndMostRecentTime(ke);
983 * This fix allows to correctly dispatch events when native
984 * event proxying mechanism is active.
985 * If it is active we should redispatch key events after
986 * we detected its correct target.
988 if (KeyboardFocusManager.isProxyActive(ke)) {
989 Component source = (Component)ke.getSource();
990 Container target = source.getNativeContainer();
991 if (target != null) {
992 ComponentPeer peer = target.getPeer();
994 peer.handleEvent(ke);
996 * Fix for 4478780 - consume event after it was dispatched by peer.
1004 java.util.List dispatchers = getKeyEventDispatchers();
1005 if (dispatchers != null) {
1006 for (java.util.Iterator iter = dispatchers.iterator();
1009 if (((KeyEventDispatcher)(iter.next())).
1010 dispatchKeyEvent(ke))
1016 return dispatchKeyEvent(ke);
1020 * @param e is a KEY_PRESSED event that can be used
1021 * to track the next KEY_TYPED related.
1023 private void consumeNextKeyTyped(KeyEvent e) {
1024 consumeNextKeyTyped = true;
1027 private void consumeTraversalKey(KeyEvent e) {
1029 consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED) &&
1034 * return true if event was consumed
1036 private boolean consumeProcessedKeyEvent(KeyEvent e) {
1037 if ((e.getID() == KeyEvent.KEY_TYPED) && consumeNextKeyTyped) {
1039 consumeNextKeyTyped = false;
1046 * This method initiates a focus traversal operation if and only if the
1047 * KeyEvent represents a focus traversal key for the specified
1048 * focusedComponent. It is expected that focusedComponent is the current
1049 * focus owner, although this need not be the case. If it is not,
1050 * focus traversal will nevertheless proceed as if focusedComponent
1051 * were the focus owner.
1053 * @param focusedComponent the Component that is the basis for a focus
1054 * traversal operation if the specified event represents a focus
1055 * traversal key for the Component
1056 * @param e the event that may represent a focus traversal key
1058 public void processKeyEvent(Component focusedComponent, KeyEvent e) {
1059 // consume processed event if needed
1060 if (consumeProcessedKeyEvent(e)) {
1064 // KEY_TYPED events cannot be focus traversal keys
1065 if (e.getID() == KeyEvent.KEY_TYPED) {
1069 if (focusedComponent.getFocusTraversalKeysEnabled() &&
1072 AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e),
1073 oppStroke = AWTKeyStroke.getAWTKeyStroke(stroke.getKeyCode(),
1074 stroke.getModifiers(),
1075 !stroke.isOnKeyRelease());
1077 boolean contains, containsOpp;
1079 toTest = focusedComponent.getFocusTraversalKeys(
1080 KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
1081 contains = toTest.contains(stroke);
1082 containsOpp = toTest.contains(oppStroke);
1084 if (contains || containsOpp) {
1085 consumeTraversalKey(e);
1087 focusNextComponent(focusedComponent);
1090 } else if (e.getID() == KeyEvent.KEY_PRESSED) {
1091 // Fix for 6637607: consumeNextKeyTyped should be reset.
1092 consumeNextKeyTyped = false;
1095 toTest = focusedComponent.getFocusTraversalKeys(
1096 KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
1097 contains = toTest.contains(stroke);
1098 containsOpp = toTest.contains(oppStroke);
1100 if (contains || containsOpp) {
1101 consumeTraversalKey(e);
1103 focusPreviousComponent(focusedComponent);
1108 toTest = focusedComponent.getFocusTraversalKeys(
1109 KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
1110 contains = toTest.contains(stroke);
1111 containsOpp = toTest.contains(oppStroke);
1113 if (contains || containsOpp) {
1114 consumeTraversalKey(e);
1116 upFocusCycle(focusedComponent);
1121 if (!((focusedComponent instanceof Container) &&
1122 ((Container)focusedComponent).isFocusCycleRoot())) {
1126 toTest = focusedComponent.getFocusTraversalKeys(
1127 KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
1128 contains = toTest.contains(stroke);
1129 containsOpp = toTest.contains(oppStroke);
1131 if (contains || containsOpp) {
1132 consumeTraversalKey(e);
1134 downFocusCycle((Container)focusedComponent);
1141 * Delays dispatching of KeyEvents until the specified Component becomes
1142 * the focus owner. KeyEvents with timestamps later than the specified
1143 * timestamp will be enqueued until the specified Component receives a
1144 * FOCUS_GAINED event, or the AWT cancels the delay request by invoking
1145 * <code>dequeueKeyEvents</code> or <code>discardKeyEvents</code>.
1147 * @param after timestamp of current event, or the current, system time if
1148 * the current event has no timestamp, or the AWT cannot determine
1149 * which event is currently being handled
1150 * @param untilFocused Component which will receive a FOCUS_GAINED event
1151 * before any pending KeyEvents
1152 * @see #dequeueKeyEvents
1153 * @see #discardKeyEvents
1155 protected synchronized void enqueueKeyEvents(long after,
1156 Component untilFocused) {
1157 if (untilFocused == null) {
1161 focusLog.finer("Enqueue at {0} for {1}",
1162 after, untilFocused);
1164 int insertionIndex = 0,
1165 i = typeAheadMarkers.size();
1166 ListIterator iter = typeAheadMarkers.listIterator(i);
1168 for (; i > 0; i--) {
1169 TypeAheadMarker marker = (TypeAheadMarker)iter.previous();
1170 if (marker.after <= after) {
1176 typeAheadMarkers.add(insertionIndex,
1177 new TypeAheadMarker(after, untilFocused));
1181 * Releases for normal dispatching to the current focus owner all
1182 * KeyEvents which were enqueued because of a call to
1183 * <code>enqueueKeyEvents</code> with the same timestamp and Component.
1184 * If the given timestamp is less than zero, the outstanding enqueue
1185 * request for the given Component with the <b>oldest</b> timestamp (if
1186 * any) should be cancelled.
1188 * @param after the timestamp specified in the call to
1189 * <code>enqueueKeyEvents</code>, or any value < 0
1190 * @param untilFocused the Component specified in the call to
1191 * <code>enqueueKeyEvents</code>
1192 * @see #enqueueKeyEvents
1193 * @see #discardKeyEvents
1195 protected synchronized void dequeueKeyEvents(long after,
1196 Component untilFocused) {
1197 if (untilFocused == null) {
1201 focusLog.finer("Dequeue at {0} for {1}",
1202 after, untilFocused);
1204 TypeAheadMarker marker;
1205 ListIterator iter = typeAheadMarkers.listIterator
1206 ((after >= 0) ? typeAheadMarkers.size() : 0);
1209 while (iter.hasNext()) {
1210 marker = (TypeAheadMarker)iter.next();
1211 if (marker.untilFocused == untilFocused)
1218 while (iter.hasPrevious()) {
1219 marker = (TypeAheadMarker)iter.previous();
1220 if (marker.untilFocused == untilFocused &&
1221 marker.after == after)
1231 * Discards all KeyEvents which were enqueued because of one or more calls
1232 * to <code>enqueueKeyEvents</code> with the specified Component, or one of
1235 * @param comp the Component specified in one or more calls to
1236 * <code>enqueueKeyEvents</code>, or a parent of such a Component
1237 * @see #enqueueKeyEvents
1238 * @see #dequeueKeyEvents
1240 protected synchronized void discardKeyEvents(Component comp) {
1247 for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
1248 TypeAheadMarker marker = (TypeAheadMarker)iter.next();
1249 Component toTest = marker.untilFocused;
1250 boolean match = (toTest == comp);
1251 while (!match && toTest != null && !(toTest instanceof Window)) {
1252 toTest = toTest.getParent();
1253 match = (toTest == comp);
1257 start = marker.after;
1260 } else if (start >= 0) {
1261 purgeStampedEvents(start, marker.after);
1266 purgeStampedEvents(start, -1);
1270 // * must be called inside a synchronized block
1271 // * if 'start' is < 0, then this function does nothing
1272 // * if 'end' is < 0, then all KeyEvents from 'start' to the end of the
1273 // queue will be removed
1274 private void purgeStampedEvents(long start, long end) {
1279 for (Iterator iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {
1280 KeyEvent ke = (KeyEvent)iter.next();
1281 long time = ke.getWhen();
1283 if (start < time && (end < 0 || time <= end)) {
1287 if (end >= 0 && time > end) {
1294 * Focuses the Component before aComponent, typically based on a
1295 * FocusTraversalPolicy.
1297 * @param aComponent the Component that is the basis for the focus
1298 * traversal operation
1299 * @see FocusTraversalPolicy
1300 * @see Component#transferFocusBackward
1302 public void focusPreviousComponent(Component aComponent) {
1303 if (aComponent != null) {
1304 aComponent.transferFocusBackward();
1309 * Focuses the Component after aComponent, typically based on a
1310 * FocusTraversalPolicy.
1312 * @param aComponent the Component that is the basis for the focus
1313 * traversal operation
1314 * @see FocusTraversalPolicy
1315 * @see Component#transferFocus
1317 public void focusNextComponent(Component aComponent) {
1318 if (aComponent != null) {
1319 aComponent.transferFocus();
1324 * Moves the focus up one focus traversal cycle. Typically, the focus owner
1325 * is set to aComponent's focus cycle root, and the current focus cycle
1326 * root is set to the new focus owner's focus cycle root. If, however,
1327 * aComponent's focus cycle root is a Window, then the focus owner is set
1328 * to the focus cycle root's default Component to focus, and the current
1329 * focus cycle root is unchanged.
1331 * @param aComponent the Component that is the basis for the focus
1332 * traversal operation
1333 * @see Component#transferFocusUpCycle
1335 public void upFocusCycle(Component aComponent) {
1336 if (aComponent != null) {
1337 aComponent.transferFocusUpCycle();
1342 * Moves the focus down one focus traversal cycle. If aContainer is a focus
1343 * cycle root, then the focus owner is set to aContainer's default
1344 * Component to focus, and the current focus cycle root is set to
1345 * aContainer. If aContainer is not a focus cycle root, then no focus
1346 * traversal operation occurs.
1348 * @param aContainer the Container that is the basis for the focus
1349 * traversal operation
1350 * @see Container#transferFocusDownCycle
1352 public void downFocusCycle(Container aContainer) {
1353 if (aContainer != null && aContainer.isFocusCycleRoot()) {
1354 aContainer.transferFocusDownCycle();