As most people would by now realize with the key listener, is that in the keyPressed method, java registers one press of a key, then pauses for about half a second then records a steady stream of you pressing the key. My problem is that I would like java to immediately register a steady stream keyDown events as soon as a key is pressed down. I have read many articles on this problem and many of them speak of the swing timers, of which I am also in the dark about. To make the following piece of code nicer and easier to look at, I just trimmed out the fat and put the key listener into a separate class! Any input on this would be greatly appreciated!
public class Keyer implements KeyListener
{
Keyer(){}
@Override
public void keyPressed(KeyEvent ovent)
{
int keyCode = ovent.getKeyCode();
System.out.println("You pressed: "+keyCode);
}
@Override
public void keyReleased(KeyEvent ovent)
{
}
@Override
public void keyTyped(KeyEvent ovent)
{
}
}
If a key being pressed down is a trigger to update you GUI, that's when you need to incorperate SwingTimers. If it's not triggering an update to your GUI, you can just use normal threads.
What I assume the articles are referring to is
KeyListener
Here's a sample of how you could incorporate that into your KeyListener
:
public class Keyer implements KeyListener{
/** Stores currently pressed keys */
HashSet<Integer> pressedKeys = new HashSet<Integer>();
public Keyer(){
//Check every 100ms if there's keys pressed
//(This is the Swing Timer they talk about)
new Timer(100, new ActionListener(){
@Override
public void actionPerformed(ActionEvent arg0) {
String keysString = "";
if(!pressedKeys.isEmpty()){
Iterator<Integer> i = pressedKeys.iterator();
while(i.hasNext()){
keysString += i.next() + ",";
}
}
System.out.println(keysString);
}
}).start();
}
@Override
public void keyPressed(KeyEvent ovent){
//Add key to hashSet when pressed
int keyCode = ovent.getKeyCode();
pressedKeys.add(keyCode);
}
@Override
public void keyReleased(KeyEvent ovent){
//Remove key from hashset when released
int keyCode = ovent.getKeyCode();
pressedKeys.remove(keyCode);
}
@Override
public void keyTyped(KeyEvent ovent){}
}
Here's a sample where everything is put together - a label is updated telling you exactly what keys are pressed (by keycode).
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
public class TempProject extends JPanel{
/** Label to update with currently pressed keys */
JLabel output = new JLabel();
public TempProject(){
super();
setFocusable(true);
add(output, BorderLayout.CENTER);
requestFocus();
addKeyListener(new Keyer());
}
public static void main(String args[])
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.setContentPane(new TempProject());
frame.pack();
frame.setVisible(true);
new TempProject();
}
});
}
public class Keyer implements KeyListener{
/** Stores currently pressed keys */
HashSet<Integer> pressedKeys = new HashSet<Integer>();
public Keyer(){
//Check every 100ms if there's keys pressed
//(This is the Swing Timer they talk about)
new Timer(100, new ActionListener(){
@Override
public void actionPerformed(ActionEvent arg0) {
String keysString = "";
if(!pressedKeys.isEmpty()){
Iterator<Integer> i = pressedKeys.iterator();
while(i.hasNext()){
keysString += i.next() + ",";
}
}
output.setText(keysString);
}
}).start();
}
@Override
public void keyPressed(KeyEvent ovent){
//Add key to hashSet when pressed
int keyCode = ovent.getKeyCode();
pressedKeys.add(keyCode);
}
@Override
public void keyReleased(KeyEvent ovent){
//Remove key from hashset when released
int keyCode = ovent.getKeyCode();
pressedKeys.remove(keyCode);
}
@Override
public void keyTyped(KeyEvent ovent){}
}
}
Edit
Also, please see warnings posted by @HovercraftFullOfEels about KeyListener
. Depending on what you're trying to accomplish, you may want to look into using Key Bindings (same principle as this post applies). Here's a useful tutorial on Key Bindings if you'd like to take a look.
I think that this is not a Java issue but rather an OS issue -- the OS delays in sending key strokes for a set period of time before sending a stream of key strokes. A solution is to start a Swing Timer on key press. I would also recommend that you use Key Bindings rather than a KeyListener.
Also you state that you are "in the dark" about Swing Timers, and if so, I urge you to do what the rest of us have done when in this situation: check the related tutorial. Google will help you find it quite quickly. Also a search of this site will help you find examples of using key bindings with a Swing Timer, for example, have a look here.
Edit
KeyListener is a low-level construct, and in general you should prefer to use higher-level constructs as they are safer and easier to use without causing side effects or having problems. For instance, it is easy to run into problems with focus issues if you use a KeyListener since it only works if the component listened to has the focus. This is easily circumvented if you used key bindings instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With