JDK-4632139 : KeyStroke does not honor KeyEvent location
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: solaris_7,windows_2000
  • CPU: x86,sparc
  • Submitted: 2002-02-01
  • Updated: 2007-03-05
Related Reports
Duplicate :  

Name: eh37734			Date: 02/01/2002

D:\j2sdk1.4.0-beta3\bin>java -version
java version "1.4.0-beta3"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-beta3-b84)
Java HotSpot(TM) Client VM (build 1.4.0-beta3-b84, mixed mode)

Windows 2000 (problem is in Java code, not native)


There is no signature of KeyStroke.getKeyStroke that takes
a key location (e.g., KEY_LOCATION_STANDARD, or
KEY_LOCATION_NUMPAD), so it seems to be impossible to make
a KeyStroke for includion in a key map that pays attention
to location.

Further, the KeyStroke code appears to ignore the location
when finding map entries based on KeyEvents.

1. Since there is no KeyStroke.getKeyStroke method that
accepts a location, it is necessary to construct a KeyEvent
call KeyStroke.getKeyStrokeForEvent on it. The KeyEvent
should specify a KEY_PRESSED event on VK_ENTER with no
modifiers, and a location of KEY_LOCATION_STANDARD.

2. Insert the returned KeyStroke into a map (ActionMap,
InputMap, or DefaultKeyMap).

3. Repeat the #1 and 2 with an identical event, except use

4. Try to find the event in the map with a real KeyEvent
for a key press on the normal and numpad Enter (Return)
keys. Notice that both events find the same Action.

I expected to be able to make two KeyStrokes that are
identical except for location, and to be able to insert
them in a map and find them when I get a matching event,
including matching on location.

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
java.awt.Component c = new java.awt.Label( "fake" );
KeyEvent returnKeyEvent = new KeyEvent(
  c,                              // Component
  KeyEvent.KEY_PRESSED,           // id
  0,                              // when
  0,                              // modifiers
  KeyEvent.VK_ENTER,              // keyCode
  KeyEvent.CHAR_UNDEFINED,        // keyChar
  KeyEvent.KEY_LOCATION_STANDARD  // location

KeyEvent enterKeyEvent = new KeyEvent(
  c,                              // Component
  KeyEvent.KEY_PRESSED,           // id
  0,                              // when
  0,                              // modifiers
  KeyEvent.VK_ENTER,              // keyCode
  KeyEvent.CHAR_UNDEFINED,        // keyChar
  KeyEvent.KEY_LOCATION_NUMPAD    // location

/* I would have preferred to use this:

  KeyEvent.VK_ENTER,              // keyCode
  0,                              // no modifiers
  KeyEvent.KEY_LOCATION_STANDARD  // normal keyboard

  KeyEvent.VK_ENTER,              // keyCode
  0,                              // no modifiers
  KeyEvent.KEY_LOCATION_NUMPAD    // numpad

// then insert in map

// later, find in map with:

KeyStroke k = KeyStroke.getKeyStrokeForEvent(inEvent);
Action a = binding.getAction(k);

// Right now, 'binding' is a Keymap that I got with:
// JTextComponent.addKeymap( "Root Map", null );

// I'm not sure if I'm supposed to be using an ActionMap or InputMap instead of
the DefaultKeymap from JTextComponent.addKeymap

---------- END SOURCE ----------
(Review ID: 138515) 

EVALUATION We'll probably need a way to test for equality of KeyStrokes that include location, and that don't include location. My original idea was to have AWTKeyStroke implement the java.util.Comparator interface, and have equals() and compare() be inconsistent. The problem, of course, is that this would impede use of AWTKeyStroke in Maps. Perhaps a better idea would be simply to provide two APIs: equals() and equalsDespiteLocation() (perhaps with a better name). Maybe equals(Object o) and equals(Object o, boolean ignoreLocation) ? Note: we'll do this for AWTKeyStroke: perhaps getAWTKeyStroke(int keyCode, int modifiers, boolean onKeyRelease, int keyLocation) I assume we'll have to duplicate this method in KeyStroke as well, since static methods are not inherited. Since KEY_TYPED events do not have a keyLocation, we won't need to add new versions of getAWTKeyStroke(char keyChar) or getAWTKeyStroke(Character keyChar, int modifiers) that specify location. We can probably do this for Tiger. ###@###.### 2002-02-01 I wrote up some new APIs and a prototype implementation: > + public final int getKeyLocation() { > + return location; > + } > + public static AWTKeyStroke getAWTKeyStrokeForEvent(KeyEvent anEvent, > + int location) { > + public static AWTKeyStroke getAWTKeyStroke(int keyCode, int modifiers, > + boolean onKeyRelease, int location) { and similar for KeyStroke. However, this will not satisfy the customer's needs, since he needs to be able to use location-aware keystrokes in a KeyMap, and that would require changing the hashcode() and equals() calculations to include key location. We are concerned that this would have an impact on backwards compatibility if anyone is using their own maps. There was an alternate proposal to add methods to Keymap (and/or InputMap) and AWTKeyStroke/KeyStroke to toggle whether they are location-aware, but there is a cost to this as well. It would make our keymaps more heavyweight, and it would require client code to make these changes to a couple of different classes, and keep the changes in sync. It is possible to do this, but so far, we haven't seen great demand for it. So, I think we will defer consideration of this rfe, and reconsider it for a future release if it garners more interest. ###@###.### 2003-06-03