865 lines · 32.2 KB · Java
RawDownload
/* * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code 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.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 in the LICENSE file that * accompanied this code). * * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package java.awt; import java.awt.event.KeyEvent;import java.awt.event.InputEvent;import java.util.Collections;import java.util.HashMap;import java.util.Map;import java.util.StringTokenizer;import java.io.Serializable;import java.security.AccessController;import java.security.PrivilegedAction;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Modifier;import java.lang.reflect.Field; /** * An <code>AWTKeyStroke</code> represents a key action on the * keyboard, or equivalent input device. <code>AWTKeyStroke</code>s * can correspond to only a press or release of a * particular key, just as <code>KEY_PRESSED</code> and * <code>KEY_RELEASED</code> <code>KeyEvent</code>s do; * alternately, they can correspond to typing a specific Java character, just * as <code>KEY_TYPED</code> <code>KeyEvent</code>s do. * In all cases, <code>AWTKeyStroke</code>s can specify modifiers * (alt, shift, control, meta, altGraph, or a combination thereof) which must be present * during the action for an exact match. * <p> * <code>AWTKeyStrokes</code> are immutable, and are intended * to be unique. Client code should never create an * <code>AWTKeyStroke</code> on its own, but should instead use * a variant of <code>getAWTKeyStroke</code>. Client use of these factory * methods allows the <code>AWTKeyStroke</code> implementation * to cache and share instances efficiently. * * @see #getAWTKeyStroke * * @author Arnaud Weber * @author David Mendenhall * @since 1.4 */public class AWTKeyStroke implements Serializable {    static final long serialVersionUID = -6430539691155161871L;     private static Map cache;    private static AWTKeyStroke cacheKey;    private static Constructor ctor = getCtor(AWTKeyStroke.class);    private static Map modifierKeywords;    /**     * Associates VK_XXX (as a String) with code (as Integer). This is     * done to avoid the overhead of the reflective call to find the     * constant.     */    private static VKCollection vks;     private char keyChar = KeyEvent.CHAR_UNDEFINED;    private int keyCode = KeyEvent.VK_UNDEFINED;    private int modifiers;    private boolean onKeyRelease;     static {        /* ensure that the necessary native libraries are loaded */        Toolkit.loadLibraries();    }     /**     * Constructs an <code>AWTKeyStroke</code> with default values.     * The default values used are:     * <table border="1" summary="AWTKeyStroke default values">     * <tr><th>Property</th><th>Default Value</th></tr>     * <tr>     *    <td>Key Char</td>     *    <td><code>KeyEvent.CHAR_UNDEFINED</code></td>     * </tr>     * <tr>     *    <td>Key Code</td>     *    <td><code>KeyEvent.VK_UNDEFINED</code></td>     * </tr>     * <tr>     *    <td>Modifiers</td>     *    <td>none</td>     * </tr>     * <tr>     *    <td>On key release?</td>     *    <td><code>false</code></td>     * </tr>     * </table>     *     * <code>AWTKeyStroke</code>s should not be constructed     * by client code. Use a variant of <code>getAWTKeyStroke</code>     * instead.     *     * @see #getAWTKeyStroke     */    protected AWTKeyStroke() {    }     /**     * Constructs an <code>AWTKeyStroke</code> with the specified     * values. <code>AWTKeyStroke</code>s should not be constructed     * by client code. Use a variant of <code>getAWTKeyStroke</code>     * instead.     *     * @param keyChar the character value for a keyboard key     * @param keyCode the key code for this <code>AWTKeyStroke</code>     * @param modifiers a bitwise-ored combination of any modifiers     * @param onKeyRelease <code>true</code> if this     *        <code>AWTKeyStroke</code> corresponds     *        to a key release; <code>false</code> otherwise     * @see #getAWTKeyStroke     */    protected AWTKeyStroke(char keyChar, int keyCode, int modifiers,                           boolean onKeyRelease) {        this.keyChar = keyChar;        this.keyCode = keyCode;        this.modifiers = modifiers;        this.onKeyRelease = onKeyRelease;    }     /**     * Registers a new class which the factory methods in     * <code>AWTKeyStroke</code> will use when generating new     * instances of <code>AWTKeyStroke</code>s. After invoking this     * method, the factory methods will return instances of the specified     * Class. The specified Class must be either <code>AWTKeyStroke</code>     * or derived from <code>AWTKeyStroke</code>, and it must have a     * no-arg constructor. The constructor can be of any accessibility,     * including <code>private</code>. This operation     * flushes the current <code>AWTKeyStroke</code> cache.     *     * @param subclass the new Class of which the factory methods should create     *        instances     * @throws IllegalArgumentException if subclass is <code>null</code>,     *         or if subclass does not have a no-arg constructor     * @throws ClassCastException if subclass is not     *         <code>AWTKeyStroke</code>, or a class derived from     *         <code>AWTKeyStroke</code>     */    protected static void registerSubclass(Class<?> subclass) {        if (subclass == null) {            throw new IllegalArgumentException("subclass cannot be null");        }        if (AWTKeyStroke.ctor.getDeclaringClass().equals(subclass)) {            // Already registered            return;        }        if (!AWTKeyStroke.class.isAssignableFrom(subclass)) {            throw new ClassCastException("subclass is not derived from AWTKeyStroke");        }         Constructor ctor = getCtor(subclass);         String couldNotInstantiate = "subclass could not be instantiated";         if (ctor == null) {            throw new IllegalArgumentException(couldNotInstantiate);        }        try {            AWTKeyStroke stroke = (AWTKeyStroke)ctor.newInstance((Object[]) null);            if (stroke == null) {                throw new IllegalArgumentException(couldNotInstantiate);            }        } catch (NoSuchMethodError e) {            throw new IllegalArgumentException(couldNotInstantiate);        } catch (ExceptionInInitializerError e) {            throw new IllegalArgumentException(couldNotInstantiate);        } catch (InstantiationException e) {            throw new IllegalArgumentException(couldNotInstantiate);        } catch (IllegalAccessException e) {            throw new IllegalArgumentException(couldNotInstantiate);        } catch (InvocationTargetException e) {            throw new IllegalArgumentException(couldNotInstantiate);        }         synchronized (AWTKeyStroke.class) {            AWTKeyStroke.ctor = ctor;            cache = null;            cacheKey = null;        }    }     /* returns noarg Constructor for class with accessible flag. No security       threat as accessible flag is set only for this Constructor object,       not for Class constructor.     */    private static Constructor getCtor(final Class clazz)    {        Object ctor = AccessController.doPrivileged(new PrivilegedAction() {            public Object run() {                try {                    Constructor ctor = clazz.getDeclaredConstructor((Class[]) null);                    if (ctor != null) {                        ctor.setAccessible(true);                    }                    return ctor;                } catch (SecurityException e) {                } catch (NoSuchMethodException e) {                }                return null;            }        });        return (Constructor)ctor;    }     private static synchronized AWTKeyStroke getCachedStroke        (char keyChar, int keyCode, int modifiers, boolean onKeyRelease)    {        if (cache == null) {            cache = new HashMap();        }         if (cacheKey == null) {            try {                cacheKey = (AWTKeyStroke)ctor.newInstance((Object[]) null);            } catch (InstantiationException e) {                assert(false);            } catch (IllegalAccessException e) {                assert(false);            } catch (InvocationTargetException e) {                assert(false);            }        }        cacheKey.keyChar = keyChar;        cacheKey.keyCode = keyCode;        cacheKey.modifiers = mapNewModifiers(mapOldModifiers(modifiers));        cacheKey.onKeyRelease = onKeyRelease;         AWTKeyStroke stroke = (AWTKeyStroke)cache.get(cacheKey);        if (stroke == null) {            stroke = cacheKey;            cache.put(stroke, stroke);            cacheKey = null;        }         return stroke;    }     /**     * Returns a shared instance of an <code>AWTKeyStroke</code>     * that represents a <code>KEY_TYPED</code> event for the     * specified character.     *     * @param keyChar the character value for a keyboard key     * @return an <code>AWTKeyStroke</code> object for that key     */    public static AWTKeyStroke getAWTKeyStroke(char keyChar) {        return getCachedStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false);    }     /**     * Returns a shared instance of an {@code AWTKeyStroke}     * that represents a {@code KEY_TYPED} event for the     * specified Character object and a set of modifiers. Note     * that the first parameter is of type Character rather than     * char. This is to avoid inadvertent clashes with     * calls to <code>getAWTKeyStroke(int keyCode, int modifiers)</code>.     *     * The modifiers consist of any combination of following:<ul>     * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK     * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK     * <li>java.awt.event.InputEvent.META_DOWN_MASK     * <li>java.awt.event.InputEvent.ALT_DOWN_MASK     * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK     * </ul>     * The old modifiers listed below also can be used, but they are     * mapped to _DOWN_ modifiers. <ul>     * <li>java.awt.event.InputEvent.SHIFT_MASK     * <li>java.awt.event.InputEvent.CTRL_MASK     * <li>java.awt.event.InputEvent.META_MASK     * <li>java.awt.event.InputEvent.ALT_MASK     * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK     * </ul>     * also can be used, but they are mapped to _DOWN_ modifiers.     *     * Since these numbers are all different powers of two, any combination of     * them is an integer in which each bit represents a different modifier     * key. Use 0 to specify no modifiers.     *     * @param keyChar the Character object for a keyboard character     * @param modifiers a bitwise-ored combination of any modifiers     * @return an <code>AWTKeyStroke</code> object for that key     * @throws IllegalArgumentException if <code>keyChar</code> is     *       <code>null</code>     *     * @see java.awt.event.InputEvent     */    public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers)    {        if (keyChar == null) {            throw new IllegalArgumentException("keyChar cannot be null");        }        return getCachedStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED,                               modifiers, false);    }     /**     * Returns a shared instance of an <code>AWTKeyStroke</code>,     * given a numeric key code and a set of modifiers, specifying     * whether the key is activated when it is pressed or released.     * <p>     * The "virtual key" constants defined in     * <code>java.awt.event.KeyEvent</code> can be     * used to specify the key code. For example:<ul>     * <li><code>java.awt.event.KeyEvent.VK_ENTER</code>     * <li><code>java.awt.event.KeyEvent.VK_TAB</code>     * <li><code>java.awt.event.KeyEvent.VK_SPACE</code>     * </ul>     * Alternatively, the key code may be obtained by calling     * <code>java.awt.event.KeyEvent.getExtendedKeyCodeForChar</code>.     *     * The modifiers consist of any combination of:<ul>     * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK     * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK     * <li>java.awt.event.InputEvent.META_DOWN_MASK     * <li>java.awt.event.InputEvent.ALT_DOWN_MASK     * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK     * </ul>     * The old modifiers <ul>     * <li>java.awt.event.InputEvent.SHIFT_MASK     * <li>java.awt.event.InputEvent.CTRL_MASK     * <li>java.awt.event.InputEvent.META_MASK     * <li>java.awt.event.InputEvent.ALT_MASK     * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK     * </ul>     * also can be used, but they are mapped to _DOWN_ modifiers.     *     * Since these numbers are all different powers of two, any combination of     * them is an integer in which each bit represents a different modifier     * key. Use 0 to specify no modifiers.     *     * @param keyCode an int specifying the numeric code for a keyboard key     * @param modifiers a bitwise-ored combination of any modifiers     * @param onKeyRelease <code>true</code> if the <code>AWTKeyStroke</code>     *        should represent a key release; <code>false</code> otherwise     * @return an AWTKeyStroke object for that key     *     * @see java.awt.event.KeyEvent     * @see java.awt.event.InputEvent     */    public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers,                                               boolean onKeyRelease) {        return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,                               onKeyRelease);    }     /**     * Returns a shared instance of an <code>AWTKeyStroke</code>,     * given a numeric key code and a set of modifiers. The returned     * <code>AWTKeyStroke</code> will correspond to a key press.     * <p>     * The "virtual key" constants defined in     * <code>java.awt.event.KeyEvent</code> can be     * used to specify the key code. For example:<ul>     * <li><code>java.awt.event.KeyEvent.VK_ENTER</code>     * <li><code>java.awt.event.KeyEvent.VK_TAB</code>     * <li><code>java.awt.event.KeyEvent.VK_SPACE</code>     * </ul>     * The modifiers consist of any combination of:<ul>     * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK     * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK     * <li>java.awt.event.InputEvent.META_DOWN_MASK     * <li>java.awt.event.InputEvent.ALT_DOWN_MASK     * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK     * </ul>     * The old modifiers <ul>     * <li>java.awt.event.InputEvent.SHIFT_MASK     * <li>java.awt.event.InputEvent.CTRL_MASK     * <li>java.awt.event.InputEvent.META_MASK     * <li>java.awt.event.InputEvent.ALT_MASK     * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK     * </ul>     * also can be used, but they are mapped to _DOWN_ modifiers.     *     * Since these numbers are all different powers of two, any combination of     * them is an integer in which each bit represents a different modifier     * key. Use 0 to specify no modifiers.     *     * @param keyCode an int specifying the numeric code for a keyboard key     * @param modifiers a bitwise-ored combination of any modifiers     * @return an <code>AWTKeyStroke</code> object for that key     *     * @see java.awt.event.KeyEvent     * @see java.awt.event.InputEvent     */    public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) {        return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,                               false);    }     /**     * Returns an <code>AWTKeyStroke</code> which represents the     * stroke which generated a given <code>KeyEvent</code>.     * <p>     * This method obtains the keyChar from a <code>KeyTyped</code>     * event, and the keyCode from a <code>KeyPressed</code> or     * <code>KeyReleased</code> event. The <code>KeyEvent</code> modifiers are     * obtained for all three types of <code>KeyEvent</code>.     *     * @param anEvent the <code>KeyEvent</code> from which to     *      obtain the <code>AWTKeyStroke</code>     * @throws NullPointerException if <code>anEvent</code> is null     * @return the <code>AWTKeyStroke</code> that precipitated the event     */    public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) {        int id = anEvent.getID();        switch(id) {          case KeyEvent.KEY_PRESSED:          case KeyEvent.KEY_RELEASED:            return getCachedStroke(KeyEvent.CHAR_UNDEFINED,                                   anEvent.getKeyCode(),                                   anEvent.getModifiers(),                                   (id == KeyEvent.KEY_RELEASED));          case KeyEvent.KEY_TYPED:            return getCachedStroke(anEvent.getKeyChar(),                                   KeyEvent.VK_UNDEFINED,                                   anEvent.getModifiers(),                                   false);          default:            // Invalid ID for this KeyEvent            return null;        }    }     /**     * Parses a string and returns an <code>AWTKeyStroke</code>.     * The string must have the following syntax:     * <pre>     *    &lt;modifiers&gt;* (&lt;typedID&gt; | &lt;pressedReleasedID&gt;)     *     *    modifiers := shift | control | ctrl | meta | alt | altGraph     *    typedID := typed &lt;typedKey&gt;     *    typedKey := string of length 1 giving Unicode character.     *    pressedReleasedID := (pressed | released) key     *    key := KeyEvent key code name, i.e. the name following "VK_".     * </pre>     * If typed, pressed or released is not specified, pressed is assumed. Here     * are some examples:     * <pre>     *     "INSERT" => getAWTKeyStroke(KeyEvent.VK_INSERT, 0);     *     "control DELETE" => getAWTKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK);     *     "alt shift X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK);     *     "alt shift released X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true);     *     "typed a" => getAWTKeyStroke('a');     * </pre>     *     * @param s a String formatted as described above     * @return an <code>AWTKeyStroke</code> object for that String     * @throws IllegalArgumentException if <code>s</code> is <code>null</code>,     *        or is formatted incorrectly     */    public static AWTKeyStroke getAWTKeyStroke(String s) {        if (s == null) {            throw new IllegalArgumentException("String cannot be null");        }         final String errmsg = "String formatted incorrectly";         StringTokenizer st = new StringTokenizer(s, " ");         int mask = 0;        boolean released = false;        boolean typed = false;        boolean pressed = false;         synchronized (AWTKeyStroke.class) {            if (modifierKeywords == null) {                Map uninitializedMap = new HashMap(8, 1.0f);                uninitializedMap.put("shift",                                     Integer.valueOf(InputEvent.SHIFT_DOWN_MASK                                                     |InputEvent.SHIFT_MASK));                uninitializedMap.put("control",                                     Integer.valueOf(InputEvent.CTRL_DOWN_MASK                                                     |InputEvent.CTRL_MASK));                uninitializedMap.put("ctrl",                                     Integer.valueOf(InputEvent.CTRL_DOWN_MASK                                                     |InputEvent.CTRL_MASK));

Lines 1–500 of 865.