Frames | No Frames |
1: /* AWTKeyStroke.java -- an immutable key stroke 2: Copyright (C) 2002, 2004, 2005 Free Software Foundation 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.awt; 40: 41: import java.awt.event.InputEvent; 42: import java.awt.event.KeyEvent; 43: import java.io.ObjectStreamException; 44: import java.io.Serializable; 45: import java.lang.reflect.Constructor; 46: import java.lang.reflect.Field; 47: import java.lang.reflect.InvocationTargetException; 48: import java.security.AccessController; 49: import java.security.PrivilegedAction; 50: import java.security.PrivilegedActionException; 51: import java.security.PrivilegedExceptionAction; 52: import java.util.HashMap; 53: import java.util.LinkedHashMap; 54: import java.util.Map; 55: import java.util.StringTokenizer; 56: 57: /** 58: * This class mirrors KeyEvents, representing both low-level key presses and 59: * key releases, and high level key typed inputs. However, this class forms 60: * immutable strokes, and can be efficiently reused via the factory methods 61: * for creating them. 62: * 63: * <p>For backwards compatibility with Swing, this supports a way to build 64: * instances of a subclass, using reflection, provided the subclass has a 65: * no-arg constructor (of any accessibility). 66: * 67: * @author Eric Blake (ebb9@email.byu.edu) 68: * @see #getAWTKeyStroke(char) 69: * @since 1.4 70: * @status updated to 1.4 71: */ 72: public class AWTKeyStroke implements Serializable 73: { 74: /** 75: * Compatible with JDK 1.4+. 76: */ 77: private static final long serialVersionUID = -6430539691155161871L; 78: 79: /** The mask for modifiers. */ 80: private static final int MODIFIERS_MASK = 0x3fef; 81: 82: /** 83: * The cache of recently created keystrokes. This maps KeyStrokes to 84: * KeyStrokes in a cache which removes the least recently accessed entry, 85: * under the assumption that garbage collection of a new keystroke is 86: * easy when we find the old one that it matches in the cache. 87: */ 88: private static final LinkedHashMap cache = new LinkedHashMap(11, 0.75f, true) 89: { 90: /** The largest the keystroke cache can grow. */ 91: private static final int MAX_CACHE_SIZE = 2048; 92: 93: /** Prune stale entries. */ 94: protected boolean removeEldestEntry(Map.Entry eldest) 95: { // XXX - FIXME Use Map.Entry, not just Entry as gcj 3.1 workaround. 96: return size() > MAX_CACHE_SIZE; 97: } 98: }; 99: 100: /** The most recently generated keystroke, or null. */ 101: private static AWTKeyStroke recent; 102: 103: /** 104: * The no-arg constructor of a subclass, or null to use AWTKeyStroke. Note 105: * that this will be left accessible, to get around private access; but 106: * it should not be a security risk as it is highly unlikely that creating 107: * protected instances of the subclass via reflection will do much damage. 108: */ 109: private static Constructor ctor; 110: 111: /** 112: * A table of keyCode names to values. This is package-private to 113: * avoid an accessor method. 114: * 115: * @see #getAWTKeyStroke(String) 116: */ 117: static final HashMap vktable = new HashMap(); 118: static 119: { 120: // Using reflection saves the hassle of keeping this in sync with KeyEvent, 121: // at the price of an expensive initialization. 122: AccessController.doPrivileged(new PrivilegedAction() 123: { 124: public Object run() 125: { 126: Field[] fields = KeyEvent.class.getFields(); 127: int i = fields.length; 128: try 129: { 130: while (--i >= 0) 131: { 132: Field f = fields[i]; 133: String name = f.getName(); 134: if (name.startsWith("VK_")) 135: vktable.put(name.substring(3), f.get(null)); 136: } 137: } 138: catch (Exception e) 139: { 140: throw (Error) new InternalError().initCause(e); 141: } 142: return null; 143: } 144: }); 145: } 146: 147: /** 148: * The typed character, or CHAR_UNDEFINED for key presses and releases. 149: * 150: * @serial the keyChar 151: */ 152: private char keyChar; 153: 154: /** 155: * The virtual key code, or VK_UNDEFINED for key typed. Package visible for 156: * use by Component. 157: * 158: * @serial the keyCode 159: */ 160: int keyCode; 161: 162: /** 163: * The modifiers in effect. To match Sun, this stores the old style masks 164: * for shift, control, alt, meta, and alt-graph (but not button1); as well 165: * as the new style of extended modifiers for all modifiers. 166: * 167: * @serial bitwise or of the *_DOWN_MASK modifiers 168: */ 169: private int modifiers; 170: 171: /** 172: * True if this is a key release; should only be true if keyChar is 173: * CHAR_UNDEFINED. 174: * 175: * @serial true to distinguish key pressed from key released 176: */ 177: private boolean onKeyRelease; 178: 179: /** 180: * Construct a keystroke with default values: it will be interpreted as a 181: * key typed event with an invalid character and no modifiers. Client code 182: * should use the factory methods instead. 183: * 184: * @see #getAWTKeyStroke(char) 185: * @see #getAWTKeyStroke(Character, int) 186: * @see #getAWTKeyStroke(int, int, boolean) 187: * @see #getAWTKeyStroke(int, int) 188: * @see #getAWTKeyStrokeForEvent(KeyEvent) 189: * @see #getAWTKeyStroke(String) 190: */ 191: protected AWTKeyStroke() 192: { 193: keyChar = KeyEvent.CHAR_UNDEFINED; 194: } 195: 196: /** 197: * Construct a keystroke with the given values. Client code should use the 198: * factory methods instead. 199: * 200: * @param keyChar the character entered, if this is a key typed 201: * @param keyCode the key pressed or released, or VK_UNDEFINED for key typed 202: * @param modifiers the modifier keys for the keystroke, in old or new style 203: * @param onKeyRelease true if this is a key release instead of a press 204: * @see #getAWTKeyStroke(char) 205: * @see #getAWTKeyStroke(Character, int) 206: * @see #getAWTKeyStroke(int, int, boolean) 207: * @see #getAWTKeyStroke(int, int) 208: * @see #getAWTKeyStrokeForEvent(KeyEvent) 209: * @see #getAWTKeyStroke(String) 210: */ 211: protected AWTKeyStroke(char keyChar, int keyCode, int modifiers, 212: boolean onKeyRelease) 213: { 214: this.keyChar = keyChar; 215: this.keyCode = keyCode; 216: // No need to call extend(), as only trusted code calls this constructor. 217: this.modifiers = modifiers; 218: this.onKeyRelease = onKeyRelease; 219: } 220: 221: /** 222: * Registers a new subclass as being the type of keystrokes to generate in 223: * the factory methods. This operation flushes the cache of stored keystrokes 224: * if the class differs from the current one. The new class must be 225: * AWTKeyStroke or a subclass, and must have a no-arg constructor (which may 226: * be private). 227: * 228: * @param subclass the new runtime type of generated keystrokes 229: * @throws IllegalArgumentException subclass doesn't have no-arg constructor 230: * @throws ClassCastException subclass doesn't extend AWTKeyStroke 231: */ 232: protected static void registerSubclass(final Class subclass) 233: { 234: if (subclass == null) 235: throw new IllegalArgumentException(); 236: if (subclass.equals(ctor == null ? AWTKeyStroke.class 237: : ctor.getDeclaringClass())) 238: return; 239: if (subclass.equals(AWTKeyStroke.class)) 240: { 241: cache.clear(); 242: recent = null; 243: ctor = null; 244: return; 245: } 246: try 247: { 248: ctor = (Constructor) AccessController.doPrivileged 249: (new PrivilegedExceptionAction() 250: { 251: public Object run() 252: throws NoSuchMethodException, InstantiationException, 253: IllegalAccessException, InvocationTargetException 254: { 255: Constructor c = subclass.getDeclaredConstructor(null); 256: c.setAccessible(true); 257: // Create a new instance, to make sure that we can, and 258: // to cause any ClassCastException. 259: AWTKeyStroke dummy = (AWTKeyStroke) c.newInstance(null); 260: return c; 261: } 262: }); 263: } 264: catch (PrivilegedActionException e) 265: { 266: // e.getCause() will not ever be ClassCastException; that should 267: // escape on its own. 268: throw (RuntimeException) 269: new IllegalArgumentException().initCause(e.getCause()); 270: } 271: cache.clear(); 272: recent = null; 273: } 274: 275: /** 276: * Returns a keystroke representing a typed character. 277: * 278: * @param keyChar the typed character 279: * @return the specified keystroke 280: */ 281: public static AWTKeyStroke getAWTKeyStroke(char keyChar) 282: { 283: return getAWTKeyStroke(keyChar, KeyEvent.VK_UNDEFINED, 0, false); 284: } 285: 286: /** 287: * Returns a keystroke representing a typed character with the given 288: * modifiers. Note that keyChar is a <code>Character</code> instead of a 289: * <code>char</code> to avoid accidental ambiguity with 290: * <code>getAWTKeyStroke(int, int)</code>. The modifiers are the bitwise 291: * or of the masks found in {@link InputEvent}; the new style (*_DOWN_MASK) 292: * is preferred, but the old style will work. 293: * 294: * @param keyChar the typed character 295: * @param modifiers the modifiers, or 0 296: * @return the specified keystroke 297: * @throws IllegalArgumentException if keyChar is null 298: */ 299: public static AWTKeyStroke getAWTKeyStroke(Character keyChar, int modifiers) 300: { 301: if (keyChar == null) 302: throw new IllegalArgumentException(); 303: return getAWTKeyStroke(keyChar.charValue(), KeyEvent.VK_UNDEFINED, 304: extend(modifiers), false); 305: } 306: 307: /** 308: * Returns a keystroke representing a pressed or released key event, with 309: * the given modifiers. The "virtual key" should be one of the VK_* 310: * constants in {@link KeyEvent}. The modifiers are the bitwise or of the 311: * masks found in {@link InputEvent}; the new style (*_DOWN_MASK) is 312: * preferred, but the old style will work. 313: * 314: * @param keyCode the virtual key 315: * @param modifiers the modifiers, or 0 316: * @param release true if this is a key release instead of a key press 317: * @return the specified keystroke 318: */ 319: public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers, 320: boolean release) 321: { 322: return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, 323: extend(modifiers), release); 324: } 325: 326: /** 327: * Returns a keystroke representing a pressed key event, with the given 328: * modifiers. The "virtual key" should be one of the VK_* constants in 329: * {@link KeyEvent}. The modifiers are the bitwise or of the masks found 330: * in {@link InputEvent}; the new style (*_DOWN_MASK) is preferred, but the 331: * old style will work. 332: * 333: * @param keyCode the virtual key 334: * @param modifiers the modifiers, or 0 335: * @return the specified keystroke 336: */ 337: public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers) 338: { 339: return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, keyCode, 340: extend(modifiers), false); 341: } 342: 343: /** 344: * Returns a keystroke representing what caused the key event. 345: * 346: * @param event the key event to convert 347: * @return the specified keystroke, or null if the event is invalid 348: * @throws NullPointerException if event is null 349: */ 350: public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent event) 351: { 352: switch (event.id) 353: { 354: case KeyEvent.KEY_TYPED: 355: return getAWTKeyStroke(event.getKeyChar(), KeyEvent.VK_UNDEFINED, 356: extend(event.getModifiersEx()), false); 357: case KeyEvent.KEY_PRESSED: 358: return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, event.getKeyCode(), 359: extend(event.getModifiersEx()), false); 360: case KeyEvent.KEY_RELEASED: 361: return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, event.getKeyCode(), 362: extend(event.getModifiersEx()), true); 363: default: 364: return null; 365: } 366: } 367: 368: /** 369: * Parses a string and returns the keystroke that it represents. The syntax 370: * for keystrokes is listed below, with tokens separated by an arbitrary 371: * number of spaces: 372: * <pre> 373: * keyStroke := <modifiers>* ( <typedID> | <codeID> ) 374: * modifiers := ( shift | control | ctrl | meta | alt 375: * | button1 | button2 | button3 ) 376: * typedID := typed <single Unicode character> 377: * codeID := ( pressed | released )? <name> 378: * name := <the KeyEvent field name less the leading "VK_"> 379: * </pre> 380: * 381: * <p>Note that the grammar is rather weak, and not all valid keystrokes 382: * can be generated in this manner (for example, a typed space, or anything 383: * with the alt-graph modifier!). The output of AWTKeyStroke.toString() 384: * will not meet the grammar. If pressed or released is not specified, 385: * pressed is assumed. Examples:<br> 386: * <code> 387: * "INSERT" => getAWTKeyStroke(KeyEvent.VK_INSERT, 0);<br> 388: * "control DELETE" => 389: * getAWTKeyStroke(KeyEvent.VK_DELETE, InputEvent.CTRL_MASK);<br> 390: * "alt shift X" => getAWTKeyStroke(KeyEvent.VK_X, 391: * InputEvent.ALT_MASK | InputEvent.SHIFT_MASK);<br> 392: * "alt shift released X" => getAWTKeyStroke(KeyEvent.VK_X, 393: * InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true);<br> 394: * "typed a" => getAWTKeyStroke('a'); 395: * </code> 396: * 397: * @param s the string to parse 398: * @throws IllegalArgumentException if s is null or cannot be parsed 399: * @return the specified keystroke 400: */ 401: public static AWTKeyStroke getAWTKeyStroke(String s) 402: { 403: if (s == null) 404: throw new IllegalArgumentException("null argument"); 405: StringTokenizer t = new StringTokenizer(s, " "); 406: if (! t.hasMoreTokens()) 407: throw new IllegalArgumentException("no tokens '" + s + "'"); 408: int modifiers = 0; 409: boolean released = false; 410: String token = null; 411: do 412: { 413: token = t.nextToken(); 414: if ("shift".equals(token)) 415: { 416: modifiers |= KeyEvent.SHIFT_MASK; 417: modifiers |= KeyEvent.SHIFT_DOWN_MASK; 418: } 419: else if ("ctrl".equals(token) || "control".equals(token)) 420: { 421: modifiers |= KeyEvent.CTRL_MASK; 422: modifiers |= KeyEvent.CTRL_DOWN_MASK; 423: } 424: else if ("meta".equals(token)) 425: { 426: modifiers |= KeyEvent.META_MASK; 427: modifiers |= KeyEvent.META_DOWN_MASK; 428: } 429: else if ("alt".equals(token)) 430: { 431: modifiers |= KeyEvent.ALT_MASK; 432: modifiers |= KeyEvent.ALT_DOWN_MASK; 433: } 434: else if ("button1".equals(token)) 435: modifiers |= KeyEvent.BUTTON1_DOWN_MASK; 436: else if ("button2".equals(token)) 437: modifiers |= KeyEvent.BUTTON2_DOWN_MASK; 438: else if ("button3".equals(token)) 439: modifiers |= KeyEvent.BUTTON3_DOWN_MASK; 440: else if ("typed".equals(token)) 441: { 442: if (t.hasMoreTokens()) 443: { 444: token = t.nextToken(); 445: if (! t.hasMoreTokens() && token.length() == 1) 446: return getAWTKeyStroke(token.charAt(0), 447: KeyEvent.VK_UNDEFINED, modifiers, 448: false); 449: } 450: throw new IllegalArgumentException("Invalid 'typed' argument '" 451: + s + "'"); 452: } 453: else if ("pressed".equals(token)) 454: { 455: if (t.hasMoreTokens()) 456: token = t.nextToken(); 457: break; 458: } 459: else if ("released".equals(token)) 460: { 461: released = true; 462: if (t.hasMoreTokens()) 463: token = t.nextToken(); 464: break; 465: } 466: else 467: break; 468: } 469: while (t.hasMoreTokens()); 470: // Now token contains the VK name we must parse. 471: Integer code = (Integer) vktable.get(token); 472: if (code == null) 473: throw new IllegalArgumentException("Unknown token '" + token 474: + "' in '" + s + "'"); 475: if (t.hasMoreTokens()) 476: throw new IllegalArgumentException("Too many tokens: " + s); 477: return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, code.intValue(), 478: modifiers, released); 479: } 480: 481: /** 482: * Returns the character of this keystroke, if it was typed. 483: * 484: * @return the character value, or CHAR_UNDEFINED 485: * @see #getAWTKeyStroke(char) 486: */ 487: public final char getKeyChar() 488: { 489: return keyChar; 490: } 491: 492: /** 493: * Returns the virtual key code of this keystroke, if it was pressed or 494: * released. This will be a VK_* constant from KeyEvent. 495: * 496: * @return the virtual key code value, or VK_UNDEFINED 497: * @see #getAWTKeyStroke(int, int) 498: */ 499: public final int getKeyCode() 500: { 501: return keyCode; 502: } 503: 504: /** 505: * Returns the modifiers for this keystroke. This will be a bitwise or of 506: * constants from InputEvent; it includes the old style masks for shift, 507: * control, alt, meta, and alt-graph (but not button1); as well as the new 508: * style of extended modifiers for all modifiers. 509: * 510: * @return the modifiers 511: * @see #getAWTKeyStroke(Character, int) 512: * @see #getAWTKeyStroke(int, int) 513: */ 514: public final int getModifiers() 515: { 516: return modifiers; 517: } 518: 519: /** 520: * Tests if this keystroke is a key release. 521: * 522: * @return true if this is a key release 523: * @see #getAWTKeyStroke(int, int, boolean) 524: */ 525: public final boolean isOnKeyRelease() 526: { 527: return onKeyRelease; 528: } 529: 530: /** 531: * Returns the AWT event type of this keystroke. This is one of 532: * {@link KeyEvent#KEY_TYPED}, {@link KeyEvent#KEY_PRESSED}, or 533: * {@link KeyEvent#KEY_RELEASED}. 534: * 535: * @return the key event type 536: */ 537: public final int getKeyEventType() 538: { 539: return keyCode == KeyEvent.VK_UNDEFINED ? KeyEvent.KEY_TYPED 540: : onKeyRelease ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED; 541: } 542: 543: /** 544: * Returns a hashcode for this key event. It is not documented, but appears 545: * to be: <code>(getKeyChar() + 1) * (getKeyCode() + 1) 546: * * (getModifiers() + 1) * 2 + (isOnKeyRelease() ? 1 : 2)</code>. 547: * 548: * @return the hashcode 549: */ 550: public int hashCode() 551: { 552: return (keyChar + 1) * (keyCode + 1) * (modifiers + 1) * 2 553: + (onKeyRelease ? 1 : 2); 554: } 555: 556: /** 557: * Tests two keystrokes for equality. 558: * 559: * @param o the object to test 560: * @return true if it is equal 561: */ 562: public final boolean equals(Object o) 563: { 564: if (! (o instanceof AWTKeyStroke)) 565: return false; 566: AWTKeyStroke s = (AWTKeyStroke) o; 567: return this == o || (keyChar == s.keyChar && keyCode == s.keyCode 568: && modifiers == s.modifiers 569: && onKeyRelease == s.onKeyRelease); 570: } 571: 572: /** 573: * Returns a string representation of this keystroke. For typed keystrokes, 574: * this is <code>"keyChar " + KeyEvent.getKeyModifiersText(getModifiers()) 575: + getKeyChar()</code>; for pressed and released keystrokes, this is 576: * <code>"keyCode " + KeyEvent.getKeyModifiersText(getModifiers()) 577: * + KeyEvent.getKeyText(getKeyCode()) 578: * + (isOnKeyRelease() ? "-R" : "-P")</code>. 579: * 580: * @return a string representation 581: */ 582: public String toString() 583: { 584: if (keyCode == KeyEvent.VK_UNDEFINED) 585: return "keyChar " + KeyEvent.getKeyModifiersText(modifiers) + keyChar; 586: return "keyCode " + KeyEvent.getKeyModifiersText(modifiers) 587: + KeyEvent.getKeyText(keyCode) + (onKeyRelease ? "-R" : "-P"); 588: } 589: 590: /** 591: * Returns a cached version of the deserialized keystroke, if available. 592: * 593: * @return a cached replacement 594: * @throws ObjectStreamException if something goes wrong 595: */ 596: protected Object readResolve() throws ObjectStreamException 597: { 598: AWTKeyStroke s = (AWTKeyStroke) cache.get(this); 599: if (s != null) 600: return s; 601: cache.put(this, this); 602: return this; 603: } 604: 605: /** 606: * Gets the appropriate keystroke, creating one if necessary. 607: * 608: * @param keyChar the keyChar 609: * @param keyCode the keyCode 610: * @param modifiers the modifiers 611: * @param release true for key release 612: * @return the specified keystroke 613: */ 614: private static AWTKeyStroke getAWTKeyStroke(char keyChar, int keyCode, 615: int modifiers, boolean release) 616: { 617: // Check level 0 cache. 618: AWTKeyStroke stroke = recent; // Avoid thread races. 619: if (stroke != null && stroke.keyChar == keyChar 620: && stroke.keyCode == keyCode && stroke.modifiers == modifiers 621: && stroke.onKeyRelease == release) 622: return stroke; 623: // Create a new object, on the assumption that if it has a match in the 624: // cache, the VM can easily garbage collect it as it is temporary. 625: Constructor c = ctor; // Avoid thread races. 626: if (c == null) 627: stroke = new AWTKeyStroke(keyChar, keyCode, modifiers, release); 628: else 629: try 630: { 631: stroke = (AWTKeyStroke) c.newInstance(null); 632: stroke.keyChar = keyChar; 633: stroke.keyCode = keyCode; 634: stroke.modifiers = modifiers; 635: stroke.onKeyRelease = release; 636: } 637: catch (Exception e) 638: { 639: throw (Error) new InternalError().initCause(e); 640: } 641: // Check level 1 cache. 642: AWTKeyStroke cached = (AWTKeyStroke) cache.get(stroke); 643: if (cached == null) 644: cache.put(stroke, stroke); 645: else 646: stroke = cached; 647: return recent = stroke; 648: } 649: 650: /** 651: * Converts the modifiers to the appropriate format. 652: * 653: * @param mod the modifiers to convert 654: * @return the adjusted modifiers 655: */ 656: private static int extend(int mod) 657: { 658: if ((mod & (KeyEvent.SHIFT_MASK | KeyEvent.SHIFT_DOWN_MASK)) != 0) 659: mod |= KeyEvent.SHIFT_MASK | KeyEvent.SHIFT_DOWN_MASK; 660: if ((mod & (KeyEvent.CTRL_MASK | KeyEvent.CTRL_DOWN_MASK)) != 0) 661: mod |= KeyEvent.CTRL_MASK | KeyEvent.CTRL_DOWN_MASK; 662: if ((mod & (KeyEvent.META_MASK | KeyEvent.META_DOWN_MASK)) != 0) 663: mod |= KeyEvent.META_MASK | KeyEvent.META_DOWN_MASK; 664: if ((mod & (KeyEvent.ALT_MASK | KeyEvent.ALT_DOWN_MASK)) != 0) 665: mod |= KeyEvent.ALT_MASK | KeyEvent.ALT_DOWN_MASK; 666: if ((mod & (KeyEvent.ALT_GRAPH_MASK | KeyEvent.ALT_GRAPH_DOWN_MASK)) != 0) 667: mod |= KeyEvent.ALT_GRAPH_MASK | KeyEvent.ALT_GRAPH_DOWN_MASK; 668: if ((mod & KeyEvent.BUTTON1_MASK) != 0) 669: mod |= KeyEvent.BUTTON1_DOWN_MASK; 670: return mod & MODIFIERS_MASK; 671: } 672: } // class AWTKeyStroke