src/share/classes/java/awt/AWTKeyStroke.java

Print this page




  50  * In all cases, <code>AWTKeyStroke</code>s can specify modifiers
  51  * (alt, shift, control, meta, altGraph, or a combination thereof) which must be present
  52  * during the action for an exact match.
  53  * <p>
  54  * <code>AWTKeyStrokes</code> are immutable, and are intended
  55  * to be unique. Client code should never create an
  56  * <code>AWTKeyStroke</code> on its own, but should instead use
  57  * a variant of <code>getAWTKeyStroke</code>. Client use of these factory
  58  * methods allows the <code>AWTKeyStroke</code> implementation
  59  * to cache and share instances efficiently.
  60  *
  61  * @see #getAWTKeyStroke
  62  *
  63  * @author Arnaud Weber
  64  * @author David Mendenhall
  65  * @since 1.4
  66  */
  67 public class AWTKeyStroke implements Serializable {
  68     static final long serialVersionUID = -6430539691155161871L;
  69 
  70     private static Map modifierKeywords;
  71     /**
  72      * Associates VK_XXX (as a String) with code (as Integer). This is
  73      * done to avoid the overhead of the reflective call to find the
  74      * constant.
  75      */
  76     private static VKCollection vks;
  77 
  78     //A key for the collection of AWTKeyStrokes within AppContext.
  79     private static Object APP_CONTEXT_CACHE_KEY = new Object();
  80     //A key withing the cache
  81     private static AWTKeyStroke APP_CONTEXT_KEYSTROKE_KEY = new AWTKeyStroke();
  82 
  83     /*
  84      * Reads keystroke class from AppContext and if null, puts there the
  85      * AWTKeyStroke class.
  86      * Must be called under locked AWTKeyStro
  87      */
  88     private static Class getAWTKeyStrokeClass() {
  89         Class clazz = (Class)AppContext.getAppContext().get(AWTKeyStroke.class);
  90         if (clazz == null) {
  91             clazz = AWTKeyStroke.class;
  92             AppContext.getAppContext().put(AWTKeyStroke.class, AWTKeyStroke.class);
  93         }
  94         return clazz;
  95     }
  96 
  97     private char keyChar = KeyEvent.CHAR_UNDEFINED;
  98     private int keyCode = KeyEvent.VK_UNDEFINED;
  99     private int modifiers;
 100     private boolean onKeyRelease;
 101 
 102     static {
 103         /* ensure that the necessary native libraries are loaded */
 104         Toolkit.loadLibraries();
 105     }
 106 
 107     /**
 108      * Constructs an <code>AWTKeyStroke</code> with default values.
 109      * The default values used are:


 165      * method, the factory methods will return instances of the specified
 166      * Class. The specified Class must be either <code>AWTKeyStroke</code>
 167      * or derived from <code>AWTKeyStroke</code>, and it must have a
 168      * no-arg constructor. The constructor can be of any accessibility,
 169      * including <code>private</code>. This operation
 170      * flushes the current <code>AWTKeyStroke</code> cache.
 171      *
 172      * @param subclass the new Class of which the factory methods should create
 173      *        instances
 174      * @throws IllegalArgumentException if subclass is <code>null</code>,
 175      *         or if subclass does not have a no-arg constructor
 176      * @throws ClassCastException if subclass is not
 177      *         <code>AWTKeyStroke</code>, or a class derived from
 178      *         <code>AWTKeyStroke</code>
 179      */
 180     protected static void registerSubclass(Class<?> subclass) {
 181         if (subclass == null) {
 182             throw new IllegalArgumentException("subclass cannot be null");
 183         }
 184         synchronized (AWTKeyStroke.class) {
 185             Class keyStrokeClass = (Class)AppContext.getAppContext().get(AWTKeyStroke.class);
 186             if (keyStrokeClass != null && keyStrokeClass.equals(subclass)){
 187                 // Already registered
 188                 return;
 189             }
 190         }
 191         if (!AWTKeyStroke.class.isAssignableFrom(subclass)) {
 192             throw new ClassCastException("subclass is not derived from AWTKeyStroke");
 193         }
 194 
 195         Constructor ctor = getCtor(subclass);
 196 
 197         String couldNotInstantiate = "subclass could not be instantiated";
 198 
 199         if (ctor == null) {
 200             throw new IllegalArgumentException(couldNotInstantiate);
 201         }
 202         try {
 203             AWTKeyStroke stroke = (AWTKeyStroke)ctor.newInstance((Object[]) null);
 204             if (stroke == null) {
 205                 throw new IllegalArgumentException(couldNotInstantiate);


 212             throw new IllegalArgumentException(couldNotInstantiate);
 213         } catch (IllegalAccessException e) {
 214             throw new IllegalArgumentException(couldNotInstantiate);
 215         } catch (InvocationTargetException e) {
 216             throw new IllegalArgumentException(couldNotInstantiate);
 217         }
 218 
 219         synchronized (AWTKeyStroke.class) {
 220             AppContext.getAppContext().put(AWTKeyStroke.class, subclass);
 221             AppContext.getAppContext().remove(APP_CONTEXT_CACHE_KEY);
 222             AppContext.getAppContext().remove(APP_CONTEXT_KEYSTROKE_KEY);
 223         }
 224     }
 225 
 226     /* returns noarg Constructor for class with accessible flag. No security
 227        threat as accessible flag is set only for this Constructor object,
 228        not for Class constructor.
 229      */
 230     private static Constructor getCtor(final Class clazz)
 231     {
 232         Object ctor = AccessController.doPrivileged(new PrivilegedAction() {
 233             public Object run() {
 234                 try {
 235                     Constructor ctor = clazz.getDeclaredConstructor((Class[]) null);
 236                     if (ctor != null) {
 237                         ctor.setAccessible(true);
 238                     }
 239                     return ctor;
 240                 } catch (SecurityException e) {
 241                 } catch (NoSuchMethodException e) {
 242                 }
 243                 return null;
 244             }
 245         });
 246         return (Constructor)ctor;
 247     }
 248 
 249     private static synchronized AWTKeyStroke getCachedStroke
 250         (char keyChar, int keyCode, int modifiers, boolean onKeyRelease)
 251     {
 252         Map cache = (Map)AppContext.getAppContext().get(APP_CONTEXT_CACHE_KEY);
 253         AWTKeyStroke cacheKey = (AWTKeyStroke)AppContext.getAppContext().get(APP_CONTEXT_KEYSTROKE_KEY);
 254 
 255         if (cache == null) {
 256             cache = new HashMap();
 257             AppContext.getAppContext().put(APP_CONTEXT_CACHE_KEY, cache);
 258         }
 259 
 260         if (cacheKey == null) {
 261             try {
 262                 Class clazz = getAWTKeyStrokeClass();
 263                 cacheKey = (AWTKeyStroke)getCtor(clazz).newInstance((Object[]) null);
 264                 AppContext.getAppContext().put(APP_CONTEXT_KEYSTROKE_KEY, cacheKey);
 265             } catch (InstantiationException e) {
 266                 assert(false);
 267             } catch (IllegalAccessException e) {
 268                 assert(false);
 269             } catch (InvocationTargetException e) {
 270                 assert(false);
 271             }
 272         }
 273         cacheKey.keyChar = keyChar;
 274         cacheKey.keyCode = keyCode;
 275         cacheKey.modifiers = mapNewModifiers(mapOldModifiers(modifiers));
 276         cacheKey.onKeyRelease = onKeyRelease;
 277 
 278         AWTKeyStroke stroke = (AWTKeyStroke)cache.get(cacheKey);
 279         if (stroke == null) {
 280             stroke = cacheKey;
 281             cache.put(stroke, stroke);
 282             AppContext.getAppContext().remove(APP_CONTEXT_KEYSTROKE_KEY);


 496      * @return an <code>AWTKeyStroke</code> object for that String
 497      * @throws IllegalArgumentException if <code>s</code> is <code>null</code>,
 498      *        or is formatted incorrectly
 499      */
 500     public static AWTKeyStroke getAWTKeyStroke(String s) {
 501         if (s == null) {
 502             throw new IllegalArgumentException("String cannot be null");
 503         }
 504 
 505         final String errmsg = "String formatted incorrectly";
 506 
 507         StringTokenizer st = new StringTokenizer(s, " ");
 508 
 509         int mask = 0;
 510         boolean released = false;
 511         boolean typed = false;
 512         boolean pressed = false;
 513 
 514         synchronized (AWTKeyStroke.class) {
 515             if (modifierKeywords == null) {
 516                 Map uninitializedMap = new HashMap(8, 1.0f);
 517                 uninitializedMap.put("shift",
 518                                      Integer.valueOf(InputEvent.SHIFT_DOWN_MASK
 519                                                      |InputEvent.SHIFT_MASK));
 520                 uninitializedMap.put("control",
 521                                      Integer.valueOf(InputEvent.CTRL_DOWN_MASK
 522                                                      |InputEvent.CTRL_MASK));
 523                 uninitializedMap.put("ctrl",
 524                                      Integer.valueOf(InputEvent.CTRL_DOWN_MASK
 525                                                      |InputEvent.CTRL_MASK));
 526                 uninitializedMap.put("meta",
 527                                      Integer.valueOf(InputEvent.META_DOWN_MASK
 528                                                      |InputEvent.META_MASK));
 529                 uninitializedMap.put("alt",
 530                                      Integer.valueOf(InputEvent.ALT_DOWN_MASK
 531                                                      |InputEvent.ALT_MASK));
 532                 uninitializedMap.put("altGraph",
 533                                      Integer.valueOf(InputEvent.ALT_GRAPH_DOWN_MASK
 534                                                      |InputEvent.ALT_GRAPH_MASK));
 535                 uninitializedMap.put("button1",
 536                                      Integer.valueOf(InputEvent.BUTTON1_DOWN_MASK));


 844         }
 845         if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0) {
 846             modifiers |= InputEvent.ALT_MASK;
 847         }
 848         if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) {
 849             modifiers |= InputEvent.ALT_GRAPH_MASK;
 850         }
 851         if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0) {
 852             modifiers |= InputEvent.CTRL_MASK;
 853         }
 854         if ((modifiers & InputEvent.META_DOWN_MASK) != 0) {
 855             modifiers |= InputEvent.META_MASK;
 856         }
 857 
 858         return modifiers;
 859     }
 860 
 861 }
 862 
 863 class VKCollection {
 864     Map code2name;
 865     Map name2code;
 866 
 867     public VKCollection() {
 868         code2name = new HashMap();
 869         name2code = new HashMap();
 870     }
 871 
 872     public synchronized void put(String name, Integer code) {
 873         assert((name != null) && (code != null));
 874         assert(findName(code) == null);
 875         assert(findCode(name) == null);
 876         code2name.put(code, name);
 877         name2code.put(name, code);
 878     }
 879 
 880     public synchronized Integer findCode(String name) {
 881         assert(name != null);
 882         return (Integer)name2code.get(name);
 883     }
 884 
 885     public synchronized String findName(Integer code) {
 886         assert(code != null);
 887         return (String)code2name.get(code);
 888     }
 889 }


  50  * In all cases, <code>AWTKeyStroke</code>s can specify modifiers
  51  * (alt, shift, control, meta, altGraph, or a combination thereof) which must be present
  52  * during the action for an exact match.
  53  * <p>
  54  * <code>AWTKeyStrokes</code> are immutable, and are intended
  55  * to be unique. Client code should never create an
  56  * <code>AWTKeyStroke</code> on its own, but should instead use
  57  * a variant of <code>getAWTKeyStroke</code>. Client use of these factory
  58  * methods allows the <code>AWTKeyStroke</code> implementation
  59  * to cache and share instances efficiently.
  60  *
  61  * @see #getAWTKeyStroke
  62  *
  63  * @author Arnaud Weber
  64  * @author David Mendenhall
  65  * @since 1.4
  66  */
  67 public class AWTKeyStroke implements Serializable {
  68     static final long serialVersionUID = -6430539691155161871L;
  69 
  70     private static Map<String, Integer> modifierKeywords;
  71     /**
  72      * Associates VK_XXX (as a String) with code (as Integer). This is
  73      * done to avoid the overhead of the reflective call to find the
  74      * constant.
  75      */
  76     private static VKCollection vks;
  77 
  78     //A key for the collection of AWTKeyStrokes within AppContext.
  79     private static Object APP_CONTEXT_CACHE_KEY = new Object();
  80     //A key withing the cache
  81     private static AWTKeyStroke APP_CONTEXT_KEYSTROKE_KEY = new AWTKeyStroke();
  82 
  83     /*
  84      * Reads keystroke class from AppContext and if null, puts there the
  85      * AWTKeyStroke class.
  86      * Must be called under locked AWTKeyStro
  87      */
  88     private static Class<AWTKeyStroke> getAWTKeyStrokeClass() {
  89         Class<AWTKeyStroke> clazz = (Class)AppContext.getAppContext().get(AWTKeyStroke.class);
  90         if (clazz == null) {
  91             clazz = AWTKeyStroke.class;
  92             AppContext.getAppContext().put(AWTKeyStroke.class, AWTKeyStroke.class);
  93         }
  94         return clazz;
  95     }
  96 
  97     private char keyChar = KeyEvent.CHAR_UNDEFINED;
  98     private int keyCode = KeyEvent.VK_UNDEFINED;
  99     private int modifiers;
 100     private boolean onKeyRelease;
 101 
 102     static {
 103         /* ensure that the necessary native libraries are loaded */
 104         Toolkit.loadLibraries();
 105     }
 106 
 107     /**
 108      * Constructs an <code>AWTKeyStroke</code> with default values.
 109      * The default values used are:


 165      * method, the factory methods will return instances of the specified
 166      * Class. The specified Class must be either <code>AWTKeyStroke</code>
 167      * or derived from <code>AWTKeyStroke</code>, and it must have a
 168      * no-arg constructor. The constructor can be of any accessibility,
 169      * including <code>private</code>. This operation
 170      * flushes the current <code>AWTKeyStroke</code> cache.
 171      *
 172      * @param subclass the new Class of which the factory methods should create
 173      *        instances
 174      * @throws IllegalArgumentException if subclass is <code>null</code>,
 175      *         or if subclass does not have a no-arg constructor
 176      * @throws ClassCastException if subclass is not
 177      *         <code>AWTKeyStroke</code>, or a class derived from
 178      *         <code>AWTKeyStroke</code>
 179      */
 180     protected static void registerSubclass(Class<?> subclass) {
 181         if (subclass == null) {
 182             throw new IllegalArgumentException("subclass cannot be null");
 183         }
 184         synchronized (AWTKeyStroke.class) {
 185             Class<AWTKeyStroke> keyStrokeClass = (Class)AppContext.getAppContext().get(AWTKeyStroke.class);
 186             if (keyStrokeClass != null && keyStrokeClass.equals(subclass)){
 187                 // Already registered
 188                 return;
 189             }
 190         }
 191         if (!AWTKeyStroke.class.isAssignableFrom(subclass)) {
 192             throw new ClassCastException("subclass is not derived from AWTKeyStroke");
 193         }
 194 
 195         Constructor ctor = getCtor(subclass);
 196 
 197         String couldNotInstantiate = "subclass could not be instantiated";
 198 
 199         if (ctor == null) {
 200             throw new IllegalArgumentException(couldNotInstantiate);
 201         }
 202         try {
 203             AWTKeyStroke stroke = (AWTKeyStroke)ctor.newInstance((Object[]) null);
 204             if (stroke == null) {
 205                 throw new IllegalArgumentException(couldNotInstantiate);


 212             throw new IllegalArgumentException(couldNotInstantiate);
 213         } catch (IllegalAccessException e) {
 214             throw new IllegalArgumentException(couldNotInstantiate);
 215         } catch (InvocationTargetException e) {
 216             throw new IllegalArgumentException(couldNotInstantiate);
 217         }
 218 
 219         synchronized (AWTKeyStroke.class) {
 220             AppContext.getAppContext().put(AWTKeyStroke.class, subclass);
 221             AppContext.getAppContext().remove(APP_CONTEXT_CACHE_KEY);
 222             AppContext.getAppContext().remove(APP_CONTEXT_KEYSTROKE_KEY);
 223         }
 224     }
 225 
 226     /* returns noarg Constructor for class with accessible flag. No security
 227        threat as accessible flag is set only for this Constructor object,
 228        not for Class constructor.
 229      */
 230     private static Constructor getCtor(final Class clazz)
 231     {
 232         Constructor ctor = AccessController.doPrivileged(new PrivilegedAction<Constructor>() {
 233             public Constructor run() {
 234                 try {
 235                     Constructor ctor = clazz.getDeclaredConstructor((Class[]) null);
 236                     if (ctor != null) {
 237                         ctor.setAccessible(true);
 238                     }
 239                     return ctor;
 240                 } catch (SecurityException e) {
 241                 } catch (NoSuchMethodException e) {
 242                 }
 243                 return null;
 244             }
 245         });
 246         return (Constructor)ctor;
 247     }
 248 
 249     private static synchronized AWTKeyStroke getCachedStroke
 250         (char keyChar, int keyCode, int modifiers, boolean onKeyRelease)
 251     {
 252         Map<AWTKeyStroke, AWTKeyStroke> cache = (Map)AppContext.getAppContext().get(APP_CONTEXT_CACHE_KEY);
 253         AWTKeyStroke cacheKey = (AWTKeyStroke)AppContext.getAppContext().get(APP_CONTEXT_KEYSTROKE_KEY);
 254 
 255         if (cache == null) {
 256             cache = new HashMap<>();
 257             AppContext.getAppContext().put(APP_CONTEXT_CACHE_KEY, cache);
 258         }
 259 
 260         if (cacheKey == null) {
 261             try {
 262                 Class<AWTKeyStroke> clazz = getAWTKeyStrokeClass();
 263                 cacheKey = (AWTKeyStroke)getCtor(clazz).newInstance((Object[]) null);
 264                 AppContext.getAppContext().put(APP_CONTEXT_KEYSTROKE_KEY, cacheKey);
 265             } catch (InstantiationException e) {
 266                 assert(false);
 267             } catch (IllegalAccessException e) {
 268                 assert(false);
 269             } catch (InvocationTargetException e) {
 270                 assert(false);
 271             }
 272         }
 273         cacheKey.keyChar = keyChar;
 274         cacheKey.keyCode = keyCode;
 275         cacheKey.modifiers = mapNewModifiers(mapOldModifiers(modifiers));
 276         cacheKey.onKeyRelease = onKeyRelease;
 277 
 278         AWTKeyStroke stroke = (AWTKeyStroke)cache.get(cacheKey);
 279         if (stroke == null) {
 280             stroke = cacheKey;
 281             cache.put(stroke, stroke);
 282             AppContext.getAppContext().remove(APP_CONTEXT_KEYSTROKE_KEY);


 496      * @return an <code>AWTKeyStroke</code> object for that String
 497      * @throws IllegalArgumentException if <code>s</code> is <code>null</code>,
 498      *        or is formatted incorrectly
 499      */
 500     public static AWTKeyStroke getAWTKeyStroke(String s) {
 501         if (s == null) {
 502             throw new IllegalArgumentException("String cannot be null");
 503         }
 504 
 505         final String errmsg = "String formatted incorrectly";
 506 
 507         StringTokenizer st = new StringTokenizer(s, " ");
 508 
 509         int mask = 0;
 510         boolean released = false;
 511         boolean typed = false;
 512         boolean pressed = false;
 513 
 514         synchronized (AWTKeyStroke.class) {
 515             if (modifierKeywords == null) {
 516                 Map<String, Integer> uninitializedMap = new HashMap<>(8, 1.0f);
 517                 uninitializedMap.put("shift",
 518                                      Integer.valueOf(InputEvent.SHIFT_DOWN_MASK
 519                                                      |InputEvent.SHIFT_MASK));
 520                 uninitializedMap.put("control",
 521                                      Integer.valueOf(InputEvent.CTRL_DOWN_MASK
 522                                                      |InputEvent.CTRL_MASK));
 523                 uninitializedMap.put("ctrl",
 524                                      Integer.valueOf(InputEvent.CTRL_DOWN_MASK
 525                                                      |InputEvent.CTRL_MASK));
 526                 uninitializedMap.put("meta",
 527                                      Integer.valueOf(InputEvent.META_DOWN_MASK
 528                                                      |InputEvent.META_MASK));
 529                 uninitializedMap.put("alt",
 530                                      Integer.valueOf(InputEvent.ALT_DOWN_MASK
 531                                                      |InputEvent.ALT_MASK));
 532                 uninitializedMap.put("altGraph",
 533                                      Integer.valueOf(InputEvent.ALT_GRAPH_DOWN_MASK
 534                                                      |InputEvent.ALT_GRAPH_MASK));
 535                 uninitializedMap.put("button1",
 536                                      Integer.valueOf(InputEvent.BUTTON1_DOWN_MASK));


 844         }
 845         if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0) {
 846             modifiers |= InputEvent.ALT_MASK;
 847         }
 848         if ((modifiers & InputEvent.ALT_GRAPH_DOWN_MASK) != 0) {
 849             modifiers |= InputEvent.ALT_GRAPH_MASK;
 850         }
 851         if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0) {
 852             modifiers |= InputEvent.CTRL_MASK;
 853         }
 854         if ((modifiers & InputEvent.META_DOWN_MASK) != 0) {
 855             modifiers |= InputEvent.META_MASK;
 856         }
 857 
 858         return modifiers;
 859     }
 860 
 861 }
 862 
 863 class VKCollection {
 864     Map<Integer, String> code2name;
 865     Map<String, Integer> name2code;
 866 
 867     public VKCollection() {
 868         code2name = new HashMap<>();
 869         name2code = new HashMap<>();
 870     }
 871 
 872     public synchronized void put(String name, Integer code) {
 873         assert((name != null) && (code != null));
 874         assert(findName(code) == null);
 875         assert(findCode(name) == null);
 876         code2name.put(code, name);
 877         name2code.put(name, code);
 878     }
 879 
 880     public synchronized Integer findCode(String name) {
 881         assert(name != null);
 882         return (Integer)name2code.get(name);
 883     }
 884 
 885     public synchronized String findName(Integer code) {
 886         assert(code != null);
 887         return (String)code2name.get(code);
 888     }
 889 }