Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6363104

Grammar for param of AWTKeyStroke.getAWTKeyStroke(String) should be improved

    Details

    • Subcomponent:
    • Understanding:
      Cause Known
    • CPU:
      generic
    • OS:
      generic

      Description

      Right now grammar which this method accepts is rather restrictive (i.e. it is case-sensitive)
      We should try to improve it.
      This issue was discussed on javadesktop.org (http://www.javadesktop.org/forums/thread.jspa?threadID=20712&tstart=0)
      See below for a suggested fix submitted by java.net community member leouser:


      A DESCRIPTION OF THE FIX :
      file: java.awt.AWTKeyStroke
      version: jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin
        Description( embedded in test code as well ):
      /*
        Rationale behind change:
        AWTKeyStroke.getAWTKeyStroke( String s ) is a convenience method. It exists to allow simple acquisition of AWTKeyStroke instances. Yet the grammar is more restrictive than necessary. Capitalisation plays too prevalent a role in determining if a valid KeyStroke is returned. Hence the capitialisation requirement of the grammar has been removed. Any sequence of characters that match a AWTKeyStroke will now be accepted. Another change is the allowance of + and - as token separators. This will ease the production of AWTKeyStrokes from user defined KeyStrokes. User in this case would be someone who is utilising an application that allows them to specify keystrokes. + and - play a prevalent token separator role in many an application that uses this. Also, other toolkits use these tokens as well, hence it will also ease someone switching from another toolkit to Swing.


        TestAWTKeyStroke is a junit test of changing the method AWTKeyStroke.getKeyStroke( String s ) so it will be more accepting. The old ways should work but with some slight modifications to the methods code we are able to parse and succesfully get KeyStrokes from a variety of Strings. This test tests from 2 different levels: The AWTKeyStroke itself and swing's KeyStroke which makes direct use of KeyStroke and may very well be the class that uses it the most in the SDK. The test(s) is writtens so it will fail with the old code, but succeed in the new. This AWTKeyStroke was modified against:
      jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin

      and also executed on a Suse Linux 7.3 distribution.

      IMPORTANT NOTE: This Test does not test the conversion of old style Map instances to generified Map instances. It is assumed that the compiler will correctly show if there is an error in the usage of the generified Map instances. After generifying the Map instances no more warnings were issued in compilation. Also, this test exercises a method that directly works with a generified Map.

      Brian Harry
      ###@###.###
      Mon Dec 19, 2005

       */

      unified diff:
      --- AWTKeyStroke.java Mon Dec 19 11:06:43 2005
      +++ AWTKeyStroke.java Mon Dec 19 10:22:03 2005
      @@ -49,10 +49,10 @@
       public class AWTKeyStroke implements Serializable {
           static final long serialVersionUID = -6430539691155161871L;
       
      - private static Map cache;
      + private static Map<AWTKeyStroke,AWTKeyStroke> cache;
           private static AWTKeyStroke cacheKey;
           private static Constructor ctor = getCtor(AWTKeyStroke.class);
      - private static Map modifierKeywords;
      + private static Map<String,Integer> modifierKeywords;
           /**
            * Associates VK_XXX (as a String) with code (as Integer). This is
            * done to avoid the overhead of the reflective call to find the
      @@ -192,8 +192,8 @@
            */
           private static Constructor getCtor(final Class clazz)
           {
      - Object ctor = AccessController.doPrivileged(new PrivilegedAction() {
      - public Object run() {
      + Constructor ctor = AccessController.doPrivileged(new PrivilegedAction<Constructor>() {
      + public Constructor run() {
                       try {
                           Constructor ctor = clazz.getDeclaredConstructor((Class[]) null);
                           if (ctor != null) {
      @@ -206,14 +206,14 @@
                       return null;
                   }
               });
      - return (Constructor)ctor;
      + return ctor;
           }
       
           private static synchronized AWTKeyStroke getCachedStroke
               (char keyChar, int keyCode, int modifiers, boolean onKeyRelease)
           {
        if (cache == null) {
      - cache = new HashMap();
      + cache = new HashMap<AWTKeyStroke,AWTKeyStroke>();
        }
        
        if (cacheKey == null) {
      @@ -232,7 +232,7 @@
        cacheKey.modifiers = mapNewModifiers(mapOldModifiers(modifiers));
        cacheKey.onKeyRelease = onKeyRelease;
        
      - AWTKeyStroke stroke = (AWTKeyStroke)cache.get(cacheKey);
      + AWTKeyStroke stroke = cache.get(cacheKey);
        if (stroke == null) {
        stroke = cacheKey;
        cache.put(stroke, stroke);
      @@ -444,6 +444,14 @@
            * "alt shift released X" => getAWTKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK | InputEvent.SHIFT_MASK, true);
            * "typed a" => getAWTKeyStroke('a');
            * </pre>
      + * <pre>Note: an enhancement to the grammar now allows the usage of - or + as
      + * well as whitespace to act as the token separator. Also note, that case
      + * is no longer important for the correct identification of tokens.
      + * Some examples:
      + * ALT+x
      + * AlT+EnteR
      + * CTRL-v
      + * </pre>
            *
            * @param s a String formatted as described above
            * @return an <code>AWTKeyStroke</code> object for that String
      @@ -457,7 +465,7 @@
       
               final String errmsg = "String formatted incorrectly";
       
      - StringTokenizer st = new StringTokenizer(s, " ");
      + StringTokenizer st = new StringTokenizer(s, "+- ");
       
        int mask = 0;
        boolean released = false;
      @@ -467,30 +475,30 @@
               if (modifierKeywords == null) {
        synchronized (AWTKeyStroke.class) {
        if (modifierKeywords == null) {
      - Map uninitializedMap = new HashMap(8, 1.0f);
      - uninitializedMap.put("shift",
      + Map<String,Integer> uninitializedMap = new HashMap<String,Integer>(8, 1.0f);
      + uninitializedMap.put("SHIFT",
        Integer.valueOf(InputEvent.SHIFT_DOWN_MASK
        |InputEvent.SHIFT_MASK));
      - uninitializedMap.put("control",
      + uninitializedMap.put("CONTROL",
        Integer.valueOf(InputEvent.CTRL_DOWN_MASK
        |InputEvent.CTRL_MASK));
      - uninitializedMap.put("ctrl",
      + uninitializedMap.put("CTRL",
        Integer.valueOf(InputEvent.CTRL_DOWN_MASK
        |InputEvent.CTRL_MASK));
      - uninitializedMap.put("meta",
      + uninitializedMap.put("META",
        Integer.valueOf(InputEvent.META_DOWN_MASK
        |InputEvent.META_MASK));
      - uninitializedMap.put("alt",
      + uninitializedMap.put("ALT",
        Integer.valueOf(InputEvent.ALT_DOWN_MASK
        |InputEvent.ALT_MASK));
      - uninitializedMap.put("altGraph",
      + uninitializedMap.put("ALTGRAPH",
        Integer.valueOf(InputEvent.ALT_GRAPH_DOWN_MASK
        |InputEvent.ALT_GRAPH_MASK));
      - uninitializedMap.put("button1",
      + uninitializedMap.put("BUTTON1",
        Integer.valueOf(InputEvent.BUTTON1_DOWN_MASK));
      - uninitializedMap.put("button2",
      + uninitializedMap.put("BUTTON2",
        Integer.valueOf(InputEvent.BUTTON2_DOWN_MASK));
      - uninitializedMap.put("button3",
      + uninitializedMap.put("BUTTON3",
        Integer.valueOf(InputEvent.BUTTON3_DOWN_MASK));
        modifierKeywords =
        Collections.synchronizedMap(uninitializedMap);
      @@ -501,7 +509,7 @@
        int count = st.countTokens();
       
        for (int i = 1; i <= count; i++) {
      - String token = st.nextToken();
      + String token = st.nextToken().toUpperCase();
       
        if (typed) {
        if (token.length() != 1 || i != count) {
      @@ -523,20 +531,20 @@
        mask, released);
        }
       
      - if (token.equals("released")) {
      + if (token.equals("RELEASED")) {
        released = true;
        continue;
        }
      - if (token.equals("pressed")) {
      + if (token.equals("PRESSED")) {
        pressed = true;
        continue;
        }
      - if (token.equals("typed")) {
      + if (token.equals("TYPED")) {
        typed = true;
        continue;
        }
       
      - Integer tokenMask = (Integer)modifierKeywords.get(token);
      + Integer tokenMask = modifierKeywords.get(token);
        if (tokenMask != null) {
        mask |= tokenMask.intValue();
        } else {
      @@ -815,12 +823,12 @@
       }
       
       class VKCollection {
      - Map code2name;
      - Map name2code;
      + Map<Integer,String> code2name;
      + Map<String,Integer> name2code;
       
           public VKCollection() {
      - code2name = new HashMap();
      - name2code = new HashMap();
      + code2name = new HashMap<Integer,String>();
      + name2code = new HashMap<String,Integer>();
           }
       
           public synchronized void put(String name, Integer code) {
      @@ -833,12 +841,12 @@
       
           public synchronized Integer findCode(String name) {
               assert(name != null);
      - return (Integer)name2code.get(name);
      + return name2code.get(name);
           }
       
           public synchronized String findName(Integer code) {
               assert(code != null);
      - return (String)code2name.get(code);
      + return code2name.get(code);
           }
       }
       




      JUnit TESTCASE :
      import junit.framework.TestCase;
      import junit.textui.TestRunner;
      import java.awt.AWTKeyStroke;
      import javax.swing.KeyStroke;
      import static java.lang.System.out;

      /*
        Rationale behind change:
        AWTKeyStroke.getAWTKeyStroke( String s ) is a convenience method. It exists to allow simple acquisition of AWTKeyStroke instances. Yet the grammar is more restrictive than necessary. Capitalisation plays too prevalent a role in determining if a valid KeyStroke is returned. Hence the capitialisation requirement of the grammar has been removed. Any sequence of characters that match a AWTKeyStroke will now be accepted. Another change is the allowance of + and - as token separators. This will ease the production of AWTKeyStrokes from user defined KeyStrokes. User in this case would be someone who is utilising an application that allows them to specify keystrokes. + and - play a prevalent token separator role in many an application that uses this. Also, other toolkits use these tokens as well, hence it will also ease someone switching from another toolkit to Swing.


        TestAWTKeyStroke is a junit test of changing the method AWTKeyStroke.getKeyStroke( String s ) so it will be more accepting. The old ways should work but with some slight modifications to the methods code we are able to parse and succesfully get KeyStrokes from a variety of Strings. This test tests from 2 different levels: The AWTKeyStroke itself and swing's KeyStroke which makes direct use of KeyStroke and may very well be the class that uses it the most in the SDK. The test(s) is writtens so it will fail with the old code, but succeed in the new. This AWTKeyStroke was modified against:
      jdk-6-rc-bin-b64-linux-i586-15_dec_2005.bin

      and also executed on a Suse Linux 7.3 distribution.

      IMPORTANT NOTE: This Test does not test the conversion of old style Map instances to generified Map instances. It is assumed that the compiler will correctly show if there is an error in the usage of the generified Map instances. After generifying the Map instances no more warnings were issued in compilation. Also, this test exercises a method that directly works with a generified Map.

      Brian Harry
      ###@###.###
      Mon Dec 19, 2005

       */
      public class TestAWTKeyStroke extends TestCase{


          public TestAWTKeyStroke( String s ){

      super( s );

          }

          public void testVariationsInAWTKeyStrokes(){

      //these should always work....
      out.println( "" );
      AWTKeyStroke aw_aks = AWTKeyStroke.getAWTKeyStroke( "ctrl A" );
      assertNotNull( "AWTKeyStroke:ctrl A produced null?", aw_aks );
      out.println( aw_aks );
      AWTKeyStroke aw_aks2 = AWTKeyStroke.getAWTKeyStroke( "ctrl alt ENTER" );
      assertNotNull( "AWTKeyStroke: ctrl alt ENTER produced a null?", aw_aks2 );

      out.println( aw_aks2 );
              //these next AWTKeyStrokes should always fail with the old code
      AWTKeyStroke aks1 = null;
      try{

      aks1 = AWTKeyStroke.getAWTKeyStroke( "CTRL+9" );

      }
      catch( Exception x ){}
      assertNotNull( "AWTKeyStroke: CTRL+9 produced a null?", aks1 );
      out.println( aks1 );

      AWTKeyStroke aks2 = null;
      try{
      aks2 = AWTKeyStroke.getAWTKeyStroke( "CTRL a" );
      }
      catch( Exception x ){}
      assertNotNull( "AWTKeyStroke:CTRL a produced null?", aks2 );
      out.println( aks2 );

      AWTKeyStroke aks3 = null;
      try{
      aks3 = AWTKeyStroke.getAWTKeyStroke( "CTrl+-+-+a" );
      }
      catch( Exception x ){}
      assertNotNull( "AWTKeyStroke:Ctrl+-+-+a produced null?", aks3 );
      out.println( aks3 );

      AWTKeyStroke aks4 = null;
      try{

      aks4 = AWTKeyStroke.getAWTKeyStroke( "CTRL-ALT-Enter" );

      }
      catch( Exception x ){}
      assertNotNull( "AWTKeyStroke:CTRL-ALT-Enter produced a null", aks4 );
      out.println( aks4 );

      AWTKeyStroke aks5 = null;
      try{

      aks5 = AWTKeyStroke.getAWTKeyStroke( " ALT+ + - - asterisk " );

      }
      catch( Exception x ){}
      assertNotNull( " ALT+ + - - asterisk produced a null", aks5 );
      out.println( aks5 );

      //these should always be null...
      AWTKeyStroke failure1 = null;
      try{

      failure1 = AWTKeyStroke.getAWTKeyStroke( "ALT>>a" );

      }
      catch( Exception x ){}
      assertNull( "AWTKeyStroke:ALT>>a produced didn't produce a null?", failure1 );
      out.println( failure1 );

          }

          public void testVariationsInKeyStrokes(){

      out.println( "" );
      KeyStroke aks = KeyStroke.getKeyStroke( "ctrl A" );// should always work.
      assertNotNull( "KeyStroke:ctrl A produced null?", aks );
      //these next KeyStrokes should always fail with the old code
      KeyStroke aks2 = null;
      try{
      aks2 = KeyStroke.getKeyStroke( "CTRL a" );
      }
      catch( Exception x ){}
      assertNotNull( "KeyStroke:CTRL a produced null?", aks2 );
      out.println( aks2 );

      KeyStroke aks3 = null;
      try{
      aks3 = KeyStroke.getKeyStroke( "CTrl+-+-+a" );
      }
      catch( Exception x ){}
      assertNotNull( "KeyStroke:CTrl+-+-+a produced null?", aks3 );
      out.println( aks3 );

      KeyStroke aks4 = null;
      try{

      aks4 = KeyStroke.getKeyStroke( "CTRL-ALT-Enter" );

      }
      catch( Exception x ){}
      assertNotNull( "KeyStroke:CTRL-ALT-Enter produced a null", aks4 );
      out.println( aks4 );

      //these should always be null...
      KeyStroke failure1 = null;
      try{

      failure1 = KeyStroke.getKeyStroke( "ALT>>a" );

      }
      catch( Exception x ){}
      assertNull( "KeyStroke:ALT>>a didn't produce a null", failure1 );
      out.println( failure1 );

          }

          public static void main( String[] args ){

      TestCase tc1 = new TestAWTKeyStroke( "testVariationsInAWTKeyStrokes" );
         out.println( "Testing Variations In AWTKeyStroke:" );
      out.println( "------" );
      TestRunner.run( tc1 );
      TestCase tc2 = new TestAWTKeyStroke( "testVariationsInKeyStrokes" );
      out.println( "Testing Variations In KeyStroke:" );
      out.println( "-----" );
              TestRunner.run( tc2 );

          }


      }


      FIX FOR BUG NUMBER:
      6363104

        Attachments

          Activity

            People

            • Assignee:
              dav Andrei Dmitriev (Inactive)
              Reporter:
              son Oleg Sukhodolsky (Inactive)
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Imported:
                Indexed: