Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

Results 1 to 5 of 5

Thread: [KeyStroke] - How to avoid keyboard auto-repeat ?

  1. #1
    Junior Member
    Join Date
    Oct 2014
    Posts
    4
    Thanks
    1
    Thanked 0 Times in 0 Posts

    Default [KeyStroke] - How to avoid keyboard auto-repeat ?

    Hello everyone,

    To train, I wanted to make a small program to move a small rectangle by pressing the WASD keys.

    The program works, except that when I hold a key to move the rectangle, after a second, auto-repeat starts up, and the rectangle motion accelerates. I want to prevent automatic repeat to activate, so that the rectangle moves at a constant speed when I hold a key and stops when I released.

    Does anyone have a solution for this problem?

    Thank you in advance!


    Here is the ButtonMotion classe :

    import java.awt.event.ActionEvent;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import javax.swing.AbstractAction;
    import javax.swing.Action;
    import javax.swing.JButton;
    import javax.swing.KeyStroke;
     
    public class ButtonMotion extends JButton implements MouseListener{
        Animation an = new Animation();
        char a;
        boolean animated = false;
        private Thread t;
        private Action motion;
        private Action stop;
     
        public ButtonMotion(Animation an, char a){
            super("Up");
            this.an = an;
            this.a = a;
            this.addMouseListener(this);
            motion = new Motion();
            stop = new Stop();
            switch(a){  //The direction depends on the key
            case 'w' :
                an.getInputMap().put(KeyStroke.getKeyStroke(a), "MotionU");
                an.getActionMap().put("MotionU", motion);
                break;
            case 's' :
                an.getInputMap().put(KeyStroke.getKeyStroke(a), "MotionD");
                an.getActionMap().put("MotionD", motion);
                break;
            case 'a' :
                an.getInputMap().put(KeyStroke.getKeyStroke(a), "MotionL");
                an.getActionMap().put("MotionL", motion);
                break;
            case 'd' :
                an.getInputMap().put(KeyStroke.getKeyStroke(a), "MotionR");
                an.getActionMap().put("MotionR", motion);
                break;
        }
     
            switch(a){  //The motion is stopped when the key is released
                case 'w' :
                    an.getInputMap().put(KeyStroke.getKeyStroke(87,0,true), "StopU");
                    an.getActionMap().put("StopU", stop);
                    break;
                case 's' :
                    an.getInputMap().put(KeyStroke.getKeyStroke(83,0,true), "StopD");
                    an.getActionMap().put("StopD", stop);
                    break;
                case 'a' :
                    an.getInputMap().put(KeyStroke.getKeyStroke(65,0,true), "StopL");
                    an.getActionMap().put("StopL", stop);
                    break;
                case 'd' :
                    an.getInputMap().put(KeyStroke.getKeyStroke(68,0,true), "StopR");
                    an.getActionMap().put("StopR", stop);
                    break;
            }  
        }
     
        private void go(){
            while(animated){
                int y = an.getPosY();
                int x = an.getPosX();
     
                switch(a){
                case 'w' :
                    y--;   
                    break;
                case 's' :
                    y++;
                    break;
                case 'a' :
                    x--;
                    break;
                case 'd' :
                    x++;
                    break;
                }
     
                an.setPosY(y);
                an.setPosX(x);
                an.repaint();
                try {
                    Thread.sleep(8);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
     
        class PlayAnimation implements Runnable{
            public void run(){
                go();
            }
        }
     
        private class Motion extends AbstractAction
        {
            public void actionPerformed( ActionEvent tf )
            {
                animated = true;
                t = new Thread(new PlayAnimation());
                t.start();
                switch(a){
                case 'w' :
                    System.out.println("up");
                    break;
                case 's' :
                    System.out.println("down");
                    break;
                case 'a' :
                    System.out.println("left");
                    break;
                case 'd' :
                    System.out.println("right");
                    break;
                }
            }
        }
     
        private class Stop extends AbstractAction
        {
            public void actionPerformed( ActionEvent tf )
            {
                animated = false;
                System.out.println("Stop");
            }
        }
     
        public void mouseClicked(MouseEvent e) {}
     
        public void mouseEntered(MouseEvent e) {}
     
        public void mouseExited(MouseEvent e) {}
     
        public void mousePressed(MouseEvent e) {
            animated = true;
            t = new Thread(new PlayAnimation());
            t.start();
        }
     
        public void mouseReleased(MouseEvent e) {
            animated = false;
        }
    }

    Here is the animation classe :

    import java.awt.Color;
    import java.awt.Graphics;
    import javax.swing.JPanel;
     
    public class Animation extends JPanel{
        private int posX = 145;
        private int posY = 145;
     
        public void paintComponent(Graphics g){
            g.setColor(Color.white);
            g.fillRect(0,0,this.getWidth(), this.getHeight());
            g.setColor(Color.blue);
            g.fillRect(posX, posY, 20, 30);
        }
     
        public int getPosX() {
            return posX;
        }
     
        public void setPosX(int posX) {
            this.posX = posX;
        }
     
        public int getPosY() {
            return posY;
        }
     
        public void setPosY(int posY) {
            this.posY = posY;
        }  
    }

    Here is the Window class :

    import java.awt.BorderLayout;
    import java.awt.Color;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
     
    public class Window extends JFrame{
        private JPanel container = new JPanel();
        private Animation an = new Animation();
        private ButtonMotion left = new ButtonMotion(an, 'a');
        private ButtonMotion right = new ButtonMotion(an, 'd');
        private ButtonMotion up = new ButtonMotion(an, 'w');
        private ButtonMotion down = new ButtonMotion(an, 's');
     
        public Window(){
            this.setTitle("First project !");
            this.setSize(300,300);
            this.setDefaultCloseOperation(EXIT_ON_CLOSE);
            this.setLocationRelativeTo(null);
     
            container.setBackground(Color.white);
            container.setLayout(new BorderLayout());
            JPanel south = new JPanel();
            JPanel center = new JPanel();
            center.setLayout(new BorderLayout());
            center.add(up, BorderLayout.NORTH);
            center.add(down, BorderLayout.SOUTH);
            south.add(left);
            south.add(center);
            south.add(right);
            container.add(south, BorderLayout.SOUTH);
            container.add(an, BorderLayout.CENTER);
     
            this.setContentPane(container);
            this.setVisible(true);
        }
    }

    Here is the Test class :
    public class Test {
     
        public static void main(String[] args) {
            Window win = new Window();
        }
    }


  2. #2
    Forum VIP
    Join Date
    Jul 2010
    Posts
    1,676
    Thanks
    25
    Thanked 329 Times in 305 Posts

    Default Re: [KeyStroke] - How to avoid keyboard auto-repeat ?

    Some comments:
    1. You are moving the rectangle on a different thread -- good
    2. You have not synchronized shared variables between threads -- bad
    3. You have, in my opinion, made the program more complicated than it needs to be

    Let's look at what you want for the basic flow:
    1. You press a button, and a variable is set based on the button pressed
    2. The animation runs
    3. You press a button, and the animation is triggered to stop

    You have that flow down. However, you are triggering different threads every time a button is pressed. So if the mousePressed() method triggers again, a new thread is created (which is what you are seeing).
    What I would suggest instead is:
    1. Create a single PlayAnimation thread at startup, and place the thread in the wait state
    2. When a button is pressed, set the variables like you do now but then simply tell the thread to continue running
    3. When a button is released, do what you normally do, but this time just tell the thread to wait

    How is this different? If the mousePressed() method triggers a second time when the thread is already running, you would be telling the PlayAnimation thread to continue running. Since it is already running, it would ignore the request.
    NOTE TO NEW PEOPLE LOOKING FOR HELP ON FORUM:

    When asking for help, please follow these guidelines to receive better and more prompt help:
    1. Put your code in Java Tags. To do this, put [highlight=java] before your code and [/highlight] after your code.
    2. Give full details of errors and provide us with as much information about the situation as possible.
    3. Give us an example of what the output should look like when done correctly.

    Join the Airline Management Simulation Game to manage your own airline against other users in a virtual recreation of the United States Airline Industry. For more details, visit: http://airlinegame.orgfree.com/

  3. The Following 2 Users Say Thank You to aussiemcgr For This Useful Post:

    GregBrannon (October 8th, 2014), vdlmrc (October 8th, 2014)

  4. #3
    Junior Member
    Join Date
    Oct 2014
    Posts
    4
    Thanks
    1
    Thanked 0 Times in 0 Posts

    Default Re: [KeyStroke] - How to avoid keyboard auto-repeat ?

    Thank you for your answer. I'll work on that.

  5. #4
    Junior Member
    Join Date
    Oct 2014
    Posts
    4
    Thanks
    1
    Thanked 0 Times in 0 Posts

    Default Re: [KeyStroke] - How to avoid keyboard auto-repeat ?

    So I tried to use your strategy, by putting the PlayAnimation thread at startup and putting in the wait state. I really had hard time with this, I guess it has to do with the fact that I am a beginner, hehe.
    Well, you mentioned that the problem was that with the auto-repeat I trigger many thread. So I resolved this problem by putting a "if" condition in the Motion class. A boolean, "animated" is set to false at startup. The method go() can run only if the animated is true, which is the case when I press a key. In the new code I use a "if" condition : if animated is false, pressing a key will set animated to true and trigger a thread, if animated is already true, nothing happen. With this, if I hold a key, I can't lunch several thread as animated is true since I pressed the key (animated goes back to false only when I release the key).

    So now everythings works as I want. Thank you !


    import java.awt.event.ActionEvent;
    import java.awt.event.MouseEvent;
    import java.awt.event.MouseListener;
    import javax.swing.AbstractAction;
    import javax.swing.Action;
    import javax.swing.JButton;
    import javax.swing.KeyStroke;
     
    public class ButtonMotion extends JButton implements MouseListener{
        Animation an = new Animation();
        char a;
        boolean animated = false;
        private Thread t;
        private Action motion;
        private Action stop;
     
        public ButtonMotion(Animation an, char a){
            super("Up");
            this.an = an;
            this.a = a;
            this.addMouseListener(this);
            motion = new Motion();
            stop = new Stop();
            switch(a){  //The direction depends on the key
            case 'w' :
                an.getInputMap().put(KeyStroke.getKeyStroke(a), "MotionU");
                an.getActionMap().put("MotionU", motion);
                break;
            case 's' :
                an.getInputMap().put(KeyStroke.getKeyStroke(a), "MotionD");
                an.getActionMap().put("MotionD", motion);
                break;
            case 'a' :
                an.getInputMap().put(KeyStroke.getKeyStroke(a), "MotionL");
                an.getActionMap().put("MotionL", motion);
                break;
            case 'd' :
                an.getInputMap().put(KeyStroke.getKeyStroke(a), "MotionR");
                an.getActionMap().put("MotionR", motion);
                break;
        }
     
            switch(a){  //The motion is stopped when the key is released
                case 'w' :
                    an.getInputMap().put(KeyStroke.getKeyStroke(87,0,true), "StopU");
                    an.getActionMap().put("StopU", stop);
                    break;
                case 's' :
                    an.getInputMap().put(KeyStroke.getKeyStroke(83,0,true), "StopD");
                    an.getActionMap().put("StopD", stop);
                    break;
                case 'a' :
                    an.getInputMap().put(KeyStroke.getKeyStroke(65,0,true), "StopL");
                    an.getActionMap().put("StopL", stop);
                    break;
                case 'd' :
                    an.getInputMap().put(KeyStroke.getKeyStroke(68,0,true), "StopR");
                    an.getActionMap().put("StopR", stop);
                    break;
            }  
        }
     
        private void go(){
            while(animated){
                int y = an.getPosY();
                int x = an.getPosX();
     
                switch(a){
                case 'w' :
                    y--;   
                    break;
                case 's' :
                    y++;
                    break;
                case 'a' :
                    x--;
                    break;
                case 'd' :
                    x++;
                    break;
                }
     
                an.setPosY(y);
                an.setPosX(x);
                an.repaint();
                try {
                    Thread.sleep(8);
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }
            }
        }
     
        class PlayAnimation implements Runnable{
            public void run(){
                go();
            }
        }
     
        private class Motion extends AbstractAction
        {
            public void actionPerformed( ActionEvent tf )
            {
                if(!animated){
                    animated = true;
                    t = new Thread(new PlayAnimation());
                    t.start();
                    switch(a){
                    case 'w' :
                        System.out.println("up");
                        break;
                    case 's' :
                        System.out.println("down");
                        break;
                    case 'a' :
                        System.out.println("left");
                        break;
                    case 'd' :
                        System.out.println("right");
                        break;
                    }
                }
                else if(animated)
                    System.out.println("animated is already true !");
            }
        }
     
        private class Stop extends AbstractAction
        {
            public void actionPerformed( ActionEvent tf )
            {
                animated = false;
                System.out.println("Stop");
            }
        }
     
        public void mouseClicked(MouseEvent e) {}
     
        public void mouseEntered(MouseEvent e) {}
     
        public void mouseExited(MouseEvent e) {}
     
        public void mousePressed(MouseEvent e) {
            animated = true;
            t = new Thread(new PlayAnimation());
            t.start();
        }
     
        public void mouseReleased(MouseEvent e) {
            animated = false;
        }
    }

  6. #5
    Forum VIP
    Join Date
    Jul 2010
    Posts
    1,676
    Thanks
    25
    Thanked 329 Times in 305 Posts

    Default Re: [KeyStroke] - How to avoid keyboard auto-repeat ?

    For reference, my solution was suggesting something like this:
    public class ButtonMotion extends JButton implements MouseListener{
        ...
        volatile boolean animated = false;    // animated set to false by default, set volatile for multithreading safety
        private Thread t;
        ...
     
        public ButtonMotion(Animation an, char a){
            super("Up");
            t = new Thread(new PlayAnimation());    // Create New thread
            t.start();                              // Start thread, will put itself in wait because animated==false		
            ...
        }
     
        ...
     
        private void go(){
            while(true){        // Run forever
                if(animated) {  // If animated==true, do operation
                    int y = an.getPosY();
                    int x = an.getPosX();
     
                    ...
     
                    try {
                        Thread.sleep(8);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                } else {
                    t.wait();   // If animated!=true, set thread to wait
                }
            }
        }
     
        ...
     
        private class Motion extends AbstractAction
        {
            public void actionPerformed( ActionEvent tf )
            {
                if(!animated){
                    animated = true;
                    t.notify();    // Notify thread to wake it back up and run
                    switch(a){
                    case 'w' :
                        System.out.println("up");
                        break;
                    case 's' :
                        System.out.println("down");
                        break;
                    case 'a' :
                        System.out.println("left");
                        break;
                    case 'd' :
                        System.out.println("right");
                        break;
                    }
                }
                else if(animated)
                    System.out.println("animated is already true !");
            }
        }
     
        ...
     
        public void mousePressed(MouseEvent e) {
            animated = true;
            t.notify();    // Notify thread to wake it back up and run
        }
     
        ...
    }

    I haven't ran the code above, but I think it works properly. We are running the thread until the animation boolean is set to false. When the animation boolean is set to false, we are suspending the thread by putting it in the waiting state. The thread will stay there until it is woken up by a notify call. We wake up the thread when the mousePressed() method is called, or the actionPerformed() in the Motion class.
    NOTE TO NEW PEOPLE LOOKING FOR HELP ON FORUM:

    When asking for help, please follow these guidelines to receive better and more prompt help:
    1. Put your code in Java Tags. To do this, put [highlight=java] before your code and [/highlight] after your code.
    2. Give full details of errors and provide us with as much information about the situation as possible.
    3. Give us an example of what the output should look like when done correctly.

    Join the Airline Management Simulation Game to manage your own airline against other users in a virtual recreation of the United States Airline Industry. For more details, visit: http://airlinegame.orgfree.com/

Similar Threads

  1. Auto click and auto populate Data
    By jigarsarsenal in forum What's Wrong With My Code?
    Replies: 2
    Last Post: September 26th, 2014, 11:32 AM
  2. Simulate keystroke
    By java() in forum Java Theory & Questions
    Replies: 2
    Last Post: September 18th, 2014, 05:40 AM
  3. Java & Keystroke Dynamics
    By shrushtha212 in forum What's Wrong With My Code?
    Replies: 1
    Last Post: September 3rd, 2013, 02:15 AM
  4. Auto contrast and auto brightness
    By oxxxis in forum Java Theory & Questions
    Replies: 0
    Last Post: January 21st, 2010, 03:00 PM
  5. Simple program that detects my keystroke
    By chronoz13 in forum Java Theory & Questions
    Replies: 3
    Last Post: December 27th, 2009, 11:44 PM