/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.awt; import java.awt.event.FocusEvent; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.util.Iterator; import java.util.Set; public class DefaultKeyboardFocusManager extends KeyboardFocusManager { private static Window prevFocusedWindow; private static Component prevFocusOwner; private static Window prevActiveWindow; private static boolean consumeKeyTyped; private final Toolkit toolkit = Toolkit.getDefaultToolkit(); static boolean isActivateable(Window w) { // return true if activeWindow can be set to w return ( (w == null) || w.isActivateable()); } protected void dequeueKeyEvents(long a0, Component a1) { toolkit.lockAWT(); try { // currently do nothing, this method // is never called by AWT implementation } finally { toolkit.unlockAWT(); } } protected void discardKeyEvents(Component a0) { toolkit.lockAWT(); try { // currently do nothing, this method // is never called by AWT implementation } finally { toolkit.unlockAWT(); } } public boolean dispatchEvent(AWTEvent e) { if (e instanceof KeyEvent) { KeyEvent ke = (KeyEvent) e; return (preProcessKeyEvent(ke) || dispatchKeyEvent(ke)); } else if (e instanceof FocusEvent) { FocusEvent fe = (FocusEvent) e; return dispatchFocusEvent(fe); } else if (e instanceof WindowEvent) { WindowEvent we = (WindowEvent) e; return dispatchWindowEvent(we); } else if (e == null) { throw new NullPointerException(); } return false; } private boolean preProcessKeyEvent(KeyEvent ke) { // first pass event to every key event dispatcher: Iterator kediter = getKeyEventDispatchers().iterator(); while (kediter.hasNext()) { KeyEventDispatcher ked = (KeyEventDispatcher) kediter.next(); if (ked.dispatchKeyEvent(ke)) { return true; } } return false; } private boolean dispatchFocusEvent(FocusEvent fe) { boolean doRedispatch = false; Component comp = fe.getComponent(); toolkit.lockAWT(); try { Component newFocusOwner = focusOwner; switch (fe.getID()) { case FocusEvent.FOCUS_GAINED: if ((focusedWindow != null) && (comp.getWindowAncestor() == focusedWindow)) { newFocusOwner = comp; } break; case FocusEvent.FOCUS_LOST: // Focus changes in which a Component // loses focus to itself must be discarded if (comp == fe.getOppositeComponent()) { return true; } if (focusOwner != null) { Container hwContainer = ((comp instanceof Container) ? (Container)comp : null); if ((hwContainer != null) && hwContainer.isAncestorOf(focusOwner)) { comp = focusOwner; fe.setSource(comp); } if (comp == focusOwner) { newFocusOwner = null; prevFocusOwner = focusOwner; } } break; default: return false; } if (newFocusOwner == focusOwner) { return true; } boolean temp = fe.isTemporary(); setFocusOwner(newFocusOwner, temp); // rejection recovery [if (newFocusOwner != focusOwner)] boolean success = (newFocusOwner == getFocusOwner()); if (success) { doRedispatch = true; } else { recoverFocusOwner(temp); } } finally { toolkit.unlockAWT(); } if (doRedispatch) { redispatchEvent(comp, fe); } return true; } private boolean recoverFocusOwner(boolean temp) { if (focusOwner == null) { return true; } // focus owner will be reset to the Component // which was previously the focus owner boolean success = prevFocusOwner.requestFocusImpl(temp, true, true); // If that is not possible, // then it will be reset to the next Component // in the focus traversal cycle after the previous focus owner if (!success) { Container root = prevFocusOwner.getFocusCycleRootAncestor(); Component newFocusOwner = root.getFocusTraversalPolicy().getComponentAfter(root, focusOwner); success = ((newFocusOwner != null) && newFocusOwner.requestFocusImpl(temp, true, true)); } // If that is also not possible, // then the KeyboardFocusManager will clear the global focus owner if (!success) { clearGlobalFocusOwner(); } return success; } private void setFocusOwner(Component newFocusOwner, boolean temp) { if (temp) { setGlobalFocusOwner(newFocusOwner); } else { setGlobalPermanentFocusOwner(newFocusOwner); } } private boolean dispatchWindowEvent(WindowEvent we) { Window win = we.getWindow(); Window opposite = we.getOppositeWindow(); int id = we.getID(); switch (id) { case WindowEvent.WINDOW_ACTIVATED: case WindowEvent.WINDOW_DEACTIVATED: processWindowActivation(we); return true; case WindowEvent.WINDOW_GAINED_FOCUS: boolean doRedispatch = false; toolkit.lockAWT(); try { // skip events in illegal state(to preserve their order), // don't reorder them [as opposed to spec] if (win.getFrameDialogOwner() != getGlobalActiveWindow()) { return true; } if ( ((opposite != null) && (opposite == win)) || (win == focusedWindow) ) { return true; } setGlobalFocusedWindow(win); // rejection recovery before redispatching doRedispatch = (getFocusedWindow() == win); if (!doRedispatch) { recoverWindow(prevFocusedWindow); } } finally { toolkit.unlockAWT(); } if (doRedispatch) { redispatchEvent(win, we); } return true; case WindowEvent.WINDOW_LOST_FOCUS: if ( (focusedWindow != null) && (opposite == focusedWindow)) { return true; } // Events posted by the peer layer claiming // that the active Window has lost focus to // the focused Window must be discarded if ((win == activeWindow) && (focusedWindow != null) && (opposite == focusedWindow)) { return true; } dispatchWindowLostFocus(we, win, opposite); return true; } return false; } private void dispatchWindowLostFocus(WindowEvent we, Window win, Window opposite) { boolean doRedispatch = false; toolkit.lockAWT(); try { if ((focusedWindow != null) && (win != focusedWindow)) { win = focusedWindow; } we.setSource(win); if (win == focusedWindow) { // remember last focused window to request focus back if // needed prevFocusedWindow = focusedWindow; setGlobalFocusedWindow(null); doRedispatch = true; } } finally { toolkit.unlockAWT(); } if (doRedispatch) { redispatchEvent(win, we); } } private boolean recoverWindow(Window prevWindow) { // focused Window will be reset to the Window // which was previously the focused Window if (prevWindow != null) { // do the same thing as when native "focus gained" event comes on // prevFocusedWindow, but call behavior // to generate native event & activate ancestor Frame requestFocusInWindow(prevWindow, true); } else { // If there is no such Window, // then the KeyboardFocusManager will clear the global focus owner. clearGlobalFocusOwner(); return false; } return true; } private void processWindowActivation(WindowEvent we) { boolean active = (we.getID() == WindowEvent.WINDOW_ACTIVATED); Window win = we.getWindow(); win = (isActivateable(win) ? win : win.getFrameDialogOwner()); // ignore activating already active window // & deactivating any not active window if (active == (activeWindow == win)) { return; } Window newActiveWindow = (active ? win : null); Window oldActiveWindow = activeWindow; setGlobalActiveWindow(newActiveWindow); if (getGlobalActiveWindow() == newActiveWindow) { if (!active) { prevActiveWindow = oldActiveWindow; } we.setSource(win); redispatchEvent(win, we); } else if (active) { // initiate activeWindow recovery if the change was // rejected by a vetoable change listener // recover only after WINDOW_ACTIVATED Window winToRecover = null; if ((prevFocusedWindow != null) && (prevFocusedWindow.getFrameDialogOwner() == prevActiveWindow)) { winToRecover = prevFocusedWindow; } recoverWindow(winToRecover); } } public boolean dispatchKeyEvent(KeyEvent e) { boolean doRedispatch = false; toolkit.lockAWT(); try { if ((focusOwner != null) && focusOwner.isKeyEnabled()) { doRedispatch = !e.isConsumed(); } } finally { toolkit.unlockAWT(); } if (doRedispatch) { e.setSource(focusOwner); redispatchEvent(focusOwner, e); } postProcessKeyEvent(e); return true; // no further dispatching } public void downFocusCycle(Container aContainer) { toolkit.lockAWT(); try { if (aContainer != null) { aContainer.transferFocusDownCycle(); } } finally { toolkit.unlockAWT(); } } protected void enqueueKeyEvents(long a0, Component a1) { toolkit.lockAWT(); try { // currently do nothing, // this method is never called by AWT implementation } finally { toolkit.unlockAWT(); } } public void focusNextComponent(Component aComponent) { toolkit.lockAWT(); try { if (aComponent != null) { aComponent.transferFocus(); } } finally { toolkit.unlockAWT(); } } public void focusPreviousComponent(Component aComponent) { toolkit.lockAWT(); try { if (aComponent != null) { aComponent.transferFocusBackward(); } } finally { toolkit.unlockAWT(); } } public boolean postProcessKeyEvent(KeyEvent ke) { // pass event to every key event postprocessor: Iterator kepiter = getKeyEventPostProcessors().iterator(); while (kepiter.hasNext()) { KeyEventPostProcessor kep = (KeyEventPostProcessor) kepiter.next(); if (kep.postProcessKeyEvent(ke)) { return true; } } // postprocess the event if no KeyEventPostProcessor dispatched it if (!ke.isConsumed()) { handleShortcut(ke); } return true;// discard KeyEvents if there's no focus owner } private void handleShortcut(KeyEvent ke) { toolkit.lockAWT(); try { if (MenuShortcut.isShortcut(ke) && (activeWindow instanceof Frame)) { MenuBar mb = ((Frame) activeWindow).getMenuBar(); if (mb != null) { mb.handleShortcut(ke); } } } finally { toolkit.unlockAWT(); } } public void processKeyEvent(Component focusedComponent, KeyEvent e) { toolkit.lockAWT(); try { AWTKeyStroke ks = ((e.getID() == KeyEvent.KEY_TYPED) ? null : AWTKeyStroke.getAWTKeyStrokeForEvent(e)); Container container = ((focusedComponent instanceof Container) ? (Container)focusedComponent : null); Set back = focusedComponent.getFocusTraversalKeys(BACKWARD_TRAVERSAL_KEYS); Set forward = focusedComponent.getFocusTraversalKeys(FORWARD_TRAVERSAL_KEYS); Set up = focusedComponent.getFocusTraversalKeys(UP_CYCLE_TRAVERSAL_KEYS); Set down = (((container != null) && container.isFocusCycleRoot()) ? container.getFocusTraversalKeys(DOWN_CYCLE_TRAVERSAL_KEYS) : null); // all KeyEvents related to the focus traversal key, including the // associated KEY_TYPED event, // will be consumed, and will not be dispatched to any Component Set[] sets = { back, forward, up, down }; consume(e, sets); if (back.contains(ks)) { focusPreviousComponent(focusedComponent); } else if (forward.contains(ks)) { focusNextComponent(focusedComponent); } else if (up.contains(ks)) { upFocusCycle(focusedComponent); } else if ((down != null) && (container != null) && down.contains(ks)) { downFocusCycle(container); } } finally { toolkit.unlockAWT(); } } /** * @param sets * @param e * Consumes key event e if any set of focus-traversal keystrokes * (i. e. not of type KEY_TYPED) from sets contains a keystroke * with same code (or char) & modifiers as e */ private void consume(KeyEvent e, Set[] sets) { int keyCode = e.getKeyCode(); int mod = (e.getModifiersEx() | e.getModifiers()); boolean codeDefined = (keyCode != KeyEvent.VK_UNDEFINED); if (!codeDefined) { // consume any KEY_TYPED event after // consumed KEY_PRESSED and before // any unconsumed KEY_PRESSED or any // KEY_RELEASED if (consumeKeyTyped) { e.consume(); } return; } for (int i = 0; i < sets.length; ++i) { Set s = sets[i]; if (s != null) { AWTKeyStroke[] keys = (AWTKeyStroke[]) s.toArray(new AWTKeyStroke[0]); for (int j = 0; j < keys.length; ++j) { AWTKeyStroke key = keys[j]; if ( (key.getKeyCode() == keyCode) && (key.getModifiers() == mod) ) { e.consume(); if (e.getID() == KeyEvent.KEY_PRESSED) { // consume next KEY_TYPED event consumeKeyTyped = true; } else { consumeKeyTyped = false; } return; } } } } consumeKeyTyped = false; } public void upFocusCycle(Component aComponent) { toolkit.lockAWT(); try { if (aComponent != null) { aComponent.transferFocusUpCycle(); } } finally { toolkit.unlockAWT(); } } }