1. /*
  2. * @(#)AWTKeyStroke.java 1.14 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt;
  8. import java.awt.event.KeyEvent;
  9. import java.awt.event.InputEvent;
  10. import java.util.Collections;
  11. import java.util.HashMap;
  12. import java.util.Map;
  13. import java.util.StringTokenizer;
  14. import java.io.Serializable;
  15. /**
  16. * An <code>AWTKeyStroke</code> represents a key action on the
  17. * keyboard, or equivalent input device. <code>AWTKeyStroke</code>s
  18. * can correspond to only a press or release of a
  19. * particular key, just as <code>KEY_PRESSED</code> and
  20. * <code>KEY_RELEASED</code> <code>KeyEvent</code>s do;
  21. * alternately, they can correspond to typing a specific Java character, just
  22. * as <code>KEY_TYPED</code> <code>KeyEvent</code>s do.
  23. * In all cases, <code>AWTKeyStroke</code>s can specify modifiers
  24. * (alt, shift, control, meta, or a combination thereof) which must be present
  25. * during the action for an exact match.
  26. * <p>
  27. * <code>AWTKeyStrokes</code> are immutable, and are intended
  28. * to be unique. Client code should never create an
  29. * <code>AWTKeyStroke</code> on its own, but should instead use
  30. * a variant of <code>getAWTKeyStroke</code>. Client use of these factory
  31. * methods allows the <code>AWTKeyStroke</code> implementation
  32. * to cache and share instances efficiently.
  33. *
  34. * @see #getAWTKeyStroke
  35. *
  36. * @version 1.14, 01/23/03
  37. * @author Arnaud Weber
  38. * @author David Mendenhall
  39. * @since 1.4
  40. */
  41. public class AWTKeyStroke implements Serializable {
  42. private static Map cache;
  43. private static AWTKeyStroke cacheKey;
  44. private static Class subclass = AWTKeyStroke.class;
  45. private static Map modifierKeywords;
  46. /**
  47. * Maps from VK_XXX (as a String) to an Integer. This is done to
  48. * avoid the overhead of the reflective call to find the constant.
  49. */
  50. private static Map vkMap;
  51. private char keyChar = KeyEvent.CHAR_UNDEFINED;
  52. private int keyCode = KeyEvent.VK_UNDEFINED;
  53. private int modifiers;
  54. private boolean onKeyRelease;
  55. static {
  56. /* ensure that the necessary native libraries are loaded */
  57. Toolkit.loadLibraries();
  58. }
  59. /**
  60. * Constructs an <code>AWTKeyStroke</code> with default values.
  61. * The default values used are:
  62. * <table border="1" summary="AWTKeyStroke default values">
  63. * <tr><th>Property</th><th>Default Value</th></tr>
  64. * <tr>
  65. * <td>Key Char</td>
  66. * <td><code>KeyEvent.CHAR_UNDEFINED</code></td>
  67. * </tr>
  68. * <tr>
  69. * <td>Key Code</td>
  70. * <td><code>KeyEvent.VK_UNDEFINED</code></td>
  71. * </tr>
  72. * <tr>
  73. * <td>Modifiers</td>
  74. * <td>none</td>
  75. * </tr>
  76. * <tr>
  77. * <td>On key release?</td>
  78. * <td><code>false</code></td>
  79. * </tr>
  80. * </table>
  81. *
  82. * <code>AWTKeyStroke</code>s should not be constructed
  83. * by client code. Use a variant of <code>getAWTKeyStroke</code>
  84. * instead.
  85. *
  86. * @see #getAWTKeyStroke
  87. */
  88. protected AWTKeyStroke() {
  89. }
  90. /**
  91. * Constructs an <code>AWTKeyStroke</code> with the specified
  92. * values. <code>AWTKeyStroke</code>s should not be constructed
  93. * by client code. Use a variant of <code>getAWTKeyStroke</code>
  94. * instead.
  95. *
  96. * @param keyChar the character value for a keyboard key
  97. * @param keyCode the key code for this <code>AWTKeyStroke</code>
  98. * @param modifiers a bitwise-ored combination of any modifiers
  99. * @param onKeyRelease <code>true</code> if this
  100. * <code>AWTKeyStroke</code> corresponds
  101. * to a key release; <code>false</code> otherwise
  102. * @see #getAWTKeyStroke
  103. */
  104. protected AWTKeyStroke(char keyChar, int keyCode, int modifiers,
  105. boolean onKeyRelease) {
  106. this.keyChar = keyChar;
  107. this.keyCode = keyCode;
  108. this.modifiers = modifiers;
  109. this.onKeyRelease = onKeyRelease;
  110. }
  111. private void copy(AWTKeyStroke rhs) {
  112. this.keyChar = rhs.keyChar;
  113. this.keyCode = rhs.keyCode;
  114. this.modifiers = rhs.modifiers;
  115. this.onKeyRelease = rhs.onKeyRelease;
  116. }
  117. /**
  118. * Registers a new class which the factory methods in
  119. * <code>AWTKeyStroke</code> will use when generating new
  120. * instances of <code>AWTKeyStroke</code>s. After invoking this
  121. * method, the factory methods will return instances of the specified
  122. * Class. The specified Class must be either <code>AWTKeyStroke</code>
  123. * or derived from <code>AWTKeyStroke</code>, and it must have a
  124. * no-arg constructor. The constructor can be of any accessibility,
  125. * including <code>private</code>. This operation
  126. * flushes the current <code>AWTKeyStroke</code> cache.
  127. *
  128. * @param subclass the new Class of which the factory methods should create
  129. * instances
  130. * @throws IllegalArgumentException if subclass is <code>null</code>,
  131. * or if subclass does not have a no-arg constructor
  132. * @throws ClassCastException if subclass is not
  133. * <code>AWTKeyStroke</code>, or a class derived from
  134. * <code>AWTKeyStroke</code>
  135. */
  136. protected static void registerSubclass(Class subclass) {
  137. if (subclass == null) {
  138. throw new IllegalArgumentException("subclass cannot be null");
  139. }
  140. if (AWTKeyStroke.subclass.equals(subclass)) {
  141. // Already registered
  142. return;
  143. }
  144. if (!AWTKeyStroke.class.isAssignableFrom(subclass)) {
  145. throw new ClassCastException("subclass is not derived from AWTKeyStroke");
  146. }
  147. String couldNotInstantiate = "subclass could not be instantiated";
  148. try {
  149. AWTKeyStroke stroke = allocateNewInstance(subclass);
  150. if (stroke == null) {
  151. throw new IllegalArgumentException(couldNotInstantiate);
  152. }
  153. } catch (NoSuchMethodError e) {
  154. throw new IllegalArgumentException(couldNotInstantiate);
  155. } catch (ExceptionInInitializerError e) {
  156. throw new IllegalArgumentException(couldNotInstantiate);
  157. } catch (InstantiationException e) {
  158. throw new IllegalArgumentException(couldNotInstantiate);
  159. }
  160. synchronized (AWTKeyStroke.class) {
  161. AWTKeyStroke.subclass = subclass;
  162. cache = null;
  163. cacheKey = null;
  164. }
  165. }
  166. // Native function allows us to bypass all security and access
  167. // restrictions. This allows us to define javax.swing.KeyStroke with only
  168. // a private no-arg constructor, yet still instantiate it from AWT without
  169. // special knowledge of Swing.
  170. private static native AWTKeyStroke allocateNewInstance(Class clazz)
  171. throws InstantiationException;
  172. private static synchronized AWTKeyStroke getCachedStroke
  173. (char keyChar, int keyCode, int modifiers, boolean onKeyRelease)
  174. {
  175. if (cache == null) {
  176. cache = new HashMap();
  177. }
  178. if (cacheKey == null) {
  179. try {
  180. cacheKey = allocateNewInstance(subclass);
  181. } catch (InstantiationException e) {
  182. }
  183. }
  184. cacheKey.keyChar = keyChar;
  185. cacheKey.keyCode = keyCode;
  186. cacheKey.modifiers = mapNewModifiers(mapOldModifiers(modifiers));
  187. cacheKey.onKeyRelease = onKeyRelease;
  188. AWTKeyStroke stroke = (AWTKeyStroke)cache.get(cacheKey);
  189. if (stroke == null) {
  190. stroke = cacheKey;
  191. cache.put(stroke, stroke);
  192. cacheKey = null;
  193. }
  194. return stroke;
  195. }
  196. /**
  197. * Returns a shared instance of an <code>AWTKeyStroke</code>
  198. * that represents a <code>KEY_TYPED</code> event for the
  199. * specified character.
  200. *
  201. * @param keyChar the character value for a keyboard key
  202. * @return an <code>AWTKeyStroke</code> object for that key
  203. */
  204. public static AWTKeyStroke getAWTKeyStroke(char keyChar) {
  205. return getCachedStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false);
  206. }
  207. /**
  208. * Returns a shared instance of an <code>AWTKeyStroke</code>,
  209. * given a Character object and a set of modifiers. Note
  210. * that the first parameter is of type Character rather than
  211. * char. This is to avoid inadvertent clashes with
  212. * calls to <code>getAWTKeyStroke(int keyCode, int modifiers)</code>.
  213. *
  214. * The modifiers consist of any combination of:<ul>
  215. * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
  216. * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
  217. * <li>java.awt.event.InputEvent.META_DOWN_MASK
  218. * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
  219. * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  220. * <li>java.awt.event.InputEvent.BUTTON1_DOWN_MASK
  221. * <li>java.awt.event.InputEvent.BUTTON2_DOWN_MASK
  222. * <li>java.awt.event.InputEvent.BUTTON3_DOWN_MASK
  223. * </ul>
  224. * The old modifiers <ul>
  225. * <li>java.awt.event.InputEvent.SHIFT_MASK
  226. * <li>java.awt.event.InputEvent.CTRL_MASK
  227. * <li>java.awt.event.InputEvent.META_MASK
  228. * <li>java.awt.event.InputEvent.ALT_MASK
  229. * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
  230. * </ul>
  231. * also can be used, but they are mapped to _DOWN_ modifiers.
  232. *
  233. * Since these numbers are all different powers of two, any combination of
  234. * them is an integer in which each bit represents a different modifier
  235. * key. Use 0 to specify no modifiers.
  236. *
  237. * @param keyChar the Character object for a keyboard character
  238. * @param modifiers a bitwise-ored combination of any modifiers
  239. * @return an <code>AWTKeyStroke</code> object for that key
  240. * @throws IllegalArgumentException if <code>keyChar</code> is
  241. * <code>null</code>
  242. *
  243. * @see java.awt.event.InputEvent
  244. */
  245. public static AWTKeyStroke getAWTKeyStroke(Character keyChar,
  246. int modifiers) {
  247. if (keyChar == null) {
  248. throw new IllegalArgumentException("keyChar cannot be null");
  249. }
  250. return getCachedStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED,
  251. modifiers, false);
  252. }
  253. /**
  254. * Returns a shared instance of an <code>AWTKeyStroke</code>,
  255. * given a numeric key code and a set of modifiers, specifying
  256. * whether the key is activated when it is pressed or released.
  257. * <p>
  258. * The "virtual key" constants defined in
  259. * <code>java.awt.event.KeyEvent</code> can be
  260. * used to specify the key code. For example:<ul>
  261. * <li><code>java.awt.event.KeyEvent.VK_ENTER</code>
  262. * <li><code>java.awt.event.KeyEvent.VK_TAB</code>
  263. * <li><code>java.awt.event.KeyEvent.VK_SPACE</code>
  264. * </ul>
  265. * The modifiers consist of any combination of:<ul>
  266. * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
  267. * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
  268. * <li>java.awt.event.InputEvent.META_DOWN_MASK
  269. * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
  270. * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  271. * <li>java.awt.event.InputEvent.BUTTON1_DOWN_MASK
  272. * <li>java.awt.event.InputEvent.BUTTON2_DOWN_MASK
  273. * <li>java.awt.event.InputEvent.BUTTON3_DOWN_MASK
  274. * </ul>
  275. * The old modifiers <ul>
  276. * <li>java.awt.event.InputEvent.SHIFT_MASK
  277. * <li>java.awt.event.InputEvent.CTRL_MASK
  278. * <li>java.awt.event.InputEvent.META_MASK
  279. * <li>java.awt.event.InputEvent.ALT_MASK
  280. * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
  281. * </ul>
  282. * also can be used, but they are mapped to _DOWN_ modifiers.
  283. *
  284. * Since these numbers are all different powers of two, any combination of
  285. * them is an integer in which each bit represents a different modifier
  286. * key. Use 0 to specify no modifiers.
  287. *
  288. * @param keyCode an int specifying the numeric code for a keyboard key
  289. * @param modifiers a bitwise-ored combination of any modifiers
  290. * @param onKeyRelease <code>true</code> if the <code>AWTKeyStroke</code>
  291. * should represent a key release; <code>false</code> otherwise
  292. * @return an AWTKeyStroke object for that key
  293. *
  294. * @see java.awt.event.KeyEvent
  295. * @see java.awt.event.InputEvent
  296. */
  297. public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers,
  298. boolean onKeyRelease) {
  299. return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,
  300. onKeyRelease);
  301. }
  302. /**
  303. * Returns a shared instance of an <code>AWTKeyStroke</code>,
  304. * given a numeric key code and a set of modifiers. The returned
  305. * <code>AWTKeyStroke</code> will correspond to a key press.
  306. * <p>
  307. * The "virtual key" constants defined in
  308. * <code>java.awt.event.KeyEvent</code> can be
  309. * used to specify the key code. For example:<ul>
  310. * <li><code>java.awt.event.KeyEvent.VK_ENTER</code>
  311. * <li><code>java.awt.event.KeyEvent.VK_TAB</code>
  312. * <li><code>java.awt.event.KeyEvent.VK_SPACE</code>
  313. * </ul>
  314. * The modifiers consist of any combination of:<ul>
  315. * <li>java.awt.event.InputEvent.SHIFT_DOWN_MASK
  316. * <li>java.awt.event.InputEvent.CTRL_DOWN_MASK
  317. * <li>java.awt.event.InputEvent.META_DOWN_MASK
  318. * <li>java.awt.event.InputEvent.ALT_DOWN_MASK
  319. * <li>java.awt.event.InputEvent.ALT_GRAPH_DOWN_MASK
  320. * <li>java.awt.event.InputEvent.BUTTON1_DOWN_MASK
  321. * <li>java.awt.event.InputEvent.BUTTON2_DOWN_MASK
  322. * <li>java.awt.event.InputEvent.BUTTON3_DOWN_MASK
  323. * </ul>
  324. * The old modifiers <ul>
  325. * <li>java.awt.event.InputEvent.SHIFT_MASK
  326. * <li>java.awt.event.InputEvent.CTRL_MASK
  327. * <li>java.awt.event.InputEvent.META_MASK
  328. * <li>java.awt.event.InputEvent.ALT_MASK
  329. * <li>java.awt.event.InputEvent.ALT_GRAPH_MASK
  330. * </ul>
  331. * also can be used, but they are mapped to _DOWN_ modifiers.
  332. *
  333. * Since these numbers are all different powers of two, any combination of
  334. * them is an integer in which each bit represents a different modifier
  335. * key. Use 0 to specify no modifiers.
  336. *
  337. * @param keyCode an int specifying the numeric code for a keyboard key
  338. * @param modifiers a bitwise-ored combination of any modifiers
  339. * @return an <code>AWTKeyStroke</code> object for that key
  340. *
  341. * @see java.awt.event.KeyEvent
  342. * @see java.awt.event.InputEvent
  343. */
  344. public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) {
  345. return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode, modifiers,
  346. false);
  347. }
  348. /**
  349. * Returns an <code>AWTKeyStroke</code> which represents the
  350. * stroke which generated a given <code>KeyEvent</code>.
  351. * <p>
  352. * This method obtains the key char from a <code>KeyTyped</code>
  353. * event, and the key code from a <code>KeyPressed</code> or
  354. * <code>KeyReleased</code> event. The <code>KeyEvent</code> modifiers are
  355. * obtained for all three types of <code>KeyEvent</code>.
  356. *
  357. * @param anEvent the <code>KeyEvent</code> from which to
  358. * obtain the <code>AWTKeyStroke</code>
  359. * @return the <code>AWTKeyStroke</code> that precipitated the event
  360. */
  361. public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) {
  362. int id = anEvent.getID();
  363. switch(id) {
  364. case KeyEvent.KEY_PRESSED:
  365. case KeyEvent.KEY_RELEASED:
  366. return getCachedStroke(KeyEvent.CHAR_UNDEFINED,
  367. anEvent.getKeyCode(),
  368. anEvent.getModifiers(),
  369. (id == KeyEvent.KEY_RELEASED));
  370. case KeyEvent.KEY_TYPED:
  371. return getCachedStroke(anEvent.getKeyChar(),
  372. KeyEvent.VK_UNDEFINED,
  373. anEvent.getModifiers(),
  374. false);
  375. default:
  376. // Invalid ID for this KeyEvent
  377. return null;
  378. }
  379. }
  380. /**
  381. * Parses a string and returns an <code>AWTKeyStroke</code>.
  382. * The string must have the following syntax:
  383. * <pre>
  384. * <modifiers>* (<typedID> | <pressedReleasedID>)
  385. *
  386. * modifiers := shift | control | ctrl | meta | alt | button1 | button2 | button3
  387. * typedID := typed <typedKey>
  388. * typedKey := string of length 1 giving Unicode character.
  389. * pressedReleasedID := (pressed | released) key
  390. * key := KeyEvent key code name, i.e. the name following "VK_".
  391. * </pre>
  392. * If typed, pressed or released is not specified, pressed is assumed. Here
  393. * are some examples:
  394. * <pre>
  395. * "INSERT" => getAWTKeyStroke(KeyEvent.VK_INSERT, 0);
  396. * "control DELETE" => getAWTKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK);
  397. * "alt shift X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK);
  398. * "alt shift released X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true);
  399. * "typed a" => getAWTKeyStroke('a');
  400. * </pre>
  401. *
  402. * @param s a String formatted as described above
  403. * @return an <code>AWTKeyStroke</code> object for that String
  404. * @throws IllegalArgumentException if <code>s</code> is <code>null</code>,
  405. * or is formatted incorrectly
  406. */
  407. public static AWTKeyStroke getAWTKeyStroke(String s) {
  408. if (s == null) {
  409. throw new IllegalArgumentException("String cannot be null");
  410. }
  411. final String errmsg = "String formatted incorrectly";
  412. StringTokenizer st = new StringTokenizer(s, " ");
  413. int mask = 0;
  414. boolean released = false;
  415. boolean typed = false;
  416. boolean pressed = false;
  417. if (modifierKeywords == null) {
  418. synchronized (AWTKeyStroke.class) {
  419. if (modifierKeywords == null) {
  420. Map uninitializedMap = new HashMap(8, 1.0f);
  421. uninitializedMap.put("shift",
  422. new Integer(InputEvent.SHIFT_DOWN_MASK
  423. |InputEvent.SHIFT_MASK));
  424. uninitializedMap.put("control",
  425. new Integer(InputEvent.CTRL_DOWN_MASK
  426. |InputEvent.CTRL_MASK));
  427. uninitializedMap.put("ctrl",
  428. new Integer(InputEvent.CTRL_DOWN_MASK
  429. |InputEvent.CTRL_MASK));
  430. uninitializedMap.put("meta",
  431. new Integer(InputEvent.META_DOWN_MASK
  432. |InputEvent.META_MASK));
  433. uninitializedMap.put("alt",
  434. new Integer(InputEvent.ALT_DOWN_MASK
  435. |InputEvent.ALT_MASK));
  436. uninitializedMap.put("altGraph",
  437. new Integer(InputEvent.ALT_GRAPH_DOWN_MASK
  438. |InputEvent.ALT_GRAPH_MASK));
  439. uninitializedMap.put("button1",
  440. new Integer(InputEvent.BUTTON1_DOWN_MASK));
  441. uninitializedMap.put("button2",
  442. new Integer(InputEvent.BUTTON2_DOWN_MASK));
  443. uninitializedMap.put("button3",
  444. new Integer(InputEvent.BUTTON3_DOWN_MASK));
  445. modifierKeywords =
  446. Collections.synchronizedMap(uninitializedMap);
  447. }
  448. }
  449. }
  450. int count = st.countTokens();
  451. for (int i = 1; i <= count; i++) {
  452. String token = st.nextToken();
  453. if (typed) {
  454. if (token.length() != 1 || i != count) {
  455. throw new IllegalArgumentException(errmsg);
  456. }
  457. return getCachedStroke(token.charAt(0), KeyEvent.VK_UNDEFINED,
  458. mask, false);
  459. }
  460. if (pressed || released || i == count) {
  461. if (i != count) {
  462. throw new IllegalArgumentException(errmsg);
  463. }
  464. String keyCodeName = "VK_" + token;
  465. int keyCode = getVKValue(keyCodeName);
  466. return getCachedStroke(KeyEvent.CHAR_UNDEFINED, keyCode,
  467. mask, released);
  468. }
  469. if (token.equals("released")) {
  470. released = true;
  471. continue;
  472. }
  473. if (token.equals("pressed")) {
  474. pressed = true;
  475. continue;
  476. }
  477. if (token.equals("typed")) {
  478. typed = true;
  479. continue;
  480. }
  481. Integer tokenMask = (Integer)modifierKeywords.get(token);
  482. if (tokenMask != null) {
  483. mask |= tokenMask.intValue();
  484. } else {
  485. throw new IllegalArgumentException(errmsg);
  486. }
  487. }
  488. throw new IllegalArgumentException(errmsg);
  489. }
  490. /**
  491. * Returns the integer constant for the KeyEvent.VK field named
  492. * <code>key</code>. This will throw an
  493. * <code>IllegalArgumentException</code> if <code>key</code> is
  494. * not a valid constant.
  495. */
  496. private static int getVKValue(String key) {
  497. if (vkMap == null) {
  498. vkMap = Collections.synchronizedMap(new HashMap());
  499. }
  500. Integer value = (Integer)vkMap.get(key);
  501. if (value == null) {
  502. int keyCode = 0;
  503. final String errmsg = "String formatted incorrectly";
  504. try {
  505. keyCode = KeyEvent.class.getField(key).getInt(KeyEvent.class);
  506. } catch (NoSuchFieldException nsfe) {
  507. throw new IllegalArgumentException(errmsg);
  508. } catch (IllegalAccessException iae) {
  509. throw new IllegalArgumentException(errmsg);
  510. }
  511. value = new Integer(keyCode);
  512. vkMap.put(key, value);
  513. }
  514. return value.intValue();
  515. }
  516. /**
  517. * Returns the character for this <code>AWTKeyStroke</code>.
  518. *
  519. * @return a char value
  520. * @see #getAWTKeyStroke(char)
  521. */
  522. public final char getKeyChar() {
  523. return keyChar;
  524. }
  525. /**
  526. * Returns the numeric key code for this <code>AWTKeyStroke</code>.
  527. *
  528. * @return an int containing the key code value
  529. * @see #getAWTKeyStroke(int,int)
  530. */
  531. public final int getKeyCode() {
  532. return keyCode;
  533. }
  534. /**
  535. * Returns the modifier keys for this <code>AWTKeyStroke</code>.
  536. *
  537. * @return an int containing the modifiers
  538. * @see #getAWTKeyStroke(int,int)
  539. */
  540. public final int getModifiers() {
  541. return modifiers;
  542. }
  543. /**
  544. * Returns whether this <code>AWTKeyStroke</code> represents a key release.
  545. *
  546. * @return <code>true</code> if this <code>AWTKeyStroke</code>
  547. * represents a key release; <code>false</code> otherwise
  548. * @see #getAWTKeyStroke(int,int,boolean)
  549. */
  550. public final boolean isOnKeyRelease() {
  551. return onKeyRelease;
  552. }
  553. /**
  554. * Returns the type of <code>KeyEvent</code> which corresponds to
  555. * this <code>AWTKeyStroke</code>.
  556. *
  557. * @return <code>KeyEvent.KEY_PRESSED</code>,
  558. * <code>KeyEvent.KEY_TYPED</code>,
  559. * or <code>KeyEvent.KEY_RELEASED</code>
  560. * @see java.awt.event.KeyEvent
  561. */
  562. public final int getKeyEventType() {
  563. if (keyCode == KeyEvent.VK_UNDEFINED) {
  564. return KeyEvent.KEY_TYPED;
  565. } else {
  566. return (onKeyRelease)
  567. ? KeyEvent.KEY_RELEASED
  568. : KeyEvent.KEY_PRESSED;
  569. }
  570. }
  571. /**
  572. * Returns a numeric value for this object that is likely to be unique,
  573. * making it a good choice as the index value in a hash table.
  574. *
  575. * @return an int that represents this object
  576. */
  577. public int hashCode() {
  578. return (((int)keyChar) + 1) * (2 * (keyCode + 1)) * (modifiers + 1) +
  579. (onKeyRelease ? 1 : 2);
  580. }
  581. /**
  582. * Returns true if this object is identical to the specified object.
  583. *
  584. * @param anObject the Object to compare this object to
  585. * @return true if the objects are identical
  586. */
  587. public final boolean equals(Object anObject) {
  588. if (anObject instanceof AWTKeyStroke) {
  589. AWTKeyStroke ks = (AWTKeyStroke)anObject;
  590. return (ks.keyChar == keyChar && ks.keyCode == keyCode &&
  591. ks.onKeyRelease == onKeyRelease &&
  592. ks.modifiers == modifiers);
  593. }
  594. return false;
  595. }
  596. /**
  597. * Returns a string that displays and identifies this object's properties.
  598. *
  599. * @return a String representation of this object
  600. */
  601. public String toString() {
  602. if (keyCode == KeyEvent.VK_UNDEFINED) {
  603. return "keyChar " + KeyEvent.getKeyModifiersText(modifiers) +
  604. keyChar;
  605. } else {
  606. return "keyCode " + KeyEvent.getKeyModifiersText(modifiers) +
  607. KeyEvent.getKeyText(keyCode) + (onKeyRelease ? "-R" : "-P");
  608. }
  609. }
  610. /**
  611. * Returns a cached instance of <code>AWTKeyStroke</code> (or a subclass of
  612. * <code>AWTKeyStroke</code>) which is equal to this instance.
  613. *
  614. * @return a cached instance which is equal to this instance
  615. */
  616. protected Object readResolve() throws java.io.ObjectStreamException {
  617. synchronized (AWTKeyStroke.class) {
  618. Class newClass = getClass();
  619. if (!newClass.equals(subclass)) {
  620. registerSubclass(newClass);
  621. }
  622. return getCachedStroke(keyChar, keyCode, modifiers, onKeyRelease);
  623. }
  624. }
  625. private static int mapOldModifiers(int modifiers) {
  626. if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
  627. modifiers |= InputEvent.SHIFT_DOWN_MASK;
  628. }
  629. if ((modifiers & InputEvent.ALT_MASK) != 0) {
  630. modifiers |= InputEvent.ALT_DOWN_MASK;
  631. }
  632. if ((modifiers & InputEvent.ALT_GRAPH_MASK) != 0) {
  633. modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
  634. }
  635. if ((modifiers & InputEvent.CTRL_MASK) != 0) {
  636. modifiers |= InputEvent.CTRL_DOWN_MASK;
  637. }
  638. if ((modifiers & InputEvent.META_MASK) != 0) {
  639. modifiers |= InputEvent.META_DOWN_MASK;
  640. }
  641. if ((modifiers & InputEvent.BUTTON1_MASK) != 0) {
  642. modifiers |= InputEvent.BUTTON1_DOWN_MASK;
  643. }
  644. modifiers &= InputEvent.SHIFT_DOWN_MASK
  645. | InputEvent.ALT_DOWN_MASK
  646. | InputEvent.ALT_GRAPH_DOWN_MASK
  647. | InputEvent.CTRL_DOWN_MASK
  648. | InputEvent.META_DOWN_MASK
  649. | InputEvent.BUTTON1_DOWN_MASK
  650. | InputEvent.BUTTON2_DOWN_MASK
  651. | InputEvent.BUTTON3_DOWN_MASK;
  652. return modifiers;
  653. }
  654. private static int mapNewModifiers(int modifiers) {
  655. if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0) {
  656. modifiers |= InputEvent.SHIFT_MASK;
  657. }
  658. if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0) {
  659. modifiers |= InputEvent.ALT_MASK;
  660. }
  661. if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) {
  662. modifiers |= InputEvent.ALT_GRAPH_MASK;
  663. }
  664. if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0) {
  665. modifiers |= InputEvent.CTRL_MASK;
  666. }
  667. if ((modifiers & InputEvent.META_DOWN_MASK) != 0) {
  668. modifiers |= InputEvent.META_MASK;
  669. }
  670. return modifiers;
  671. }
  672. }