Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4153069
Votes 18
Synopsis keyReleased behaviour incorrect
Category java:classes_awt
Reported Against 1.1.6 , 1.4.1
Release Fixed
State 6-Fix Understood, bug
Priority: 4-Low
Related Bugs 4839127 , 4817479
Submit Date 29-JUN-1998
Description


The Event tests in the JCK:

api/java_awt/interactive/EventTests.html

fail on Solaris due to the fact that keyReleased implements 
incorrect behaviour. On Solaris the keyReleased event occurs 
after about half a second regardless of whether the key has 
been released or not. This is not a problem on NT as everything
works as designed.

The test case below shows this.

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;

public class testkey extends Frame
{

   public void init( ){
      checkKey check = new checkKey();
      setSize( 300, 300 );
      setLayout(new GridLayout(0,1));
      TextField message = new TextField( "Hello Sailor" );
      message.addKeyListener( check );
      add( message );
   }
   public static void main( String args[] )
   {
      testkey test = new testkey();
      test.init( );
      test.show( );
   }
   void testkey( )
   {
   }
}

class checkKey implements KeyListener
{
   public int KeyHits = 0;
   public void keyTyped( java.awt.event.KeyEvent e ) {
//    System.out.println( e );
   }
   public void keyPressed( java.awt.event.KeyEvent e ) {
//    System.out.println( e );
   }
   public void keyReleased( java.awt.event.KeyEvent e ) {
      System.out.println( e );
      KeyHits++;
   }
}

Uncomment the System.out  lines and another possible problem
can be seen. keyPressed and keyTyped events are generated for
each auto repeat if the key is held down. Is this behaving as 
designed?
======================================================================
  xxxxx@xxxxx   10/5/04 07:42 GMT
Work Around
N/A
Evaluation
will be filed by   xxxxx@xxxxx  




This bug doesn't meet Hopper criteria. It will be fixed  in Mantis.


======================================================================

It appears that the problem is somewhat more complicated than I expected.
Key released events come from native level, and I see no way to tell the events
that arrive even if the key is pressed from the events that arrive if you
actually release a key.

I'll commit the bug to tiger in case a solution can be found.
  xxxxx@xxxxx   2002-07-12 

It may not be desirable to fix this: most people will want Java applications 
to act the same as other applications on their system.  See 4274879 and 
4701055.  

If we do try to fix the problem, we will need to have both behaviors 
supported for backwards compatibility.  

  xxxxx@xxxxx   2003-03-27
Comments
  
  Include a link with my name & email   

Submitted On 03-OCT-2004
gdeg
A workaround for this X11/Unix problem is described here:

http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/video/x11/SDL_x11events.c?rev=1.15

/* Check to see if this is a repeated key.
   (idea shamelessly lifted from GII -- thanks guys! :)
 */
static int X11_KeyRepeat(Display *display, XEvent *event)
{
	XEvent peekevent;
	int repeated;

	repeated = 0;
	if ( XPending(display) ) {
		XPeekEvent(display, &peekevent);
		if ( (peekevent.type == KeyPress) &&
		     (peekevent.xkey.keycode == event->xkey.keycode) &&
		     ((peekevent.xkey.time-event->xkey.time) < 2) ) {
			repeated = 1;
			XNextEvent(display, &peekevent);
		}
	}
	return(repeated);
}

I tried doing the same from within Java, using EventQueue.peekEvent(), and IIRC it worked correctly for about 10 seconds after the program started - then the queue was empty when i checked.

Java on Windows and Mac don't generate these bogus events, and provides the information needed to distinguish between keys pressed, keys repeated and keys released. The Unix way is simply broken here, and nobody will want Java to be broken the same way.


Submitted On 25-MAY-2007
Ekipur
The program xev on my Linux system revealed an interesting detail: The difference in time between a KeyRelease and a succeeding KeyPress is zero, while the difference between a KeyPress and a KeyRelease is even greater than zero; so to detect a real, final KeyRelease, you have to wait only one millisecond when a KeyRelease event occures. If then after this millisecond there is no KeyPress event we've got that final key release.

Based on this knowledge i implemented the
following class:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.Timer;

public class TimedKeyListener
  implements KeyListener, ActionListener {
  private final Timer timer;
  
  private boolean released = false;
  private KeyEvent releaseEvent;
  
  public TimedKeyListener() {
    /* Just a millisecond is necessary
     * to detect a final key release.
     */
    timer = new Timer(1, this);
  }
  
  public void keyPressed(KeyEvent e) {
    released = false;
    /* This key pressed event indicates
     * that the recent key release event
     * was no real, final key release,
     * so we have to stop the timer.
     */
    timer.stop();
  }
  
  public void keyReleased(KeyEvent e) {
    if (!released) {
      /* Store the current key release
       * event, as it is sent finally
       * by our timer.
       */
      releaseEvent = e;
      timer.restart();
    }
  }
  
  public void keyTyped(KeyEvent e) {
  }
  
  public void actionPerformed(ActionEvent e) {
    /* When the timer sends its action event
     * we know that no key press event has
     * followed the last key release event,
     * so we resend the recently stored
     * key release event; but now we set
     * released to true to indicate that
     * we've got the final key release.
     */
    released = true;
    timer.stop();
    keyReleased(releaseEvent);
  }

  /**
   * Do we have a real final key release?
   * @return True, if the KeyEvent obtained
   * via keyReleased() is a real final key
   * release.
   */
  protected boolean getReleased() {
    return released;
  }
}

Now you can use TimedKeyListener as shown in the following code snippet:

public class TimedKeyListenerDemo extends JFrame {
  public TimedKeyListenerDemo() {
    // some code...
    TimedKeyListener kl = new TimedKeyListener() {
      public void keyPressed(KeyEvent evt) {
        // Must be called prior to any other action!
        super.keyPressed(evt);
        System.out.println(".");
      }
      public void keyReleased(KeyEvent evt) {
        // Must be called prior to any other action!
        super.keyReleased(evt);
        // Do we have a real final key release?
        if (getReleased()) {
          // Yes, indeed :)
          System.out.println("#");
        }
      }
    };
    JButton button = new JButton("Press any key");
    button.addKeyListener(kl);
    // some code...
  }
}


Submitted On 25-JUN-2007
Ekipur
For a final version of TimedKeyListener.java, please take a look at the http://www.arco.in-berlin.de/keyevent.html


Submitted On 13-JUN-2008
oakidoaki
Quote: "most people will want Java applications 
to act the same as other applications on their system"

I don't agree with this. If Java is based on platform independence, there should be only one "Java-Way" of doing it. As it is now, I have to check for the operating system inside my Java code to know what kind of behaviour to expect  from my key events!


Submitted On 16-SEP-2008
grigor.iliev
Currently I'm implementing a virtual MIDI keyboard and I faced this bug. I find it very annoying  and I'm amazed how 10 years are not enough for fixing it. I thought that the prime objective of java is write once, run everywhere.
If you really need backwards compatibility for a bug, at least provide some method like isAutoRepeat() to KeyEvent class.


Submitted On 23-APR-2009
vickirk
Maybe oracle will change the emphasis of which bugs to fix based on target platform independence so this bug can get raised in priority?  This was raised almost 11 years ago.



PLEASE NOTE: JDK6 is formerly known as Project Mustang