【问题标题】:Using Java's Robot to hold a key down使用 Java 的机器人按住键
【发布时间】:2013-06-24 08:47:42
【问题描述】:

目前我正在尝试让 java 按住如下键:

Robot rob;

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

这应该按住 enter 3 秒钟,在一秒钟左右后产生重复效果。换句话说,如果您要手动按住“r”键,它会首先键入 r,然后大约一秒钟后它会变成 rrrrrrrr。我想要机器人的这种效果。我也试过了:

curTime = System.currentTimeMillis();

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

然而,这是非常敏感的,并且持续时间为 1 秒输出......好吧,你的计算机在 1 秒内可以输出多少。价值数千行。这不是我的本意。有任何想法吗?谢谢!

附:我想要这种行为的原因是因为我正在编写一个小脚本语言来自动化游戏。如果我想像正常人一样按住向上箭头键,我认为我需要我正在谈论的行为。

编辑:

由于似乎有些混乱,我很抱歉。让我详细说明。在我的第一个代码中,如果我选择“r”作为字符,无论持续时间如何,它都会打印一个 r。如果您在键盘上按“r” 5 秒钟,它将变为 -> r...rrrrrrrrrrrrrrrr 其中 ... 表示像一秒钟的时间。那是我想要的行为,但我不会得到它。第二个代码是我尝试垃圾邮件单击“按”的地方,但每次执行时都会输入“r”。所以如果我在一个定时循环中持续一段时间,每次循环迭代它都会发送“r”按钮。那不是我想要的。同样,我想要的结果与您在键盘上按下 r 3 秒时会发生相同的结果。首先它只有一个 r,然后是 rrrrrrrrrrrrrrrrrrrrrr。我什至不确定 release() 方法是做什么的......我想如果你在没有释放的情况下将它留在新闻中,它只会在循环中向屏幕发送垃圾邮件!为什么不呢,钥匙被按下了?这让我感到困惑。显然,当按下一个键时,它不会一直按下。

【问题讨论】:

  • 你没有告诉我们你的代码是什么或如何不工作的。
  • 我可以验证一下,您当前的代码是否产生重复字符?我的测试没有
  • @MadProgrammer:你是对的。问题是机器人没有keyDown() 方法。我想这可以通过 JNI 或 JNA 以依赖于平台的方式完成。
  • 我假设 keyPress() 是 keyDown(),因为有一个 keyRelease()。嗯
  • 我会推荐使用 AutoHotKey。这是一个选择吗?

标签: java awt awtrobot


【解决方案1】:

如果我了解您的问题,您在使用 RobotkeyPress 时不会出现重复键。

在这种情况下,您可能需要产生“psudo”“长”按键。

基本上,我尝试过这样的事情:

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);
}

在一段时间内快速按下并释放键...

我用这个来测试它...

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);

        }
    }
}

更新

通过一些测试,我能够让它工作......

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);

现在,如果您使用autoDelay 属性,您可以调整每个事件之间的时间(以毫秒为单位),这可能会产生更理想的效果...

【讨论】:

  • 是的,您更新的解决方案似乎与其他答案相似。也就是说,在每次按键之间设置延迟。因此,如果延迟为 50 毫秒,持续时间为 1000 毫秒,我们将看到 20 次按下。似乎没有直接的方法来模拟键盘保持而不实际创建“hacky”代码来实现效果。现在看来不得不进入游戏并使用“按住键”脚本命令的实现,看看哪个效果最好。感谢您的时间和回答,我很感激!
【解决方案2】:

为什么不使用for 循环?

for (int i = 0; i < 10; i++)
    rob.keyPress(whatever);

或者,模拟您想要的按住效果:

rob.keyPress(whatever);
Thread.sleep(500);
for (int i = 0; i < 10; i++) {
    rob.keyPress(whatever);
    Thread.sleep(10);
}

如果您想要更多“有机”行为,只需随机化迭代次数即可。

【讨论】:

  • 你的第二个代码块似乎正是它真正的工作方式......也就是说,“r”,然后是 1/2 秒,然后每 10 毫秒左右 rrrrrr。我想问题是它是如何从键盘发生的。如果我试图在游戏中按住“右箭头”,并且我将它按住在键盘上,我会得到一定的结果。如果我只是在一个while循环中发送垃圾邮件keyPress,它会产生相同的效果,还是我需要像你一样的小10毫秒缓冲区?我想我得尝试一下,但谢谢你的回答
  • @user2045279 这是你必须测试的东西。我不知道你试图控制的应用程序将如何同时处理这么多键盘事件。
  • 我在移动中尝试了 50 毫秒。它看起来就像我要在键盘上按下它一样。感谢您的方法,它似乎在延迟 50 毫秒时效果很好。
猜你喜欢
  • 2014-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-11
  • 2013-07-20
  • 2021-07-19
相关资源
最近更新 更多