1 /*
2  * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
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.
10  *
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).
16  *
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.
20  *
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
23  * questions.
24  */
25 package java.awt;
26 
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.security.AccessController;
34 import java.security.PrivilegedAction;
35 import java.util.Iterator;
36 import java.util.LinkedList;
37 import java.util.ListIterator;
38 import java.util.Set;
39 
40 import sun.awt.AWTAccessor;
41 import sun.awt.AppContext;
42 import sun.awt.SunToolkit;
43 import sun.awt.TimedWindowEvent;
44 import sun.util.logging.PlatformLogger;
45 
46 /**
47  * The default KeyboardFocusManager for AWT applications. Focus traversal is
48  * done in response to a Component's focus traversal keys, and using a
49  * Container's FocusTraversalPolicy.
50  * <p>
51  * Please see
52  * <a href="https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html">
53  * How to Use the Focus Subsystem</a>,
54  * a section in <em>The Java Tutorial</em>, and the
55  * <a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
56  * for more information.
57  *
58  * @author David Mendenhall
59  *
60  * @see FocusTraversalPolicy
61  * @see Component#setFocusTraversalKeys
62  * @see Component#getFocusTraversalKeys
63  * @since 1.4
64  */
65 public class DefaultKeyboardFocusManager extends KeyboardFocusManager {
66     private static final PlatformLogger focusLog = PlatformLogger.getLogger("java.awt.focus.DefaultKeyboardFocusManager");
67 
68     // null weak references to not create too many objects
69     private static final WeakReference<Window> NULL_WINDOW_WR =
70         new WeakReference<Window>(null);
71     private static final WeakReference<Component> NULL_COMPONENT_WR =
72         new WeakReference<Component>(null);
73     private WeakReference<Window> realOppositeWindowWR = NULL_WINDOW_WR;
74     private WeakReference<Component> realOppositeComponentWR = NULL_COMPONENT_WR;
75     private int inSendMessage;
76     private LinkedList<KeyEvent> enqueuedKeyEvents = new LinkedList<KeyEvent>();
77     private LinkedList<TypeAheadMarker> typeAheadMarkers = new LinkedList<TypeAheadMarker>();
78     private boolean consumeNextKeyTyped;
79     private Component restoreFocusTo;
80 
81     private static boolean fxAppThreadIsDispatchThread;
82 
83     static {
AWTAccessor.setDefaultKeyboardFocusManagerAccessor( new AWTAccessor.DefaultKeyboardFocusManagerAccessor() { public void consumeNextKeyTyped(DefaultKeyboardFocusManager dkfm, KeyEvent e) { dkfm.consumeNextKeyTyped(e); } })84         AWTAccessor.setDefaultKeyboardFocusManagerAccessor(
85             new AWTAccessor.DefaultKeyboardFocusManagerAccessor() {
86                 public void consumeNextKeyTyped(DefaultKeyboardFocusManager dkfm, KeyEvent e) {
87                     dkfm.consumeNextKeyTyped(e);
88                 }
89             });
AccessController.doPrivileged(new PrivilegedAction<Object>() { public Object run() { fxAppThreadIsDispatchThread = R.equals(System.getProperty(R)); return null; } })90         AccessController.doPrivileged(new PrivilegedAction<Object>() {
91             public Object run() {
92                 fxAppThreadIsDispatchThread =
93                         "true".equals(System.getProperty("javafx.embed.singleThread"));
94                 return null;
95             }
96         });
97     }
98 
99     private static class TypeAheadMarker {
100         long after;
101         Component untilFocused;
102 
TypeAheadMarker(long after, Component untilFocused)103         TypeAheadMarker(long after, Component untilFocused) {
104             this.after = after;
105             this.untilFocused = untilFocused;
106         }
107         /**
108          * Returns string representation of the marker
109          */
toString()110         public String toString() {
111             return ">>> Marker after " + after + " on " + untilFocused;
112         }
113     }
114 
getOwningFrameDialog(Window window)115     private Window getOwningFrameDialog(Window window) {
116         while (window != null && !(window instanceof Frame ||
117                                    window instanceof Dialog)) {
118             window = (Window)window.getParent();
119         }
120         return window;
121     }
122 
123     /*
124      * This series of restoreFocus methods is used for recovering from a
125      * rejected focus or activation change. Rejections typically occur when
126      * the user attempts to focus a non-focusable Component or Window.
127      */
restoreFocus(FocusEvent fe, Window newFocusedWindow)128     private void restoreFocus(FocusEvent fe, Window newFocusedWindow) {
129         Component realOppositeComponent = this.realOppositeComponentWR.get();
130         Component vetoedComponent = fe.getComponent();
131 
132         if (newFocusedWindow != null && restoreFocus(newFocusedWindow,
133                                                      vetoedComponent, false))
134         {
135         } else if (realOppositeComponent != null &&
136                    doRestoreFocus(realOppositeComponent, vetoedComponent, false)) {
137         } else if (fe.getOppositeComponent() != null &&
138                    doRestoreFocus(fe.getOppositeComponent(), vetoedComponent, false)) {
139         } else {
140             clearGlobalFocusOwnerPriv();
141         }
142     }
restoreFocus(WindowEvent we)143     private void restoreFocus(WindowEvent we) {
144         Window realOppositeWindow = this.realOppositeWindowWR.get();
145         if (realOppositeWindow != null
146             && restoreFocus(realOppositeWindow, null, false))
147         {
148             // do nothing, everything is done in restoreFocus()
149         } else if (we.getOppositeWindow() != null &&
150                    restoreFocus(we.getOppositeWindow(), null, false))
151         {
152             // do nothing, everything is done in restoreFocus()
153         } else {
154             clearGlobalFocusOwnerPriv();
155         }
156     }
restoreFocus(Window aWindow, Component vetoedComponent, boolean clearOnFailure)157     private boolean restoreFocus(Window aWindow, Component vetoedComponent,
158                                  boolean clearOnFailure) {
159         restoreFocusTo = null;
160         Component toFocus =
161             KeyboardFocusManager.getMostRecentFocusOwner(aWindow);
162 
163         if (toFocus != null && toFocus != vetoedComponent) {
164             if (getHeavyweight(aWindow) != getNativeFocusOwner()) {
165                 // cannot restore focus synchronously
166                 if (!toFocus.isShowing() || !toFocus.canBeFocusOwner()) {
167                     toFocus = toFocus.getNextFocusCandidate();
168                 }
169                 if (toFocus != null && toFocus != vetoedComponent) {
170                     if (!toFocus.requestFocus(false,
171                                                    FocusEvent.Cause.ROLLBACK)) {
172                         restoreFocusTo = toFocus;
173                     }
174                     return true;
175                 }
176             } else if (doRestoreFocus(toFocus, vetoedComponent, false)) {
177                 return true;
178             }
179         }
180         if (clearOnFailure) {
181             clearGlobalFocusOwnerPriv();
182             return true;
183         } else {
184             return false;
185         }
186     }
restoreFocus(Component toFocus, boolean clearOnFailure)187     private boolean restoreFocus(Component toFocus, boolean clearOnFailure) {
188         return doRestoreFocus(toFocus, null, clearOnFailure);
189     }
doRestoreFocus(Component toFocus, Component vetoedComponent, boolean clearOnFailure)190     private boolean doRestoreFocus(Component toFocus, Component vetoedComponent,
191                                    boolean clearOnFailure)
192     {
193         boolean success = true;
194         if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.canBeFocusOwner() &&
195             (success = toFocus.requestFocus(false, FocusEvent.Cause.ROLLBACK)))
196         {
197             return true;
198         } else {
199             if (!success && getGlobalFocusedWindow() != SunToolkit.getContainingWindow(toFocus)) {
200                 restoreFocusTo = toFocus;
201                 return true;
202             }
203             Component nextFocus = toFocus.getNextFocusCandidate();
204             if (nextFocus != null && nextFocus != vetoedComponent &&
205                 nextFocus.requestFocusInWindow(FocusEvent.Cause.ROLLBACK))
206             {
207                 return true;
208             } else if (clearOnFailure) {
209                 clearGlobalFocusOwnerPriv();
210                 return true;
211             } else {
212                 return false;
213             }
214         }
215     }
216 
217     /**
218      * A special type of SentEvent which updates a counter in the target
219      * KeyboardFocusManager if it is an instance of
220      * DefaultKeyboardFocusManager.
221      */
222     private static class DefaultKeyboardFocusManagerSentEvent
223         extends SentEvent
224     {
225         /*
226          * serialVersionUID
227          */
228         private static final long serialVersionUID = -2924743257508701758L;
229 
DefaultKeyboardFocusManagerSentEvent(AWTEvent nested, AppContext toNotify)230         public DefaultKeyboardFocusManagerSentEvent(AWTEvent nested,
231                                                     AppContext toNotify) {
232             super(nested, toNotify);
233         }
dispatch()234         public final void dispatch() {
235             KeyboardFocusManager manager =
236                 KeyboardFocusManager.getCurrentKeyboardFocusManager();
237             DefaultKeyboardFocusManager defaultManager =
238                 (manager instanceof DefaultKeyboardFocusManager)
239                 ? (DefaultKeyboardFocusManager)manager
240                 : null;
241 
242             if (defaultManager != null) {
243                 synchronized (defaultManager) {
244                     defaultManager.inSendMessage++;
245                 }
246             }
247 
248             super.dispatch();
249 
250             if (defaultManager != null) {
251                 synchronized (defaultManager) {
252                     defaultManager.inSendMessage--;
253                 }
254             }
255         }
256     }
257 
258     /**
259      * Sends a synthetic AWTEvent to a Component. If the Component is in
260      * the current AppContext, then the event is immediately dispatched.
261      * If the Component is in a different AppContext, then the event is
262      * posted to the other AppContext's EventQueue, and this method blocks
263      * until the event is handled or target AppContext is disposed.
264      * Returns true if successfully dispatched event, false if failed
265      * to dispatch.
266      */
sendMessage(Component target, AWTEvent e)267     static boolean sendMessage(Component target, AWTEvent e) {
268         e.isPosted = true;
269         AppContext myAppContext = AppContext.getAppContext();
270         final AppContext targetAppContext = target.appContext;
271         final SentEvent se =
272             new DefaultKeyboardFocusManagerSentEvent(e, myAppContext);
273 
274         if (myAppContext == targetAppContext) {
275             se.dispatch();
276         } else {
277             if (targetAppContext.isDisposed()) {
278                 return false;
279             }
280             SunToolkit.postEvent(targetAppContext, se);
281             if (EventQueue.isDispatchThread()) {
282                 if (Thread.currentThread() instanceof EventDispatchThread) {
283                     EventDispatchThread edt = (EventDispatchThread)
284                             Thread.currentThread();
285                     edt.pumpEvents(SentEvent.ID, new Conditional() {
286                         public boolean evaluate() {
287                             return !se.dispatched && !targetAppContext.isDisposed();
288                         }
289                     });
290                 } else {
291                     if (fxAppThreadIsDispatchThread) {
292                         Thread fxCheckDispatchThread = new Thread() {
293                             @Override
294                             public void run() {
295                                 while (!se.dispatched && !targetAppContext.isDisposed()) {
296                                     try {
297                                         Thread.sleep(100);
298                                     } catch (InterruptedException e) {
299                                         break;
300                                     }
301                                 }
302                             }
303                         };
304                         fxCheckDispatchThread.start();
305                         try {
306                             // check if event is dispatched or disposed
307                             // but since this user app thread is same as
308                             // dispatch thread in fx when run with
309                             // javafx.embed.singleThread=true
310                             // we do not wait infinitely to avoid deadlock
311                             // as dispatch will ultimately be done by this thread
312                             fxCheckDispatchThread.join(500);
313                         } catch (InterruptedException ex) {
314                         }
315                     }
316                 }
317             } else {
318                 synchronized (se) {
319                     while (!se.dispatched && !targetAppContext.isDisposed()) {
320                         try {
321                             se.wait(1000);
322                         } catch (InterruptedException ie) {
323                             break;
324                         }
325                     }
326                 }
327             }
328         }
329         return se.dispatched;
330     }
331 
332     /*
333      * Checks if the focus window event follows key events waiting in the type-ahead
334      * queue (if any). This may happen when a user types ahead in the window, the client
335      * listeners hang EDT for a while, and the user switches b/w toplevels. In that
336      * case the focus window events may be dispatched before the type-ahead events
337      * get handled. This may lead to wrong focus behavior and in order to avoid it,
338      * the focus window events are reposted to the end of the event queue. See 6981400.
339      */
repostIfFollowsKeyEvents(WindowEvent e)340     private boolean repostIfFollowsKeyEvents(WindowEvent e) {
341         if (!(e instanceof TimedWindowEvent)) {
342             return false;
343         }
344         TimedWindowEvent we = (TimedWindowEvent)e;
345         long time = we.getWhen();
346         synchronized (this) {
347             KeyEvent ke = enqueuedKeyEvents.isEmpty() ? null : enqueuedKeyEvents.getFirst();
348             if (ke != null && time >= ke.getWhen()) {
349                 TypeAheadMarker marker = typeAheadMarkers.isEmpty() ? null : typeAheadMarkers.getFirst();
350                 if (marker != null) {
351                     Window toplevel = marker.untilFocused.getContainingWindow();
352                     // Check that the component awaiting focus belongs to
353                     // the current focused window. See 8015454.
354                     if (toplevel != null && toplevel.isFocused()) {
355                         SunToolkit.postEvent(AppContext.getAppContext(), new SequencedEvent(e));
356                         return true;
357                     }
358                 }
359             }
360         }
361         return false;
362     }
363 
364     /**
365      * This method is called by the AWT event dispatcher requesting that the
366      * current KeyboardFocusManager dispatch the specified event on its behalf.
367      * DefaultKeyboardFocusManagers dispatch all FocusEvents, all WindowEvents
368      * related to focus, and all KeyEvents. These events are dispatched based
369      * on the KeyboardFocusManager's notion of the focus owner and the focused
370      * and active Windows, sometimes overriding the source of the specified
371      * AWTEvent. If this method returns {@code false}, then the AWT event
372      * dispatcher will attempt to dispatch the event itself.
373      *
374      * @param e the AWTEvent to be dispatched
375      * @return {@code true} if this method dispatched the event;
376      *         {@code false} otherwise
377      */
dispatchEvent(AWTEvent e)378     public boolean dispatchEvent(AWTEvent e) {
379         if (focusLog.isLoggable(PlatformLogger.Level.FINE) && (e instanceof WindowEvent || e instanceof FocusEvent)) {
380             focusLog.fine("" + e);
381         }
382         switch (e.getID()) {
383             case WindowEvent.WINDOW_GAINED_FOCUS: {
384                 if (repostIfFollowsKeyEvents((WindowEvent)e)) {
385                     break;
386                 }
387 
388                 WindowEvent we = (WindowEvent)e;
389                 Window oldFocusedWindow = getGlobalFocusedWindow();
390                 Window newFocusedWindow = we.getWindow();
391                 if (newFocusedWindow == oldFocusedWindow) {
392                     break;
393                 }
394 
395                 if (!(newFocusedWindow.isFocusableWindow()
396                       && newFocusedWindow.isVisible()
397                       && newFocusedWindow.isDisplayable()))
398                 {
399                     // we can not accept focus on such window, so reject it.
400                     restoreFocus(we);
401                     break;
402                 }
403                 // If there exists a current focused window, then notify it
404                 // that it has lost focus.
405                 if (oldFocusedWindow != null) {
406                     boolean isEventDispatched =
407                         sendMessage(oldFocusedWindow,
408                                 new WindowEvent(oldFocusedWindow,
409                                                 WindowEvent.WINDOW_LOST_FOCUS,
410                                                 newFocusedWindow));
411                     // Failed to dispatch, clear by ourselves
412                     if (!isEventDispatched) {
413                         setGlobalFocusOwner(null);
414                         setGlobalFocusedWindow(null);
415                     }
416                 }
417 
418                 // Because the native libraries do not post WINDOW_ACTIVATED
419                 // events, we need to synthesize one if the active Window
420                 // changed.
421                 Window newActiveWindow =
422                     getOwningFrameDialog(newFocusedWindow);
423                 Window currentActiveWindow = getGlobalActiveWindow();
424                 if (newActiveWindow != currentActiveWindow) {
425                     sendMessage(newActiveWindow,
426                                 new WindowEvent(newActiveWindow,
427                                                 WindowEvent.WINDOW_ACTIVATED,
428                                                 currentActiveWindow));
429                     if (newActiveWindow != getGlobalActiveWindow()) {
430                         // Activation change was rejected. Unlikely, but
431                         // possible.
432                         restoreFocus(we);
433                         break;
434                     }
435                 }
436 
437                 setGlobalFocusedWindow(newFocusedWindow);
438 
439                 if (newFocusedWindow != getGlobalFocusedWindow()) {
440                     // Focus change was rejected. Will happen if
441                     // newFocusedWindow is not a focusable Window.
442                     restoreFocus(we);
443                     break;
444                 }
445 
446                 // Restore focus to the Component which last held it. We do
447                 // this here so that client code can override our choice in
448                 // a WINDOW_GAINED_FOCUS handler.
449                 //
450                 // Make sure that the focus change request doesn't change the
451                 // focused Window in case we are no longer the focused Window
452                 // when the request is handled.
453                 if (inSendMessage == 0) {
454                     // Identify which Component should initially gain focus
455                     // in the Window.
456                     //
457                     // * If we're in SendMessage, then this is a synthetic
458                     //   WINDOW_GAINED_FOCUS message which was generated by a
459                     //   the FOCUS_GAINED handler. Allow the Component to
460                     //   which the FOCUS_GAINED message was targeted to
461                     //   receive the focus.
462                     // * Otherwise, look up the correct Component here.
463                     //   We don't use Window.getMostRecentFocusOwner because
464                     //   window is focused now and 'null' will be returned
465 
466 
467                     // Calculating of most recent focus owner and focus
468                     // request should be synchronized on KeyboardFocusManager.class
469                     // to prevent from thread race when user will request
470                     // focus between calculation and our request.
471                     // But if focus transfer is synchronous, this synchronization
472                     // may cause deadlock, thus we don't synchronize this block.
473                     Component toFocus = KeyboardFocusManager.
474                         getMostRecentFocusOwner(newFocusedWindow);
475                     boolean isFocusRestore = restoreFocusTo != null &&
476                                                       toFocus == restoreFocusTo;
477                     if ((toFocus == null) &&
478                         newFocusedWindow.isFocusableWindow())
479                     {
480                         toFocus = newFocusedWindow.getFocusTraversalPolicy().
481                             getInitialComponent(newFocusedWindow);
482                     }
483                     Component tempLost = null;
484                     synchronized(KeyboardFocusManager.class) {
485                         tempLost = newFocusedWindow.setTemporaryLostComponent(null);
486                     }
487 
488                     // The component which last has the focus when this window was focused
489                     // should receive focus first
490                     if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
491                         focusLog.finer("tempLost {0}, toFocus {1}",
492                                        tempLost, toFocus);
493                     }
494                     if (tempLost != null) {
495                         tempLost.requestFocusInWindow(
496                                     isFocusRestore && tempLost == toFocus ?
497                                                 FocusEvent.Cause.ROLLBACK :
498                                                 FocusEvent.Cause.ACTIVATION);
499                     }
500 
501                     if (toFocus != null && toFocus != tempLost) {
502                         // If there is a component which requested focus when this window
503                         // was inactive it expects to receive focus after activation.
504                         toFocus.requestFocusInWindow(FocusEvent.Cause.ACTIVATION);
505                     }
506                 }
507                 restoreFocusTo = null;
508 
509                 Window realOppositeWindow = this.realOppositeWindowWR.get();
510                 if (realOppositeWindow != we.getOppositeWindow()) {
511                     we = new WindowEvent(newFocusedWindow,
512                                          WindowEvent.WINDOW_GAINED_FOCUS,
513                                          realOppositeWindow);
514                 }
515                 return typeAheadAssertions(newFocusedWindow, we);
516             }
517 
518             case WindowEvent.WINDOW_ACTIVATED: {
519                 WindowEvent we = (WindowEvent)e;
520                 Window oldActiveWindow = getGlobalActiveWindow();
521                 Window newActiveWindow = we.getWindow();
522                 if (oldActiveWindow == newActiveWindow) {
523                     break;
524                 }
525 
526                 // If there exists a current active window, then notify it that
527                 // it has lost activation.
528                 if (oldActiveWindow != null) {
529                     boolean isEventDispatched =
530                         sendMessage(oldActiveWindow,
531                                 new WindowEvent(oldActiveWindow,
532                                                 WindowEvent.WINDOW_DEACTIVATED,
533                                                 newActiveWindow));
534                     // Failed to dispatch, clear by ourselves
535                     if (!isEventDispatched) {
536                         setGlobalActiveWindow(null);
537                     }
538                     if (getGlobalActiveWindow() != null) {
539                         // Activation change was rejected. Unlikely, but
540                         // possible.
541                         break;
542                     }
543                 }
544 
545                 setGlobalActiveWindow(newActiveWindow);
546 
547                 if (newActiveWindow != getGlobalActiveWindow()) {
548                     // Activation change was rejected. Unlikely, but
549                     // possible.
550                     break;
551                 }
552 
553                 return typeAheadAssertions(newActiveWindow, we);
554             }
555 
556             case FocusEvent.FOCUS_GAINED: {
557                 restoreFocusTo = null;
558                 FocusEvent fe = (FocusEvent)e;
559                 Component oldFocusOwner = getGlobalFocusOwner();
560                 Component newFocusOwner = fe.getComponent();
561                 if (oldFocusOwner == newFocusOwner) {
562                     if (focusLog.isLoggable(PlatformLogger.Level.FINE)) {
563                         focusLog.fine("Skipping {0} because focus owner is the same", e);
564                     }
565                     // We can't just drop the event - there could be
566                     // type-ahead markers associated with it.
567                     dequeueKeyEvents(-1, newFocusOwner);
568                     break;
569                 }
570 
571                 // If there exists a current focus owner, then notify it that
572                 // it has lost focus.
573                 if (oldFocusOwner != null) {
574                     boolean isEventDispatched =
575                         sendMessage(oldFocusOwner,
576                                     new FocusEvent(oldFocusOwner,
577                                                    FocusEvent.FOCUS_LOST,
578                                                    fe.isTemporary(),
579                                                    newFocusOwner, fe.getCause()));
580                     // Failed to dispatch, clear by ourselves
581                     if (!isEventDispatched) {
582                         setGlobalFocusOwner(null);
583                         if (!fe.isTemporary()) {
584                             setGlobalPermanentFocusOwner(null);
585                         }
586                     }
587                 }
588 
589                 // Because the native windowing system has a different notion
590                 // of the current focus and activation states, it is possible
591                 // that a Component outside of the focused Window receives a
592                 // FOCUS_GAINED event. We synthesize a WINDOW_GAINED_FOCUS
593                 // event in that case.
594                 final Window newFocusedWindow = SunToolkit.getContainingWindow(newFocusOwner);
595                 final Window currentFocusedWindow = getGlobalFocusedWindow();
596                 if (newFocusedWindow != null &&
597                     newFocusedWindow != currentFocusedWindow)
598                 {
599                     sendMessage(newFocusedWindow,
600                                 new WindowEvent(newFocusedWindow,
601                                         WindowEvent.WINDOW_GAINED_FOCUS,
602                                                 currentFocusedWindow));
603                     if (newFocusedWindow != getGlobalFocusedWindow()) {
604                         // Focus change was rejected. Will happen if
605                         // newFocusedWindow is not a focusable Window.
606 
607                         // Need to recover type-ahead, but don't bother
608                         // restoring focus. That was done by the
609                         // WINDOW_GAINED_FOCUS handler
610                         dequeueKeyEvents(-1, newFocusOwner);
611                         break;
612                     }
613                 }
614 
615                 if (!(newFocusOwner.isFocusable() && newFocusOwner.isShowing() &&
616                     // Refuse focus on a disabled component if the focus event
617                     // isn't of UNKNOWN reason (i.e. not a result of a direct request
618                     // but traversal, activation or system generated).
619                     (newFocusOwner.isEnabled() || fe.getCause().equals(FocusEvent.Cause.UNKNOWN))))
620                 {
621                     // we should not accept focus on such component, so reject it.
622                     dequeueKeyEvents(-1, newFocusOwner);
623                     if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
624                         // If FOCUS_GAINED is for a disposed component (however
625                         // it shouldn't happen) its toplevel parent is null. In this
626                         // case we have to try to restore focus in the current focused
627                         // window (for the details: 6607170).
628                         if (newFocusedWindow == null) {
629                             restoreFocus(fe, currentFocusedWindow);
630                         } else {
631                             restoreFocus(fe, newFocusedWindow);
632                         }
633                         setMostRecentFocusOwner(newFocusedWindow, null); // see: 8013773
634                     }
635                     break;
636                 }
637 
638                 setGlobalFocusOwner(newFocusOwner);
639 
640                 if (newFocusOwner != getGlobalFocusOwner()) {
641                     // Focus change was rejected. Will happen if
642                     // newFocusOwner is not focus traversable.
643                     dequeueKeyEvents(-1, newFocusOwner);
644                     if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
645                         restoreFocus(fe, newFocusedWindow);
646                     }
647                     break;
648                 }
649 
650                 if (!fe.isTemporary()) {
651                     setGlobalPermanentFocusOwner(newFocusOwner);
652 
653                     if (newFocusOwner != getGlobalPermanentFocusOwner()) {
654                         // Focus change was rejected. Unlikely, but possible.
655                         dequeueKeyEvents(-1, newFocusOwner);
656                         if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
657                             restoreFocus(fe, newFocusedWindow);
658                         }
659                         break;
660                     }
661                 }
662 
663                 setNativeFocusOwner(getHeavyweight(newFocusOwner));
664 
665                 Component realOppositeComponent = this.realOppositeComponentWR.get();
666                 if (realOppositeComponent != null &&
667                     realOppositeComponent != fe.getOppositeComponent()) {
668                     fe = new FocusEvent(newFocusOwner,
669                                         FocusEvent.FOCUS_GAINED,
670                                         fe.isTemporary(),
671                                         realOppositeComponent, fe.getCause());
672                     ((AWTEvent) fe).isPosted = true;
673                 }
674                 return typeAheadAssertions(newFocusOwner, fe);
675             }
676 
677             case FocusEvent.FOCUS_LOST: {
678                 FocusEvent fe = (FocusEvent)e;
679                 Component currentFocusOwner = getGlobalFocusOwner();
680                 if (currentFocusOwner == null) {
681                     if (focusLog.isLoggable(PlatformLogger.Level.FINE))
682                         focusLog.fine("Skipping {0} because focus owner is null", e);
683                     break;
684                 }
685                 // Ignore cases where a Component loses focus to itself.
686                 // If we make a mistake because of retargeting, then the
687                 // FOCUS_GAINED handler will correct it.
688                 if (currentFocusOwner == fe.getOppositeComponent()) {
689                     if (focusLog.isLoggable(PlatformLogger.Level.FINE))
690                         focusLog.fine("Skipping {0} because current focus owner is equal to opposite", e);
691                     break;
692                 }
693 
694                 setGlobalFocusOwner(null);
695 
696                 if (getGlobalFocusOwner() != null) {
697                     // Focus change was rejected. Unlikely, but possible.
698                     restoreFocus(currentFocusOwner, true);
699                     break;
700                 }
701 
702                 if (!fe.isTemporary()) {
703                     setGlobalPermanentFocusOwner(null);
704 
705                     if (getGlobalPermanentFocusOwner() != null) {
706                         // Focus change was rejected. Unlikely, but possible.
707                         restoreFocus(currentFocusOwner, true);
708                         break;
709                     }
710                 } else {
711                     Window owningWindow = currentFocusOwner.getContainingWindow();
712                     if (owningWindow != null) {
713                         owningWindow.setTemporaryLostComponent(currentFocusOwner);
714                     }
715                 }
716 
717                 setNativeFocusOwner(null);
718 
719                 fe.setSource(currentFocusOwner);
720 
721                 realOppositeComponentWR = (fe.getOppositeComponent() != null)
722                     ? new WeakReference<Component>(currentFocusOwner)
723                     : NULL_COMPONENT_WR;
724 
725                 return typeAheadAssertions(currentFocusOwner, fe);
726             }
727 
728             case WindowEvent.WINDOW_DEACTIVATED: {
729                 WindowEvent we = (WindowEvent)e;
730                 Window currentActiveWindow = getGlobalActiveWindow();
731                 if (currentActiveWindow == null) {
732                     break;
733                 }
734 
735                 if (currentActiveWindow != e.getSource()) {
736                     // The event is lost in time.
737                     // Allow listeners to precess the event but do not
738                     // change any global states
739                     break;
740                 }
741 
742                 setGlobalActiveWindow(null);
743                 if (getGlobalActiveWindow() != null) {
744                     // Activation change was rejected. Unlikely, but possible.
745                     break;
746                 }
747 
748                 we.setSource(currentActiveWindow);
749                 return typeAheadAssertions(currentActiveWindow, we);
750             }
751 
752             case WindowEvent.WINDOW_LOST_FOCUS: {
753                 if (repostIfFollowsKeyEvents((WindowEvent)e)) {
754                     break;
755                 }
756 
757                 WindowEvent we = (WindowEvent)e;
758                 Window currentFocusedWindow = getGlobalFocusedWindow();
759                 Window losingFocusWindow = we.getWindow();
760                 Window activeWindow = getGlobalActiveWindow();
761                 Window oppositeWindow = we.getOppositeWindow();
762                 if (focusLog.isLoggable(PlatformLogger.Level.FINE))
763                     focusLog.fine("Active {0}, Current focused {1}, losing focus {2} opposite {3}",
764                                   activeWindow, currentFocusedWindow,
765                                   losingFocusWindow, oppositeWindow);
766                 if (currentFocusedWindow == null) {
767                     break;
768                 }
769 
770                 // Special case -- if the native windowing system posts an
771                 // event claiming that the active Window has lost focus to the
772                 // focused Window, then discard the event. This is an artifact
773                 // of the native windowing system not knowing which Window is
774                 // really focused.
775                 if (inSendMessage == 0 && losingFocusWindow == activeWindow &&
776                     oppositeWindow == currentFocusedWindow)
777                 {
778                     break;
779                 }
780 
781                 Component currentFocusOwner = getGlobalFocusOwner();
782                 if (currentFocusOwner != null) {
783                     // The focus owner should always receive a FOCUS_LOST event
784                     // before the Window is defocused.
785                     Component oppositeComp = null;
786                     if (oppositeWindow != null) {
787                         oppositeComp = oppositeWindow.getTemporaryLostComponent();
788                         if (oppositeComp == null) {
789                             oppositeComp = oppositeWindow.getMostRecentFocusOwner();
790                         }
791                     }
792                     if (oppositeComp == null) {
793                         oppositeComp = oppositeWindow;
794                     }
795                     sendMessage(currentFocusOwner,
796                                 new FocusEvent(currentFocusOwner,
797                                                FocusEvent.FOCUS_LOST,
798                                                true,
799                                                oppositeComp, FocusEvent.Cause.ACTIVATION));
800                 }
801 
802                 setGlobalFocusedWindow(null);
803                 if (getGlobalFocusedWindow() != null) {
804                     // Focus change was rejected. Unlikely, but possible.
805                     restoreFocus(currentFocusedWindow, null, true);
806                     break;
807                 }
808 
809                 we.setSource(currentFocusedWindow);
810                 realOppositeWindowWR = (oppositeWindow != null)
811                     ? new WeakReference<Window>(currentFocusedWindow)
812                     : NULL_WINDOW_WR;
813                 typeAheadAssertions(currentFocusedWindow, we);
814 
815                 if (oppositeWindow == null && activeWindow != null) {
816                     // Then we need to deactivate the active Window as well.
817                     // No need to synthesize in other cases, because
818                     // WINDOW_ACTIVATED will handle it if necessary.
819                     sendMessage(activeWindow,
820                                 new WindowEvent(activeWindow,
821                                                 WindowEvent.WINDOW_DEACTIVATED,
822                                                 null));
823                     if (getGlobalActiveWindow() != null) {
824                         // Activation change was rejected. Unlikely,
825                         // but possible.
826                         restoreFocus(currentFocusedWindow, null, true);
827                     }
828                 }
829                 break;
830             }
831 
832             case KeyEvent.KEY_TYPED:
833             case KeyEvent.KEY_PRESSED:
834             case KeyEvent.KEY_RELEASED:
835                 return typeAheadAssertions(null, e);
836 
837             default:
838                 return false;
839         }
840 
841         return true;
842     }
843 
844     /**
845      * Called by {@code dispatchEvent} if no other
846      * KeyEventDispatcher in the dispatcher chain dispatched the KeyEvent, or
847      * if no other KeyEventDispatchers are registered. If the event has not
848      * been consumed, its target is enabled, and the focus owner is not null,
849      * this method dispatches the event to its target. This method will also
850      * subsequently dispatch the event to all registered
851      * KeyEventPostProcessors. After all this operations are finished,
852      * the event is passed to peers for processing.
853      * <p>
854      * In all cases, this method returns {@code true}, since
855      * DefaultKeyboardFocusManager is designed so that neither
856      * {@code dispatchEvent}, nor the AWT event dispatcher, should take
857      * further action on the event in any situation.
858      *
859      * @param e the KeyEvent to be dispatched
860      * @return {@code true}
861      * @see Component#dispatchEvent
862      */
dispatchKeyEvent(KeyEvent e)863     public boolean dispatchKeyEvent(KeyEvent e) {
864         Component focusOwner = (((AWTEvent)e).isPosted) ? getFocusOwner() : e.getComponent();
865 
866         if (focusOwner != null && focusOwner.isShowing() && focusOwner.canBeFocusOwner()) {
867             if (!e.isConsumed()) {
868                 Component comp = e.getComponent();
869                 if (comp != null && comp.isEnabled()) {
870                     redispatchEvent(comp, e);
871                 }
872             }
873         }
874         boolean stopPostProcessing = false;
875         java.util.List<KeyEventPostProcessor> processors = getKeyEventPostProcessors();
876         if (processors != null) {
877             for (java.util.Iterator<KeyEventPostProcessor> iter = processors.iterator();
878                  !stopPostProcessing && iter.hasNext(); )
879             {
880                 stopPostProcessing = iter.next().
881                             postProcessKeyEvent(e);
882             }
883         }
884         if (!stopPostProcessing) {
885             postProcessKeyEvent(e);
886         }
887 
888         // Allow the peer to process KeyEvent
889         Component source = e.getComponent();
890         ComponentPeer peer = source.peer;
891 
892         if (peer == null || peer instanceof LightweightPeer) {
893             // if focus owner is lightweight then its native container
894             // processes event
895             Container target = source.getNativeContainer();
896             if (target != null) {
897                 peer = target.peer;
898             }
899         }
900         if (peer != null) {
901             peer.handleEvent(e);
902         }
903 
904         return true;
905     }
906 
907     /**
908      * This method will be called by {@code dispatchKeyEvent}. It will
909      * handle any unconsumed KeyEvents that map to an AWT
910      * {@code MenuShortcut} by consuming the event and activating the
911      * shortcut.
912      *
913      * @param e the KeyEvent to post-process
914      * @return {@code true}
915      * @see #dispatchKeyEvent
916      * @see MenuShortcut
917      */
postProcessKeyEvent(KeyEvent e)918     public boolean postProcessKeyEvent(KeyEvent e) {
919         if (!e.isConsumed()) {
920             Component target = e.getComponent();
921             Container p = (Container)
922                 (target instanceof Container ? target : target.getParent());
923             if (p != null) {
924                 p.postProcessKeyEvent(e);
925             }
926         }
927         return true;
928     }
929 
pumpApprovedKeyEvents()930     private void pumpApprovedKeyEvents() {
931         KeyEvent ke;
932         do {
933             ke = null;
934             synchronized (this) {
935                 if (enqueuedKeyEvents.size() != 0) {
936                     ke = enqueuedKeyEvents.getFirst();
937                     if (typeAheadMarkers.size() != 0) {
938                         TypeAheadMarker marker = typeAheadMarkers.getFirst();
939                         // Fixed 5064013: may appears that the events have the same time
940                         // if (ke.getWhen() >= marker.after) {
941                         // The fix is rolled out.
942 
943                         if (ke.getWhen() > marker.after) {
944                             ke = null;
945                         }
946                     }
947                     if (ke != null) {
948                         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
949                             focusLog.finer("Pumping approved event {0}", ke);
950                         }
951                         enqueuedKeyEvents.removeFirst();
952                     }
953                 }
954             }
955             if (ke != null) {
956                 preDispatchKeyEvent(ke);
957             }
958         } while (ke != null);
959     }
960 
961     /**
962      * Dumps the list of type-ahead queue markers to stderr
963      */
dumpMarkers()964     void dumpMarkers() {
965         if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {
966             focusLog.finest(">>> Markers dump, time: {0}", System.currentTimeMillis());
967             synchronized (this) {
968                 if (typeAheadMarkers.size() != 0) {
969                     Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator();
970                     while (iter.hasNext()) {
971                         TypeAheadMarker marker = iter.next();
972                         focusLog.finest("    {0}", marker);
973                     }
974                 }
975             }
976         }
977     }
978 
typeAheadAssertions(Component target, AWTEvent e)979     private boolean typeAheadAssertions(Component target, AWTEvent e) {
980 
981         // Clear any pending events here as well as in the FOCUS_GAINED
982         // handler. We need this call here in case a marker was removed in
983         // response to a call to dequeueKeyEvents.
984         pumpApprovedKeyEvents();
985 
986         switch (e.getID()) {
987             case KeyEvent.KEY_TYPED:
988             case KeyEvent.KEY_PRESSED:
989             case KeyEvent.KEY_RELEASED: {
990                 KeyEvent ke = (KeyEvent)e;
991                 synchronized (this) {
992                     if (e.isPosted && typeAheadMarkers.size() != 0) {
993                         TypeAheadMarker marker = typeAheadMarkers.getFirst();
994                         // Fixed 5064013: may appears that the events have the same time
995                         // if (ke.getWhen() >= marker.after) {
996                         // The fix is rolled out.
997 
998                         if (ke.getWhen() > marker.after) {
999                             if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
1000                                 focusLog.finer("Storing event {0} because of marker {1}", ke, marker);
1001                             }
1002                             enqueuedKeyEvents.addLast(ke);
1003                             return true;
1004                         }
1005                     }
1006                 }
1007 
1008                 // KeyEvent was posted before focus change request
1009                 return preDispatchKeyEvent(ke);
1010             }
1011 
1012             case FocusEvent.FOCUS_GAINED:
1013                 if (focusLog.isLoggable(PlatformLogger.Level.FINEST)) {
1014                     focusLog.finest("Markers before FOCUS_GAINED on {0}", target);
1015                 }
1016                 dumpMarkers();
1017                 // Search the marker list for the first marker tied to
1018                 // the Component which just gained focus. Then remove
1019                 // that marker, any markers which immediately follow
1020                 // and are tied to the same component, and all markers
1021                 // that precede it. This handles the case where
1022                 // multiple focus requests were made for the same
1023                 // Component in a row and when we lost some of the
1024                 // earlier requests. Since FOCUS_GAINED events will
1025                 // not be generated for these additional requests, we
1026                 // need to clear those markers too.
1027                 synchronized (this) {
1028                     boolean found = false;
1029                     if (hasMarker(target)) {
1030                         for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator();
1031                              iter.hasNext(); )
1032                         {
1033                             if (iter.next().untilFocused == target) {
1034                                 found = true;
1035                             } else if (found) {
1036                                 break;
1037                             }
1038                             iter.remove();
1039                         }
1040                     } else {
1041                         // Exception condition - event without marker
1042                         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
1043                             focusLog.finer("Event without marker {0}", e);
1044                         }
1045                     }
1046                 }
1047                 focusLog.finest("Markers after FOCUS_GAINED");
1048                 dumpMarkers();
1049 
1050                 redispatchEvent(target, e);
1051 
1052                 // Now, dispatch any pending KeyEvents which have been
1053                 // released because of the FOCUS_GAINED event so that we don't
1054                 // have to wait for another event to be posted to the queue.
1055                 pumpApprovedKeyEvents();
1056                 return true;
1057 
1058             default:
1059                 redispatchEvent(target, e);
1060                 return true;
1061         }
1062     }
1063 
1064     /**
1065      * Returns true if there are some marker associated with component {@code comp}
1066      * in a markers' queue
1067      * @since 1.5
1068      */
hasMarker(Component comp)1069     private boolean hasMarker(Component comp) {
1070         for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
1071             if (iter.next().untilFocused == comp) {
1072                 return true;
1073             }
1074         }
1075         return false;
1076     }
1077 
1078     /**
1079      * Clears markers queue
1080      * @since 1.5
1081      */
clearMarkers()1082     void clearMarkers() {
1083         synchronized(this) {
1084             typeAheadMarkers.clear();
1085         }
1086     }
1087 
1088     @SuppressWarnings("deprecation")
preDispatchKeyEvent(KeyEvent ke)1089     private boolean preDispatchKeyEvent(KeyEvent ke) {
1090         if (((AWTEvent) ke).isPosted) {
1091             Component focusOwner = getFocusOwner();
1092             ke.setSource(((focusOwner != null) ? focusOwner : getFocusedWindow()));
1093         }
1094         if (ke.getSource() == null) {
1095             return true;
1096         }
1097 
1098         // Explicitly set the key event timestamp here (not in Component.dispatchEventImpl):
1099         // - A key event is anyway passed to this method which starts its actual dispatching.
1100         // - If a key event is put to the type ahead queue, its time stamp should not be registered
1101         //   until its dispatching actually starts (by this method).
1102         EventQueue.setCurrentEventAndMostRecentTime(ke);
1103 
1104         /**
1105          * Fix for 4495473.
1106          * This fix allows to correctly dispatch events when native
1107          * event proxying mechanism is active.
1108          * If it is active we should redispatch key events after
1109          * we detected its correct target.
1110          */
1111         if (KeyboardFocusManager.isProxyActive(ke)) {
1112             Component source = (Component)ke.getSource();
1113             Container target = source.getNativeContainer();
1114             if (target != null) {
1115                 ComponentPeer peer = target.peer;
1116                 if (peer != null) {
1117                     peer.handleEvent(ke);
1118                     /**
1119                      * Fix for 4478780 - consume event after it was dispatched by peer.
1120                      */
1121                     ke.consume();
1122                 }
1123             }
1124             return true;
1125         }
1126 
1127         java.util.List<KeyEventDispatcher> dispatchers = getKeyEventDispatchers();
1128         if (dispatchers != null) {
1129             for (java.util.Iterator<KeyEventDispatcher> iter = dispatchers.iterator();
1130                  iter.hasNext(); )
1131              {
1132                  if (iter.next().
1133                      dispatchKeyEvent(ke))
1134                  {
1135                      return true;
1136                  }
1137              }
1138         }
1139         return dispatchKeyEvent(ke);
1140     }
1141 
1142     /*
1143      * @param e is a KEY_PRESSED event that can be used
1144      *          to track the next KEY_TYPED related.
1145      */
consumeNextKeyTyped(KeyEvent e)1146     private void consumeNextKeyTyped(KeyEvent e) {
1147         consumeNextKeyTyped = true;
1148     }
1149 
consumeTraversalKey(KeyEvent e)1150     private void consumeTraversalKey(KeyEvent e) {
1151         e.consume();
1152         consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED) &&
1153                               !e.isActionKey();
1154     }
1155 
1156     /*
1157      * return true if event was consumed
1158      */
consumeProcessedKeyEvent(KeyEvent e)1159     private boolean consumeProcessedKeyEvent(KeyEvent e) {
1160         if ((e.getID() == KeyEvent.KEY_TYPED) && consumeNextKeyTyped) {
1161             e.consume();
1162             consumeNextKeyTyped = false;
1163             return true;
1164         }
1165         return false;
1166     }
1167 
1168     /**
1169      * This method initiates a focus traversal operation if and only if the
1170      * KeyEvent represents a focus traversal key for the specified
1171      * focusedComponent. It is expected that focusedComponent is the current
1172      * focus owner, although this need not be the case. If it is not,
1173      * focus traversal will nevertheless proceed as if focusedComponent
1174      * were the focus owner.
1175      *
1176      * @param focusedComponent the Component that is the basis for a focus
1177      *        traversal operation if the specified event represents a focus
1178      *        traversal key for the Component
1179      * @param e the event that may represent a focus traversal key
1180      */
processKeyEvent(Component focusedComponent, KeyEvent e)1181     public void processKeyEvent(Component focusedComponent, KeyEvent e) {
1182         // consume processed event if needed
1183         if (consumeProcessedKeyEvent(e)) {
1184             return;
1185         }
1186 
1187         // KEY_TYPED events cannot be focus traversal keys
1188         if (e.getID() == KeyEvent.KEY_TYPED) {
1189             return;
1190         }
1191 
1192         if (focusedComponent.getFocusTraversalKeysEnabled() &&
1193             !e.isConsumed())
1194         {
1195             AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e),
1196                 oppStroke = AWTKeyStroke.getAWTKeyStroke(stroke.getKeyCode(),
1197                                                  stroke.getModifiers(),
1198                                                  !stroke.isOnKeyRelease());
1199             Set<AWTKeyStroke> toTest;
1200             boolean contains, containsOpp;
1201 
1202             toTest = focusedComponent.getFocusTraversalKeys(
1203                 KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
1204             contains = toTest.contains(stroke);
1205             containsOpp = toTest.contains(oppStroke);
1206 
1207             if (contains || containsOpp) {
1208                 consumeTraversalKey(e);
1209                 if (contains) {
1210                     focusNextComponent(focusedComponent);
1211                 }
1212                 return;
1213             } else if (e.getID() == KeyEvent.KEY_PRESSED) {
1214                 // Fix for 6637607: consumeNextKeyTyped should be reset.
1215                 consumeNextKeyTyped = false;
1216             }
1217 
1218             toTest = focusedComponent.getFocusTraversalKeys(
1219                 KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
1220             contains = toTest.contains(stroke);
1221             containsOpp = toTest.contains(oppStroke);
1222 
1223             if (contains || containsOpp) {
1224                 consumeTraversalKey(e);
1225                 if (contains) {
1226                     focusPreviousComponent(focusedComponent);
1227                 }
1228                 return;
1229             }
1230 
1231             toTest = focusedComponent.getFocusTraversalKeys(
1232                 KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
1233             contains = toTest.contains(stroke);
1234             containsOpp = toTest.contains(oppStroke);
1235 
1236             if (contains || containsOpp) {
1237                 consumeTraversalKey(e);
1238                 if (contains) {
1239                     upFocusCycle(focusedComponent);
1240                 }
1241                 return;
1242             }
1243 
1244             if (!((focusedComponent instanceof Container) &&
1245                   ((Container)focusedComponent).isFocusCycleRoot())) {
1246                 return;
1247             }
1248 
1249             toTest = focusedComponent.getFocusTraversalKeys(
1250                 KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
1251             contains = toTest.contains(stroke);
1252             containsOpp = toTest.contains(oppStroke);
1253 
1254             if (contains || containsOpp) {
1255                 consumeTraversalKey(e);
1256                 if (contains) {
1257                     downFocusCycle((Container)focusedComponent);
1258                 }
1259             }
1260         }
1261     }
1262 
1263     /**
1264      * Delays dispatching of KeyEvents until the specified Component becomes
1265      * the focus owner. KeyEvents with timestamps later than the specified
1266      * timestamp will be enqueued until the specified Component receives a
1267      * FOCUS_GAINED event, or the AWT cancels the delay request by invoking
1268      * {@code dequeueKeyEvents} or {@code discardKeyEvents}.
1269      *
1270      * @param after timestamp of current event, or the current, system time if
1271      *        the current event has no timestamp, or the AWT cannot determine
1272      *        which event is currently being handled
1273      * @param untilFocused Component which will receive a FOCUS_GAINED event
1274      *        before any pending KeyEvents
1275      * @see #dequeueKeyEvents
1276      * @see #discardKeyEvents
1277      */
enqueueKeyEvents(long after, Component untilFocused)1278     protected synchronized void enqueueKeyEvents(long after,
1279                                                  Component untilFocused) {
1280         if (untilFocused == null) {
1281             return;
1282         }
1283 
1284         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
1285             focusLog.finer("Enqueue at {0} for {1}",
1286                        after, untilFocused);
1287         }
1288 
1289         int insertionIndex = 0,
1290             i = typeAheadMarkers.size();
1291         ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator(i);
1292 
1293         for (; i > 0; i--) {
1294             TypeAheadMarker marker = iter.previous();
1295             if (marker.after <= after) {
1296                 insertionIndex = i;
1297                 break;
1298             }
1299         }
1300 
1301         typeAheadMarkers.add(insertionIndex,
1302                              new TypeAheadMarker(after, untilFocused));
1303     }
1304 
1305     /**
1306      * Releases for normal dispatching to the current focus owner all
1307      * KeyEvents which were enqueued because of a call to
1308      * {@code enqueueKeyEvents} with the same timestamp and Component.
1309      * If the given timestamp is less than zero, the outstanding enqueue
1310      * request for the given Component with the <b>oldest</b> timestamp (if
1311      * any) should be cancelled.
1312      *
1313      * @param after the timestamp specified in the call to
1314      *        {@code enqueueKeyEvents}, or any value &lt; 0
1315      * @param untilFocused the Component specified in the call to
1316      *        {@code enqueueKeyEvents}
1317      * @see #enqueueKeyEvents
1318      * @see #discardKeyEvents
1319      */
dequeueKeyEvents(long after, Component untilFocused)1320     protected synchronized void dequeueKeyEvents(long after,
1321                                                  Component untilFocused) {
1322         if (untilFocused == null) {
1323             return;
1324         }
1325 
1326         if (focusLog.isLoggable(PlatformLogger.Level.FINER)) {
1327             focusLog.finer("Dequeue at {0} for {1}",
1328                        after, untilFocused);
1329         }
1330 
1331         TypeAheadMarker marker;
1332         ListIterator<TypeAheadMarker> iter = typeAheadMarkers.listIterator
1333             ((after >= 0) ? typeAheadMarkers.size() : 0);
1334 
1335         if (after < 0) {
1336             while (iter.hasNext()) {
1337                 marker = iter.next();
1338                 if (marker.untilFocused == untilFocused)
1339                 {
1340                     iter.remove();
1341                     return;
1342                 }
1343             }
1344         } else {
1345             while (iter.hasPrevious()) {
1346                 marker = iter.previous();
1347                 if (marker.untilFocused == untilFocused &&
1348                     marker.after == after)
1349                 {
1350                     iter.remove();
1351                     return;
1352                 }
1353             }
1354         }
1355     }
1356 
1357     /**
1358      * Discards all KeyEvents which were enqueued because of one or more calls
1359      * to {@code enqueueKeyEvents} with the specified Component, or one of
1360      * its descendants.
1361      *
1362      * @param comp the Component specified in one or more calls to
1363      *        {@code enqueueKeyEvents}, or a parent of such a Component
1364      * @see #enqueueKeyEvents
1365      * @see #dequeueKeyEvents
1366      */
discardKeyEvents(Component comp)1367     protected synchronized void discardKeyEvents(Component comp) {
1368         if (comp == null) {
1369             return;
1370         }
1371 
1372         long start = -1;
1373 
1374         for (Iterator<TypeAheadMarker> iter = typeAheadMarkers.iterator(); iter.hasNext(); ) {
1375             TypeAheadMarker marker = iter.next();
1376             Component toTest = marker.untilFocused;
1377             boolean match = (toTest == comp);
1378             while (!match && toTest != null && !(toTest instanceof Window)) {
1379                 toTest = toTest.getParent();
1380                 match = (toTest == comp);
1381             }
1382             if (match) {
1383                 if (start < 0) {
1384                     start = marker.after;
1385                 }
1386                 iter.remove();
1387             } else if (start >= 0) {
1388                 purgeStampedEvents(start, marker.after);
1389                 start = -1;
1390             }
1391         }
1392 
1393         purgeStampedEvents(start, -1);
1394     }
1395 
1396     // Notes:
1397     //   * must be called inside a synchronized block
1398     //   * if 'start' is < 0, then this function does nothing
1399     //   * if 'end' is < 0, then all KeyEvents from 'start' to the end of the
1400     //     queue will be removed
purgeStampedEvents(long start, long end)1401     private void purgeStampedEvents(long start, long end) {
1402         if (start < 0) {
1403             return;
1404         }
1405 
1406         for (Iterator<KeyEvent> iter = enqueuedKeyEvents.iterator(); iter.hasNext(); ) {
1407             KeyEvent ke = iter.next();
1408             long time = ke.getWhen();
1409 
1410             if (start < time && (end < 0 || time <= end)) {
1411                 iter.remove();
1412             }
1413 
1414             if (end >= 0 && time > end) {
1415                 break;
1416             }
1417         }
1418     }
1419 
1420     /**
1421      * Focuses the Component before aComponent, typically based on a
1422      * FocusTraversalPolicy.
1423      *
1424      * @param aComponent the Component that is the basis for the focus
1425      *        traversal operation
1426      * @see FocusTraversalPolicy
1427      * @see Component#transferFocusBackward
1428      */
focusPreviousComponent(Component aComponent)1429     public void focusPreviousComponent(Component aComponent) {
1430         if (aComponent != null) {
1431             aComponent.transferFocusBackward();
1432         }
1433     }
1434 
1435     /**
1436      * Focuses the Component after aComponent, typically based on a
1437      * FocusTraversalPolicy.
1438      *
1439      * @param aComponent the Component that is the basis for the focus
1440      *        traversal operation
1441      * @see FocusTraversalPolicy
1442      * @see Component#transferFocus
1443      */
focusNextComponent(Component aComponent)1444     public void focusNextComponent(Component aComponent) {
1445         if (aComponent != null) {
1446             aComponent.transferFocus();
1447         }
1448     }
1449 
1450     /**
1451      * Moves the focus up one focus traversal cycle. Typically, the focus owner
1452      * is set to aComponent's focus cycle root, and the current focus cycle
1453      * root is set to the new focus owner's focus cycle root. If, however,
1454      * aComponent's focus cycle root is a Window, then the focus owner is set
1455      * to the focus cycle root's default Component to focus, and the current
1456      * focus cycle root is unchanged.
1457      *
1458      * @param aComponent the Component that is the basis for the focus
1459      *        traversal operation
1460      * @see Component#transferFocusUpCycle
1461      */
upFocusCycle(Component aComponent)1462     public void upFocusCycle(Component aComponent) {
1463         if (aComponent != null) {
1464             aComponent.transferFocusUpCycle();
1465         }
1466     }
1467 
1468     /**
1469      * Moves the focus down one focus traversal cycle. If aContainer is a focus
1470      * cycle root, then the focus owner is set to aContainer's default
1471      * Component to focus, and the current focus cycle root is set to
1472      * aContainer. If aContainer is not a focus cycle root, then no focus
1473      * traversal operation occurs.
1474      *
1475      * @param aContainer the Container that is the basis for the focus
1476      *        traversal operation
1477      * @see Container#transferFocusDownCycle
1478      */
downFocusCycle(Container aContainer)1479     public void downFocusCycle(Container aContainer) {
1480         if (aContainer != null && aContainer.isFocusCycleRoot()) {
1481             aContainer.transferFocusDownCycle();
1482         }
1483     }
1484 }
1485