History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/awt/AWTKeyStroke.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/awt/AWTKeyStroke.java+865−0
@@ -0,0 +1,865 @@
1+/*
2+ * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+package java.awt;
26+
27+import java.awt.event.KeyEvent;
28+import java.awt.event.InputEvent;
29+import java.util.Collections;
30+import java.util.HashMap;
31+import java.util.Map;
32+import java.util.StringTokenizer;
33+import java.io.Serializable;
34+import java.security.AccessController;
35+import java.security.PrivilegedAction;
36+import java.lang.reflect.Constructor;
37+import java.lang.reflect.InvocationTargetException;
38+import java.lang.reflect.Modifier;
39+import java.lang.reflect.Field;
40+
41+/**
42+ * An <code>AWTKeyStroke</code> represents a key action on the
43+ * keyboard, or equivalent input device. <code>AWTKeyStroke</code>s
44+ * can correspond to only a press or release of a
45+ * particular key, just as <code>KEY_PRESSED</code> and
46+ * <code>KEY_RELEASED</code> <code>KeyEvent</code>s do;
47+ * alternately, they can correspond to typing a specific Java character, just
48+ * as <code>KEY_TYPED</code> <code>KeyEvent</code>s do.
49+ * In all cases, <code>AWTKeyStroke</code>s can specify modifiers
50+ * (alt, shift, control, meta, altGraph, or a combination thereof) which must be present
51+ * during the action for an exact match.
52+ * <p>
53+ * <code>AWTKeyStrokes</code> are immutable, and are intended
54+ * to be unique. Client code should never create an
55+ * <code>AWTKeyStroke</code> on its own, but should instead use
56+ * a variant of <code>getAWTKeyStroke</code>. Client use of these factory
57+ * methods allows the <code>AWTKeyStroke</code> implementation
58+ * to cache and share instances efficiently.
59+ *
60+ * @see #getAWTKeyStroke
61+ *
62+ * @author Arnaud Weber
63+ * @author David Mendenhall
64+ * @since 1.4
65+ */
66+public class AWTKeyStroke implements Serializable {
67+ static final long serialVersionUID = -6430539691155161871L;
68+
69+ private static Map cache;
70+ private static AWTKeyStroke cacheKey;
71+ private static Constructor ctor = getCtor(AWTKeyStroke.class);
72+ private static Map modifierKeywords;
73+ /**
74+ * Associates VK_XXX (as a String) with code (as Integer). This is
75+ * done to avoid the overhead of the reflective call to find the
76+ * constant.
77+ */
78+ private static VKCollection vks;
79+
80+ private char keyChar = KeyEvent.CHAR_UNDEFINED;
81+ private int keyCode = KeyEvent.VK_UNDEFINED;
82+ private int modifiers;
83+ private boolean onKeyRelease;
84+
85+ static {
86+ /* ensure that the necessary native libraries are loaded */
87+ Toolkit.loadLibraries();
88+ }
89+
90+ /**
91+ * Constructs an <code>AWTKeyStroke</code> with default values.
92+ * The default values used are:
93+ * <table border="1" summary="AWTKeyStroke default values">
94+ * <tr><th>Property</th><th>Default Value</th></tr>
95+ * <tr>
96+ * <td>Key Char</td>
97+ * <td><code>KeyEvent.CHAR_UNDEFINED</code></td>
98+ * </tr>
99+ * <tr>
100+ * <td>Key Code</td>
101+ * <td><code>KeyEvent.VK_UNDEFINED</code></td>
102+ * </tr>
103+ * <tr>
104+ * <td>Modifiers</td>
105+ * <td>none</td>
106+ * </tr>
107+ * <tr>
108+ * <td>On key release?</td>
109+ * <td><code>false</code></td>
110+ * </tr>
111+ * </table>
112+ *
113+ * <code>AWTKeyStroke</code>s should not be constructed
114+ * by client code. Use a variant of <code>getAWTKeyStroke</code>
115+ * instead.
116+ *
117+ * @see #getAWTKeyStroke
118+ */
119+ protected AWTKeyStroke() {
120+ }
121+
122+ /**
123+ * Constructs an <code>AWTKeyStroke</code> with the specified
124+ * values. <code>AWTKeyStroke</code>s should not be constructed
125+ * by client code. Use a variant of <code>getAWTKeyStroke</code>
126+ * instead.
127+ *
128+ * @param keyChar the character value for a keyboard key
129+ * @param keyCode the key code for this <code>AWTKeyStroke</code>
130+ * @param modifiers a bitwise-ored combination of any modifiers
131+ * @param onKeyRelease <code>true</code> if this
132+ * <code>AWTKeyStroke</code> corresponds
133+ * to a key release; <code>false</code> otherwise
134+ * @see #getAWTKeyStroke
135+ */
136+ protected AWTKeyStroke(char keyChar, int keyCode, int modifiers,
137+ boolean onKeyRelease) {
138+ this.keyChar = keyChar;
139+ this.keyCode = keyCode;
140+ this.modifiers = modifiers;
141+ this.onKeyRelease = onKeyRelease;
142+ }
143+
144+ /**
145+ * Registers a new class which the factory methods in
146+ * <code>AWTKeyStroke</code> will use when generating new
147+ * instances of <code>AWTKeyStroke</code>s. After invoking this
148+ * method, the factory methods will return instances of the specified
149+ * Class. The specified Class must be either <code>AWTKeyStroke</code>
150+ * or derived from <code>AWTKeyStroke</code>, and it must have a
151+ * no-arg constructor. The constructor can be of any accessibility,
152+ * including <code>private</code>. This operation
153+ * flushes the current <code>AWTKeyStroke</code> cache.
154+ *
155+ * @param subclass the new Class of which the factory methods should create
156+ * instances
157+ * @throws IllegalArgumentException if subclass is <code>null</code>,
158+ * or if subclass does not have a no-arg constructor
159+ * @throws ClassCastException if subclass is not
160+ * <code>AWTKeyStroke</code>, or a class derived from
161+ * <code>AWTKeyStroke</code>
162+ */
163+ protected static void registerSubclass(Class<?> subclass) {
164+ if (subclass == null) {
165+ throw new IllegalArgumentException("subclass cannot be null");
166+ }
167+ if (AWTKeyStroke.ctor.getDeclaringClass().equals(subclass)) {
168+ // Already registered
169+ return;
170+ }
171+ if (!AWTKeyStroke.class.isAssignableFrom(subclass)) {
172+ throw new ClassCastException("subclass is not derived from AWTKeyStroke");
173+ }
174+
175+ Constructor ctor = getCtor(subclass);
176+
177+ String couldNotInstantiate = "subclass could not be instantiated";
178+
179+ if (ctor == null) {
180+ throw new IllegalArgumentException(couldNotInstantiate);
181+ }
182+ try {
183+ AWTKeyStroke stroke = (AWTKeyStroke)ctor.newInstance((Object[]) null);
184+ if (stroke == null) {
185+ throw new IllegalArgumentException(couldNotInstantiate);
186+ }
187+ } catch (NoSuchMethodError e) {
188+ throw new IllegalArgumentException(couldNotInstantiate);
189+ } catch (ExceptionInInitializerError e) {
190+ throw new IllegalArgumentException(couldNotInstantiate);
191+ } catch (InstantiationException e) {
192+ throw new IllegalArgumentException(couldNotInstantiate);
193+ } catch (IllegalAccessException e) {
194+ throw new IllegalArgumentException(couldNotInstantiate);
195+ } catch (InvocationTargetException e) {
196+ throw new IllegalArgumentException(couldNotInstantiate);
197+ }
198+
199+ synchronized (AWTKeyStroke.class) {
200+ AWTKeyStroke.ctor = ctor;
201+ cache = null;
202+ cacheKey = null;
203+ }
204+ }
205+
206+ /* returns noarg Constructor for class with accessible flag. No security
207+ threat as accessible flag is set only for this Constructor object,
208+ not for Class constructor.
209+ */
210+ private static Constructor getCtor(final Class clazz)
211+ {
212+ Object ctor = AccessController.doPrivileged(new PrivilegedAction() {
213+ public Object run() {
214+ try {
215+ Constructor ctor = clazz.getDeclaredConstructor((Class[]) null);
216+ if (ctor != null) {
217+ ctor.setAccessible(true);
218+ }
219+ return ctor;
220+ } catch (SecurityException e) {
221+ } catch (NoSuchMethodException e) {
222+ }
223+ return null;
224+ }
225+ });
226+ return (Constructor)ctor;
227+ }
228+
229+ private static synchronized AWTKeyStroke getCachedStroke
230+ (char keyChar, int keyCode, int modifiers, boolean onKeyRelease)
231+ {
232+ if (cache == null) {
233+ cache = new HashMap();
234+ }
235+
236+ if (cacheKey == null) {
237+ try {
238+ cacheKey = (AWTKeyStroke)ctor.newInstance((Object[]) null);
239+ } catch (InstantiationException e) {
240+ assert(false);
241+ } catch (IllegalAccessException e) {
242+ assert(false);
243+ } catch (InvocationTargetException e) {
244+ assert(false);
245+ }
246+ }
247+ cacheKey.keyChar = keyChar;
248+ cacheKey.keyCode = keyCode;
249+ cacheKey.modifiers = mapNewModifiers(mapOldModifiers(modifiers));
250+ cacheKey.onKeyRelease = onKeyRelease;
251+
252+ AWTKeyStroke stroke = (AWTKeyStroke)cache.get(cacheKey);
253+ if (stroke == null) {
254+ stroke = cacheKey;
255+ cache.put(stroke, stroke);
256+ cacheKey = null;
257+ }
258+
259+ return stroke;
260+ }
261+
262+ /**
263+ * Returns a shared instance of an <code>AWTKeyStroke</code>
264+ * that represents a <code>KEY_TYPED</code> event for the
265+ * specified character.
266+ *
267+ * @param keyChar the character value for a keyboard key
268+ * @return an <code>AWTKeyStroke</code> object for that key
269+ */
270+ public static AWTKeyStroke getAWTKeyStroke(char keyChar) {
271+ return getCachedStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false);
272+ }
273+
274+ /**
275+ * Returns a shared instance of an {@code AWTKeyStroke}
276+ * that represents a {@code KEY_TYPED} event for the
277+ * specified Character object and a set of modifiers. Note
278+ * that the first parameter is of type Character rather than
279+ * char. This is to avoid inadvertent clashes with
280+ * calls to <code>getAWTKeyStroke(int keyCode, int modifiers)</code>.
281+ *
282+ * The modifiers consist of any combination of following:<ul>
283+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
284+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
285+ * <li>java.awt.event.InputEvent.META_DOWN_MASK
286+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
287+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
288+ * </ul>
289+ * The old modifiers listed below also can be used, but they are
290+ * mapped to _DOWN_ modifiers. <ul>
291+ * <li>java.awt.event.InputEvent.SHIFT_MASK
292+ * <li>java.awt.event.InputEvent.CTRL_MASK
293+ * <li>java.awt.event.InputEvent.META_MASK
294+ * <li>java.awt.event.InputEvent.ALT_MASK
295+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
296+ * </ul>
297+ * also can be used, but they are mapped to _DOWN_ modifiers.
298+ *
299+ * Since these numbers are all different powers of two, any combination of
300+ * them is an integer in which each bit represents a different modifier
301+ * key. Use 0 to specify no modifiers.
302+ *
303+ * @param keyChar the Character object for a keyboard character
304+ * @param modifiers a bitwise-ored combination of any modifiers
305+ * @return an <code>AWTKeyStroke</code> object for that key
306+ * @throws IllegalArgumentException if <code>keyChar</code> is
307+ * <code>null</code>
308+ *
309+ * @see java.awt.event.InputEvent
310+ */
311+ public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers)
312+ {
313+ if (keyChar == null) {
314+ throw new IllegalArgumentException("keyChar cannot be null");
315+ }
316+ return getCachedStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED,
317+ modifiers, false);
318+ }
319+
320+ /**
321+ * Returns a shared instance of an <code>AWTKeyStroke</code>,
322+ * given a numeric key code and a set of modifiers, specifying
323+ * whether the key is activated when it is pressed or released.
324+ * <p>
325+ * The "virtual key" constants defined in
326+ * <code>java.awt.event.KeyEvent</code> can be
327+ * used to specify the key code. For example:<ul>
328+ * <li><code>java.awt.event.KeyEvent.VK_ENTER</code>
329+ * <li><code>java.awt.event.KeyEvent.VK_TAB</code>
330+ * <li><code>java.awt.event.KeyEvent.VK_SPACE</code>
331+ * </ul>
332+ * Alternatively, the key code may be obtained by calling
333+ * <code>java.awt.event.KeyEvent.getExtendedKeyCodeForChar</code>.
334+ *
335+ * The modifiers consist of any combination of:<ul>
336+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
337+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
338+ * <li>java.awt.event.InputEvent.META_DOWN_MASK
339+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
340+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
341+ * </ul>
342+ * The old modifiers <ul>
343+ * <li>java.awt.event.InputEvent.SHIFT_MASK
344+ * <li>java.awt.event.InputEvent.CTRL_MASK
345+ * <li>java.awt.event.InputEvent.META_MASK
346+ * <li>java.awt.event.InputEvent.ALT_MASK
347+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
348+ * </ul>
349+ * also can be used, but they are mapped to _DOWN_ modifiers.
350+ *
351+ * Since these numbers are all different powers of two, any combination of
352+ * them is an integer in which each bit represents a different modifier
353+ * key. Use 0 to specify no modifiers.
354+ *
355+ * @param keyCode an int specifying the numeric code for a keyboard key
356+ * @param modifiers a bitwise-ored combination of any modifiers
357+ * @param onKeyRelease <code>true</code> if the <code>AWTKeyStroke</code>
358+ * should represent a key release; <code>false</code> otherwise
359+ * @return an AWTKeyStroke object for that key
360+ *
361+ * @see java.awt.event.KeyEvent
362+ * @see java.awt.event.InputEvent
363+ */
364+ public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers,
365+ boolean onKeyRelease) {
366+ return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,
367+ onKeyRelease);
368+ }
369+
370+ /**
371+ * Returns a shared instance of an <code>AWTKeyStroke</code>,
372+ * given a numeric key code and a set of modifiers. The returned
373+ * <code>AWTKeyStroke</code> will correspond to a key press.
374+ * <p>
375+ * The "virtual key" constants defined in
376+ * <code>java.awt.event.KeyEvent</code> can be
377+ * used to specify the key code. For example:<ul>
378+ * <li><code>java.awt.event.KeyEvent.VK_ENTER</code>
379+ * <li><code>java.awt.event.KeyEvent.VK_TAB</code>
380+ * <li><code>java.awt.event.KeyEvent.VK_SPACE</code>
381+ * </ul>
382+ * The modifiers consist of any combination of:<ul>
383+ * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
384+ * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
385+ * <li>java.awt.event.InputEvent.META_DOWN_MASK
386+ * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
387+ * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
388+ * </ul>
389+ * The old modifiers <ul>
390+ * <li>java.awt.event.InputEvent.SHIFT_MASK
391+ * <li>java.awt.event.InputEvent.CTRL_MASK
392+ * <li>java.awt.event.InputEvent.META_MASK
393+ * <li>java.awt.event.InputEvent.ALT_MASK
394+ * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
395+ * </ul>
396+ * also can be used, but they are mapped to _DOWN_ modifiers.
397+ *
398+ * Since these numbers are all different powers of two, any combination of
399+ * them is an integer in which each bit represents a different modifier
400+ * key. Use 0 to specify no modifiers.
401+ *
402+ * @param keyCode an int specifying the numeric code for a keyboard key
403+ * @param modifiers a bitwise-ored combination of any modifiers
404+ * @return an <code>AWTKeyStroke</code> object for that key
405+ *
406+ * @see java.awt.event.KeyEvent
407+ * @see java.awt.event.InputEvent
408+ */
409+ public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) {
410+ return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,
411+ false);
412+ }
413+
414+ /**
415+ * Returns an <code>AWTKeyStroke</code> which represents the
416+ * stroke which generated a given <code>KeyEvent</code>.
417+ * <p>
418+ * This method obtains the keyChar from a <code>KeyTyped</code>
419+ * event, and the keyCode from a <code>KeyPressed</code> or
420+ * <code>KeyReleased</code> event. The <code>KeyEvent</code> modifiers are
421+ * obtained for all three types of <code>KeyEvent</code>.
422+ *
423+ * @param anEvent the <code>KeyEvent</code> from which to
424+ * obtain the <code>AWTKeyStroke</code>
425+ * @throws NullPointerException if <code>anEvent</code> is null
426+ * @return the <code>AWTKeyStroke</code> that precipitated the event
427+ */
428+ public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) {
429+ int id = anEvent.getID();
430+ switch(id) {
431+ case KeyEvent.KEY_PRESSED:
432+ case KeyEvent.KEY_RELEASED:
433+ return getCachedStroke(KeyEvent.CHAR_UNDEFINED,
434+ anEvent.getKeyCode(),
435+ anEvent.getModifiers(),
436+ (id == KeyEvent.KEY_RELEASED));
437+ case KeyEvent.KEY_TYPED:
438+ return getCachedStroke(anEvent.getKeyChar(),
439+ KeyEvent.VK_UNDEFINED,
440+ anEvent.getModifiers(),
441+ false);
442+ default:
443+ // Invalid ID for this KeyEvent
444+ return null;
445+ }
446+ }
447+
448+ /**
449+ * Parses a string and returns an <code>AWTKeyStroke</code>.
450+ * The string must have the following syntax:
451+ * <pre>
452+ * &lt;modifiers&gt;* (&lt;typedID&gt; | &lt;pressedReleasedID&gt;)
453+ *
454+ * modifiers := shift | control | ctrl | meta | alt | altGraph
455+ * typedID := typed &lt;typedKey&gt;
456+ * typedKey := string of length 1 giving Unicode character.
457+ * pressedReleasedID := (pressed | released) key
458+ * key := KeyEvent key code name, i.e. the name following "VK_".
459+ * </pre>
460+ * If typed, pressed or released is not specified, pressed is assumed. Here
461+ * are some examples:
462+ * <pre>
463+ * "INSERT" => getAWTKeyStroke(KeyEvent.VK_INSERT, 0);
464+ * "control DELETE" => getAWTKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK);
465+ * "alt shift X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK);
466+ * "alt shift released X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true);
467+ * "typed a" => getAWTKeyStroke('a');
468+ * </pre>
469+ *
470+ * @param s a String formatted as described above
471+ * @return an <code>AWTKeyStroke</code> object for that String
472+ * @throws IllegalArgumentException if <code>s</code> is <code>null</code>,
473+ * or is formatted incorrectly
474+ */
475+ public static AWTKeyStroke getAWTKeyStroke(String s) {
476+ if (s == null) {
477+ throw new IllegalArgumentException("String cannot be null");
478+ }
479+
480+ final String errmsg = "String formatted incorrectly";
481+
482+ StringTokenizer st = new StringTokenizer(s, " ");
483+
484+ int mask = 0;
485+ boolean released = false;
486+ boolean typed = false;
487+ boolean pressed = false;
488+
489+ synchronized (AWTKeyStroke.class) {
490+ if (modifierKeywords == null) {
491+ Map uninitializedMap = new HashMap(8, 1.0f);
492+ uninitializedMap.put("shift",
493+ Integer.valueOf(InputEvent.SHIFT_DOWN_MASK
494+ |InputEvent.SHIFT_MASK));
495+ uninitializedMap.put("control",
496+ Integer.valueOf(InputEvent.CTRL_DOWN_MASK
497+ |InputEvent.CTRL_MASK));
498+ uninitializedMap.put("ctrl",
499+ Integer.valueOf(InputEvent.CTRL_DOWN_MASK
500+ |InputEvent.CTRL_MASK));
501+ uninitializedMap.put("meta",
502+ Integer.valueOf(InputEvent.META_DOWN_MASK
503+ |InputEvent.META_MASK));
504+ uninitializedMap.put("alt",
505+ Integer.valueOf(InputEvent.ALT_DOWN_MASK
506+ |InputEvent.ALT_MASK));
507+ uninitializedMap.put("altGraph",
508+ Integer.valueOf(InputEvent.ALT_GRAPH_DOWN_MASK
509+ |InputEvent.ALT_GRAPH_MASK));
510+ uninitializedMap.put("button1",
511+ Integer.valueOf(InputEvent.BUTTON1_DOWN_MASK));
512+ uninitializedMap.put("button2",
513+ Integer.valueOf(InputEvent.BUTTON2_DOWN_MASK));
514+ uninitializedMap.put("button3",
515+ Integer.valueOf(InputEvent.BUTTON3_DOWN_MASK));
516+ modifierKeywords =
517+ Collections.synchronizedMap(uninitializedMap);
518+ }
519+ }
520+
521+ int count = st.countTokens();
522+
523+ for (int i = 1; i <= count; i++) {
524+ String token = st.nextToken();
525+
526+ if (typed) {
527+ if (token.length() != 1 || i != count) {
528+ throw new IllegalArgumentException(errmsg);
529+ }
530+ return getCachedStroke(token.charAt(0), KeyEvent.VK_UNDEFINED,
531+ mask, false);
532+ }
533+
534+ if (pressed || released || i == count) {
535+ if (i != count) {
536+ throw new IllegalArgumentException(errmsg);
537+ }
538+
539+ String keyCodeName = "VK_" + token;
540+ int keyCode = getVKValue(keyCodeName);
541+
542+ return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode,
543+ mask, released);
544+ }
545+
546+ if (token.equals("released")) {
547+ released = true;
548+ continue;
549+ }
550+ if (token.equals("pressed")) {
551+ pressed = true;
552+ continue;
553+ }
554+ if (token.equals("typed")) {
555+ typed = true;
556+ continue;
557+ }
558+
559+ Integer tokenMask = (Integer)modifierKeywords.get(token);
560+ if (tokenMask != null) {
561+ mask |= tokenMask.intValue();
562+ } else {
563+ throw new IllegalArgumentException(errmsg);
564+ }
565+ }
566+
567+ throw new IllegalArgumentException(errmsg);
568+ }
569+
570+ private static VKCollection getVKCollection() {
571+ if (vks == null) {
572+ vks = new VKCollection();
573+ }
574+ return vks;
575+ }
576+ /**
577+ * Returns the integer constant for the KeyEvent.VK field named
578+ * <code>key</code>. This will throw an
579+ * <code>IllegalArgumentException</code> if <code>key</code> is
580+ * not a valid constant.
581+ */
582+ private static int getVKValue(String key) {
583+ VKCollection vkCollect = getVKCollection();
584+
585+ Integer value = vkCollect.findCode(key);
586+
587+ if (value == null) {
588+ int keyCode = 0;
589+ final String errmsg = "String formatted incorrectly";
590+
591+ try {
592+ keyCode = KeyEvent.class.getField(key).getInt(KeyEvent.class);
593+ } catch (NoSuchFieldException nsfe) {
594+ throw new IllegalArgumentException(errmsg);
595+ } catch (IllegalAccessException iae) {
596+ throw new IllegalArgumentException(errmsg);
597+ }
598+ value = Integer.valueOf(keyCode);
599+ vkCollect.put(key, value);
600+ }
601+ return value.intValue();
602+ }
603+
604+ /**
605+ * Returns the character for this <code>AWTKeyStroke</code>.
606+ *
607+ * @return a char value
608+ * @see #getAWTKeyStroke(char)
609+ * @see KeyEvent#getKeyChar
610+ */
611+ public final char getKeyChar() {
612+ return keyChar;
613+ }
614+
615+ /**
616+ * Returns the numeric key code for this <code>AWTKeyStroke</code>.
617+ *
618+ * @return an int containing the key code value
619+ * @see #getAWTKeyStroke(int,int)
620+ * @see KeyEvent#getKeyCode
621+ */
622+ public final int getKeyCode() {
623+ return keyCode;
624+ }
625+
626+ /**
627+ * Returns the modifier keys for this <code>AWTKeyStroke</code>.
628+ *
629+ * @return an int containing the modifiers
630+ * @see #getAWTKeyStroke(int,int)
631+ */
632+ public final int getModifiers() {
633+ return modifiers;
634+ }
635+
636+ /**
637+ * Returns whether this <code>AWTKeyStroke</code> represents a key release.
638+ *
639+ * @return <code>true</code> if this <code>AWTKeyStroke</code>
640+ * represents a key release; <code>false</code> otherwise
641+ * @see #getAWTKeyStroke(int,int,boolean)
642+ */
643+ public final boolean isOnKeyRelease() {
644+ return onKeyRelease;
645+ }
646+
647+ /**
648+ * Returns the type of <code>KeyEvent</code> which corresponds to
649+ * this <code>AWTKeyStroke</code>.
650+ *
651+ * @return <code>KeyEvent.KEY_PRESSED</code>,
652+ * <code>KeyEvent.KEY_TYPED</code>,
653+ * or <code>KeyEvent.KEY_RELEASED</code>
654+ * @see java.awt.event.KeyEvent
655+ */
656+ public final int getKeyEventType() {
657+ if (keyCode == KeyEvent.VK_UNDEFINED) {
658+ return KeyEvent.KEY_TYPED;
659+ } else {
660+ return (onKeyRelease)
661+ ? KeyEvent.KEY_RELEASED
662+ : KeyEvent.KEY_PRESSED;
663+ }
664+ }
665+
666+ /**
667+ * Returns a numeric value for this object that is likely to be unique,
668+ * making it a good choice as the index value in a hash table.
669+ *
670+ * @return an int that represents this object
671+ */
672+ public int hashCode() {
673+ return (((int)keyChar) + 1) * (2 * (keyCode + 1)) * (modifiers + 1) +
674+ (onKeyRelease ? 1 : 2);
675+ }
676+
677+ /**
678+ * Returns true if this object is identical to the specified object.
679+ *
680+ * @param anObject the Object to compare this object to
681+ * @return true if the objects are identical
682+ */
683+ public final boolean equals(Object anObject) {
684+ if (anObject instanceof AWTKeyStroke) {
685+ AWTKeyStroke ks = (AWTKeyStroke)anObject;
686+ return (ks.keyChar == keyChar && ks.keyCode == keyCode &&
687+ ks.onKeyRelease == onKeyRelease &&
688+ ks.modifiers == modifiers);
689+ }
690+ return false;
691+ }
692+
693+ /**
694+ * Returns a string that displays and identifies this object's properties.
695+ * The <code>String</code> returned by this method can be passed
696+ * as a parameter to <code>getAWTKeyStroke(String)</code> to produce
697+ * a key stroke equal to this key stroke.
698+ *
699+ * @return a String representation of this object
700+ * @see #getAWTKeyStroke(String)
701+ */
702+ public String toString() {
703+ if (keyCode == KeyEvent.VK_UNDEFINED) {
704+ return getModifiersText(modifiers) + "typed " + keyChar;
705+ } else {
706+ return getModifiersText(modifiers) +
707+ (onKeyRelease ? "released" : "pressed") + " " +
708+ getVKText(keyCode);
709+ }
710+ }
711+
712+ static String getModifiersText(int modifiers) {
713+ StringBuilder buf = new StringBuilder();
714+
715+ if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0 ) {
716+ buf.append("shift ");
717+ }
718+ if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0 ) {
719+ buf.append("ctrl ");
720+ }
721+ if ((modifiers & InputEvent.META_DOWN_MASK) != 0 ) {
722+ buf.append("meta ");
723+ }
724+ if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0 ) {
725+ buf.append("alt ");
726+ }
727+ if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0 ) {
728+ buf.append("altGraph ");
729+ }
730+ if ((modifiers & InputEvent.BUTTON1_DOWN_MASK) != 0 ) {
731+ buf.append("button1 ");
732+ }
733+ if ((modifiers & InputEvent.BUTTON2_DOWN_MASK) != 0 ) {
734+ buf.append("button2 ");
735+ }
736+ if ((modifiers & InputEvent.BUTTON3_DOWN_MASK) != 0 ) {
737+ buf.append("button3 ");
738+ }
739+
740+ return buf.toString();
741+ }
742+
743+ static String getVKText(int keyCode) {
744+ VKCollection vkCollect = getVKCollection();
745+ Integer key = Integer.valueOf(keyCode);
746+ String name = vkCollect.findName(key);
747+ if (name != null) {
748+ return name.substring(3);
749+ }
750+ int expected_modifiers =
751+ (Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL);
752+
753+ Field[] fields = KeyEvent.class.getDeclaredFields();
754+ for (int i = 0; i < fields.length; i++) {
755+ try {
756+ if (fields[i].getModifiers() == expected_modifiers
757+ && fields[i].getType() == Integer.TYPE
758+ && fields[i].getName().startsWith("VK_")
759+ && fields[i].getInt(KeyEvent.class) == keyCode)
760+ {
761+ name = fields[i].getName();
762+ vkCollect.put(name, key);
763+ return name.substring(3);
764+ }
765+ } catch (IllegalAccessException e) {
766+ assert(false);
767+ }
768+ }
769+ return "UNKNOWN";
770+ }
771+
772+ /**
773+ * Returns a cached instance of <code>AWTKeyStroke</code> (or a subclass of
774+ * <code>AWTKeyStroke</code>) which is equal to this instance.
775+ *
776+ * @return a cached instance which is equal to this instance
777+ */
778+ protected Object readResolve() throws java.io.ObjectStreamException {
779+ synchronized (AWTKeyStroke.class) {
780+ Class newClass = getClass();
781+ if (!newClass.equals(ctor.getDeclaringClass())) {
782+ registerSubclass(newClass);
783+ }
784+ return getCachedStroke(keyChar, keyCode, modifiers, onKeyRelease);
785+ }
786+ }
787+
788+ private static int mapOldModifiers(int modifiers) {
789+ if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
790+ modifiers |= InputEvent.SHIFT_DOWN_MASK;
791+ }
792+ if ((modifiers & InputEvent.ALT_MASK) != 0) {
793+ modifiers |= InputEvent.ALT_DOWN_MASK;
794+ }
795+ if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {
796+ modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
797+ }
798+ if ((modifiers & InputEvent.CTRL_MASK) != 0) {
799+ modifiers |= InputEvent.CTRL_DOWN_MASK;
800+ }
801+ if ((modifiers & InputEvent.META_MASK) != 0) {
802+ modifiers |= InputEvent.META_DOWN_MASK;
803+ }
804+
805+ modifiers &= InputEvent.SHIFT_DOWN_MASK
806+ | InputEvent.ALT_DOWN_MASK
807+ | InputEvent.ALT_GRAPH_DOWN_MASK
808+ | InputEvent.CTRL_DOWN_MASK
809+ | InputEvent.META_DOWN_MASK
810+ | InputEvent.BUTTON1_DOWN_MASK
811+ | InputEvent.BUTTON2_DOWN_MASK
812+ | InputEvent.BUTTON3_DOWN_MASK;
813+
814+ return modifiers;
815+ }
816+
817+ private static int mapNewModifiers(int modifiers) {
818+ if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0) {
819+ modifiers |= InputEvent.SHIFT_MASK;
820+ }
821+ if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0) {
822+ modifiers |= InputEvent.ALT_MASK;
823+ }
824+ if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) {
825+ modifiers |= InputEvent.ALT_GRAPH_MASK;
826+ }
827+ if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0) {
828+ modifiers |= InputEvent.CTRL_MASK;
829+ }
830+ if ((modifiers & InputEvent.META_DOWN_MASK) != 0) {
831+ modifiers |= InputEvent.META_MASK;
832+ }
833+
834+ return modifiers;
835+ }
836+
837+}
838+
839+class VKCollection {
840+ Map code2name;
841+ Map name2code;
842+
843+ public VKCollection() {
844+ code2name = new HashMap();
845+ name2code = new HashMap();
846+ }
847+
848+ public synchronized void put(String name, Integer code) {
849+ assert((name != null) && (code != null));
850+ assert(findName(code) == null);
851+ assert(findCode(name) == null);
852+ code2name.put(code, name);
853+ name2code.put(name, code);
854+ }
855+
856+ public synchronized Integer findCode(String name) {
857+ assert(name != null);
858+ return (Integer)name2code.get(name);
859+ }
860+
861+ public synchronized String findName(Integer code) {
862+ assert(code != null);
863+ return (String)code2name.get(code);
864+ }
865+}