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