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