/*
* 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 sun.awt.AppContext;
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 AWTKeyStroke
represents a key action on the
keyboard, or equivalent input device. AWTKeyStroke
s
can correspond to only a press or release of a
particular key, just as KEY_PRESSED
and
KEY_RELEASED
KeyEvent
s do;
alternately, they can correspond to typing a specific Java character, just
as KEY_TYPED
KeyEvent
s do.
In all cases, AWTKeyStroke
s can specify modifiers
(alt, shift, control, meta, altGraph, or a combination thereof) which must be present
during the action for an exact match.
AWTKeyStrokes
are immutable, and are intended
to be unique. Client code should never create an
AWTKeyStroke
on its own, but should instead use
a variant of getAWTKeyStroke
. Client use of these factory
methods allows the AWTKeyStroke
implementation
to cache and share instances efficiently.
Author: Arnaud Weber, David Mendenhall See Also: - getAWTKeyStroke
Since: 1.4
/**
* 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 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.
/**
* 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;
//A key for the collection of AWTKeyStrokes within AppContext.
private static Object APP_CONTEXT_CACHE_KEY = new Object();
//A key withing the cache
private static AWTKeyStroke APP_CONTEXT_KEYSTROKE_KEY = new AWTKeyStroke();
/*
* Reads keystroke class from AppContext and if null, puts there the
* AWTKeyStroke class.
* Must be called under locked AWTKeyStroke.class
*/
private static Class getAWTKeyStrokeClass() {
AppContext appContext = AppContext.getAppContext();
Class clazz = (Class)appContext.get(AWTKeyStroke.class);
if (clazz == null) {
clazz = AWTKeyStroke.class;
appContext.put(AWTKeyStroke.class, AWTKeyStroke.class);
}
return clazz;
}
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 AWTKeyStroke
with default values.
The default values used are:
Property Default Value
Key Char
KeyEvent.CHAR_UNDEFINED
Key Code
KeyEvent.VK_UNDEFINED
Modifiers
none
On key release?
false
AWTKeyStroke
s should not be constructed
by client code. Use a variant of getAWTKeyStroke
instead.
See Also: - getAWTKeyStroke
/**
* 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 AWTKeyStroke
with the specified
values. AWTKeyStroke
s should not be constructed
by client code. Use a variant of getAWTKeyStroke
instead.
Params: - keyChar – the character value for a keyboard key
- keyCode – the key code for this
AWTKeyStroke
- modifiers – a bitwise-ored combination of any modifiers
- onKeyRelease –
true
if this
AWTKeyStroke
corresponds
to a key release; false
otherwise
See Also:
/**
* 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
AWTKeyStroke
will use when generating new
instances of AWTKeyStroke
s. After invoking this
method, the factory methods will return instances of the specified
Class. The specified Class must be either AWTKeyStroke
or derived from AWTKeyStroke
, and it must have a
no-arg constructor. The constructor can be of any accessibility,
including private
. This operation
flushes the current AWTKeyStroke
cache.
Params: - subclass – the new Class of which the factory methods should create
instances
Throws: - IllegalArgumentException – if subclass is
null
,
or if subclass does not have a no-arg constructor - ClassCastException – if subclass is not
AWTKeyStroke
, or a class derived from
AWTKeyStroke
/**
* 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");
}
AppContext appContext = AppContext.getAppContext();
synchronized (AWTKeyStroke.class) {
Class keyStrokeClass = (Class)appContext.get(AWTKeyStroke.class);
if (keyStrokeClass != null && keyStrokeClass.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) {
appContext.put(AWTKeyStroke.class, subclass);
appContext.remove(APP_CONTEXT_CACHE_KEY);
appContext.remove(APP_CONTEXT_KEYSTROKE_KEY);
}
}
/* 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)
{
AppContext appContext = AppContext.getAppContext();
Map cache = (Map)appContext.get(APP_CONTEXT_CACHE_KEY);
AWTKeyStroke cacheKey = (AWTKeyStroke)appContext.get(APP_CONTEXT_KEYSTROKE_KEY);
if (cache == null) {
cache = new HashMap();
appContext.put(APP_CONTEXT_CACHE_KEY, cache);
}
if (cacheKey == null) {
try {
Class clazz = getAWTKeyStrokeClass();
cacheKey = (AWTKeyStroke)getCtor(clazz).newInstance((Object[]) null);
appContext.put(APP_CONTEXT_KEYSTROKE_KEY, cacheKey);
} 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);
appContext.remove(APP_CONTEXT_KEYSTROKE_KEY);
}
return stroke;
}
Returns a shared instance of an AWTKeyStroke
that represents a KEY_TYPED
event for the
specified character.
Params: - keyChar – the character value for a keyboard key
Returns: an AWTKeyStroke
object for that key
/**
* 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 AWTKeyStroke
that represents a 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 getAWTKeyStroke(int keyCode, int modifiers)
.
The modifiers consist of any combination of following:
- java.awt.event.InputEvent.SHIFT_DOWN_MASK
- java.awt.event.InputEvent.CTRL_DOWN_MASK
- java.awt.event.InputEvent.META_DOWN_MASK
- java.awt.event.InputEvent.ALT_DOWN_MASK
- java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
The old modifiers listed below also can be used, but they are
mapped to _DOWN_ modifiers.
- java.awt.event.InputEvent.SHIFT_MASK
- java.awt.event.InputEvent.CTRL_MASK
- java.awt.event.InputEvent.META_MASK
- java.awt.event.InputEvent.ALT_MASK
- java.awt.event.InputEvent.ALT_GRAPH_MASK
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.
Params: - keyChar – the Character object for a keyboard character
- modifiers – a bitwise-ored combination of any modifiers
Throws: - IllegalArgumentException – if
keyChar
is
null
See Also: Returns: an AWTKeyStroke
object for that key
/**
* 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 AWTKeyStroke
,
given a numeric key code and a set of modifiers, specifying
whether the key is activated when it is pressed or released.
The "virtual key" constants defined in
java.awt.event.KeyEvent
can be
used to specify the key code. For example:
java.awt.event.KeyEvent.VK_ENTER
java.awt.event.KeyEvent.VK_TAB
java.awt.event.KeyEvent.VK_SPACE
Alternatively, the key code may be obtained by calling
java.awt.event.KeyEvent.getExtendedKeyCodeForChar
.
The modifiers consist of any combination of:
- java.awt.event.InputEvent.SHIFT_DOWN_MASK
- java.awt.event.InputEvent.CTRL_DOWN_MASK
- java.awt.event.InputEvent.META_DOWN_MASK
- java.awt.event.InputEvent.ALT_DOWN_MASK
- java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
The old modifiers
- java.awt.event.InputEvent.SHIFT_MASK
- java.awt.event.InputEvent.CTRL_MASK
- java.awt.event.InputEvent.META_MASK
- java.awt.event.InputEvent.ALT_MASK
- java.awt.event.InputEvent.ALT_GRAPH_MASK
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.
Params: - keyCode – an int specifying the numeric code for a keyboard key
- modifiers – a bitwise-ored combination of any modifiers
- onKeyRelease –
true
if the AWTKeyStroke
should represent a key release; false
otherwise
See Also: Returns: an AWTKeyStroke object for that key
/**
* 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 AWTKeyStroke
,
given a numeric key code and a set of modifiers. The returned
AWTKeyStroke
will correspond to a key press.
The "virtual key" constants defined in
java.awt.event.KeyEvent
can be
used to specify the key code. For example:
java.awt.event.KeyEvent.VK_ENTER
java.awt.event.KeyEvent.VK_TAB
java.awt.event.KeyEvent.VK_SPACE
The modifiers consist of any combination of:
- java.awt.event.InputEvent.SHIFT_DOWN_MASK
- java.awt.event.InputEvent.CTRL_DOWN_MASK
- java.awt.event.InputEvent.META_DOWN_MASK
- java.awt.event.InputEvent.ALT_DOWN_MASK
- java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
The old modifiers
- java.awt.event.InputEvent.SHIFT_MASK
- java.awt.event.InputEvent.CTRL_MASK
- java.awt.event.InputEvent.META_MASK
- java.awt.event.InputEvent.ALT_MASK
- java.awt.event.InputEvent.ALT_GRAPH_MASK
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.
Params: - keyCode – an int specifying the numeric code for a keyboard key
- modifiers – a bitwise-ored combination of any modifiers
See Also: Returns: an AWTKeyStroke
object for that key
/**
* 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 AWTKeyStroke
which represents the
stroke which generated a given KeyEvent
.
This method obtains the keyChar from a KeyTyped
event, and the keyCode from a KeyPressed
or
KeyReleased
event. The KeyEvent
modifiers are
obtained for all three types of KeyEvent
.
Params: - anEvent – the
KeyEvent
from which to
obtain the AWTKeyStroke
Throws: - NullPointerException – if
anEvent
is null
Returns: the AWTKeyStroke
that precipitated the event
/**
* 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 AWTKeyStroke
.
The string must have the following syntax:
<modifiers>* (<typedID> | <pressedReleasedID>)
modifiers := shift | control | ctrl | meta | alt | altGraph
typedID := typed <typedKey>
typedKey := string of length 1 giving Unicode character.
pressedReleasedID := (pressed | released) key
key := KeyEvent key code name, i.e. the name following "VK_".
If typed, pressed or released is not specified, pressed is assumed. Here
are some examples:
"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');
Params: - s – a String formatted as described above
Throws: - IllegalArgumentException – if
s
is null
,
or is formatted incorrectly
Returns: an AWTKeyStroke
object for that String
/**
* Parses a string and returns an <code>AWTKeyStroke</code>.
* The string must have the following syntax:
* <pre>
* <modifiers>* (<typedID> | <pressedReleasedID>)
*
* modifiers := shift | control | ctrl | meta | alt | altGraph
* typedID := typed <typedKey>
* 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));
uninitializedMap.put("meta",
Integer.valueOf(InputEvent.META_DOWN_MASK
|InputEvent.META_MASK));
uninitializedMap.put("alt",
Integer.valueOf(InputEvent.ALT_DOWN_MASK
|InputEvent.ALT_MASK));
uninitializedMap.put("altGraph",
Integer.valueOf(InputEvent.ALT_GRAPH_DOWN_MASK
|InputEvent.ALT_GRAPH_MASK));
uninitializedMap.put("button1",
Integer.valueOf(InputEvent.BUTTON1_DOWN_MASK));
uninitializedMap.put("button2",
Integer.valueOf(InputEvent.BUTTON2_DOWN_MASK));
uninitializedMap.put("button3",
Integer.valueOf(InputEvent.BUTTON3_DOWN_MASK));
modifierKeywords =
Collections.synchronizedMap(uninitializedMap);
}
}
int count = st.countTokens();
for (int i = 1; i <= count; i++) {
String token = st.nextToken();
if (typed) {
if (token.length() != 1 || i != count) {
throw new IllegalArgumentException(errmsg);
}
return getCachedStroke(token.charAt(0), KeyEvent.VK_UNDEFINED,
mask, false);
}
if (pressed || released || i == count) {
if (i != count) {
throw new IllegalArgumentException(errmsg);
}
String keyCodeName = "VK_" + token;
int keyCode = getVKValue(keyCodeName);
return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode,
mask, released);
}
if (token.equals("released")) {
released = true;
continue;
}
if (token.equals("pressed")) {
pressed = true;
continue;
}
if (token.equals("typed")) {
typed = true;
continue;
}
Integer tokenMask = (Integer)modifierKeywords.get(token);
if (tokenMask != null) {
mask |= tokenMask.intValue();
} else {
throw new IllegalArgumentException(errmsg);
}
}
throw new IllegalArgumentException(errmsg);
}
private static VKCollection getVKCollection() {
if (vks == null) {
vks = new VKCollection();
}
return vks;
}
Returns the integer constant for the KeyEvent.VK field named
key
. This will throw an
IllegalArgumentException
if key
is
not a valid constant.
/**
* Returns the integer constant for the KeyEvent.VK field named
* <code>key</code>. This will throw an
* <code>IllegalArgumentException</code> if <code>key</code> is
* not a valid constant.
*/
private static int getVKValue(String key) {
VKCollection vkCollect = getVKCollection();
Integer value = vkCollect.findCode(key);
if (value == null) {
int keyCode = 0;
final String errmsg = "String formatted incorrectly";
try {
keyCode = KeyEvent.class.getField(key).getInt(KeyEvent.class);
} catch (NoSuchFieldException nsfe) {
throw new IllegalArgumentException(errmsg);
} catch (IllegalAccessException iae) {
throw new IllegalArgumentException(errmsg);
}
value = Integer.valueOf(keyCode);
vkCollect.put(key, value);
}
return value.intValue();
}
Returns the character for this AWTKeyStroke
.
See Also: Returns: a char value
/**
* Returns the character for this <code>AWTKeyStroke</code>.
*
* @return a char value
* @see #getAWTKeyStroke(char)
* @see KeyEvent#getKeyChar
*/
public final char getKeyChar() {
return keyChar;
}
Returns the numeric key code for this AWTKeyStroke
.
See Also: Returns: an int containing the key code value
/**
* Returns the numeric key code for this <code>AWTKeyStroke</code>.
*
* @return an int containing the key code value
* @see #getAWTKeyStroke(int,int)
* @see KeyEvent#getKeyCode
*/
public final int getKeyCode() {
return keyCode;
}
Returns the modifier keys for this AWTKeyStroke
.
See Also: Returns: an int containing the modifiers
/**
* Returns the modifier keys for this <code>AWTKeyStroke</code>.
*
* @return an int containing the modifiers
* @see #getAWTKeyStroke(int,int)
*/
public final int getModifiers() {
return modifiers;
}
Returns whether this AWTKeyStroke
represents a key release.
See Also: Returns: true
if this AWTKeyStroke
represents a key release; false
otherwise
/**
* Returns whether this <code>AWTKeyStroke</code> represents a key release.
*
* @return <code>true</code> if this <code>AWTKeyStroke</code>
* represents a key release; <code>false</code> otherwise
* @see #getAWTKeyStroke(int,int,boolean)
*/
public final boolean isOnKeyRelease() {
return onKeyRelease;
}
Returns the type of KeyEvent
which corresponds to
this AWTKeyStroke
.
See Also: Returns: KeyEvent.KEY_PRESSED
,
KeyEvent.KEY_TYPED
,
or KeyEvent.KEY_RELEASED
/**
* Returns the type of <code>KeyEvent</code> which corresponds to
* this <code>AWTKeyStroke</code>.
*
* @return <code>KeyEvent.KEY_PRESSED</code>,
* <code>KeyEvent.KEY_TYPED</code>,
* or <code>KeyEvent.KEY_RELEASED</code>
* @see java.awt.event.KeyEvent
*/
public final int getKeyEventType() {
if (keyCode == KeyEvent.VK_UNDEFINED) {
return KeyEvent.KEY_TYPED;
} else {
return (onKeyRelease)
? KeyEvent.KEY_RELEASED
: KeyEvent.KEY_PRESSED;
}
}
Returns a numeric value for this object that is likely to be unique,
making it a good choice as the index value in a hash table.
Returns: an int that represents this object
/**
* Returns a numeric value for this object that is likely to be unique,
* making it a good choice as the index value in a hash table.
*
* @return an int that represents this object
*/
public int hashCode() {
return (((int)keyChar) + 1) * (2 * (keyCode + 1)) * (modifiers + 1) +
(onKeyRelease ? 1 : 2);
}
Returns true if this object is identical to the specified object.
Params: - anObject – the Object to compare this object to
Returns: true if the objects are identical
/**
* Returns true if this object is identical to the specified object.
*
* @param anObject the Object to compare this object to
* @return true if the objects are identical
*/
public final boolean equals(Object anObject) {
if (anObject instanceof AWTKeyStroke) {
AWTKeyStroke ks = (AWTKeyStroke)anObject;
return (ks.keyChar == keyChar && ks.keyCode == keyCode &&
ks.onKeyRelease == onKeyRelease &&
ks.modifiers == modifiers);
}
return false;
}
Returns a string that displays and identifies this object's properties.
The String
returned by this method can be passed
as a parameter to getAWTKeyStroke(String)
to produce
a key stroke equal to this key stroke.
See Also: Returns: a String representation of this object
/**
* Returns a string that displays and identifies this object's properties.
* The <code>String</code> returned by this method can be passed
* as a parameter to <code>getAWTKeyStroke(String)</code> to produce
* a key stroke equal to this key stroke.
*
* @return a String representation of this object
* @see #getAWTKeyStroke(String)
*/
public String toString() {
if (keyCode == KeyEvent.VK_UNDEFINED) {
return getModifiersText(modifiers) + "typed " + keyChar;
} else {
return getModifiersText(modifiers) +
(onKeyRelease ? "released" : "pressed") + " " +
getVKText(keyCode);
}
}
static String getModifiersText(int modifiers) {
StringBuilder buf = new StringBuilder();
if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0 ) {
buf.append("shift ");
}
if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0 ) {
buf.append("ctrl ");
}
if ((modifiers & InputEvent.META_DOWN_MASK) != 0 ) {
buf.append("meta ");
}
if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0 ) {
buf.append("alt ");
}
if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0 ) {
buf.append("altGraph ");
}
if ((modifiers & InputEvent.BUTTON1_DOWN_MASK) != 0 ) {
buf.append("button1 ");
}
if ((modifiers & InputEvent.BUTTON2_DOWN_MASK) != 0 ) {
buf.append("button2 ");
}
if ((modifiers & InputEvent.BUTTON3_DOWN_MASK) != 0 ) {
buf.append("button3 ");
}
return buf.toString();
}
static String getVKText(int keyCode) {
VKCollection vkCollect = getVKCollection();
Integer key = Integer.valueOf(keyCode);
String name = vkCollect.findName(key);
if (name != null) {
return name.substring(3);
}
int expected_modifiers =
(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
Field[] fields = KeyEvent.class.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
try {
if (fields[i].getModifiers() == expected_modifiers
&& fields[i].getType() == Integer.TYPE
&& fields[i].getName().startsWith("VK_")
&& fields[i].getInt(KeyEvent.class) == keyCode)
{
name = fields[i].getName();
vkCollect.put(name, key);
return name.substring(3);
}
} catch (IllegalAccessException e) {
assert(false);
}
}
return "UNKNOWN";
}
Returns a cached instance of AWTKeyStroke
(or a subclass of
AWTKeyStroke
) which is equal to this instance.
Returns: a cached instance which is equal to this instance
/**
* Returns a cached instance of <code>AWTKeyStroke</code> (or a subclass of
* <code>AWTKeyStroke</code>) which is equal to this instance.
*
* @return a cached instance which is equal to this instance
*/
protected Object readResolve() throws java.io.ObjectStreamException {
synchronized (AWTKeyStroke.class) {
if (getClass().equals(getAWTKeyStrokeClass())) {
return getCachedStroke(keyChar, keyCode, modifiers, onKeyRelease);
}
}
return this;
}
private static int mapOldModifiers(int modifiers) {
if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
modifiers |= InputEvent.SHIFT_DOWN_MASK;
}
if ((modifiers & InputEvent.ALT_MASK) != 0) {
modifiers |= InputEvent.ALT_DOWN_MASK;
}
if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {
modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
}
if ((modifiers & InputEvent.CTRL_MASK) != 0) {
modifiers |= InputEvent.CTRL_DOWN_MASK;
}
if ((modifiers & InputEvent.META_MASK) != 0) {
modifiers |= InputEvent.META_DOWN_MASK;
}
modifiers &= InputEvent.SHIFT_DOWN_MASK
| InputEvent.ALT_DOWN_MASK
| InputEvent.ALT_GRAPH_DOWN_MASK
| InputEvent.CTRL_DOWN_MASK
| InputEvent.META_DOWN_MASK
| InputEvent.BUTTON1_DOWN_MASK
| InputEvent.BUTTON2_DOWN_MASK
| InputEvent.BUTTON3_DOWN_MASK;
return modifiers;
}
private static int mapNewModifiers(int modifiers) {
if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0) {
modifiers |= InputEvent.SHIFT_MASK;
}
if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0) {
modifiers |= InputEvent.ALT_MASK;
}
if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) {
modifiers |= InputEvent.ALT_GRAPH_MASK;
}
if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0) {
modifiers |= InputEvent.CTRL_MASK;
}
if ((modifiers & InputEvent.META_DOWN_MASK) != 0) {
modifiers |= InputEvent.META_MASK;
}
return modifiers;
}
}
class VKCollection {
Map code2name;
Map name2code;
public VKCollection() {
code2name = new HashMap();
name2code = new HashMap();
}
public synchronized void put(String name, Integer code) {
assert((name != null) && (code != null));
assert(findName(code) == null);
assert(findCode(name) == null);
code2name.put(code, name);
name2code.put(name, code);
}
public synchronized Integer findCode(String name) {
assert(name != null);
return (Integer)name2code.get(name);
}
public synchronized String findName(Integer code) {
assert(code != null);
return (String)code2name.get(code);
}
}