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