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