/*
*
* Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package java.awt;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedList;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Set;
import sun.awt.AppContext;
import sun.awt.SunToolkit;
import sun.awt.peer.ComponentPeer;
import sun.awt.peer.LightweightPeer;
class DefaultKeyboardFocusManager extends KeyboardFocusManager {
private boolean consumeNextKeyTyped;
private boolean posting = false;
private Window mostRecentFocusedWindow;
private Window pendingWindow;
private Window previousActiveWindow;
private Component pendingComponent;
private LinkedList enqueuedKeyEvents = new LinkedList();
private LinkedList typeAheadMarkers = new LinkedList();
private Window realOppositeWindow;
private Component realOppositeComponent;
private int inSendMessage;
private static class TypeAheadMarker {
long after;
Component untilFocused;
TypeAheadMarker(long after, Component untilFocused) {
this.after = after;
this.untilFocused = untilFocused;
}
}
private Window getOwningFrameDialog(Window window) {
while (window != null && !(window instanceof Frame ||
window instanceof Dialog)) {
window = (Window)window.getParent();
}
return window;
}
/*
* This series of restoreFocus methods is used for recovering from a
* rejected focus or activation change. Rejections typically occur when
* the user attempts to focus a non-focusable Component or Window.
*/
private void restoreFocus(FocusEvent fe, Window newFocusedWindow) {
Component realOppositeComponent = this.realOppositeComponent;
Component vetoedComponent = fe.getComponent();
if (newFocusedWindow != null && restoreFocus(newFocusedWindow,
vetoedComponent, false))
{
} else if (realOppositeComponent != null &&
restoreFocus(realOppositeComponent, false)) {
} else if (fe.getOppositeComponent() != null &&
restoreFocus(fe.getOppositeComponent(), false)) {
} else {
clearGlobalFocusOwner();
}
}
private void restoreFocus(WindowEvent we) {
Window realOppositeWindow = this.realOppositeWindow;
if (realOppositeWindow != null && restoreFocus(realOppositeWindow,
null, false)) {
} else if (we.getOppositeWindow() != null &&
restoreFocus(we.getOppositeWindow(), null, false)) {
} else {
clearGlobalFocusOwner();
}
}
private boolean restoreFocus(Window aWindow, Component vetoedComponent,
boolean clearOnFailure) {
// bug 6203068 always call setActive - Qt may have a different notion
// of the active window than we do. Also this takes care of generating
// a WINDOW_GAINED_FOCUS event should we need one
if (aWindow.isDisplayable()) {// && getGlobalActiveWindow() != aWindow) {
sun.awt.peer.WindowPeer wpeer =
(sun.awt.peer.WindowPeer)aWindow.peer;
wpeer.setActive();
}
Component toFocus =
KeyboardFocusManager.getMostRecentFocusOwner(aWindow);
if (toFocus != null && toFocus != vetoedComponent && restoreFocus(toFocus, false)) {
return true;
} else if (clearOnFailure) {
clearGlobalFocusOwner();
return true;
} else {
return false;
}
}
private boolean restoreFocus(Component toFocus, boolean clearOnFailure) {
// LMK - as part of focus mgmt changes, requestFocusHelper no longer
// returns false w/o consulting the peer. So we no longer need this
// extra check here
// 6198823: vetoableChangeListener not working as expected when trying
// to veto a FOCUS_LOST event.
//if (toFocus.hasFocus()) {
// return true;
//}
// 6198823: vetoableChangeListener not working as expected when trying
// to veto a FOCUS_LOST event.
//
// The new focus management system puts a check at the beginning of
// the Component.requestFocusHelper() method to see whether the
// component hasFocus(), if true, just returns false without going
// through the steps of asking peer to request the focus. This has
// the implication that if the clearGlobalFocusOwner() call was vetoed
// by a vetoable change listener and the logic flow falls back to the
// restoreFocus() call, after trying the first if branch and then the
// second if branch without success, calling the third branch will lead
// to an infinite recursion leading to stack overflow.
if (toFocus.isShowing() && toFocus.isFocusable() &&
toFocus.requestFocus(false)) {
return true;
} else if (toFocus.nextFocusHelper()) {
return true;
} else if (clearOnFailure) {
clearGlobalFocusOwner();
return true;
} else {
return false;
}
}
/**
* A special type of SentEvent which updates a counter in the target
* KeyboardFocusManager if it is an instance of
* DefaultKeyboardFocusManager.
*/
private static class DefaultKeyboardFocusManagerSentEvent
extends SentEvent
{
public DefaultKeyboardFocusManagerSentEvent(AWTEvent nested,
AppContext toNotify) {
super(nested, toNotify);
}
public final void dispatch() {
KeyboardFocusManager manager =
KeyboardFocusManager.getCurrentKeyboardFocusManager();
DefaultKeyboardFocusManager defaultManager =
(manager instanceof DefaultKeyboardFocusManager)
? (DefaultKeyboardFocusManager)manager
: null;
if (defaultManager != null) {
synchronized (defaultManager) {
defaultManager.inSendMessage++;
}
}
super.dispatch();
if (defaultManager != null) {
synchronized (defaultManager) {
defaultManager.inSendMessage--;
}
}
}
}
/**
* Sends a synthetic AWTEvent to a Component. If the Component is in
* the current AppContext, then the event is immediately dispatched.
* If the Component is in a different AppContext, then the event is
* posted to the other AppContext's EventQueue, and this method blocks
* until the event is handled or target AppContext is disposed.
* Returns true if successfuly dispatched event, false if failed
* to dispatch.
*/
private boolean sendMessage(Component target, AWTEvent e) {
AppContext myAppContext = AppContext.getAppContext();
final AppContext targetAppContext = target.appContext;
final SentEvent se =
new DefaultKeyboardFocusManagerSentEvent(e, myAppContext);
if (myAppContext == targetAppContext) {
se.dispatch();
} else {
if (targetAppContext.isDisposed()) {
return false;
}
SunToolkit.postEvent(targetAppContext, se);
if (EventQueue.isDispatchThread()) {
EventDispatchThread edt = (EventDispatchThread)
Thread.currentThread();
edt.pumpEvents(SentEvent.ID, new Conditional() {
public boolean evaluate() {
return !se.dispatched
&& !targetAppContext.isDisposed();
}
});
} else {
synchronized (se) {
while (!se.dispatched
&& !targetAppContext.isDisposed()) {
try {
se.wait(1000);
} catch (InterruptedException ie) {
break;
}
}
}
}
}
return se.dispatched;
}
public boolean dispatchEvent(AWTEvent e) {
if (!(e instanceof WindowEvent) && !(e instanceof FocusEvent)
&& !(e instanceof KeyEvent)) {
return false;
}
switch (e.getID()) {
case WindowEvent.WINDOW_ACTIVATED: {
WindowEvent we = (WindowEvent) e;
Window newActiveWindow = we.getWindow();
Window oldActiveWindow = getGlobalActiveWindow();
Window oldFocusedWindow = getGlobalFocusedWindow();
if (oldActiveWindow == newActiveWindow) {
break;
}
// If there exists a current active window, then notify it that
// it has lost activation.
if (oldActiveWindow != null) {
boolean isEventDispatched =
sendMessage(oldActiveWindow,
new WindowEvent(oldActiveWindow,
WindowEvent.WINDOW_DEACTIVATED,
newActiveWindow));
// Failed to dispatch, clear by ourselfves
if (!isEventDispatched) {
setGlobalActiveWindow(null);
}
if (getGlobalActiveWindow() != null) {
// Activation change was rejected. Unlikely, but
// possible.
break;
}
}
setGlobalActiveWindow(newActiveWindow);
if (newActiveWindow != getGlobalActiveWindow()) {
// active change was rejected
break;
}
return typeAheadAssertions(newActiveWindow, we);
}
case WindowEvent.WINDOW_GAINED_FOCUS: {
WindowEvent we = (WindowEvent) e;
Window newFocusedWindow = we.getWindow();
Window oldFocusedWindow = getGlobalFocusedWindow();
if (newFocusedWindow == oldFocusedWindow) {
break;
}
/*
// If there exists a current focused window, then notify it
// that it has lost focus.
if (oldFocusedWindow != null) {
boolean isEventDispatched =
sendMessage(oldFocusedWindow,
new WindowEvent(oldFocusedWindow,
WindowEvent.WINDOW_LOST_FOCUS,
newFocusedWindow));
// Failed to dispatch, clear by ourselfves
if (!isEventDispatched) {
setGlobalFocusOwner(null);
setGlobalFocusedWindow(null);
}
}
*/
// Fix for bug 6188289 - fire WINDOW_ACTIVATE event
// Because the native libraries do not post WINDOW_ACTIVATED
// events, we need to synthesize one if the active Window
// changed.
Window newActiveWindow =
getOwningFrameDialog(newFocusedWindow);
Window currentActiveWindow = getGlobalActiveWindow();
if (newActiveWindow != currentActiveWindow) {
sendMessage(newActiveWindow,
new WindowEvent(newActiveWindow,
WindowEvent.WINDOW_ACTIVATED,
currentActiveWindow));
if (newActiveWindow != getGlobalActiveWindow()) {
// Activation change was rejected. Unlikely, but
// possible.
restoreFocus(we);
break;
}
}
setGlobalFocusedWindow(newFocusedWindow);
if (newFocusedWindow != getGlobalFocusedWindow()) {
// Focus change was rejected. Will happen if
// newFocusedWindow is not a focusable Window.
restoreFocus(we);
break;
}
// Restore focus to the Component which last held it. We do
// this here so that client code can override our choice in
// a WINDOW_GAINED_FOCUS handler.
//
// Make sure that the focus change request doesn't change the
// focused Window in case we are no longer the focused Window
// when the request is handled.
if (inSendMessage == 0) {
// Identify which Component should initially gain focus
// in the Window.
//
// * If we're in SendMessage, then this is a synthetic
// WINDOW_GAINED_FOCUS message which was generated by a
// the FOCUS_GAINED handler. Allow the Component to
// which the FOCUS_GAINED message was targeted to
// receive the focus.
// * Otherwise, look up the correct Component here.
// We don't use Window.getMostRecentFocusOwner because
// window is focused now and 'null' will be returned
// Calculating of most recent focus owner and focus
// request should be synchronized on KeyboardFocusManager.class
// to prevent from thread race when user will request
// focus between calculation and our request.
// But if focus transfer is synchronous, this synchronization
// may cause deadlock, thus we don't synchronize this block.
Component toFocus = KeyboardFocusManager.
getMostRecentFocusOwner(newFocusedWindow);
if ((toFocus == null) &&
newFocusedWindow.isFocusableWindow())
{
toFocus = newFocusedWindow.getFocusTraversalPolicy().
getInitialComponent(newFocusedWindow);
}
Component tempLost = null;
synchronized(KeyboardFocusManager.class) {
tempLost = newFocusedWindow.setTemporaryLostComponent(null);
}
// The component which last has the focus when this window was focused
// should receive focus first
if (tempLost != null) {
tempLost.requestFocusInWindow();
}
if (toFocus != null && toFocus != tempLost) {
// If there is a component which requested focus when this
// window was inactive it expects to receive focus
// after activation
toFocus.requestFocusInWindow();
}
}
Window realOppositeWindow = this.realOppositeWindow;
if (realOppositeWindow != we.getOppositeWindow()) {
we = new WindowEvent(newFocusedWindow,
WindowEvent.WINDOW_GAINED_FOCUS,
realOppositeWindow);
}
boolean retval = typeAheadAssertions(newFocusedWindow, we);
return retval;
}
case FocusEvent.FOCUS_GAINED: {
FocusEvent fe = (FocusEvent) e;
Component oldFocusOwner = getGlobalFocusOwner();
Component newFocusOwner = fe.getComponent();
if (oldFocusOwner == newFocusOwner) {
break;
}
// If there exists a current focus owner, then notify it that
// it has lost focus.
if (oldFocusOwner != null) {
boolean isEventDispatched =
sendMessage(oldFocusOwner,
new FocusEvent(oldFocusOwner,
FocusEvent.FOCUS_LOST,
fe.isTemporary(),
newFocusOwner));
// Failed to dispatch, clear by ourselfves
if (!isEventDispatched) {
setGlobalFocusOwner(null);
if (!fe.isTemporary()) {
setGlobalPermanentFocusOwner(null);
}
}
}
// Because the native windowing system has a different notion
// of the current focus and activation states, it is possible
// that a Component outside of the focused Window receives a
// FOCUS_GAINED event. We synthesize a WINDOW_GAINED_FOCUS
// event in that case.
Component newFocusedWindow = newFocusOwner;
while (newFocusedWindow != null &&
!(newFocusedWindow instanceof Window)) {
newFocusedWindow = newFocusedWindow.parent;
}
// Bug 6188289
/*
Window currentFocusedWindow = getGlobalFocusedWindow();
if (newFocusedWindow != null &&
newFocusedWindow != currentFocusedWindow)
{
sendMessage(newFocusedWindow,
new WindowEvent((Window)newFocusedWindow,
WindowEvent.WINDOW_GAINED_FOCUS,
currentFocusedWindow));
if (newFocusedWindow != getGlobalFocusedWindow()) {
// Focus change was rejected. Will happen if
// newFocusedWindow is not a focusable Window.
// Need to recover type-ahead, but don't bother
// restoring focus. That was done by the
// WINDOW_GAINED_FOCUS handler
dequeueKeyEvents(-1, newFocusOwner);
break;
}
}
*/
setGlobalFocusOwner(newFocusOwner);
if (newFocusOwner != getGlobalFocusOwner()) {
// roll back the change
// Bug 6211287 - we were calling the wrong version of
// the restoreFocus method - here is the correct call and
// the add'l necessary call to dequeueKeyEvents
dequeueKeyEvents(-1, newFocusOwner);
restoreFocus(fe, (Window)newFocusedWindow);
break;
}
if (!fe.isTemporary()) {
setGlobalPermanentFocusOwner(newFocusOwner);
// what if it was vetoed...?
if (newFocusOwner != getGlobalFocusOwner()) {
// Focus change was rejected. Will happen if
// newFocusOwner is not focus traversable.
dequeueKeyEvents(-1, newFocusOwner);
restoreFocus(fe, (Window)newFocusedWindow);
break;
}
}
Component realOppositeComponent = this.realOppositeComponent;
if (realOppositeComponent != null &&
realOppositeComponent != fe.getOppositeComponent()) {
fe = new FocusEvent(newFocusOwner,
FocusEvent.FOCUS_GAINED,
fe.isTemporary(),
realOppositeComponent);
}
boolean retval = typeAheadAssertions(newFocusOwner, fe);
return retval;
}
case FocusEvent.FOCUS_LOST: {
FocusEvent fe = (FocusEvent) e;
Component currentFocusOwner = getGlobalFocusOwner();
if (currentFocusOwner == null) {
break;
}
// Ignore cases where a Component loses focus to itself.
// If we make a mistake because of retargeting, then the
// FOCUS_GAINED handler will correct it.
if (currentFocusOwner == fe.getOppositeComponent()) {
break;
}
setGlobalFocusOwner(null);
if (getGlobalFocusOwner() != null) {
// Focus change was rejected. Unlikely, but possible.
restoreFocus(currentFocusOwner, true);
break;
}
if (!fe.isTemporary()) {
setGlobalPermanentFocusOwner(null);
// what if it was vetoed...?
if (getGlobalPermanentFocusOwner() != null) {
// Focus change was rejected. Unlikely, but possible.
restoreFocus(currentFocusOwner, true);
break;
}
}
else {
Window owningWindow = getContainingWindow(currentFocusOwner);
if (owningWindow != null) {
owningWindow.setTemporaryLostComponent(currentFocusOwner);
}
}
// 6238261 - now that AWTEvent.setSource is package protected,
// need to cast focus event as AWTEvent so we're in the same
// package before calling setSource
((AWTEvent)fe).setSource(currentFocusOwner);
realOppositeComponent = (fe.getOppositeComponent() != null)
? currentFocusOwner : null;
return typeAheadAssertions(currentFocusOwner, fe);
}
case WindowEvent.WINDOW_LOST_FOCUS: {
WindowEvent we = (WindowEvent) e;
Window currentFocusedWindow = getGlobalFocusedWindow();
if (currentFocusedWindow == null) {
break;
}
// Special case -- if the native windowing system posts an
// event claiming that the active Window has lost focus to the
// focused Window, then discard the event. This is an artifact
// of the native windowing system not knowing which Window is
// really focused.
Window losingFocusWindow = we.getWindow();
Window activeWindow = getGlobalActiveWindow();
Window oppositeWindow = we.getOppositeWindow();
if (inSendMessage == 0 && losingFocusWindow == activeWindow &&
oppositeWindow == currentFocusedWindow)
{
break;
}
Component currentFocusOwner = getGlobalFocusOwner();
if (currentFocusOwner != null) {
// The focus owner should always receive a FOCUS_LOST event
// before the Window is defocused.
Component oppositeComp = null;
if (oppositeWindow != null) {
oppositeComp = oppositeWindow.getTemporaryLostComponent();
if (oppositeComp == null) {
oppositeComp = oppositeWindow.getMostRecentFocusOwner();
}
}
if (oppositeComp == null) {
oppositeComp = oppositeWindow;
}
sendMessage(currentFocusOwner,
new FocusEvent(currentFocusOwner,
FocusEvent.FOCUS_LOST,
true,
oppositeComp));
}
// LMK added - opposite info isn't available in pp1.1 focus events
realOppositeWindow = currentFocusedWindow;
setGlobalFocusedWindow(null);
if (getGlobalFocusedWindow() != null) {
// Focus change was rejected. Unlikely, but possible.
restoreFocus(currentFocusedWindow, null, true);
break;
}
// 6238261 - now that AWTEvent.setSource is package protected,
// need to cast focus event as AWTEvent so we're in the same
// package before calling setSource
((AWTEvent)we).setSource(currentFocusedWindow);
/* LMK added code above - in pp1.1 we never have opposite window info in an
* event
realOppositeWindow = (oppositeWindow != null)
? currentFocusedWindow
: null;
*/
typeAheadAssertions(currentFocusedWindow, we);
// if (oppositeWindow == null) {
// oppositeWindow is always null for personal. So we also need to
// check if activeWindow is NOT null before we send this event
if (oppositeWindow == null && activeWindow != null) {
// Then we need to deactive the active Window as well.
// No need to synthesize in other cases, because
// WINDOW_ACTIVATED will handle it if necessary.
sendMessage(activeWindow,
new WindowEvent(activeWindow,
WindowEvent.WINDOW_DEACTIVATED,
null));
if (getGlobalActiveWindow() != null) {
// Activation change was rejected. Unlikely,
// but possible.
restoreFocus(currentFocusedWindow, null, true);
}
}
break;
}
case WindowEvent.WINDOW_DEACTIVATED: {
WindowEvent we = (WindowEvent) e;
Window currentActiveWindow = getGlobalActiveWindow();
if (currentActiveWindow == null) {
break;
}
setGlobalActiveWindow(null);
if (getGlobalActiveWindow() != null) {
// Activation change was rejected. Unlikely, but possible.
break;
}
// 6238261 - now that AWTEvent.setSource is package protected,
// need to cast focus event as AWTEvent so we're in the same
// package before calling setSource
((AWTEvent)we).setSource(currentActiveWindow);
return typeAheadAssertions(currentActiveWindow, we);
}
case KeyEvent.KEY_TYPED:
case KeyEvent.KEY_PRESSED:
case KeyEvent.KEY_RELEASED: {
return typeAheadAssertions(null, e);
}
default:
return false;
}
return true;
}
public boolean dispatchKeyEvent(KeyEvent e) {
Component focusOwner = getFocusOwner();
if (focusOwner != null && focusOwner.isShowing()
&& focusOwner.isFocusable() && focusOwner.isEnabled()) {
if (!e.isConsumed()) {
Component comp = e.getComponent();
if (comp != null && comp.isEnabled()) {
redispatchEvent(comp, e);
}
}
}
boolean stopPostProcessing = false;
java.util.List processors = getKeyEventPostProcessors();
if (processors != null) {
for (java.util.Iterator iter = processors.iterator();
!stopPostProcessing && iter.hasNext();) {
stopPostProcessing = (((KeyEventPostProcessor) (iter.next())).postProcessKeyEvent(e));
}
}
if (!stopPostProcessing) {
postProcessKeyEvent(e);
}
/*
// Allow the peer to process KeyEvent
Component source = e.getComponent();
ComponentPeer peer = source.peer;
if (peer == null || peer instanceof LightweightPeer) {
// if focus owner is lightweight then its native container
// processes event
Container target = source.getNativeContainer();
if (target != null) {
peer = target.peer;
}
}
if (peer != null) {
peer.handleEvent(e);
}
*/
return true;
}
public boolean postProcessKeyEvent(KeyEvent e) {
if (!e.isConsumed()) {
Component target = e.getComponent();
if (target != null) {
Container p = (Container)
(target instanceof Container ? target : target.getParent());
if (p != null) {
p.postProcessKeyEvent(e);
}
}
}
Component source = e.getComponent();
if (source != null) {
sun.awt.peer.ComponentPeer peer = source.peer;
if (peer == null || peer instanceof sun.awt.peer.LightweightPeer) {
Container target = source.getNativeContainer();
if (target != null) {
peer = target.peer;
}
}
if (peer != null) {
peer.handleEvent(e);
}
}
return true;
}
private void pumpApprovedKeyEvents() {
KeyEvent ke;
if (requestCount() == 0) {
synchronized(this) {
typeAheadMarkers.clear();
}
}
do {
ke = null;
synchronized (this) {
if (enqueuedKeyEvents.size() != 0) {
ke = (KeyEvent) enqueuedKeyEvents.getFirst();
if (typeAheadMarkers.size() != 0) {
TypeAheadMarker marker = (TypeAheadMarker)
typeAheadMarkers.getFirst();
if (ke.getWhen() > marker.after) {
ke = null;
}
}
if (ke != null) {
enqueuedKeyEvents.removeFirst();
}
}
}
if (ke != null) {
preDispatchKeyEvent(ke);
}
} while (ke != null);
}
private boolean typeAheadAssertions(Component target, AWTEvent e) {
// Clear any pending events here as well as in the FOCUS_GAINED
// handler. We need this call here in case a marker was removed in
// response to a call to dequeueKeyEvents.
pumpApprovedKeyEvents();
switch (e.getID()) {
case KeyEvent.KEY_TYPED:
case KeyEvent.KEY_PRESSED:
case KeyEvent.KEY_RELEASED: {
KeyEvent ke = (KeyEvent) e;
synchronized (this) {
if (typeAheadMarkers.size() != 0) {
TypeAheadMarker marker = (TypeAheadMarker)
typeAheadMarkers.getFirst();
if (ke.getWhen() > marker.after) {
enqueuedKeyEvents.addLast(ke);
return true;
}
}
}
// KeyEvent was posted before focus change request
boolean retval = preDispatchKeyEvent(ke);
return retval;
//return preDispatchKeyEvent(ke);
}
case FocusEvent.FOCUS_GAINED:
// Search the marker list for the first marker tied to the
// Component which just gained focus. Then remove that marker
// and any markers which immediately follow and are tied to
// the same Component. This handles the case where multiple
// focus requests were made for the same Component in a row.
// Since FOCUS_GAINED events will not be generated for these
// additional requests, we need to clear those markers too.
synchronized (this) {
boolean found = false;
for (Iterator iter = typeAheadMarkers.iterator();
iter.hasNext();) {
if (((TypeAheadMarker) iter.next()).untilFocused == target) {
iter.remove();
found = true;
} else if (found) {
break;
}
}
}
redispatchEvent(target, e);
// Now, dispatch any pending KeyEvents which have been
// released because of the FOCUS_GAINED event so that we don't
// have to wait for another event to be posted to the queue.
pumpApprovedKeyEvents();
return true;
default:
redispatchEvent(target, e);
return true;
}
}
private boolean preDispatchKeyEvent(KeyEvent ke) {
Component focusOwner = getFocusOwner();
// 6238261 - now that AWTEvent.setSource is package protected,
// need to cast focus event as AWTEvent so we're in the same
// package before calling setSource
ke.setSource(((focusOwner != null) ? focusOwner : getFocusedWindow()));
if (ke.getSource() == null) {
return true;
}
EventQueue.setCurrentEventAndMostRecentTime(ke);
java.util.List dispatchers = getKeyEventDispatchers();
if (dispatchers != null) {
for (java.util.Iterator iter = dispatchers.iterator();
iter.hasNext();) {
if (((KeyEventDispatcher) (iter.next())).dispatchKeyEvent(ke)) {
return true;
}
}
}
return dispatchKeyEvent(ke);
}
public void processKeyEvent(Component focusedComponent, KeyEvent e) {
if (e.getID() == KeyEvent.KEY_TYPED) {
if (consumeNextKeyTyped) {
e.consume();
consumeNextKeyTyped = false;
}
return;
}
if (focusedComponent.getFocusTraversalKeysEnabled() && !e.isConsumed()) {
AWTKeyStroke stroke = AWTKeyStroke.getAWTKeyStrokeForEvent(e),
oppStroke = AWTKeyStroke.getAWTKeyStroke(stroke.getKeyCode(),
stroke.getModifiers(), !stroke.isOnKeyRelease());
Set toTest;
boolean contains, containsOpp;
toTest = focusedComponent.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
contains = toTest.contains(stroke);
containsOpp = toTest.contains(oppStroke);
if (contains || containsOpp) {
if (contains) {
focusNextComponent(focusedComponent);
}
e.consume();
consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED);
return;
}
toTest = focusedComponent.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
contains = toTest.contains(stroke);
containsOpp = toTest.contains(oppStroke);
if (contains || containsOpp) {
if (contains) {
focusPreviousComponent(focusedComponent);
}
e.consume();
consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED);
return;
}
toTest = focusedComponent.getFocusTraversalKeys(KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS);
contains = toTest.contains(stroke);
containsOpp = toTest.contains(oppStroke);
if (contains || containsOpp) {
if (contains) {
upFocusCycle(focusedComponent);
}
e.consume();
consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED);
return;
}
if (!((focusedComponent instanceof Container)
&& ((Container) focusedComponent).isFocusCycleRoot())) {
return;
}
toTest = focusedComponent.getFocusTraversalKeys(KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS);
contains = toTest.contains(stroke);
containsOpp = toTest.contains(oppStroke);
if (contains || containsOpp) {
if (contains) {
downFocusCycle((Container) focusedComponent);
}
e.consume();
consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED);
}
}
}
protected synchronized void enqueueKeyEvents(long after,
Component untilFocused) {
if (untilFocused == null) {
return;
}
int insertionIndex = 0,
i = typeAheadMarkers.size();
ListIterator iter = typeAheadMarkers.listIterator(i);
for (; i > 0; i--) {
TypeAheadMarker marker = (TypeAheadMarker) iter.previous();
if (marker.after <= after) {
insertionIndex = i;
break;
}
}
typeAheadMarkers.add(insertionIndex, new TypeAheadMarker(after, untilFocused));
}
protected synchronized void dequeueKeyEvents(long after,
Component untilFocused) {
if (untilFocused == null) {
return;
}
TypeAheadMarker marker;
ListIterator iter = typeAheadMarkers.listIterator
((after >= 0) ? typeAheadMarkers.size() : 0);
if (after < 0) {
while (iter.hasNext()) {
marker = (TypeAheadMarker) iter.next();
if (marker.untilFocused == untilFocused) {
iter.remove();
return;
}
}
} else {
while (iter.hasPrevious()) {
marker = (TypeAheadMarker) iter.previous();
if (marker.untilFocused == untilFocused && marker.after == after) {
iter.remove();
return;
}
}
}
}
protected synchronized void discardKeyEvents(Component comp) {
if (comp == null) {
return;
}
long start = -1;
for (Iterator iter = typeAheadMarkers.iterator(); iter.hasNext();) {
TypeAheadMarker marker = (TypeAheadMarker) iter.next();
Component toTest = marker.untilFocused;
boolean match = (toTest == comp);
while (!match && toTest != null && !(toTest instanceof Window)) {
toTest = toTest.getParent();
match = (toTest == comp);
}
if (match) {
if (start < 0) {
start = marker.after;
}
iter.remove();
} else if (start >= 0) {
purgeStampedEvents(start, marker.after);
start = -1;
}
}
purgeStampedEvents(start, -1);
}
// Notes:
// * must be called inside a synchronized block
// * if 'start' is < 0, then this function does nothing
// * if 'end' is < 0, then all KeyEvents from 'start' to the end of the
// queue will be removed
private void purgeStampedEvents(long start, long end) {
if (start < 0) {
return;
}
for (Iterator iter = enqueuedKeyEvents.iterator(); iter.hasNext();) {
KeyEvent ke = (KeyEvent) iter.next();
long time = ke.getWhen();
if (start < time && (end < 0 || time <= end)) {
iter.remove();
}
if (end >= 0 && time > end) {
break;
}
}
}
public void focusPreviousComponent(Component aComponent) {
if (aComponent != null) {
aComponent.transferFocusBackward();
}
}
public void focusNextComponent(Component aComponent) {
if (aComponent != null) {
aComponent.transferFocus();
}
}
public void upFocusCycle(Component aComponent) {
if (aComponent != null) {
aComponent.transferFocusUpCycle();
}
}
public void downFocusCycle(Container aContainer) {
if (aContainer != null && aContainer.isFocusCycleRoot()) {
aContainer.transferFocusDownCycle();
}
}
}