001: /*
002: *
003: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License version
008: * 2 only, as published by the Free Software Foundation.
009: *
010: * This program is distributed in the hope that it will be useful, but
011: * WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * General Public License version 2 for more details (a copy is
014: * included at /legal/license.txt).
015: *
016: * You should have received a copy of the GNU General Public License
017: * version 2 along with this work; if not, write to the Free Software
018: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019: * 02110-1301 USA
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
022: * Clara, CA 95054 or visit www.sun.com if you need additional
023: * information or have any questions.
024: */
025: package java.awt;
026:
027: import java.awt.event.KeyEvent;
028: import java.awt.event.InputEvent;
029: import java.util.Collections;
030: import java.util.HashMap;
031: import java.util.Map;
032: import java.util.StringTokenizer;
033: import java.io.Serializable;
034: import java.lang.reflect.*;
035:
036: /**
037: * An <code>AWTKeyStroke</code> represents a key action on the
038: * keyboard, or equivalent input device. <code>AWTKeyStroke</code>s
039: * can correspond to only a press or release of a
040: * particular key, just as <code>KEY_PRESSED</code> and
041: * <code>KEY_RELEASED</code> <code>KeyEvent</code>s do;
042: * alternately, they can correspond to typing a specific Java character, just
043: * as <code>KEY_TYPED</code> <code>KeyEvent</code>s do.
044: * In all cases, <code>AWTKeyStroke</code>s can specify modifiers
045: * (alt, shift, control, meta, or a combination thereof) which must be present
046: * during the action for an exact match.
047: * <p>
048: * <code>AWTKeyStrokes</code> are immutable, and are intended
049: * to be unique. Client code should never create an
050: * <code>AWTKeyStroke</code> on its own, but should instead use
051: * a variant of <code>getAWTKeyStroke</code>. Client use of these factory
052: * methods allows the <code>AWTKeyStroke</code> implementation
053: * to cache and share instances efficiently.
054: *
055: * @see #getAWTKeyStroke
056: *
057: * @version 1.14, 01/23/03
058: * @author Arnaud Weber
059: * @author David Mendenhall
060: * @since 1.4
061: */
062: public class AWTKeyStroke implements Serializable {
063: private static Map cache;
064: private static AWTKeyStroke cacheKey;
065: private static Class subclass = AWTKeyStroke.class;
066: private static Map modifierKeywords;
067:
068: /**
069: * Maps from VK_XXX (as a String) to an Integer. This is done to
070: * avoid the overhead of the reflective call to find the constant.
071: */
072: private static Map vkMap;
073:
074: // Fix 6234000.
075: static final long serialVersionUID = -6430539691155161871L;
076:
077: private char keyChar = KeyEvent.CHAR_UNDEFINED;
078: private int keyCode = KeyEvent.VK_UNDEFINED;
079: private int modifiers;
080: private boolean onKeyRelease;
081:
082: /**
083: * Constructs an <code>AWTKeyStroke</code> with default values.
084: * The default values used are:
085: * <table border="1" summary="AWTKeyStroke default values">
086: * <tr><th>Property</th><th>Default Value</th></tr>
087: * <tr>
088: * <td>Key Char</td>
089: * <td><code>KeyEvent.CHAR_UNDEFINED</code></td>
090: * </tr>
091: * <tr>
092: * <td>Key Code</td>
093: * <td><code>KeyEvent.VK_UNDEFINED</code></td>
094: * </tr>
095: * <tr>
096: * <td>Modifiers</td>
097: * <td>none</td>
098: * </tr>
099: * <tr>
100: * <td>On key release?</td>
101: * <td><code>false</code></td>
102: * </tr>
103: * </table>
104: *
105: * <code>AWTKeyStroke</code>s should not be constructed
106: * by client code. Use a variant of <code>getAWTKeyStroke</code>
107: * instead.
108: *
109: * @see #getAWTKeyStroke
110: */
111: // PBP/PP 6218482
112: // Make package private
113: // protected AWTKeyStroke() { }
114: AWTKeyStroke() {
115: }
116:
117: /**
118: * Constructs an <code>AWTKeyStroke</code> with the specified
119: * values. <code>AWTKeyStroke</code>s should not be constructed
120: * by client code. Use a variant of <code>getAWTKeyStroke</code>
121: * instead.
122: *
123: * @param keyChar the character value for a keyboard key
124: * @param keyCode the key code for this <code>AWTKeyStroke</code>
125: * @param modifiers a bitwise-ored combination of any modifiers
126: * @param onKeyRelease <code>true</code> if this
127: * <code>AWTKeyStroke</code> corresponds
128: * to a key release; <code>false</code> otherwise
129: * @see #getAWTKeyStroke
130: */
131: // PBP/PP 6218482
132: // Make package private
133: // protected AWTKeyStroke(char keyChar, int keyCode, int modifiers,
134: // boolean onKeyRelease) {
135: AWTKeyStroke(char keyChar, int keyCode, int modifiers,
136: boolean onKeyRelease) {
137: this .keyChar = keyChar;
138: this .keyCode = keyCode;
139: this .modifiers = modifiers;
140: this .onKeyRelease = onKeyRelease;
141: }
142:
143: private void copy(AWTKeyStroke rhs) {
144: this .keyChar = rhs.keyChar;
145: this .keyCode = rhs.keyCode;
146: this .modifiers = rhs.modifiers;
147: this .onKeyRelease = rhs.onKeyRelease;
148: }
149:
150: /**
151: * Registers a new class which the factory methods in
152: * <code>AWTKeyStroke</code> will use when generating new
153: * instances of <code>AWTKeyStroke</code>s. After invoking this
154: * method, the factory methods will return instances of the specified
155: * Class. The specified Class must be either <code>AWTKeyStroke</code>
156: * or derived from <code>AWTKeyStroke</code>, and it must have a
157: * no-arg constructor. The constructor can be of any accessibility,
158: * including <code>private</code>. This operation
159: * flushes the current <code>AWTKeyStroke</code> cache.
160: *
161: * @param subclass the new Class of which the factory methods should create
162: * instances
163: * @throws IllegalArgumentException if subclass is <code>null</code>,
164: * or if subclass does not have a no-arg constructor
165: * @throws ClassCastException if subclass is not
166: * <code>AWTKeyStroke</code>, or a class derived from
167: * <code>AWTKeyStroke</code>
168: */
169: // PBP/PP 6218482
170: // Remove registerSubClass().
171: /*
172: protected static void registerSubclass(Class subclass) {
173: if (subclass == null) {
174: throw new IllegalArgumentException("subclass cannot be null");
175: }
176: if (AWTKeyStroke.subclass.equals(subclass)) {
177: // Already registered
178: return;
179: }
180: if (!AWTKeyStroke.class.isAssignableFrom(subclass)) {
181: throw new ClassCastException("subclass is not derived from AWTKeyStroke");
182: }
183: String couldNotInstantiate = "subclass could not be instantiated";
184: try {
185: AWTKeyStroke stroke = allocateNewInstance(subclass);
186: if (stroke == null) {
187: throw new IllegalArgumentException(couldNotInstantiate);
188: }
189: } catch (NoSuchMethodError e) {
190: throw new IllegalArgumentException(couldNotInstantiate);
191: } catch (ExceptionInInitializerError e) {
192: throw new IllegalArgumentException(couldNotInstantiate);
193: } catch (InstantiationException e) {
194: throw new IllegalArgumentException(couldNotInstantiate);
195: }
196: synchronized (AWTKeyStroke.class) {
197: AWTKeyStroke.subclass = subclass;
198: cache = null;
199: cacheKey = null;
200: }
201: }
202: */
203:
204: // Reflection allows us to bypass all security and access restrictions.
205: // This allows us to define javax.swing.KeyStroke with only a private
206: // no-arg constructor, yet still instantiate it from AWT without
207: // special knowledge of Swing.
208: private static AWTKeyStroke allocateNewInstance(Class clazz)
209: throws InstantiationException {
210: Class[] parameterTypes = new Class[0];
211: AWTKeyStroke newInstance = null;
212: try {
213: final Constructor constructor = clazz
214: .getDeclaredConstructor(parameterTypes);
215: java.security.AccessController
216: .doPrivileged(new java.security.PrivilegedAction() {
217: public Object run() {
218: constructor.setAccessible(true);
219: return null;
220: }
221: });
222:
223: Object[] args = new Object[0];
224: newInstance = (AWTKeyStroke) constructor.newInstance(args);
225: } catch (InstantiationException ie) {
226: throw ie;
227: } catch (Exception e) {
228: throw new InstantiationException(
229: "Couldn't instantiate class " + clazz.getName());
230: }
231: return newInstance;
232: }
233:
234: private static synchronized AWTKeyStroke getCachedStroke(
235: char keyChar, int keyCode, int modifiers,
236: boolean onKeyRelease) {
237: if (cache == null) {
238: cache = new HashMap();
239: }
240: if (cacheKey == null) {
241: try {
242: cacheKey = allocateNewInstance(subclass);
243: } catch (InstantiationException e) {
244: }
245: }
246: cacheKey.keyChar = keyChar;
247: cacheKey.keyCode = keyCode;
248: cacheKey.modifiers = mapNewModifiers(mapOldModifiers(modifiers));
249: cacheKey.onKeyRelease = onKeyRelease;
250: AWTKeyStroke stroke = (AWTKeyStroke) cache.get(cacheKey);
251: if (stroke == null) {
252: stroke = cacheKey;
253: cache.put(stroke, stroke);
254: cacheKey = null;
255: }
256: return stroke;
257: }
258:
259: /**
260: * Returns a shared instance of an <code>AWTKeyStroke</code>
261: * that represents a <code>KEY_TYPED</code> event for the
262: * specified character.
263: *
264: * @param keyChar the character value for a keyboard key
265: * @return an <code>AWTKeyStroke</code> object for that key
266: */
267: public static AWTKeyStroke getAWTKeyStroke(char keyChar) {
268: return getCachedStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false);
269: }
270:
271: /**
272: * Returns a shared instance of an <code>AWTKeyStroke</code>,
273: * given a Character object and a set of modifiers. Note
274: * that the first parameter is of type Character rather than
275: * char. This is to avoid inadvertent clashes with
276: * calls to <code>getAWTKeyStroke(int keyCode, int modifiers)</code>.
277: *
278: * The modifiers consist of any combination of:<ul>
279: * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
280: * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
281: * <li>java.awt.event.InputEvent.META_DOWN_MASK
282: * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
283: * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
284: * <li>java.awt.event.InputEvent.BUTTON1_DOWN_MASK
285: * <li>java.awt.event.InputEvent.BUTTON2_DOWN_MASK
286: * <li>java.awt.event.InputEvent.BUTTON3_DOWN_MASK
287: * </ul>
288: * The old modifiers <ul>
289: * <li>java.awt.event.InputEvent.SHIFT_MASK
290: * <li>java.awt.event.InputEvent.CTRL_MASK
291: * <li>java.awt.event.InputEvent.META_MASK
292: * <li>java.awt.event.InputEvent.ALT_MASK
293: * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
294: * </ul>
295: * also can be used, but they are mapped to _DOWN_ modifiers.
296: *
297: * Since these numbers are all different powers of two, any combination of
298: * them is an integer in which each bit represents a different modifier
299: * key. Use 0 to specify no modifiers.
300: *
301: * @param keyChar the Character object for a keyboard character
302: * @param modifiers a bitwise-ored combination of any modifiers
303: * @return an <code>AWTKeyStroke</code> object for that key
304: * @throws IllegalArgumentException if <code>keyChar</code> is
305: * <code>null</code>
306: *
307: * @see java.awt.event.InputEvent
308: */
309: public static AWTKeyStroke getAWTKeyStroke(Character keyChar,
310: int modifiers) {
311: if (keyChar == null) {
312: throw new IllegalArgumentException("keyChar cannot be null");
313: }
314: return getCachedStroke(keyChar.charValue(),
315: KeyEvent.VK_UNDEFINED, modifiers, false);
316: }
317:
318: /**
319: * Returns a shared instance of an <code>AWTKeyStroke</code>,
320: * given a numeric key code and a set of modifiers, specifying
321: * whether the key is activated when it is pressed or released.
322: * <p>
323: * The "virtual key" constants defined in
324: * <code>java.awt.event.KeyEvent</code> can be
325: * used to specify the key code. For example:<ul>
326: * <li><code>java.awt.event.KeyEvent.VK_ENTER</code>
327: * <li><code>java.awt.event.KeyEvent.VK_TAB</code>
328: * <li><code>java.awt.event.KeyEvent.VK_SPACE</code>
329: * </ul>
330: * The modifiers consist of any combination of:<ul>
331: * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
332: * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
333: * <li>java.awt.event.InputEvent.META_DOWN_MASK
334: * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
335: * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
336: * <li>java.awt.event.InputEvent.BUTTON1_DOWN_MASK
337: * <li>java.awt.event.InputEvent.BUTTON2_DOWN_MASK
338: * <li>java.awt.event.InputEvent.BUTTON3_DOWN_MASK
339: * </ul>
340: * The old modifiers <ul>
341: * <li>java.awt.event.InputEvent.SHIFT_MASK
342: * <li>java.awt.event.InputEvent.CTRL_MASK
343: * <li>java.awt.event.InputEvent.META_MASK
344: * <li>java.awt.event.InputEvent.ALT_MASK
345: * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
346: * </ul>
347: * also can be used, but they are mapped to _DOWN_ modifiers.
348: *
349: * Since these numbers are all different powers of two, any combination of
350: * them is an integer in which each bit represents a different modifier
351: * key. Use 0 to specify no modifiers.
352: *
353: * @param keyCode an int specifying the numeric code for a keyboard key
354: * @param modifiers a bitwise-ored combination of any modifiers
355: * @param onKeyRelease <code>true</code> if the <code>AWTKeyStroke</code>
356: * should represent a key release; <code>false</code> otherwise
357: * @return an AWTKeyStroke object for that key
358: *
359: * @see java.awt.event.KeyEvent
360: * @see java.awt.event.InputEvent
361: */
362: public static AWTKeyStroke getAWTKeyStroke(int keyCode,
363: int modifiers, boolean onKeyRelease) {
364: return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode,
365: modifiers, onKeyRelease);
366: }
367:
368: /**
369: * Returns a shared instance of an <code>AWTKeyStroke</code>,
370: * given a numeric key code and a set of modifiers. The returned
371: * <code>AWTKeyStroke</code> will correspond to a key press.
372: * <p>
373: * The "virtual key" constants defined in
374: * <code>java.awt.event.KeyEvent</code> can be
375: * used to specify the key code. For example:<ul>
376: * <li><code>java.awt.event.KeyEvent.VK_ENTER</code>
377: * <li><code>java.awt.event.KeyEvent.VK_TAB</code>
378: * <li><code>java.awt.event.KeyEvent.VK_SPACE</code>
379: * </ul>
380: * The modifiers consist of any combination of:<ul>
381: * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
382: * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
383: * <li>java.awt.event.InputEvent.META_DOWN_MASK
384: * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
385: * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
386: * <li>java.awt.event.InputEvent.BUTTON1_DOWN_MASK
387: * <li>java.awt.event.InputEvent.BUTTON2_DOWN_MASK
388: * <li>java.awt.event.InputEvent.BUTTON3_DOWN_MASK
389: * </ul>
390: * The old modifiers <ul>
391: * <li>java.awt.event.InputEvent.SHIFT_MASK
392: * <li>java.awt.event.InputEvent.CTRL_MASK
393: * <li>java.awt.event.InputEvent.META_MASK
394: * <li>java.awt.event.InputEvent.ALT_MASK
395: * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
396: * </ul>
397: * also can be used, but they are mapped to _DOWN_ modifiers.
398: *
399: * Since these numbers are all different powers of two, any combination of
400: * them is an integer in which each bit represents a different modifier
401: * key. Use 0 to specify no modifiers.
402: *
403: * @param keyCode an int specifying the numeric code for a keyboard key
404: * @param modifiers a bitwise-ored combination of any modifiers
405: * @return an <code>AWTKeyStroke</code> object for that key
406: *
407: * @see java.awt.event.KeyEvent
408: * @see java.awt.event.InputEvent
409: */
410: public static AWTKeyStroke getAWTKeyStroke(int keyCode,
411: int modifiers) {
412: return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode,
413: modifiers, false);
414: }
415:
416: /**
417: * Returns an <code>AWTKeyStroke</code> which represents the
418: * stroke which generated a given <code>KeyEvent</code>.
419: * <p>
420: * This method obtains the key char from a <code>KeyTyped</code>
421: * event, and the key code from a <code>KeyPressed</code> or
422: * <code>KeyReleased</code> event. The <code>KeyEvent</code> modifiers are
423: * obtained for all three types of <code>KeyEvent</code>.
424: *
425: * @param anEvent the <code>KeyEvent</code> from which to
426: * obtain the <code>AWTKeyStroke</code>
427: * @return the <code>AWTKeyStroke</code> that precipitated the event
428: */
429: public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) {
430: int id = anEvent.getID();
431: switch (id) {
432: case KeyEvent.KEY_PRESSED:
433: case KeyEvent.KEY_RELEASED:
434: return getCachedStroke(KeyEvent.CHAR_UNDEFINED, anEvent
435: .getKeyCode(), anEvent.getModifiers(),
436: (id == KeyEvent.KEY_RELEASED));
437: case KeyEvent.KEY_TYPED:
438: return getCachedStroke(anEvent.getKeyChar(),
439: KeyEvent.VK_UNDEFINED, anEvent.getModifiers(),
440: false);
441: default:
442: // Invalid ID for this KeyEvent
443: return null;
444: }
445: }
446:
447: /**
448: * Parses a string and returns an <code>AWTKeyStroke</code>.
449: * The string must have the following syntax:
450: * <pre>
451: * <modifiers>* (<typedID> | <pressedReleasedID>)
452: *
453: * modifiers := shift | control | ctrl | meta | alt | button1 | button2 | button3
454: * typedID := typed <typedKey>
455: * typedKey := string of length 1 giving Unicode character.
456: * pressedReleasedID := (pressed | released) key
457: * key := KeyEvent key code name, i.e. the name following "VK_".
458: * </pre>
459: * If typed, pressed or released is not specified, pressed is assumed. Here
460: * are some examples:
461: * <pre>
462: * "INSERT" => getAWTKeyStroke(KeyEvent.VK_INSERT, 0);
463: * "control DELETE" => getAWTKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK);
464: * "alt shift X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK);
465: * "alt shift released X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true);
466: * "typed a" => getAWTKeyStroke('a');
467: * </pre>
468: *
469: * @param s a String formatted as described above
470: * @return an <code>AWTKeyStroke</code> object for that String
471: * @throws IllegalArgumentException if <code>s</code> is <code>null</code>,
472: * or is formatted incorrectly
473: */
474: public static AWTKeyStroke getAWTKeyStroke(String s) {
475: if (s == null) {
476: throw new IllegalArgumentException("String cannot be null");
477: }
478: final String errmsg = "String formatted incorrectly";
479: StringTokenizer st = new StringTokenizer(s, " ");
480: int mask = 0;
481: boolean released = false;
482: boolean typed = false;
483: boolean pressed = false;
484: if (modifierKeywords == null) {
485: synchronized (AWTKeyStroke.class) {
486: if (modifierKeywords == null) {
487: Map uninitializedMap = new HashMap(8, 1.0f);
488: uninitializedMap.put("shift", new Integer(
489: InputEvent.SHIFT_DOWN_MASK
490: | InputEvent.SHIFT_MASK));
491: uninitializedMap.put("control", new Integer(
492: InputEvent.CTRL_DOWN_MASK
493: | InputEvent.CTRL_MASK));
494: uninitializedMap.put("ctrl", new Integer(
495: InputEvent.CTRL_DOWN_MASK
496: | InputEvent.CTRL_MASK));
497: uninitializedMap.put("meta", new Integer(
498: InputEvent.META_DOWN_MASK
499: | InputEvent.META_MASK));
500: uninitializedMap.put("alt", new Integer(
501: InputEvent.ALT_DOWN_MASK
502: | InputEvent.ALT_MASK));
503: uninitializedMap.put("altGraph", new Integer(
504: InputEvent.ALT_GRAPH_DOWN_MASK
505: | InputEvent.ALT_GRAPH_MASK));
506: uninitializedMap.put("button1", new Integer(
507: InputEvent.BUTTON1_DOWN_MASK));
508: uninitializedMap.put("button2", new Integer(
509: InputEvent.BUTTON2_DOWN_MASK));
510: uninitializedMap.put("button3", new Integer(
511: InputEvent.BUTTON3_DOWN_MASK));
512: modifierKeywords = Collections
513: .synchronizedMap(uninitializedMap);
514: }
515: }
516: }
517: int count = st.countTokens();
518: for (int i = 1; i <= count; i++) {
519: String token = st.nextToken();
520: if (typed) {
521: if (token.length() != 1 || i != count) {
522: throw new IllegalArgumentException(errmsg);
523: }
524: return getCachedStroke(token.charAt(0),
525: KeyEvent.VK_UNDEFINED, mask, false);
526: }
527: if (pressed || released || i == count) {
528: if (i != count) {
529: throw new IllegalArgumentException(errmsg);
530: }
531: String keyCodeName = "VK_" + token;
532: int keyCode = getVKValue(keyCodeName);
533: return getCachedStroke(KeyEvent.CHAR_UNDEFINED,
534: keyCode, mask, released);
535: }
536: if (token.equals("released")) {
537: released = true;
538: continue;
539: }
540: if (token.equals("pressed")) {
541: pressed = true;
542: continue;
543: }
544: if (token.equals("typed")) {
545: typed = true;
546: continue;
547: }
548: Integer tokenMask = (Integer) modifierKeywords.get(token);
549: if (tokenMask != null) {
550: mask |= tokenMask.intValue();
551: } else {
552: throw new IllegalArgumentException(errmsg);
553: }
554: }
555: throw new IllegalArgumentException(errmsg);
556: }
557:
558: /**
559: * Returns the integer constant for the KeyEvent.VK field named
560: * <code>key</code>. This will throw an
561: * <code>IllegalArgumentException</code> if <code>key</code> is
562: * not a valid constant.
563: */
564: private static int getVKValue(String key) {
565: if (vkMap == null) {
566: vkMap = Collections.synchronizedMap(new HashMap());
567: }
568: Integer value = (Integer) vkMap.get(key);
569: if (value == null) {
570: int keyCode = 0;
571: final String errmsg = "String formatted incorrectly";
572: try {
573: keyCode = KeyEvent.class.getField(key).getInt(
574: KeyEvent.class);
575: } catch (NoSuchFieldException nsfe) {
576: throw new IllegalArgumentException(errmsg);
577: } catch (IllegalAccessException iae) {
578: throw new IllegalArgumentException(errmsg);
579: }
580: value = new Integer(keyCode);
581: vkMap.put(key, value);
582: }
583: return value.intValue();
584: }
585:
586: /**
587: * Returns the character for this <code>AWTKeyStroke</code>.
588: *
589: * @return a char value
590: * @see #getAWTKeyStroke(char)
591: */
592: public final char getKeyChar() {
593: return keyChar;
594: }
595:
596: /**
597: * Returns the numeric key code for this <code>AWTKeyStroke</code>.
598: *
599: * @return an int containing the key code value
600: * @see #getAWTKeyStroke(int,int)
601: */
602: public final int getKeyCode() {
603: return keyCode;
604: }
605:
606: /**
607: * Returns the modifier keys for this <code>AWTKeyStroke</code>.
608: *
609: * @return an int containing the modifiers
610: * @see #getAWTKeyStroke(int,int)
611: */
612: public final int getModifiers() {
613: return modifiers;
614: }
615:
616: /**
617: * Returns whether this <code>AWTKeyStroke</code> represents a key release.
618: *
619: * @return <code>true</code> if this <code>AWTKeyStroke</code>
620: * represents a key release; <code>false</code> otherwise
621: * @see #getAWTKeyStroke(int,int,boolean)
622: */
623: public final boolean isOnKeyRelease() {
624: return onKeyRelease;
625: }
626:
627: /**
628: * Returns the type of <code>KeyEvent</code> which corresponds to
629: * this <code>AWTKeyStroke</code>.
630: *
631: * @return <code>KeyEvent.KEY_PRESSED</code>,
632: * <code>KeyEvent.KEY_TYPED</code>,
633: * or <code>KeyEvent.KEY_RELEASED</code>
634: * @see java.awt.event.KeyEvent
635: */
636: public final int getKeyEventType() {
637: if (keyCode == KeyEvent.VK_UNDEFINED) {
638: return KeyEvent.KEY_TYPED;
639: } else {
640: return (onKeyRelease) ? KeyEvent.KEY_RELEASED
641: : KeyEvent.KEY_PRESSED;
642: }
643: }
644:
645: /**
646: * Returns a numeric value for this object that is likely to be unique,
647: * making it a good choice as the index value in a hash table.
648: *
649: * @return an int that represents this object
650: */
651: public int hashCode() {
652: return (((int) keyChar) + 1) * (2 * (keyCode + 1))
653: * (modifiers + 1) + (onKeyRelease ? 1 : 2);
654: }
655:
656: /**
657: * Returns true if this object is identical to the specified object.
658: *
659: * @param anObject the Object to compare this object to
660: * @return true if the objects are identical
661: */
662: public final boolean equals(Object anObject) {
663: if (anObject instanceof AWTKeyStroke) {
664: AWTKeyStroke ks = (AWTKeyStroke) anObject;
665: return (ks.keyChar == keyChar && ks.keyCode == keyCode
666: && ks.onKeyRelease == onKeyRelease && ks.modifiers == modifiers);
667: }
668: return false;
669: }
670:
671: /**
672: * Returns a string that displays and identifies this object's properties.
673: *
674: * @return a String representation of this object
675: */
676: public String toString() {
677: if (keyCode == KeyEvent.VK_UNDEFINED) {
678: return "keyChar " + KeyEvent.getKeyModifiersText(modifiers)
679: + keyChar;
680: } else {
681: return "keyCode " + KeyEvent.getKeyModifiersText(modifiers)
682: + KeyEvent.getKeyText(keyCode)
683: + (onKeyRelease ? "-R" : "-P");
684: }
685: }
686:
687: /**
688: * Returns a cached instance of <code>AWTKeyStroke</code>
689: * which is equal to this instance.
690: *
691: * @return a cached instance which is equal to this instance
692: */
693: // PBP/PP 6218482
694: // Make readResolve() private, like java.net.InetAddress.
695: // protected Object readResolve() throws java.io.ObjectStreamException {
696: private Object readResolve() throws java.io.ObjectStreamException {
697: synchronized (AWTKeyStroke.class) {
698: /*
699: Class newClass = getClass();
700: if (!newClass.equals(subclass)) {
701: registerSubclass(newClass);
702: }
703: */
704: return getCachedStroke(keyChar, keyCode, modifiers,
705: onKeyRelease);
706: }
707: }
708:
709: private static int mapOldModifiers(int modifiers) {
710: if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
711: modifiers |= InputEvent.SHIFT_DOWN_MASK;
712: }
713: if ((modifiers & InputEvent.ALT_MASK) != 0) {
714: modifiers |= InputEvent.ALT_DOWN_MASK;
715: }
716: if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {
717: modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
718: }
719: if ((modifiers & InputEvent.CTRL_MASK) != 0) {
720: modifiers |= InputEvent.CTRL_DOWN_MASK;
721: }
722: if ((modifiers & InputEvent.META_MASK) != 0) {
723: modifiers |= InputEvent.META_DOWN_MASK;
724: }
725: if ((modifiers & InputEvent.BUTTON1_MASK) != 0) {
726: modifiers |= InputEvent.BUTTON1_DOWN_MASK;
727: }
728: modifiers &= InputEvent.SHIFT_DOWN_MASK
729: | InputEvent.ALT_DOWN_MASK
730: | InputEvent.ALT_GRAPH_DOWN_MASK
731: | InputEvent.CTRL_DOWN_MASK | InputEvent.META_DOWN_MASK
732: | InputEvent.BUTTON1_DOWN_MASK
733: | InputEvent.BUTTON2_DOWN_MASK
734: | InputEvent.BUTTON3_DOWN_MASK;
735: return modifiers;
736: }
737:
738: private static int mapNewModifiers(int modifiers) {
739: if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0) {
740: modifiers |= InputEvent.SHIFT_MASK;
741: }
742: if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0) {
743: modifiers |= InputEvent.ALT_MASK;
744: }
745: if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) {
746: modifiers |= InputEvent.ALT_GRAPH_MASK;
747: }
748: if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0) {
749: modifiers |= InputEvent.CTRL_MASK;
750: }
751: if ((modifiers & InputEvent.META_DOWN_MASK) != 0) {
752: modifiers |= InputEvent.META_MASK;
753: }
754: return modifiers;
755: }
756: }
|