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 */
25package java.awt;
26
27import java.awt.event.KeyEvent;
28import java.awt.event.InputEvent;
29import java.util.Collections;
30import java.util.HashMap;
31import java.util.Map;
32import java.util.StringTokenizer;
33import java.io.Serializable;
34import java.security.AccessController;
35import java.security.PrivilegedAction;
36import java.lang.reflect.Constructor;
37import java.lang.reflect.InvocationTargetException;
38import java.lang.reflect.Modifier;
39import 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 */
66public 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
839class 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}