001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Dmitry A. Durnev
019: * @version $Revision$
020: */package java.awt;
021:
022: import java.awt.event.InputEvent;
023: import java.awt.event.KeyEvent;
024: import java.io.ObjectStreamException;
025: import java.io.Serializable;
026: import java.lang.reflect.Constructor;
027: import java.lang.reflect.Field;
028: import java.util.HashMap;
029: import java.util.Map;
030: import java.util.NoSuchElementException;
031: import java.util.StringTokenizer;
032:
033: import org.apache.harmony.awt.internal.nls.Messages;
034:
035: public class AWTKeyStroke implements Serializable {
036: private static final long serialVersionUID = -6430539691155161871L;
037:
038: private static final Map<AWTKeyStroke, AWTKeyStroke> cache = new HashMap<AWTKeyStroke, AWTKeyStroke>(); //Map<AWTKeyStroke, ? extends AWTKeyStroke>
039: private static final Map<Integer, String> keyEventTypesMap = new HashMap<Integer, String>(); //Map<int, String>
040: private static Constructor<?> subConstructor;
041:
042: static {
043: keyEventTypesMap.put(new Integer(KeyEvent.KEY_PRESSED),
044: "pressed"); //$NON-NLS-1$
045: keyEventTypesMap.put(new Integer(KeyEvent.KEY_RELEASED),
046: "released"); //$NON-NLS-1$
047: keyEventTypesMap.put(new Integer(KeyEvent.KEY_TYPED), "typed"); //$NON-NLS-1$
048: }
049:
050: private char keyChar;
051: private int keyCode;
052: private int modifiers;
053: private boolean onKeyRelease;
054:
055: protected AWTKeyStroke(char keyChar, int keyCode, int modifiers,
056: boolean onKeyRelease) {
057: setAWTKeyStroke(keyChar, keyCode, modifiers, onKeyRelease);
058: }
059:
060: private void setAWTKeyStroke(char keyChar, int keyCode,
061: int modifiers, boolean onKeyRelease) {
062: this .keyChar = keyChar;
063: this .keyCode = keyCode;
064: this .modifiers = modifiers;
065: this .onKeyRelease = onKeyRelease;
066: }
067:
068: protected AWTKeyStroke() {
069: this (KeyEvent.CHAR_UNDEFINED, KeyEvent.VK_UNDEFINED, 0, false);
070: }
071:
072: @Override
073: public int hashCode() {
074: return modifiers
075: + (keyCode != KeyEvent.VK_UNDEFINED ? keyCode : keyChar)
076: + (onKeyRelease ? -1 : 0);
077: }
078:
079: public final int getModifiers() {
080: return modifiers;
081: }
082:
083: @Override
084: public final boolean equals(Object anObject) {
085: if (anObject instanceof AWTKeyStroke) {
086: AWTKeyStroke key = (AWTKeyStroke) anObject;
087: return ((key.keyCode == keyCode)
088: && (key.keyChar == keyChar)
089: && (key.modifiers == modifiers) && (key.onKeyRelease == onKeyRelease));
090: }
091: return false;
092: }
093:
094: @Override
095: public String toString() {
096: int type = getKeyEventType();
097: return InputEvent.getModifiersExText(getModifiers()) + " " + //$NON-NLS-1$
098: keyEventTypesMap.get(new Integer(type))
099: + " " + //$NON-NLS-1$
100: (type == KeyEvent.KEY_TYPED ? new String(
101: new char[] { keyChar }) : KeyEvent
102: .getKeyText(keyCode));
103: }
104:
105: public final int getKeyCode() {
106: return keyCode;
107: }
108:
109: public final char getKeyChar() {
110: return keyChar;
111: }
112:
113: private static AWTKeyStroke getAWTKeyStroke(char keyChar,
114: int keyCode, int modifiers, boolean onKeyRelease) {
115: AWTKeyStroke key = newInstance(keyChar, keyCode, modifiers,
116: onKeyRelease);
117:
118: AWTKeyStroke value = cache.get(key);
119: if (value == null) {
120: value = key;
121: cache.put(key, value);
122: }
123: return value;
124: }
125:
126: private static AWTKeyStroke newInstance(char keyChar, int keyCode,
127: int modifiers, boolean onKeyRelease) {
128: AWTKeyStroke key;
129: if (subConstructor == null) {
130: key = new AWTKeyStroke();
131: } else {
132: try {
133: key = (AWTKeyStroke) subConstructor.newInstance();
134: } catch (Exception e) {
135: throw new RuntimeException(e);
136: }
137: }
138: int allModifiers = getAllModifiers(modifiers);
139: key.setAWTKeyStroke(keyChar, keyCode, allModifiers,
140: onKeyRelease);
141: return key;
142: }
143:
144: private static int addMask(int mod, int mask) {
145: return ((mod & mask) != 0) ? (mod | mask) : mod;
146: }
147:
148: /**
149: * return all (old & new) modifiers corresponding to
150: * @param mod old or new modifiers
151: * @return old and new modifiers together
152: */
153: static int getAllModifiers(int mod) {
154: int allMod = mod;
155: int shift = (InputEvent.SHIFT_MASK | InputEvent.SHIFT_DOWN_MASK);
156: int ctrl = (InputEvent.CTRL_MASK | InputEvent.CTRL_DOWN_MASK);
157: int meta = (InputEvent.META_MASK | InputEvent.META_DOWN_MASK);
158: int alt = (InputEvent.ALT_MASK | InputEvent.ALT_DOWN_MASK);
159: int altGr = (InputEvent.ALT_GRAPH_MASK | InputEvent.ALT_GRAPH_DOWN_MASK);
160: // button modifiers are not converted between old & new
161:
162: allMod = addMask(allMod, shift);
163: allMod = addMask(allMod, ctrl);
164: allMod = addMask(allMod, meta);
165: allMod = addMask(allMod, alt);
166: allMod = addMask(allMod, altGr);
167:
168: return allMod;
169: }
170:
171: public static AWTKeyStroke getAWTKeyStroke(String s) {
172: if (s == null) {
173: // awt.65=null argument
174: throw new IllegalArgumentException(Messages
175: .getString("awt.65")); //$NON-NLS-1$
176: }
177:
178: StringTokenizer tokenizer = new StringTokenizer(s);
179:
180: Boolean release = null;
181: int modifiers = 0;
182: int keyCode = KeyEvent.VK_UNDEFINED;
183: char keyChar = KeyEvent.CHAR_UNDEFINED;
184: boolean typed = false;
185: long modifier = 0;
186: String token = null;
187: do {
188: token = getNextToken(tokenizer);
189: modifier = parseModifier(token);
190: modifiers |= modifier;
191: } while (modifier > 0);
192:
193: typed = parseTypedID(token);
194:
195: if (typed) {
196: token = getNextToken(tokenizer);
197: keyChar = parseTypedKey(token);
198:
199: }
200: if (keyChar == KeyEvent.CHAR_UNDEFINED) {
201: release = parsePressedReleasedID(token);
202: if (release != null) {
203: token = getNextToken(tokenizer);
204: }
205: keyCode = parseKey(token);
206: }
207: if (tokenizer.hasMoreTokens()) {
208: // awt.66=Invalid format
209: throw new IllegalArgumentException(Messages
210: .getString("awt.66")); //$NON-NLS-1$
211: }
212:
213: return getAWTKeyStroke(keyChar, keyCode, modifiers,
214: release == Boolean.TRUE);
215: }
216:
217: private static String getNextToken(StringTokenizer tokenizer) {
218: try {
219: return tokenizer.nextToken();
220: } catch (NoSuchElementException exception) {
221: // awt.66=Invalid format
222: throw new IllegalArgumentException(Messages
223: .getString("awt.66")); //$NON-NLS-1$
224: }
225: }
226:
227: static int getKeyCode(String s) {
228: try {
229: Field vk = KeyEvent.class.getField("VK_" + s); //$NON-NLS-1$
230: return vk.getInt(null);
231: } catch (Exception e) {
232: if (s.length() != 1) {
233: // awt.66=Invalid format
234: throw new IllegalArgumentException(Messages
235: .getString("awt.66")); //$NON-NLS-1$
236: }
237: return KeyEvent.VK_UNDEFINED;
238: }
239: }
240:
241: public static AWTKeyStroke getAWTKeyStroke(char keyChar) {
242: return getAWTKeyStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false);
243: }
244:
245: public static AWTKeyStroke getAWTKeyStroke(int keyCode,
246: int modifiers, boolean onKeyRelease) {
247: return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode,
248: modifiers, onKeyRelease);
249: }
250:
251: public static AWTKeyStroke getAWTKeyStroke(Character keyChar,
252: int modifiers) {
253: if (keyChar == null) {
254: // awt.01='{0}' parameter is null
255: throw new IllegalArgumentException(Messages.getString(
256: "awt.01", "keyChar")); //$NON-NLS-1$ //$NON-NLS-2$
257: }
258: return getAWTKeyStroke(keyChar.charValue(),
259: KeyEvent.VK_UNDEFINED, modifiers, false);
260: }
261:
262: public static AWTKeyStroke getAWTKeyStroke(int keyCode,
263: int modifiers) {
264: return getAWTKeyStroke(keyCode, modifiers, false);
265: }
266:
267: public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent) {
268: int id = anEvent.getID();
269: char undef = KeyEvent.CHAR_UNDEFINED;
270: char keyChar = (id == KeyEvent.KEY_TYPED ? anEvent.getKeyChar()
271: : undef);
272: int keyCode = (keyChar == undef ? anEvent.getKeyCode()
273: : KeyEvent.VK_UNDEFINED);
274: return getAWTKeyStroke(keyChar, keyCode, anEvent
275: .getModifiersEx(), id == KeyEvent.KEY_RELEASED);
276: }
277:
278: public final int getKeyEventType() {
279: if (keyCode == KeyEvent.VK_UNDEFINED) {
280: return KeyEvent.KEY_TYPED;
281: }
282: return (onKeyRelease ? KeyEvent.KEY_RELEASED
283: : KeyEvent.KEY_PRESSED);
284: }
285:
286: public final boolean isOnKeyRelease() {
287: return onKeyRelease;
288: }
289:
290: protected Object readResolve() throws ObjectStreamException {
291: return getAWTKeyStroke(this .keyChar, this .keyCode,
292: this .modifiers, this .onKeyRelease);
293: }
294:
295: protected static void registerSubclass(Class<?> subclass) {
296: if (subclass == null) {
297: // awt.01='{0}' parameter is null
298: throw new IllegalArgumentException(Messages.getString(
299: "awt.01", "subclass")); //$NON-NLS-1$ //$NON-NLS-2$
300: }
301: if (!AWTKeyStroke.class.isAssignableFrom(subclass)) {
302: // awt.67=subclass is not derived from AWTKeyStroke
303: throw new ClassCastException(Messages.getString("awt.67")); //$NON-NLS-1$
304: }
305: try {
306: subConstructor = subclass.getDeclaredConstructor();
307: subConstructor.setAccessible(true);
308: } catch (SecurityException e) {
309: throw new RuntimeException(e);
310: } catch (NoSuchMethodException e) {
311: // awt.68=subclass could not be instantiated
312: throw new IllegalArgumentException(Messages
313: .getString("awt.68")); //$NON-NLS-1$
314: }
315: cache.clear(); //flush the cache
316: }
317:
318: private static long parseModifier(String strMod) {
319: long modifiers = 0l;
320: if (strMod.equals("shift")) { //$NON-NLS-1$
321: modifiers |= InputEvent.SHIFT_DOWN_MASK;
322: } else if (strMod.equals("control") || strMod.equals("ctrl")) { //$NON-NLS-1$ //$NON-NLS-2$
323: modifiers |= InputEvent.CTRL_DOWN_MASK;
324: } else if (strMod.equals("meta")) { //$NON-NLS-1$
325: modifiers |= InputEvent.META_DOWN_MASK;
326: } else if (strMod.equals("alt")) { //$NON-NLS-1$
327: modifiers |= InputEvent.ALT_DOWN_MASK;
328: } else if (strMod.equals("altGraph")) { //$NON-NLS-1$
329: modifiers |= InputEvent.ALT_GRAPH_DOWN_MASK;
330: } else if (strMod.equals("button1")) { //$NON-NLS-1$
331: modifiers |= InputEvent.BUTTON1_DOWN_MASK;
332: } else if (strMod.equals("button2")) { //$NON-NLS-1$
333: modifiers |= InputEvent.BUTTON2_DOWN_MASK;
334: } else if (strMod.equals("button3")) { //$NON-NLS-1$
335: modifiers |= InputEvent.BUTTON3_DOWN_MASK;
336: }
337: return modifiers;
338: }
339:
340: private static boolean parseTypedID(String strTyped) {
341: if (strTyped.equals("typed")) { //$NON-NLS-1$
342: return true;
343: }
344:
345: return false;
346: }
347:
348: private static char parseTypedKey(String strChar) {
349: char keyChar = KeyEvent.CHAR_UNDEFINED;
350:
351: if (strChar.length() != 1) {
352: // awt.66=Invalid format
353: throw new IllegalArgumentException(Messages
354: .getString("awt.66")); //$NON-NLS-1$
355: }
356: keyChar = strChar.charAt(0);
357: return keyChar;
358: }
359:
360: private static Boolean parsePressedReleasedID(String str) {
361:
362: if (str.equals("pressed")) { //$NON-NLS-1$
363: return Boolean.FALSE;
364: } else if (str.equals("released")) { //$NON-NLS-1$
365: return Boolean.TRUE;
366: }
367: return null;
368: }
369:
370: private static int parseKey(String strCode) {
371: int keyCode = KeyEvent.VK_UNDEFINED;
372:
373: keyCode = getKeyCode(strCode);
374:
375: if (keyCode == KeyEvent.VK_UNDEFINED) {
376: // awt.66=Invalid format
377: throw new IllegalArgumentException(Messages
378: .getString("awt.66")); //$NON-NLS-1$
379: }
380: return keyCode;
381: }
382: }
|