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