0N/A/*
2362N/A * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/Apackage java.awt;
0N/A
0N/Aimport java.awt.event.KeyEvent;
4429N/Aimport sun.awt.AppContext;
0N/Aimport java.awt.event.InputEvent;
0N/Aimport java.util.Collections;
0N/Aimport java.util.HashMap;
0N/Aimport java.util.Map;
0N/Aimport java.util.StringTokenizer;
0N/Aimport java.io.Serializable;
0N/Aimport java.security.AccessController;
0N/Aimport java.security.PrivilegedAction;
0N/Aimport java.lang.reflect.Constructor;
0N/Aimport java.lang.reflect.InvocationTargetException;
0N/Aimport java.lang.reflect.Modifier;
0N/Aimport java.lang.reflect.Field;
0N/A
0N/A/**
0N/A * An <code>AWTKeyStroke</code> represents a key action on the
0N/A * keyboard, or equivalent input device. <code>AWTKeyStroke</code>s
0N/A * can correspond to only a press or release of a
0N/A * particular key, just as <code>KEY_PRESSED</code> and
0N/A * <code>KEY_RELEASED</code> <code>KeyEvent</code>s do;
0N/A * alternately, they can correspond to typing a specific Java character, just
0N/A * as <code>KEY_TYPED</code> <code>KeyEvent</code>s do.
0N/A * In all cases, <code>AWTKeyStroke</code>s can specify modifiers
0N/A * (alt, shift, control, meta, altGraph, or a combination thereof) which must be present
0N/A * during the action for an exact match.
0N/A * <p>
0N/A * <code>AWTKeyStrokes</code> are immutable, and are intended
0N/A * to be unique. Client code should never create an
0N/A * <code>AWTKeyStroke</code> on its own, but should instead use
0N/A * a variant of <code>getAWTKeyStroke</code>. Client use of these factory
0N/A * methods allows the <code>AWTKeyStroke</code> implementation
0N/A * to cache and share instances efficiently.
0N/A *
0N/A * @see #getAWTKeyStroke
0N/A *
0N/A * @author Arnaud Weber
0N/A * @author David Mendenhall
0N/A * @since 1.4
0N/A */
0N/Apublic class AWTKeyStroke implements Serializable {
0N/A static final long serialVersionUID = -6430539691155161871L;
0N/A
0N/A private static Map modifierKeywords;
0N/A /**
0N/A * Associates VK_XXX (as a String) with code (as Integer). This is
0N/A * done to avoid the overhead of the reflective call to find the
0N/A * constant.
0N/A */
0N/A private static VKCollection vks;
0N/A
4429N/A //A key for the collection of AWTKeyStrokes within AppContext.
4429N/A private static Object APP_CONTEXT_CACHE_KEY = new Object();
4429N/A //A key withing the cache
4429N/A private static AWTKeyStroke APP_CONTEXT_KEYSTROKE_KEY = new AWTKeyStroke();
4429N/A
4429N/A /*
4429N/A * Reads keystroke class from AppContext and if null, puts there the
4429N/A * AWTKeyStroke class.
4429N/A * Must be called under locked AWTKeyStroke.class
4429N/A */
4429N/A private static Class getAWTKeyStrokeClass() {
4429N/A AppContext appContext = AppContext.getAppContext();
4429N/A Class clazz = (Class)appContext.get(AWTKeyStroke.class);
4429N/A if (clazz == null) {
4429N/A clazz = AWTKeyStroke.class;
4429N/A appContext.put(AWTKeyStroke.class, AWTKeyStroke.class);
4429N/A }
4429N/A return clazz;
4429N/A }
4429N/A
0N/A private char keyChar = KeyEvent.CHAR_UNDEFINED;
0N/A private int keyCode = KeyEvent.VK_UNDEFINED;
0N/A private int modifiers;
0N/A private boolean onKeyRelease;
0N/A
0N/A static {
0N/A /* ensure that the necessary native libraries are loaded */
0N/A Toolkit.loadLibraries();
0N/A }
0N/A
0N/A /**
0N/A * Constructs an <code>AWTKeyStroke</code> with default values.
0N/A * The default values used are:
0N/A * <table border="1" summary="AWTKeyStroke default values">
0N/A * <tr><th>Property</th><th>Default Value</th></tr>
0N/A * <tr>
0N/A * <td>Key Char</td>
0N/A * <td><code>KeyEvent.CHAR_UNDEFINED</code></td>
0N/A * </tr>
0N/A * <tr>
0N/A * <td>Key Code</td>
0N/A * <td><code>KeyEvent.VK_UNDEFINED</code></td>
0N/A * </tr>
0N/A * <tr>
0N/A * <td>Modifiers</td>
0N/A * <td>none</td>
0N/A * </tr>
0N/A * <tr>
0N/A * <td>On key release?</td>
0N/A * <td><code>false</code></td>
0N/A * </tr>
0N/A * </table>
0N/A *
0N/A * <code>AWTKeyStroke</code>s should not be constructed
0N/A * by client code. Use a variant of <code>getAWTKeyStroke</code>
0N/A * instead.
0N/A *
0N/A * @see #getAWTKeyStroke
0N/A */
0N/A protected AWTKeyStroke() {
0N/A }
0N/A
0N/A /**
0N/A * Constructs an <code>AWTKeyStroke</code> with the specified
0N/A * values. <code>AWTKeyStroke</code>s should not be constructed
0N/A * by client code. Use a variant of <code>getAWTKeyStroke</code>
0N/A * instead.
0N/A *
0N/A * @param keyChar the character value for a keyboard key
0N/A * @param keyCode the key code for this <code>AWTKeyStroke</code>
0N/A * @param modifiers a bitwise-ored combination of any modifiers
0N/A * @param onKeyRelease <code>true</code> if this
0N/A * <code>AWTKeyStroke</code> corresponds
0N/A * to a key release; <code>false</code> otherwise
0N/A * @see #getAWTKeyStroke
0N/A */
0N/A protected AWTKeyStroke(char keyChar, int keyCode, int modifiers,
0N/A boolean onKeyRelease) {
0N/A this.keyChar = keyChar;
0N/A this.keyCode = keyCode;
0N/A this.modifiers = modifiers;
0N/A this.onKeyRelease = onKeyRelease;
0N/A }
0N/A
0N/A /**
0N/A * Registers a new class which the factory methods in
0N/A * <code>AWTKeyStroke</code> will use when generating new
0N/A * instances of <code>AWTKeyStroke</code>s. After invoking this
0N/A * method, the factory methods will return instances of the specified
0N/A * Class. The specified Class must be either <code>AWTKeyStroke</code>
0N/A * or derived from <code>AWTKeyStroke</code>, and it must have a
0N/A * no-arg constructor. The constructor can be of any accessibility,
0N/A * including <code>private</code>. This operation
0N/A * flushes the current <code>AWTKeyStroke</code> cache.
0N/A *
0N/A * @param subclass the new Class of which the factory methods should create
0N/A * instances
0N/A * @throws IllegalArgumentException if subclass is <code>null</code>,
0N/A * or if subclass does not have a no-arg constructor
0N/A * @throws ClassCastException if subclass is not
0N/A * <code>AWTKeyStroke</code>, or a class derived from
0N/A * <code>AWTKeyStroke</code>
0N/A */
0N/A protected static void registerSubclass(Class<?> subclass) {
0N/A if (subclass == null) {
0N/A throw new IllegalArgumentException("subclass cannot be null");
0N/A }
4429N/A AppContext appContext = AppContext.getAppContext();
4429N/A synchronized (AWTKeyStroke.class) {
4429N/A Class keyStrokeClass = (Class)appContext.get(AWTKeyStroke.class);
4429N/A if (keyStrokeClass != null && keyStrokeClass.equals(subclass)){
4429N/A // Already registered
4429N/A return;
4429N/A }
0N/A }
0N/A if (!AWTKeyStroke.class.isAssignableFrom(subclass)) {
0N/A throw new ClassCastException("subclass is not derived from AWTKeyStroke");
0N/A }
0N/A
0N/A Constructor ctor = getCtor(subclass);
0N/A
0N/A String couldNotInstantiate = "subclass could not be instantiated";
0N/A
0N/A if (ctor == null) {
0N/A throw new IllegalArgumentException(couldNotInstantiate);
0N/A }
0N/A try {
0N/A AWTKeyStroke stroke = (AWTKeyStroke)ctor.newInstance((Object[]) null);
0N/A if (stroke == null) {
0N/A throw new IllegalArgumentException(couldNotInstantiate);
0N/A }
0N/A } catch (NoSuchMethodError e) {
0N/A throw new IllegalArgumentException(couldNotInstantiate);
0N/A } catch (ExceptionInInitializerError e) {
0N/A throw new IllegalArgumentException(couldNotInstantiate);
0N/A } catch (InstantiationException e) {
0N/A throw new IllegalArgumentException(couldNotInstantiate);
0N/A } catch (IllegalAccessException e) {
0N/A throw new IllegalArgumentException(couldNotInstantiate);
0N/A } catch (InvocationTargetException e) {
0N/A throw new IllegalArgumentException(couldNotInstantiate);
0N/A }
0N/A
0N/A synchronized (AWTKeyStroke.class) {
4429N/A appContext.put(AWTKeyStroke.class, subclass);
4429N/A appContext.remove(APP_CONTEXT_CACHE_KEY);
4429N/A appContext.remove(APP_CONTEXT_KEYSTROKE_KEY);
0N/A }
0N/A }
0N/A
0N/A /* returns noarg Constructor for class with accessible flag. No security
0N/A threat as accessible flag is set only for this Constructor object,
0N/A not for Class constructor.
0N/A */
0N/A private static Constructor getCtor(final Class clazz)
0N/A {
0N/A Object ctor = AccessController.doPrivileged(new PrivilegedAction() {
0N/A public Object run() {
0N/A try {
0N/A Constructor ctor = clazz.getDeclaredConstructor((Class[]) null);
0N/A if (ctor != null) {
0N/A ctor.setAccessible(true);
0N/A }
0N/A return ctor;
0N/A } catch (SecurityException e) {
0N/A } catch (NoSuchMethodException e) {
0N/A }
0N/A return null;
0N/A }
0N/A });
0N/A return (Constructor)ctor;
0N/A }
0N/A
0N/A private static synchronized AWTKeyStroke getCachedStroke
0N/A (char keyChar, int keyCode, int modifiers, boolean onKeyRelease)
0N/A {
4429N/A AppContext appContext = AppContext.getAppContext();
4429N/A Map cache = (Map)appContext.get(APP_CONTEXT_CACHE_KEY);
4429N/A AWTKeyStroke cacheKey = (AWTKeyStroke)appContext.get(APP_CONTEXT_KEYSTROKE_KEY);
4429N/A
0N/A if (cache == null) {
0N/A cache = new HashMap();
4429N/A appContext.put(APP_CONTEXT_CACHE_KEY, cache);
0N/A }
0N/A
0N/A if (cacheKey == null) {
0N/A try {
4429N/A Class clazz = getAWTKeyStrokeClass();
4429N/A cacheKey = (AWTKeyStroke)getCtor(clazz).newInstance((Object[]) null);
4429N/A appContext.put(APP_CONTEXT_KEYSTROKE_KEY, cacheKey);
0N/A } catch (InstantiationException e) {
0N/A assert(false);
0N/A } catch (IllegalAccessException e) {
0N/A assert(false);
0N/A } catch (InvocationTargetException e) {
0N/A assert(false);
0N/A }
0N/A }
0N/A cacheKey.keyChar = keyChar;
0N/A cacheKey.keyCode = keyCode;
0N/A cacheKey.modifiers = mapNewModifiers(mapOldModifiers(modifiers));
0N/A cacheKey.onKeyRelease = onKeyRelease;
0N/A
0N/A AWTKeyStroke stroke = (AWTKeyStroke)cache.get(cacheKey);
0N/A if (stroke == null) {
0N/A stroke = cacheKey;
0N/A cache.put(stroke, stroke);
4429N/A appContext.remove(APP_CONTEXT_KEYSTROKE_KEY);
0N/A }
0N/A return stroke;
0N/A }
0N/A
0N/A /**
0N/A * Returns a shared instance of an <code>AWTKeyStroke</code>
0N/A * that represents a <code>KEY_TYPED</code> event for the
0N/A * specified character.
0N/A *
0N/A * @param keyChar the character value for a keyboard key
0N/A * @return an <code>AWTKeyStroke</code> object for that key
0N/A */
0N/A public static AWTKeyStroke getAWTKeyStroke(char keyChar) {
0N/A return getCachedStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false);
0N/A }
0N/A
0N/A /**
0N/A * Returns a shared instance of an {@code AWTKeyStroke}
0N/A * that represents a {@code KEY_TYPED} event for the
0N/A * specified Character object and a set of modifiers. Note
0N/A * that the first parameter is of type Character rather than
0N/A * char. This is to avoid inadvertent clashes with
0N/A * calls to <code>getAWTKeyStroke(int keyCode, int modifiers)</code>.
0N/A *
0N/A * The modifiers consist of any combination of following:<ul>
0N/A * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.META_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
0N/A * </ul>
0N/A * The old modifiers listed below also can be used, but they are
0N/A * mapped to _DOWN_ modifiers. <ul>
0N/A * <li>java.awt.event.InputEvent.SHIFT_MASK
0N/A * <li>java.awt.event.InputEvent.CTRL_MASK
0N/A * <li>java.awt.event.InputEvent.META_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
0N/A * </ul>
0N/A * also can be used, but they are mapped to _DOWN_ modifiers.
0N/A *
0N/A * Since these numbers are all different powers of two, any combination of
0N/A * them is an integer in which each bit represents a different modifier
0N/A * key. Use 0 to specify no modifiers.
0N/A *
0N/A * @param keyChar the Character object for a keyboard character
0N/A * @param modifiers a bitwise-ored combination of any modifiers
0N/A * @return an <code>AWTKeyStroke</code> object for that key
0N/A * @throws IllegalArgumentException if <code>keyChar</code> is
0N/A * <code>null</code>
0N/A *
0N/A * @see java.awt.event.InputEvent
0N/A */
0N/A public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers)
0N/A {
0N/A if (keyChar == null) {
0N/A throw new IllegalArgumentException("keyChar cannot be null");
0N/A }
0N/A return getCachedStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED,
0N/A modifiers, false);
0N/A }
0N/A
0N/A /**
0N/A * Returns a shared instance of an <code>AWTKeyStroke</code>,
0N/A * given a numeric key code and a set of modifiers, specifying
0N/A * whether the key is activated when it is pressed or released.
0N/A * <p>
0N/A * The "virtual key" constants defined in
0N/A * <code>java.awt.event.KeyEvent</code> can be
0N/A * used to specify the key code. For example:<ul>
0N/A * <li><code>java.awt.event.KeyEvent.VK_ENTER</code>
0N/A * <li><code>java.awt.event.KeyEvent.VK_TAB</code>
0N/A * <li><code>java.awt.event.KeyEvent.VK_SPACE</code>
0N/A * </ul>
1067N/A * Alternatively, the key code may be obtained by calling
1067N/A * <code>java.awt.event.KeyEvent.getExtendedKeyCodeForChar</code>.
1067N/A *
0N/A * The modifiers consist of any combination of:<ul>
0N/A * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.META_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
0N/A * </ul>
0N/A * The old modifiers <ul>
0N/A * <li>java.awt.event.InputEvent.SHIFT_MASK
0N/A * <li>java.awt.event.InputEvent.CTRL_MASK
0N/A * <li>java.awt.event.InputEvent.META_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
0N/A * </ul>
0N/A * also can be used, but they are mapped to _DOWN_ modifiers.
0N/A *
0N/A * Since these numbers are all different powers of two, any combination of
0N/A * them is an integer in which each bit represents a different modifier
0N/A * key. Use 0 to specify no modifiers.
0N/A *
0N/A * @param keyCode an int specifying the numeric code for a keyboard key
0N/A * @param modifiers a bitwise-ored combination of any modifiers
0N/A * @param onKeyRelease <code>true</code> if the <code>AWTKeyStroke</code>
0N/A * should represent a key release; <code>false</code> otherwise
0N/A * @return an AWTKeyStroke object for that key
0N/A *
0N/A * @see java.awt.event.KeyEvent
0N/A * @see java.awt.event.InputEvent
0N/A */
0N/A public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers,
0N/A boolean onKeyRelease) {
0N/A return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,
0N/A onKeyRelease);
0N/A }
0N/A
0N/A /**
0N/A * Returns a shared instance of an <code>AWTKeyStroke</code>,
0N/A * given a numeric key code and a set of modifiers. The returned
0N/A * <code>AWTKeyStroke</code> will correspond to a key press.
0N/A * <p>
0N/A * The "virtual key" constants defined in
0N/A * <code>java.awt.event.KeyEvent</code> can be
0N/A * used to specify the key code. For example:<ul>
0N/A * <li><code>java.awt.event.KeyEvent.VK_ENTER</code>
0N/A * <li><code>java.awt.event.KeyEvent.VK_TAB</code>
0N/A * <li><code>java.awt.event.KeyEvent.VK_SPACE</code>
0N/A * </ul>
0N/A * The modifiers consist of any combination of:<ul>
0N/A * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.META_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
0N/A * </ul>
0N/A * The old modifiers <ul>
0N/A * <li>java.awt.event.InputEvent.SHIFT_MASK
0N/A * <li>java.awt.event.InputEvent.CTRL_MASK
0N/A * <li>java.awt.event.InputEvent.META_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_MASK
0N/A * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
0N/A * </ul>
0N/A * also can be used, but they are mapped to _DOWN_ modifiers.
0N/A *
0N/A * Since these numbers are all different powers of two, any combination of
0N/A * them is an integer in which each bit represents a different modifier
0N/A * key. Use 0 to specify no modifiers.
0N/A *
0N/A * @param keyCode an int specifying the numeric code for a keyboard key
0N/A * @param modifiers a bitwise-ored combination of any modifiers
0N/A * @return an <code>AWTKeyStroke</code> object for that key
0N/A *
0N/A * @see java.awt.event.KeyEvent
0N/A * @see java.awt.event.InputEvent
0N/A */
0N/A public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) {
0N/A return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,
0N/A false);
0N/A }
0N/A
0N/A /**
0N/A * Returns an <code>AWTKeyStroke</code> which represents the
0N/A * stroke which generated a given <code>KeyEvent</code>.
0N/A * <p>
0N/A * This method obtains the keyChar from a <code>KeyTyped</code>
0N/A * event, and the keyCode from a <code>KeyPressed</code> or
0N/A * <code>KeyReleased</code> event. The <code>KeyEvent</code> modifiers are
0N/A * obtained for all three types of <code>KeyEvent</code>.
0N/A *
0N/A * @param anEvent the <code>KeyEvent</code> from which to
0N/A * obtain the <code>AWTKeyStroke</code>
0N/A * @throws NullPointerException if <code>anEvent</code> is null
0N/A * @return the <code>AWTKeyStroke</code> that precipitated the event
0N/A */
0N/A public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) {
0N/A int id = anEvent.getID();
0N/A switch(id) {
0N/A case KeyEvent.KEY_PRESSED:
0N/A case KeyEvent.KEY_RELEASED:
0N/A return getCachedStroke(KeyEvent.CHAR_UNDEFINED,
0N/A anEvent.getKeyCode(),
0N/A anEvent.getModifiers(),
0N/A (id == KeyEvent.KEY_RELEASED));
0N/A case KeyEvent.KEY_TYPED:
0N/A return getCachedStroke(anEvent.getKeyChar(),
0N/A KeyEvent.VK_UNDEFINED,
0N/A anEvent.getModifiers(),
0N/A false);
0N/A default:
0N/A // Invalid ID for this KeyEvent
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Parses a string and returns an <code>AWTKeyStroke</code>.
0N/A * The string must have the following syntax:
0N/A * <pre>
0N/A * &lt;modifiers&gt;* (&lt;typedID&gt; | &lt;pressedReleasedID&gt;)
0N/A *
0N/A * modifiers := shift | control | ctrl | meta | alt | altGraph
0N/A * typedID := typed &lt;typedKey&gt;
0N/A * typedKey := string of length 1 giving Unicode character.
0N/A * pressedReleasedID := (pressed | released) key
0N/A * key := KeyEvent key code name, i.e. the name following "VK_".
0N/A * </pre>
0N/A * If typed, pressed or released is not specified, pressed is assumed. Here
0N/A * are some examples:
0N/A * <pre>
0N/A * "INSERT" => getAWTKeyStroke(KeyEvent.VK_INSERT, 0);
0N/A * "control DELETE" => getAWTKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK);
0N/A * "alt shift X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK);
0N/A * "alt shift released X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true);
0N/A * "typed a" => getAWTKeyStroke('a');
0N/A * </pre>
0N/A *
0N/A * @param s a String formatted as described above
0N/A * @return an <code>AWTKeyStroke</code> object for that String
0N/A * @throws IllegalArgumentException if <code>s</code> is <code>null</code>,
0N/A * or is formatted incorrectly
0N/A */
0N/A public static AWTKeyStroke getAWTKeyStroke(String s) {
0N/A if (s == null) {
0N/A throw new IllegalArgumentException("String cannot be null");
0N/A }
0N/A
0N/A final String errmsg = "String formatted incorrectly";
0N/A
0N/A StringTokenizer st = new StringTokenizer(s, " ");
0N/A
0N/A int mask = 0;
0N/A boolean released = false;
0N/A boolean typed = false;
0N/A boolean pressed = false;
0N/A
0N/A synchronized (AWTKeyStroke.class) {
0N/A if (modifierKeywords == null) {
0N/A Map uninitializedMap = new HashMap(8, 1.0f);
0N/A uninitializedMap.put("shift",
0N/A Integer.valueOf(InputEvent.SHIFT_DOWN_MASK
0N/A |InputEvent.SHIFT_MASK));
0N/A uninitializedMap.put("control",
0N/A Integer.valueOf(InputEvent.CTRL_DOWN_MASK
0N/A |InputEvent.CTRL_MASK));
0N/A uninitializedMap.put("ctrl",
0N/A Integer.valueOf(InputEvent.CTRL_DOWN_MASK
0N/A |InputEvent.CTRL_MASK));
0N/A uninitializedMap.put("meta",
0N/A Integer.valueOf(InputEvent.META_DOWN_MASK
0N/A |InputEvent.META_MASK));
0N/A uninitializedMap.put("alt",
0N/A Integer.valueOf(InputEvent.ALT_DOWN_MASK
0N/A |InputEvent.ALT_MASK));
0N/A uninitializedMap.put("altGraph",
0N/A Integer.valueOf(InputEvent.ALT_GRAPH_DOWN_MASK
0N/A |InputEvent.ALT_GRAPH_MASK));
0N/A uninitializedMap.put("button1",
0N/A Integer.valueOf(InputEvent.BUTTON1_DOWN_MASK));
0N/A uninitializedMap.put("button2",
0N/A Integer.valueOf(InputEvent.BUTTON2_DOWN_MASK));
0N/A uninitializedMap.put("button3",
0N/A Integer.valueOf(InputEvent.BUTTON3_DOWN_MASK));
0N/A modifierKeywords =
0N/A Collections.synchronizedMap(uninitializedMap);
0N/A }
0N/A }
0N/A
0N/A int count = st.countTokens();
0N/A
0N/A for (int i = 1; i <= count; i++) {
0N/A String token = st.nextToken();
0N/A
0N/A if (typed) {
0N/A if (token.length() != 1 || i != count) {
0N/A throw new IllegalArgumentException(errmsg);
0N/A }
0N/A return getCachedStroke(token.charAt(0), KeyEvent.VK_UNDEFINED,
0N/A mask, false);
0N/A }
0N/A
0N/A if (pressed || released || i == count) {
0N/A if (i != count) {
0N/A throw new IllegalArgumentException(errmsg);
0N/A }
0N/A
0N/A String keyCodeName = "VK_" + token;
0N/A int keyCode = getVKValue(keyCodeName);
0N/A
0N/A return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode,
0N/A mask, released);
0N/A }
0N/A
0N/A if (token.equals("released")) {
0N/A released = true;
0N/A continue;
0N/A }
0N/A if (token.equals("pressed")) {
0N/A pressed = true;
0N/A continue;
0N/A }
0N/A if (token.equals("typed")) {
0N/A typed = true;
0N/A continue;
0N/A }
0N/A
0N/A Integer tokenMask = (Integer)modifierKeywords.get(token);
0N/A if (tokenMask != null) {
0N/A mask |= tokenMask.intValue();
0N/A } else {
0N/A throw new IllegalArgumentException(errmsg);
0N/A }
0N/A }
0N/A
0N/A throw new IllegalArgumentException(errmsg);
0N/A }
0N/A
0N/A private static VKCollection getVKCollection() {
0N/A if (vks == null) {
0N/A vks = new VKCollection();
0N/A }
0N/A return vks;
0N/A }
0N/A /**
0N/A * Returns the integer constant for the KeyEvent.VK field named
0N/A * <code>key</code>. This will throw an
0N/A * <code>IllegalArgumentException</code> if <code>key</code> is
0N/A * not a valid constant.
0N/A */
0N/A private static int getVKValue(String key) {
0N/A VKCollection vkCollect = getVKCollection();
0N/A
0N/A Integer value = vkCollect.findCode(key);
0N/A
0N/A if (value == null) {
0N/A int keyCode = 0;
0N/A final String errmsg = "String formatted incorrectly";
0N/A
0N/A try {
0N/A keyCode = KeyEvent.class.getField(key).getInt(KeyEvent.class);
0N/A } catch (NoSuchFieldException nsfe) {
0N/A throw new IllegalArgumentException(errmsg);
0N/A } catch (IllegalAccessException iae) {
0N/A throw new IllegalArgumentException(errmsg);
0N/A }
0N/A value = Integer.valueOf(keyCode);
0N/A vkCollect.put(key, value);
0N/A }
0N/A return value.intValue();
0N/A }
0N/A
0N/A /**
0N/A * Returns the character for this <code>AWTKeyStroke</code>.
0N/A *
0N/A * @return a char value
0N/A * @see #getAWTKeyStroke(char)
0N/A * @see KeyEvent#getKeyChar
0N/A */
0N/A public final char getKeyChar() {
0N/A return keyChar;
0N/A }
0N/A
0N/A /**
0N/A * Returns the numeric key code for this <code>AWTKeyStroke</code>.
0N/A *
0N/A * @return an int containing the key code value
0N/A * @see #getAWTKeyStroke(int,int)
0N/A * @see KeyEvent#getKeyCode
0N/A */
0N/A public final int getKeyCode() {
0N/A return keyCode;
0N/A }
0N/A
0N/A /**
0N/A * Returns the modifier keys for this <code>AWTKeyStroke</code>.
0N/A *
0N/A * @return an int containing the modifiers
0N/A * @see #getAWTKeyStroke(int,int)
0N/A */
0N/A public final int getModifiers() {
0N/A return modifiers;
0N/A }
0N/A
0N/A /**
0N/A * Returns whether this <code>AWTKeyStroke</code> represents a key release.
0N/A *
0N/A * @return <code>true</code> if this <code>AWTKeyStroke</code>
0N/A * represents a key release; <code>false</code> otherwise
0N/A * @see #getAWTKeyStroke(int,int,boolean)
0N/A */
0N/A public final boolean isOnKeyRelease() {
0N/A return onKeyRelease;
0N/A }
0N/A
0N/A /**
0N/A * Returns the type of <code>KeyEvent</code> which corresponds to
0N/A * this <code>AWTKeyStroke</code>.
0N/A *
0N/A * @return <code>KeyEvent.KEY_PRESSED</code>,
0N/A * <code>KeyEvent.KEY_TYPED</code>,
0N/A * or <code>KeyEvent.KEY_RELEASED</code>
0N/A * @see java.awt.event.KeyEvent
0N/A */
0N/A public final int getKeyEventType() {
0N/A if (keyCode == KeyEvent.VK_UNDEFINED) {
0N/A return KeyEvent.KEY_TYPED;
0N/A } else {
0N/A return (onKeyRelease)
0N/A ? KeyEvent.KEY_RELEASED
0N/A : KeyEvent.KEY_PRESSED;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns a numeric value for this object that is likely to be unique,
0N/A * making it a good choice as the index value in a hash table.
0N/A *
0N/A * @return an int that represents this object
0N/A */
0N/A public int hashCode() {
0N/A return (((int)keyChar) + 1) * (2 * (keyCode + 1)) * (modifiers + 1) +
0N/A (onKeyRelease ? 1 : 2);
0N/A }
0N/A
0N/A /**
0N/A * Returns true if this object is identical to the specified object.
0N/A *
0N/A * @param anObject the Object to compare this object to
0N/A * @return true if the objects are identical
0N/A */
0N/A public final boolean equals(Object anObject) {
0N/A if (anObject instanceof AWTKeyStroke) {
0N/A AWTKeyStroke ks = (AWTKeyStroke)anObject;
0N/A return (ks.keyChar == keyChar && ks.keyCode == keyCode &&
0N/A ks.onKeyRelease == onKeyRelease &&
0N/A ks.modifiers == modifiers);
0N/A }
0N/A return false;
0N/A }
0N/A
0N/A /**
0N/A * Returns a string that displays and identifies this object's properties.
0N/A * The <code>String</code> returned by this method can be passed
0N/A * as a parameter to <code>getAWTKeyStroke(String)</code> to produce
0N/A * a key stroke equal to this key stroke.
0N/A *
0N/A * @return a String representation of this object
0N/A * @see #getAWTKeyStroke(String)
0N/A */
0N/A public String toString() {
0N/A if (keyCode == KeyEvent.VK_UNDEFINED) {
0N/A return getModifiersText(modifiers) + "typed " + keyChar;
0N/A } else {
0N/A return getModifiersText(modifiers) +
0N/A (onKeyRelease ? "released" : "pressed") + " " +
0N/A getVKText(keyCode);
0N/A }
0N/A }
0N/A
0N/A static String getModifiersText(int modifiers) {
0N/A StringBuilder buf = new StringBuilder();
0N/A
0N/A if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0 ) {
0N/A buf.append("shift ");
0N/A }
0N/A if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0 ) {
0N/A buf.append("ctrl ");
0N/A }
0N/A if ((modifiers & InputEvent.META_DOWN_MASK) != 0 ) {
0N/A buf.append("meta ");
0N/A }
0N/A if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0 ) {
0N/A buf.append("alt ");
0N/A }
0N/A if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0 ) {
0N/A buf.append("altGraph ");
0N/A }
0N/A if ((modifiers & InputEvent.BUTTON1_DOWN_MASK) != 0 ) {
0N/A buf.append("button1 ");
0N/A }
0N/A if ((modifiers & InputEvent.BUTTON2_DOWN_MASK) != 0 ) {
0N/A buf.append("button2 ");
0N/A }
0N/A if ((modifiers & InputEvent.BUTTON3_DOWN_MASK) != 0 ) {
0N/A buf.append("button3 ");
0N/A }
0N/A
0N/A return buf.toString();
0N/A }
0N/A
0N/A static String getVKText(int keyCode) {
0N/A VKCollection vkCollect = getVKCollection();
0N/A Integer key = Integer.valueOf(keyCode);
0N/A String name = vkCollect.findName(key);
0N/A if (name != null) {
0N/A return name.substring(3);
0N/A }
0N/A int expected_modifiers =
0N/A (Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
0N/A
0N/A Field[] fields = KeyEvent.class.getDeclaredFields();
0N/A for (int i = 0; i < fields.length; i++) {
0N/A try {
0N/A if (fields[i].getModifiers() == expected_modifiers
0N/A && fields[i].getType() == Integer.TYPE
0N/A && fields[i].getName().startsWith("VK_")
0N/A && fields[i].getInt(KeyEvent.class) == keyCode)
0N/A {
0N/A name = fields[i].getName();
0N/A vkCollect.put(name, key);
0N/A return name.substring(3);
0N/A }
0N/A } catch (IllegalAccessException e) {
0N/A assert(false);
0N/A }
0N/A }
0N/A return "UNKNOWN";
0N/A }
0N/A
0N/A /**
0N/A * Returns a cached instance of <code>AWTKeyStroke</code> (or a subclass of
0N/A * <code>AWTKeyStroke</code>) which is equal to this instance.
0N/A *
0N/A * @return a cached instance which is equal to this instance
0N/A */
0N/A protected Object readResolve() throws java.io.ObjectStreamException {
0N/A synchronized (AWTKeyStroke.class) {
4519N/A if (getClass().equals(getAWTKeyStrokeClass())) {
4519N/A return getCachedStroke(keyChar, keyCode, modifiers, onKeyRelease);
4519N/A }
0N/A }
4519N/A return this;
0N/A }
0N/A
0N/A private static int mapOldModifiers(int modifiers) {
0N/A if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
0N/A modifiers |= InputEvent.SHIFT_DOWN_MASK;
0N/A }
0N/A if ((modifiers & InputEvent.ALT_MASK) != 0) {
0N/A modifiers |= InputEvent.ALT_DOWN_MASK;
0N/A }
0N/A if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {
0N/A modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
0N/A }
0N/A if ((modifiers & InputEvent.CTRL_MASK) != 0) {
0N/A modifiers |= InputEvent.CTRL_DOWN_MASK;
0N/A }
0N/A if ((modifiers & InputEvent.META_MASK) != 0) {
0N/A modifiers |= InputEvent.META_DOWN_MASK;
0N/A }
0N/A
0N/A modifiers &= InputEvent.SHIFT_DOWN_MASK
0N/A | InputEvent.ALT_DOWN_MASK
0N/A | InputEvent.ALT_GRAPH_DOWN_MASK
0N/A | InputEvent.CTRL_DOWN_MASK
0N/A | InputEvent.META_DOWN_MASK
0N/A | InputEvent.BUTTON1_DOWN_MASK
0N/A | InputEvent.BUTTON2_DOWN_MASK
0N/A | InputEvent.BUTTON3_DOWN_MASK;
0N/A
0N/A return modifiers;
0N/A }
0N/A
0N/A private static int mapNewModifiers(int modifiers) {
0N/A if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0) {
0N/A modifiers |= InputEvent.SHIFT_MASK;
0N/A }
0N/A if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0) {
0N/A modifiers |= InputEvent.ALT_MASK;
0N/A }
0N/A if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) {
0N/A modifiers |= InputEvent.ALT_GRAPH_MASK;
0N/A }
0N/A if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0) {
0N/A modifiers |= InputEvent.CTRL_MASK;
0N/A }
0N/A if ((modifiers & InputEvent.META_DOWN_MASK) != 0) {
0N/A modifiers |= InputEvent.META_MASK;
0N/A }
0N/A
0N/A return modifiers;
0N/A }
0N/A
0N/A}
0N/A
0N/Aclass VKCollection {
0N/A Map code2name;
0N/A Map name2code;
0N/A
0N/A public VKCollection() {
0N/A code2name = new HashMap();
0N/A name2code = new HashMap();
0N/A }
0N/A
0N/A public synchronized void put(String name, Integer code) {
0N/A assert((name != null) && (code != null));
0N/A assert(findName(code) == null);
0N/A assert(findCode(name) == null);
0N/A code2name.put(code, name);
0N/A name2code.put(name, code);
0N/A }
0N/A
0N/A public synchronized Integer findCode(String name) {
0N/A assert(name != null);
0N/A return (Integer)name2code.get(name);
0N/A }
0N/A
0N/A public synchronized String findName(Integer code) {
0N/A assert(code != null);
0N/A return (String)code2name.get(code);
0N/A }
0N/A}