home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / swing / KeyStroke.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  15.3 KB  |  394 lines

  1. /*
  2.  * @(#)KeyStroke.java    1.18 98/02/05
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package java.awt.swing;
  21.  
  22. import java.awt.event.KeyEvent;
  23. import java.awt.event.InputEvent;
  24. import java.util.Hashtable;
  25. import java.io.Serializable;
  26.  
  27. /**
  28.  * A KeyStroke instance represents a key being typed on the keyboard -- it
  29.  * contains both a char code for the key and a modifier (alt, shift, ctrl, 
  30.  * meta, or a combination). 
  31.  * <p>
  32.  * KeyStroke objects are used to define high-level (semantic) action events.
  33.  * Instead of trapping every keystroke and throwing away the ones you are
  34.  * not interested in, those keystrokes you care about automatically initiate
  35.  * actions on the components they are registered with. 
  36.  * <p>
  37.  * KeyStroke objects handle both character-code generating keystrokes you 
  38.  * would trap with a KeyTyped event handler and key-code generating keystrokes
  39.  * (like Enter or F1) that you would trap with a KeyPressed event handler.
  40.  * <p>
  41.  * KeyStroke objects are immutable and unique.
  42.  * <p>
  43.  * All KeyStroke objects are cached. To get one, use <code>getKeyStroke</code>.
  44.  * <p>
  45.  * Warning: serialized objects of this class will not be compatible with
  46.  * future swing releases.  The current serialization support is appropriate 
  47.  * for short term storage or RMI between Swing1.0 applications.  It will
  48.  * not be possible to load serialized Swing1.0 objects with future releases
  49.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  50.  * baseline for the serialized form of Swing objects.
  51.  *
  52.  * @see JComponent#registerKeyboardAction
  53.  * @see #getKeystroke
  54.  *
  55.  * @version 1.18 02/05/98
  56.  * @author Arnaud Weber
  57.  */
  58. public class KeyStroke implements Serializable {
  59.     private static final Object pressedCharCacheKey = 
  60.         new StringBuffer("KeyStroke.pressedCharCacheKey");
  61.     private static final Object releasedCharCacheKey = 
  62.         new StringBuffer("KeyStroke.releasedCharCacheKey");
  63.     private static final Object pressedCodeCacheKey = 
  64.         new StringBuffer("KeyStroke.pressedCodeCacheKey");
  65.     private static final Object releasedCodeCacheKey = 
  66.         new StringBuffer("KeyStroke.releasedCodeCacheKey");
  67.  
  68.     char keyChar;
  69.     int  keyCode;
  70.     int  modifiers;
  71.     boolean onKeyRelease;
  72.  
  73.     /* We cache 114 key stroke with keyChar (1368 bytes) */
  74.     /* We cache 114 * 8 key stroke with keyCode and popular modifiers (10944 bytes) */ 
  75.     /* Total cache is around 11K */
  76.  
  77.     static final int MIN_ASCII_CACHE_INDEX = '\n'; 
  78.     static final int MAX_ASCII_CACHE_INDEX = 0x7F;
  79.     /* It is impossible to instantiate a KeyStroke. Use getKeyStroke() instead **/
  80.     private KeyStroke() {
  81.         
  82.     }
  83.  
  84.     static KeyStroke getCachedKeyCharKeyStroke(char keyChar,boolean onKeyRelease) {
  85.         KeyStroke result = null;
  86.         if(keyChar >= MIN_ASCII_CACHE_INDEX && keyChar < MAX_ASCII_CACHE_INDEX) {
  87.             synchronized(KeyStroke.class) {
  88.                 KeyStroke cache[];
  89.                 if(onKeyRelease) 
  90.                     cache = (KeyStroke[])SwingUtilities.appContextGet(
  91.                         releasedCharCacheKey);
  92.                 else
  93.                     cache = (KeyStroke[])SwingUtilities.appContextGet(
  94.                         pressedCharCacheKey);
  95.                 if(cache != null)
  96.                     result = cache[((int)keyChar) - MIN_ASCII_CACHE_INDEX];
  97.             }
  98.         }
  99.         return result;
  100.     }
  101.  
  102.     static void cacheKeyCharKeyStroke(KeyStroke ks,boolean onKeyRelease) {
  103.         if(ks.keyChar >= MIN_ASCII_CACHE_INDEX && ks.keyChar < MAX_ASCII_CACHE_INDEX) {
  104.             synchronized(KeyStroke.class) {
  105.                 if(onKeyRelease) {
  106.                     KeyStroke releasedKeyCharKeyStrokeCache[] = (KeyStroke[])
  107.                         SwingUtilities.appContextGet(releasedCharCacheKey);
  108.                     if(releasedKeyCharKeyStrokeCache == null) {
  109.                         releasedKeyCharKeyStrokeCache = new KeyStroke[MAX_ASCII_CACHE_INDEX - MIN_ASCII_CACHE_INDEX];
  110.                         SwingUtilities.appContextPut(
  111.                             releasedCharCacheKey, releasedKeyCharKeyStrokeCache);
  112.                     }
  113.                     releasedKeyCharKeyStrokeCache[((int)ks.keyChar) - MIN_ASCII_CACHE_INDEX] = ks;
  114.                 } else {
  115.                     KeyStroke pressedKeyCharKeyStrokeCache[] = (KeyStroke[])
  116.                         SwingUtilities.appContextGet(pressedCharCacheKey);
  117.                     if(pressedKeyCharKeyStrokeCache == null) {
  118.                         pressedKeyCharKeyStrokeCache = new KeyStroke[MAX_ASCII_CACHE_INDEX - MIN_ASCII_CACHE_INDEX];
  119.                         SwingUtilities.appContextPut(
  120.                             pressedCharCacheKey, pressedKeyCharKeyStrokeCache);
  121.                     }
  122.                     pressedKeyCharKeyStrokeCache[((int)ks.keyChar) - MIN_ASCII_CACHE_INDEX] = ks;
  123.                 }
  124.             }
  125.         }
  126.     }
  127.  
  128.     static int subIndexForModifier(int modifiers) {
  129.         if(modifiers == 0)
  130.             return 0;
  131.         else if(modifiers == InputEvent.SHIFT_MASK)
  132.             return 1;
  133.         else if(modifiers == InputEvent.CTRL_MASK)
  134.             return 2;
  135.         else if(modifiers == InputEvent.ALT_MASK)
  136.             return 3;
  137.         
  138.         return -1;
  139.     }
  140.  
  141.     static KeyStroke getCachedKeyStroke(int keyCode,int modifiers,boolean onKeyRelease) {
  142.         int subIndex;
  143.         KeyStroke result = null;
  144.         if(keyCode >= MIN_ASCII_CACHE_INDEX && keyCode < MAX_ASCII_CACHE_INDEX &&
  145.            (subIndex = subIndexForModifier(modifiers)) != -1) {
  146.             synchronized(KeyStroke.class) {
  147.                 KeyStroke cache[][];
  148.                 if(onKeyRelease) 
  149.                     cache = (KeyStroke[][])SwingUtilities.appContextGet(
  150.                         pressedCodeCacheKey);
  151.                 else
  152.                     cache = (KeyStroke[][])SwingUtilities.appContextGet(
  153.                         releasedCodeCacheKey);
  154.  
  155.                 if(cache != null)
  156.                     result = cache[subIndex][keyCode - MIN_ASCII_CACHE_INDEX];
  157.             }
  158.         }
  159.         return result;
  160.     }
  161.  
  162.     static void cacheKeyStroke(KeyStroke ks) {
  163.         int subIndex = -1;
  164.         if(ks.keyCode >= MIN_ASCII_CACHE_INDEX && ks.keyCode < MAX_ASCII_CACHE_INDEX &&
  165.            (subIndex = subIndexForModifier(ks.modifiers)) != -1) {
  166.             synchronized(KeyStroke.class) {
  167.                 KeyStroke cache[][] = null;
  168.                 if(ks.onKeyRelease) {
  169.                     KeyStroke[][] pressedKeyCodeKeyStrokeCache = (KeyStroke[][])
  170.                         SwingUtilities.appContextGet(pressedCodeCacheKey);
  171.                     if(pressedKeyCodeKeyStrokeCache == null) {
  172.                         pressedKeyCodeKeyStrokeCache = new KeyStroke[4][MAX_ASCII_CACHE_INDEX - 
  173.                                                                          MIN_ASCII_CACHE_INDEX];
  174.                         SwingUtilities.appContextPut(
  175.                             pressedCodeCacheKey, pressedKeyCodeKeyStrokeCache);
  176.                     }
  177.                     cache = pressedKeyCodeKeyStrokeCache;
  178.                 } else {
  179.                     KeyStroke[][] releasedKeyCodeKeyStrokeCache = (KeyStroke[][])
  180.                         SwingUtilities.appContextGet(releasedCodeCacheKey);
  181.                     if(releasedKeyCodeKeyStrokeCache == null) {
  182.                         releasedKeyCodeKeyStrokeCache = new KeyStroke[4][MAX_ASCII_CACHE_INDEX - 
  183.                                                                           MIN_ASCII_CACHE_INDEX];
  184.                         SwingUtilities.appContextPut(
  185.                             releasedCodeCacheKey, releasedKeyCodeKeyStrokeCache);
  186.                     }
  187.                     cache = releasedKeyCodeKeyStrokeCache;
  188.                 }
  189.  
  190.                 cache[subIndex][ks.keyCode - MIN_ASCII_CACHE_INDEX] = ks;
  191.             }
  192.         }
  193.     }
  194.     
  195.     /**
  196.      * Return a shared instance of a key stroke that is activated
  197.      * activated when the key is pressed.
  198.      *
  199.      * @param keyChar the character value for a keyboard key
  200.      * @return a KeyStroke object for that key
  201.      */
  202.     public static KeyStroke getKeyStroke(char keyChar) {
  203.         return getKeyStroke(keyChar,false);
  204.     }
  205.  
  206.     /**
  207.      * Return a shared instance of a key stroke that specifies
  208.      * whether the key is activated when it is pressed or released.
  209.      *
  210.      * @param keyChar the character value for a keyboard key
  211.      * @param onKeyRelease a boolean value. When true, specifies that
  212.      *        the key is active when it is released.
  213.      * @return a KeyStroke object for that key
  214.      */
  215.     public static KeyStroke getKeyStroke(char keyChar,boolean onKeyRelease) {
  216.         KeyStroke result = getCachedKeyCharKeyStroke(keyChar,onKeyRelease);
  217.  
  218.         if(result == null) {
  219.             result = new KeyStroke();
  220.             result.keyChar = keyChar;
  221.             result.modifiers = 0;
  222.             result.onKeyRelease = onKeyRelease;
  223.             cacheKeyCharKeyStroke(result,onKeyRelease);
  224.         }
  225.         return result;
  226.     }
  227.  
  228.     /**
  229.      * Return a shared instance of a key stroke given a char code and a set
  230.      * of modifiers, specifying whether the key is activated when it is pressed
  231.      * or released.
  232.      * <p>
  233.      * The modifiers consist of any combination of:<ul>
  234.      * <li>java.awt.Event.SHIFT_MASK (1)
  235.      * <li>java.awt.Event.CTRL_MASK (2)
  236.      * <li>java.awt.Event.META_MASK (4)
  237.      * <li>java.awt.Event.ALT_MASK (8)
  238.      * </ul>
  239.      * Since these numbers are all different powers of two, any combination of
  240.      * them is an integer in which each bit represents a different
  241.      * modifier key.
  242.      *
  243.      * @param keyChar the character value for a keyboard key
  244.      * @param modifiers an int specifying any combination of the key modifiers.
  245.      * @param onKeyRelease a boolean value. When true, specifies that
  246.      *        the key is active when it is released.
  247.      * @return a KeyStroke object for that key
  248.      */
  249.     public static KeyStroke getKeyStroke(int keyCode,int modifiers,boolean onKeyRelease) {
  250.         KeyStroke result = getCachedKeyStroke(keyCode,modifiers,onKeyRelease);
  251.  
  252.         if(result == null) {
  253.             result = new KeyStroke();
  254.             result.keyCode = keyCode;
  255.             result.modifiers = modifiers;
  256.             result.onKeyRelease = onKeyRelease;
  257.             cacheKeyStroke(result);
  258.         }
  259.  
  260.         return result;
  261.     }
  262.  
  263.     /**
  264.      * Return a shared instance of a key stroke given a char code and a set
  265.      * of modifiers -- the key is activated when it is pressed.
  266.      * <p>
  267.      * The modifiers consist of any combination of:<ul>
  268.      * <li>java.awt.Event.SHIFT_MASK (1)
  269.      * <li>java.awt.Event.CTRL_MASK (2)
  270.      * <li>java.awt.Event.META_MASK (4)
  271.      * <li>java.awt.Event.ALT_MASK (8)
  272.      * </ul>
  273.      * Since these numbers are all different powers of two, any combination of
  274.      * them is an integer in which each bit represents a different
  275.      * modifier key.
  276.      *
  277.      * @param keyChar the character value for a keyboard key
  278.      * @param modifiers an int specifying any combination of the key modifiers.
  279.      * @return a KeyStroke object for that key
  280.      */
  281.     public static KeyStroke getKeyStroke(int keyCode,int modifiers) {
  282.         return getKeyStroke(keyCode,modifiers,false);
  283.     }
  284.  
  285.     /**
  286.      * Return a keystroke from an event.
  287.      * <p>
  288.      * This method obtains the keyChar from a KeyTyped event,
  289.      * and the keyCode from a KeyPressed or KeyReleased event,
  290.      * so you don't have to.
  291.      *
  292.      * @param anEvent the KeyEvent to obtain the KeyStroke from
  293.      * @return the KeyStroke that precipitated the event
  294.      */
  295.     public static KeyStroke getKeyStrokeForEvent(KeyEvent anEvent) {
  296.         KeyStroke ks = null;
  297.     switch(anEvent.getID()) {
  298.         case KeyEvent.KEY_PRESSED:
  299.             ks = getKeyStroke(anEvent.getKeyCode(),anEvent.getModifiers(),false);
  300.         break;
  301.         case KeyEvent.KEY_RELEASED:
  302.             ks = getKeyStroke(anEvent.getKeyCode(),anEvent.getModifiers(),true);
  303.         break;
  304.     case KeyEvent.KEY_TYPED:
  305.             ks = getKeyStroke(anEvent.getKeyChar());
  306.         break;
  307.     }
  308.     return ks;
  309.     }
  310.  
  311.     /**
  312.      * Return a shared instance of a key stroke matching a string
  313.      * representation.
  314.      *
  315.      * @param representation a String specifying a KeyStroke
  316.      * @return a KeyStroke object matching the specification. 
  317.      */
  318.     public static KeyStroke getKeyStroke(String representation) {
  319.         // Not implemented
  320.         return null;
  321.     }
  322.  
  323.     /**
  324.      *
  325.      */
  326.     public char getKeyChar() { return keyChar; }
  327.     /**
  328.      *
  329.      */
  330.     public int  getKeyCode() { return keyCode; }
  331.     /**
  332.      *
  333.      */
  334.     public int getModifiers() { return modifiers; }
  335.     /**
  336.      *
  337.      */
  338.     public boolean isOnKeyRelease() { return onKeyRelease; }
  339.  
  340.     private static String getStringRepresentation(char keyChar,int modifiers,boolean kr) {
  341.         return "keyChar " + KeyEvent.getKeyModifiersText(modifiers) + keyChar +  
  342.             (kr?"-R":"-P");
  343.     }
  344.  
  345.     private static String getStringRepresentation(int keyCode,int modifiers,boolean kr) {
  346.         return "keyCode " + KeyEvent.getKeyModifiersText(modifiers) + KeyEvent.getKeyText(keyCode) +
  347.             (kr?"-R":"-P");
  348.     }
  349.  
  350.     /**
  351.      * Returns a numeric value for this object that is likely to be
  352.      * reasonably unique, so it can be used as the index value in a
  353.      * Hashtable.
  354.      *
  355.      * @return an int that "represents" this object
  356.      * @see java.util.Hashtable
  357.      */
  358.     public int hashCode() {
  359.         return (((int) keyChar) + 1) * (2 * (keyCode + 1)) * (modifiers+1) +
  360.             (onKeyRelease ? 1 : 2);
  361.     }
  362.  
  363.     /**
  364.      * Returns true if this object is identical to the specified object.
  365.      *
  366.      * @param anObject the Object to compare this object to
  367.      * @return true if the objects are identical
  368.      */
  369.     public boolean equals(Object anObject) {
  370.         if(anObject instanceof KeyStroke) {
  371.             KeyStroke ks = (KeyStroke) anObject;
  372.             if(ks.keyChar == keyChar && ks.keyCode == keyCode && 
  373.                ks.onKeyRelease == onKeyRelease && ks.modifiers == modifiers)
  374.                 return true;
  375.         }
  376.         return false;
  377.     }
  378.  
  379.     /**
  380.      * Returns a string that displays and identifies this
  381.      * object's properties.
  382.      *
  383.      * @return a String representation of this object
  384.      */
  385.     public String toString() {
  386.         if(keyChar == 0)
  387.             return getStringRepresentation(keyCode,modifiers,onKeyRelease);
  388.         else
  389.             return getStringRepresentation(keyChar,0,onKeyRelease);
  390.     }
  391. }
  392.  
  393.  
  394.