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