Using Java Robot to hold down a key

advertisements

Currently i'm trying to have java hold down a key like follows:

Robot rob;

rob.keyPress(KeyEvent.VK_ENTER);
Thread.sleep(3000);
rob.keyRelease(KeyEvent.VK_ENTER);

This should hold enter down for 3 seconds, causing the repeating effect after a second or so. In other words, if you were to manually hold the "r" key, it would first type r, and then after about a second it would go like rrrrrrrr. I want this effect from the robot. I also tried:

curTime = System.currentTimeMillis();

while(System.currentTimeMillis() - curTime < duration)
{
rob.keyPress(whatever);
}
rob.keyRelease(whatever);

This, however, is extremely sensitive and a duration of 1 second outputs... well, as many whatever's as your computer can in 1 second. Thousands of lines worth. This is not my intention. Any ideas? Thanks!

P.S. The reason I want this behavior is because im writing a little scripting language to automate games with. If I want to hold the up arrow key like a normal person, I think that I need the behavior i'm talking about.

Edit:

Since there seems to be some confusion, I appologize. Let me elaborate. In my first code peice, if I choose "r" to be the character, it will just print ONE r regardless of the duration. If you, on your keyboard, press "r" for 5 seconds, it will go -> r...rrrrrrrrrrrrrrr where ... means like a second of time. That is the behavior I want, but I wont get it. The second code is where I try to spam click "press", but this literally types "r" EVERY time it executes. So if I am in a timed loop for a duration, every time that loop iterates it will send the "r" button. That's not what I want. What I want, again , is the same result that would happen as if you pushed r down on your keyboard for 3 seconds. First its just one r, and then rrrrrrrrrrrrrrrrrrrrr. I'm not even sure what the release() method does... I figured if you left it on press without release, it would just SPAM the screen in a loop! Why wouldnt it, the key is PRESSED? This is what is confusing me. Apparently when a key is pressed it doesnt STAY pressed.


If I understand your problem, you can't get key repeats to occur when using Robot and keyPress.

In this case, you may need to produce a "psudo" "long" key press.

Basically, I tried something like this:

Robot bot = new Robot();
bot.setAutoDelay(1);

int duration = 3000;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < duration) {
    bot.keyPress(KeyEvent.VK_R);
    bot.keyRelease(KeyEvent.VK_R);
}

Which, rapidly pressed and releases the key over a period of time...

And I used this to test it...

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestRobot {

    public static void main(String[] args) {
        new TestRobot();
    }

    public TestRobot() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JTextArea ta;

        public TestPane() {

            setLayout(new BorderLayout());
            ta = new JTextArea(20, 20);
            ta.setWrapStyleWord(true);
            ta.setLineWrap(true);
            add(new JScrollPane(ta));

            JButton btn = new JButton("Start");
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    ta.requestFocusInWindow();
                    ta.append("Start\n");
                    SwingWorker worker = new SwingWorker<Object, Object>() {
                        @Override
                        protected Object doInBackground() throws Exception {

                            Robot bot = new Robot();
                            bot.setAutoDelay(1);

                            int duration = 3000;
                            long start = System.currentTimeMillis();
                            while (System.currentTimeMillis() - start < duration) {
                                bot.keyPress(KeyEvent.VK_R);
                                bot.keyRelease(KeyEvent.VK_R);
                            }
                            return null;

                        }

                        @Override
                        protected void done() {
                            ta.append("\nDone");
                        }
                    };
                    worker.execute();
                }
            });
            add(btn, BorderLayout.SOUTH);

        }
    }
}

Updated

With a little testing, I was able to get this to work...

Robot bot = new Robot();
bot.setAutoDelay(50);

int duration = 3000;
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < duration) {
    bot.keyPress(KeyEvent.VK_R);
}
bot.keyRelease(KeyEvent.VK_R);

Now, if you play around with the autoDelay property, you can adjust the time (in milliseconds) between each event, which may produce a more desirable effect...