GNU Classpath (0.17) | ||
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: modifiers |= KeyEvent.SHIFT_DOWN_MASK; 416: else if ("ctrl".equals(token) || "control".equals(token)) 417: modifiers |= KeyEvent.CTRL_DOWN_MASK; 418: else if ("meta".equals(token)) 419: modifiers |= KeyEvent.META_DOWN_MASK; 420: else if ("alt".equals(token)) 421: modifiers |= KeyEvent.ALT_DOWN_MASK; 422: else if ("button1".equals(token)) 423: modifiers |= KeyEvent.BUTTON1_DOWN_MASK; 424: else if ("button2".equals(token)) 425: modifiers |= KeyEvent.BUTTON2_DOWN_MASK; 426: else if ("button3".equals(token)) 427: modifiers |= KeyEvent.BUTTON3_DOWN_MASK; 428: else if ("typed".equals(token)) 429: { 430: if (t.hasMoreTokens()) 431: { 432: token = t.nextToken(); 433: if (! t.hasMoreTokens() && token.length() == 1) 434: return getAWTKeyStroke(token.charAt(0), 435: KeyEvent.VK_UNDEFINED, modifiers, 436: false); 437: } 438: throw new IllegalArgumentException("Invalid 'typed' argument '" 439: + s + "'"); 440: } 441: else if ("pressed".equals(token)) 442: { 443: if (t.hasMoreTokens()) 444: token = t.nextToken(); 445: break; 446: } 447: else if ("released".equals(token)) 448: { 449: released = true; 450: if (t.hasMoreTokens()) 451: token = t.nextToken(); 452: break; 453: } 454: else 455: break; 456: } 457: while (t.hasMoreTokens()); 458: // Now token contains the VK name we must parse. 459: Integer code = (Integer) vktable.get(token); 460: if (code == null) 461: throw new IllegalArgumentException("Unknown token '" + token 462: + "' in '" + s + "'"); 463: if (t.hasMoreTokens()) 464: throw new IllegalArgumentException("Too many tokens: " + s); 465: return getAWTKeyStroke(KeyEvent.CHAR_UNDEFINED, code.intValue(), 466: modifiers, released); 467: } 468: 469: /** 470: * Returns the character of this keystroke, if it was typed. 471: * 472: * @return the character value, or CHAR_UNDEFINED 473: * @see #getAWTKeyStroke(char) 474: */ 475: public final char getKeyChar() 476: { 477: return keyChar; 478: } 479: 480: /** 481: * Returns the virtual key code of this keystroke, if it was pressed or 482: * released. This will be a VK_* constant from KeyEvent. 483: * 484: * @return the virtual key code value, or VK_UNDEFINED 485: * @see #getAWTKeyStroke(int, int) 486: */ 487: public final int getKeyCode() 488: { 489: return keyCode; 490: } 491: 492: /** 493: * Returns the modifiers for this keystroke. This will be a bitwise or of 494: * constants from InputEvent; it includes the old style masks for shift, 495: * control, alt, meta, and alt-graph (but not button1); as well as the new 496: * style of extended modifiers for all modifiers. 497: * 498: * @return the modifiers 499: * @see #getAWTKeyStroke(Character, int) 500: * @see #getAWTKeyStroke(int, int) 501: */ 502: public final int getModifiers() 503: { 504: return modifiers; 505: } 506: 507: /** 508: * Tests if this keystroke is a key release. 509: * 510: * @return true if this is a key release 511: * @see #getAWTKeyStroke(int, int, boolean) 512: */ 513: public final boolean isOnKeyRelease() 514: { 515: return onKeyRelease; 516: } 517: 518: /** 519: * Returns the AWT event type of this keystroke. This is one of 520: * {@link KeyEvent#KEY_TYPED}, {@link KeyEvent#KEY_PRESSED}, or 521: * {@link KeyEvent#KEY_RELEASED}. 522: * 523: * @return the key event type 524: */ 525: public final int getKeyEventType() 526: { 527: return keyCode == KeyEvent.VK_UNDEFINED ? KeyEvent.KEY_TYPED 528: : onKeyRelease ? KeyEvent.KEY_RELEASED : KeyEvent.KEY_PRESSED; 529: } 530: 531: /** 532: * Returns a hashcode for this key event. It is not documented, but appears 533: * to be: <code>(getKeyChar() + 1) * (getKeyCode() + 1) 534: * * (getModifiers() + 1) * 2 + (isOnKeyRelease() ? 1 : 2)</code>. 535: * 536: * @return the hashcode 537: */ 538: public int hashCode() 539: { 540: return (keyChar + 1) * (keyCode + 1) * (modifiers + 1) * 2 541: + (onKeyRelease ? 1 : 2); 542: } 543: 544: /** 545: * Tests two keystrokes for equality. 546: * 547: * @param o the object to test 548: * @return true if it is equal 549: */ 550: public final boolean equals(Object o) 551: { 552: if (! (o instanceof AWTKeyStroke)) 553: return false; 554: AWTKeyStroke s = (AWTKeyStroke) o; 555: return this == o || (keyChar == s.keyChar && keyCode == s.keyCode 556: && modifiers == s.modifiers 557: && onKeyRelease == s.onKeyRelease); 558: } 559: 560: /** 561: * Returns a string representation of this keystroke. For typed keystrokes, 562: * this is <code>"keyChar " + KeyEvent.getKeyModifiersText(getModifiers()) 563: + getKeyChar()</code>; for pressed and released keystrokes, this is 564: * <code>"keyCode " + KeyEvent.getKeyModifiersText(getModifiers()) 565: * + KeyEvent.getKeyText(getKeyCode()) 566: * + (isOnKeyRelease() ? "-R" : "-P")</code>. 567: * 568: * @return a string representation 569: */ 570: public String toString() 571: { 572: if (keyCode == KeyEvent.VK_UNDEFINED) 573: return "keyChar " + KeyEvent.getKeyModifiersText(modifiers) + keyChar; 574: return "keyCode " + KeyEvent.getKeyModifiersText(modifiers) 575: + KeyEvent.getKeyText(keyCode) + (onKeyRelease ? "-R" : "-P"); 576: } 577: 578: /** 579: * Returns a cached version of the deserialized keystroke, if available. 580: * 581: * @return a cached replacement 582: * @throws ObjectStreamException if something goes wrong 583: */ 584: protected Object readResolve() throws ObjectStreamException 585: { 586: AWTKeyStroke s = (AWTKeyStroke) cache.get(this); 587: if (s != null) 588: return s; 589: cache.put(this, this); 590: return this; 591: } 592: 593: /** 594: * Gets the appropriate keystroke, creating one if necessary. 595: * 596: * @param keyChar the keyChar 597: * @param keyCode the keyCode 598: * @param modifiers the modifiers 599: * @param release true for key release 600: * @return the specified keystroke 601: */ 602: private static AWTKeyStroke getAWTKeyStroke(char keyChar, int keyCode, 603: int modifiers, boolean release) 604: { 605: // Check level 0 cache. 606: AWTKeyStroke stroke = recent; // Avoid thread races. 607: if (stroke != null && stroke.keyChar == keyChar 608: && stroke.keyCode == keyCode && stroke.modifiers == modifiers 609: && stroke.onKeyRelease == release) 610: return stroke; 611: // Create a new object, on the assumption that if it has a match in the 612: // cache, the VM can easily garbage collect it as it is temporary. 613: Constructor c = ctor; // Avoid thread races. 614: if (c == null) 615: stroke = new AWTKeyStroke(keyChar, keyCode, modifiers, release); 616: else 617: try 618: { 619: stroke = (AWTKeyStroke) c.newInstance(null); 620: stroke.keyChar = keyChar; 621: stroke.keyCode = keyCode; 622: stroke.modifiers = modifiers; 623: stroke.onKeyRelease = release; 624: } 625: catch (Exception e) 626: { 627: throw (Error) new InternalError().initCause(e); 628: } 629: // Check level 1 cache. 630: AWTKeyStroke cached = (AWTKeyStroke) cache.get(stroke); 631: if (cached == null) 632: cache.put(stroke, stroke); 633: else 634: stroke = cached; 635: return recent = stroke; 636: } 637: 638: /** 639: * Converts the modifiers to the appropriate format. 640: * 641: * @param mod the modifiers to convert 642: * @return the adjusted modifiers 643: */ 644: private static int extend(int mod) 645: { 646: if ((mod & (KeyEvent.SHIFT_MASK | KeyEvent.SHIFT_DOWN_MASK)) != 0) 647: mod |= KeyEvent.SHIFT_MASK | KeyEvent.SHIFT_DOWN_MASK; 648: if ((mod & (KeyEvent.CTRL_MASK | KeyEvent.CTRL_DOWN_MASK)) != 0) 649: mod |= KeyEvent.CTRL_MASK | KeyEvent.CTRL_DOWN_MASK; 650: if ((mod & (KeyEvent.META_MASK | KeyEvent.META_DOWN_MASK)) != 0) 651: mod |= KeyEvent.META_MASK | KeyEvent.META_DOWN_MASK; 652: if ((mod & (KeyEvent.ALT_MASK | KeyEvent.ALT_DOWN_MASK)) != 0) 653: mod |= KeyEvent.ALT_MASK | KeyEvent.ALT_DOWN_MASK; 654: if ((mod & (KeyEvent.ALT_GRAPH_MASK | KeyEvent.ALT_GRAPH_DOWN_MASK)) != 0) 655: mod |= KeyEvent.ALT_GRAPH_MASK | KeyEvent.ALT_GRAPH_DOWN_MASK; 656: if ((mod & KeyEvent.BUTTON1_MASK) != 0) 657: mod |= KeyEvent.BUTTON1_DOWN_MASK; 658: return mod & MODIFIERS_MASK; 659: } 660: } // class AWTKeyStroke
GNU Classpath (0.17) |