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