JDK-4782886 : FocusManager consumes wrong KEYTYPED-Events
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 1.4.1,5.0
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2002-11-21
  • Updated: 2003-03-14
  • Resolved: 2003-03-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
5.0 tigerFixed
Related Reports
Duplicate :  
Description

Name: jk109818			Date: 11/21/2002


FULL PRODUCT VERSION :
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-
b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)

FULL OPERATING SYSTEM VERSION :Microsoft Windows 2000 [Version
5.00.2195]


A DESCRIPTION OF THE PROBLEM :
The java.awt.DefaultKeyboardManager consumes KEYTYPED-Events for
handled FocusTraversalKeys-KEYPRESSED-Events. If one sets an ActionKey
as FocusTraversalKey (eg. LEFT or RIGHT) DefaultKeyboardManager will
do so regardlessly ActionKeys don't produce KEYTYPED-Events. Hence the
following KEYTYPED-Event will be consumed. If one traverses into a
JTextArea the first typed Key will be lost.
TAB-Key will not cause this
since it produces a KEYTYPED-Event.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
A simple program will demonstrate the effect.
Traverse with DOWN into
the JTextArea and the first typed character will be lost.



EXPECTED VERSUS ACTUAL BEHAVIOR :
First character typed into JTextArea ist lost. This ist caused by
DefaultKeyboardManager's processKeyEvent-method:

    public void
processKeyEvent(Component focusedComponent, KeyEvent e) {
	//
KEY_TYPED events cannot be focus traversal keys
	if (e.getID() ==
KeyEvent.KEY_TYPED) {
	    if (consumeNextKeyTyped)
{
		e.consume();
		consumeNextKeyTyped = false;
	    }

	    
return;
	}

        if
(focusedComponent.getFocusTraversalKeysEnabled() &&
            
!e.isConsumed())
        {
	    AWTKeyStroke stroke =
AWTKeyStroke.getAWTKeyStrokeForEvent(e),
		oppStroke =
AWTKeyStroke.getAWTKeyStroke(stroke.getKeyCode(),
						 
stroke.getModifiers(),
						 !stroke.isOnKeyRelease());
	    Set
toTest;
	    boolean contains, containsOpp;

	    toTest =
focusedComponent.getFocusTraversalKeys(
                
KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
	    contains =
toTest.contains(stroke);
	    containsOpp =
toTest.contains(oppStroke);

	    if (contains || containsOpp)
{
		if (contains) {
		    
focusNextComponent(focusedComponent);
		}
		e.consume();
		consumeNextKeyTyped
= (e.getID() == KeyEvent.KEY_PRESSED);
		return;
	    
}
[...]
}

The condition for 'consumeNextKeyTyped' should
be
"consumeNextKeyTyped = ((e.getID() == KeyEvent.KEY_PRESSED)) &&
!e.isActionKey();"
instead.


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Set;
import java.util.HashSet;

class FocusTest extends JFrame {

    public FocusTest() {
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        Container contentPane = getContentPane();
        Set ftk = new HashSet();
        ftk.add(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0));
        ftk.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
        
		contentPane.setFocusTraversalKeys(
				KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,ftk);
        Set btk = new HashSet();
        btk.add(KeyStroke.getKeyStroke(KeyEvent.VK_UP,0));
        btk.add(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
									   KeyEvent.SHIFT_DOWN_MASK));
        contentPane.setFocusTraversalKeys(
            	KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,btk);
        contentPane.setLayout(new BoxLayout(contentPane,BoxLayout.Y_AXIS));
        JCheckBox cba = new JCheckBox("test1");
        
		contentPane.add(cba);
        JTextArea jta = new JTextArea(40, 10);
        contentPane.add(jta);
        
		pack();
        setVisible(true);
    }

	public static void main(String args[]){
	
		FocusTest test = new FocusTest();

	}

}
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
Use an extended DefaultFocusManager where you've overwritten
'processKeyEvent' to not try to consume KEYTYPED-Events from
ActionKeys.
(Review ID: 167245) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger FIXED IN: tiger INTEGRATED IN: tiger tiger-b03
24-08-2004

SUGGESTED FIX Name: osR10079 Date: 12/20/2002 ------- DefaultKeyboardFocusManager.java ------- *** /tmp/dRxaiVg Tue Dec 17 13:04:41 2002 --- DefaultKeyboardFocusManager.java Tue Dec 17 13:02:08 2002 *************** *** 831,836 **** --- 831,854 ---- return dispatchKeyEvent(ke); } + private void consumeTraversalKey(KeyEvent e) { + e.consume(); + consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED) && + !e.isActionKey(); + } + + /* + * return true if event was consumed + */ + private boolean consumeProcessedKeyEvent(KeyEvent e) { + if ((e.getID() == KeyEvent.KEY_TYPED) && consumeNextKeyTyped) { + e.consume(); + consumeNextKeyTyped = false; + return true; + } + return false; + } + /** * This method initiates a focus traversal operation if and only if the * KeyEvent represents a focus traversal key for the specified *************** *** 845,857 **** * @param e the event that may represent a focus traversal key */ public void processKeyEvent(Component focusedComponent, KeyEvent e) { // KEY_TYPED events cannot be focus traversal keys if (e.getID() == KeyEvent.KEY_TYPED) { - if (consumeNextKeyTyped) { - e.consume(); - consumeNextKeyTyped = false; - } - return; } --- 863,875 ---- * @param e the event that may represent a focus traversal key */ public void processKeyEvent(Component focusedComponent, KeyEvent e) { + // consume processed event if needed + if (consumeProcessedKeyEvent(e)) { + return; + } + // KEY_TYPED events cannot be focus traversal keys if (e.getID() == KeyEvent.KEY_TYPED) { return; } *************** *** 874,881 **** if (contains) { focusNextComponent(focusedComponent); } ! e.consume(); ! consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED); return; } --- 892,898 ---- if (contains) { focusNextComponent(focusedComponent); } ! consumeTraversalKey(e); return; } *************** *** 888,895 **** if (contains) { focusPreviousComponent(focusedComponent); } ! e.consume(); ! consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED); return; } --- 905,911 ---- if (contains) { focusPreviousComponent(focusedComponent); } ! consumeTraversalKey(e); return; } *************** *** 902,909 **** if (contains) { upFocusCycle(focusedComponent); } ! e.consume(); ! consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED); return; } --- 918,924 ---- if (contains) { upFocusCycle(focusedComponent); } ! consumeTraversalKey(e); return; } *************** *** 921,928 **** if (contains) { downFocusCycle((Container)focusedComponent); } ! e.consume(); ! consumeNextKeyTyped = (e.getID() == KeyEvent.KEY_PRESSED); } } } --- 936,942 ---- if (contains) { downFocusCycle((Container)focusedComponent); } ! consumeTraversalKey(e); } } } ###@###.### 2002-12-20 ======================================================================
20-12-2002

EVALUATION Name: osR10079 Date: 11/24/2002 This is not a 1.4.1 regression, the bug is reproducible with 1.4.0 also. And it's no fixed in 1.4.2 for now. The fix suggested by customer looks correct. ###@###.### 2002-11-25 ======================================================================
25-11-2002