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