title: java keylistener on linux
body: <p>I'm trying to write a game in java3d on Linux and for that I need a proper KeyListener. 
  Did anyone of you know how to do it? I'm currently using following code, I found somewhere on the net. It's working pretty good, holding down just one key, but as soon, as I press more than one (like space and w) it will do unexpected things...</p>
  
  <pre><code>public class RepeatingReleasedEventsFixer implements AWTEventListener {
  
      private final HashMap&lt;Integer, ReleasedAction&gt; _map = new HashMap&lt;Integer, ReleasedAction&gt;();
  
      public void install() {
          Toolkit.getDefaultToolkit().addAWTEventListener(this, AWTEvent.KEY_EVENT_MASK);
      }
  
      public void remove() {
          Toolkit.getDefaultToolkit().removeAWTEventListener(this);
      }
  
      @Override
      public void eventDispatched(AWTEvent event) {
          assert event instanceof KeyEvent : "Shall only listen to KeyEvents, so no other events shall come here";
          assert assertEDT(); // REMEMBER THAT THIS IS SINGLE THREADED, so no need for synch.
  
          // ?: Is this one of our synthetic RELEASED events?
          if (event instanceof Reposted) {
              // -&gt; Yes, so we shalln't process it again.
              return;
          }
  
          // ?: KEY_TYPED event? (We're only interested in KEY_PRESSED and KEY_RELEASED).
          if (event.getID() == KeyEvent.KEY_TYPED) {
              // -&gt; Yes, TYPED, don't process.
              return;
          }
  
          final KeyEvent keyEvent = (KeyEvent) event;
  
          // ?: Is this already consumed?
          // (Note how events are passed on to all AWTEventListeners even though a previous one consumed it)
          if (keyEvent.isConsumed()) {
              return;
          }
  
          // ?: Is this RELEASED? (the problem we're trying to fix!)
          if (keyEvent.getID() == KeyEvent.KEY_RELEASED) {
              // -&gt; Yes, so stick in wait
              /**
               * Really just wait until "immediately", as the point is that the subsequent PRESSED shall already have been
               * posted on the event queue, and shall thus be the direct next event no matter which events are posted
               * afterwards. The code with the ReleasedAction handles if the Timer thread actually fires the action due to
               * lags, by cancelling the action itself upon the PRESSED.
               */
              final Timer timer = new Timer(2, null);
              ReleasedAction action = new ReleasedAction(keyEvent, timer);
              timer.addActionListener(action);
              timer.start();
  
              _map.put(Integer.valueOf(keyEvent.getKeyCode()), action);
  
              // Consume the original
              keyEvent.consume();
          }
          else if (keyEvent.getID() == KeyEvent.KEY_PRESSED) {
              // Remember that this is single threaded (EDT), so we can't have races.
              ReleasedAction action = _map.remove(Integer.valueOf(keyEvent.getKeyCode()));
              // ?: Do we have a corresponding RELEASED waiting?
              if (action != null) {
                  // -&gt; Yes, so dump it
                  action.cancel();
              }
              // System.out.println("PRESSED: [" + keyEvent + "]");
          }
          else {
              throw new AssertionError("All IDs should be covered.");
          }
      }
  
      /**
       * The ActionListener that posts the RELEASED {@link RepostedKeyEvent} if the {@link Timer} times out (and hence the
       * repeat-action was over).
       */
      private class ReleasedAction implements ActionListener {
  
          private final KeyEvent _originalKeyEvent;
          private Timer _timer;
  
          ReleasedAction(KeyEvent originalReleased, Timer timer) {
              _timer = timer;
              _originalKeyEvent = originalReleased;
          }
  
          void cancel() {
              assert assertEDT();
              _timer.stop();
              _timer = null;
              _map.remove(Integer.valueOf(_originalKeyEvent.getKeyCode()));
          }
  
          @Override
          public void actionPerformed(@SuppressWarnings ("unused") ActionEvent e) {
              assert assertEDT();
              // ?: Are we already cancelled?
              // (Judging by Timer and TimerQueue code, we can theoretically be raced to be posted onto EDT by TimerQueue,
              // due to some lag, unfair scheduling)
              if (_timer == null) {
                  // -&gt; Yes, so don't post the new RELEASED event.
                  return;
              }
              // Stop Timer and clean.
              cancel();
              // Creating new KeyEvent (we've consumed the original).
              KeyEvent newEvent = new RepostedKeyEvent((Component) _originalKeyEvent.getSource(),
                      _originalKeyEvent.getID(), _originalKeyEvent.getWhen(), _originalKeyEvent.getModifiers(),
                      _originalKeyEvent.getKeyCode(), _originalKeyEvent.getKeyChar(), _originalKeyEvent.getKeyLocation());
              // Posting to EventQueue.
              Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(newEvent);
              // System.out.println("Posted synthetic RELEASED [" + newEvent + "].");
          }
      }
  
      /**
       * Marker interface that denotes that the {@link KeyEvent} in question is reposted from some
       * {@link AWTEventListener}, including this. It denotes that the event shall not be "hack processed" by this class
       * again. (The problem is that it is not possible to state "inject this event from this point in the pipeline" - one
       * have to inject it to the event queue directly, thus it will come through this {@link AWTEventListener} too.
       */
      public interface Reposted {
          // marker
      }
  
      /**
       * Dead simple extension of {@link KeyEvent} that implements {@link Reposted}.
       */
      public static class RepostedKeyEvent extends KeyEvent implements Reposted {
          public RepostedKeyEvent(@SuppressWarnings ("hiding") Component source, @SuppressWarnings ("hiding") int id,
                  long when, int modifiers, int keyCode, char keyChar, int keyLocation) {
              super(source, id, when, modifiers, keyCode, keyChar, keyLocation);
          }
      }
  
      private static boolean assertEDT() {
          if (!EventQueue.isDispatchThread()) {
              throw new AssertionError("Not EDT, but [" + Thread.currentThread() + "].");
          }
          return true;
      }
  }
  </code></pre>
  
  <p>I can't be the only one who still runs into this - meanwhile 15 y.o. - problem and don't want to use timers...</p>
  
  <p>EDIT: What this code is doing is fix the known problem on any Linux distri, where you add a simple KeyListener, which handles keyDowns, but invokes keyReleased Event repeatedly. To clearify my problem here a simple example</p>
  
  <pre><code>import java.awt.event.KeyEvent;
  import java.awt.event.KeyListener;
  
  import javax.swing.JFrame;
  
  public class Test5 extends JFrame{
  
      public Test5() {
          addKeyListener(new KeyListener() {
              boolean keydown = false;
              @Override
              public void keyTyped(KeyEvent arg0) {
                  // TODO Auto-generated method stub
  
              }
  
              @Override
              public void keyReleased(KeyEvent arg0) {
                  keydown = false;
                  System.out.println("keyup");
              }
  
              @Override
              public void keyPressed(KeyEvent arg0) {
                  if (keydown){
                      System.out.println("key is down");
                  } else {
                      System.out.println("key not down");
                  }
                  keydown = true;
              }
          });
  
          setDefaultCloseOperation(EXIT_ON_CLOSE);
          setSize(400, 400);
          setVisible(true);
          //new RepeatingReleasedEventsFixer().install(); // This line will fix it for one key pressed
      }
      public static void main(String[] args) {
          new Test5();
      }
  
  }
  </code></pre>
  
  <p>The output without the line being commented out:</p>
  
  <pre><code>key not down
  keyup
  key not down
  keyup
  key not down
  keyup
  key not down
  keyup
  key not down
  keyup
  </code></pre>
  
  <p>otherwise:</p>
  
  <pre><code>key not down
  key is down
  key is down
  key is down
  key is down
  key is down
  key is down
  key is down
  key is down
  key is down
  keyup
  </code></pre>
  
  <p>Btw. How come, that it's not beeing fixed by now?</p>
  
  <p><strong>EDIT:</strong> 
  I tried the KeyBindings, as suggested, where it comes to these problems:</p>
  
  <pre><code>public class Test5 extends JFrame{
      long timestamp = 0;
      public Test5() {
          ((JComponent)getComponent(0)).getInputMap().put(KeyStroke.getKeyStroke('a'), "a");
          ((JComponent)getComponent(0)).getActionMap().put("a", new AbstractAction() {
  
              @Override
              public void actionPerformed(ActionEvent e) {
                  System.out.println("time: "+(System.currentTimeMillis()-timestamp));
                  timestamp = System.currentTimeMillis();
              }
          });
  
          ((JComponent)getComponent(0)).getInputMap().put(KeyStroke.getKeyStroke('s'), "s");
          ((JComponent)getComponent(0)).getActionMap().put("s", new AbstractAction() {
  
              @Override
              public void actionPerformed(ActionEvent arg0) {
                  System.out.println("s");
              }
          });
  
          ((JComponent)getComponent(0)).getInputMap().put(KeyStroke.getKeyStroke('d'), "d");
          ((JComponent)getComponent(0)).getActionMap().put("d", new AbstractAction() {
  
              @Override
              public void actionPerformed(ActionEvent arg0) {
                  System.out.println("d");
              }
          });
          setDefaultCloseOperation(EXIT_ON_CLOSE);
          setSize(400, 400);
          setVisible(true);
          new RepeatingReleasedEventsFixer().install(); // This line will fix it for one key pressed
      }
  
      /**
       * @param args
       */
      public static void main(String[] args) {
          new Test5();
      }
  </code></pre>
  
  <p>Holding down "a" will give me following output:</p>
  
  <pre><code>time: 4171
  time: 501
  time: 30
  time: 30
  time: 30
  </code></pre>
  
  <p>Where the second time is the actual problem. It takes about 470ms too long.<br>
  Holding down "s" and then somewhne pressing "d" will give me that output:</p>
  
  <pre><code>s
  s
  s
  s
  d
  d
  d
  d
  d
  </code></pre>
  
  <p>So I can't process two actions as the same time, so I can't use KeyBindings</p>