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