keylister—在java中,无焦点地侦听输入

fivyi3re  于 2021-06-30  发布在  Java
关注(0)|答案(7)|浏览(379)

我正在使用robot类用java编写一个小程序。程序接管了鼠标。在调试过程中,如果它开始以我不希望的方式运行,很难退出程序,因为在eclipse中我不能将鼠标移到终止按钮上,并且我不能使用热键来点击它,因为鼠标在另一个窗口中不断地点击,而是给那个窗口焦点。
我想做的是连接一个keylister,这样当我按q时就可以退出程序,但我知道的唯一方法是创建一个窗口,这个窗口需要焦点来捕获输入。有没有一种方法可以从任何地方监听键盘或鼠标的输入,而不管什么东西有焦点?

l2osamch

l2osamch1#

让你的程序打开第二个窗口,它显示在你的主窗口下面,但是被最大化了,那么你的鼠标错误点击都会被最大化的窗口接收,它可以接收你的键盘输入。

ca1c2owp

ca1c2owp2#

这不是一个微不足道的问题,java并没有为您提供一种优雅的方法。您可以使用Banjolly建议的解决方案,但即使这样也不会一直有效,例如,如果您错误地单击鼠标打开当前在任务栏中打开的另一个完整窗口。
事实是,java默认情况下对操作系统的控制很少。这是由两个主要原因造成的:安全性(正如java文档中提到的)和不同操作系统处理事件的方式完全不同的事实,而让一个统一的模型来表示所有这些可能没有多大意义。
所以要回答你的问题,我想你想要的是你的程序的某种行为,它在全球范围内监听按键,而不仅仅是在你的应用程序中。像这样的事情需要您访问所选操作系统提供的功能,而要用java访问它,您需要通过java本机接口(jni)层来访问它。
所以你要做的是:
用c语言实现一个程序,在你的操作系统上监听全局按键,如果这个操作系统是windows,那么在windows钩子上查找文档,这些文档由microsoft和msdn在web和其他地方很好地记录。如果您的操作系统是linux或macosx,那么您将需要使用x11开发库监听全局按键。这可以在ubunutulinux发行版上根据我在上写的howto来完成http://ubuntuforums.org/showthread.php?t=864566
通过jni将c代码连接到java代码。这一步实际上是更简单的一步。按照我在上的教程中使用的步骤操作http://ubuntuforums.org/showthread.php?t=864566 在windows和linux下,将c代码连接到java代码的过程在两个操作系统上是相同的。
要记住的重要一点是,如果您首先编写和调试c/c++代码并确保它正常工作,那么让jni代码正常工作就容易多了。那么将它与java集成就很容易了。

afdcj2ne

afdcj2ne3#

(如@masterid所述,并在jnativehook的本机键盘输入检测文档{main github project here}中显示),
此代码应足以在没有应用程序焦点的情况下监听任何键(按下和/或释放):

记住在项目中添加jnativehook库,以便能够使用它的所有实用程序<<

public class yourClass implements NativeKeyListener {//<-- Remember to add the jnativehook library

public void nativeKeyPressed(NativeKeyEvent e) {
    System.out.println("Key Pressed: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
}

public void nativeKeyReleased(NativeKeyEvent e) {
        System.out.println("Key Released: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
}

public void nativeKeyTyped(NativeKeyEvent e) {
        System.out.println("Key Typed: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
}

public static void main(String args[]){
    //Just put this into your main:
    try {
        GlobalScreen.registerNativeHook();
    }
    catch (NativeHookException ex) {
        System.err.println("There was a problem registering the native hook.");
        System.err.println(ex.getMessage());
        System.exit(1);
    }

    GlobalScreen.addNativeKeyListener(new yourClass());
    //Remember to include this^                     ^- Your class
}
}

对于这个特殊的问题,使用nativekeypressed方法如下:

public void nativeKeyPressed(NativeKeyEvent e) {
    System.out.println("Key Pressed: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
    if (e.getKeyCode() == NativeKeyEvent.VC_Q){
        System.exit(1);
    }
}

请注意,jnativehook在默认情况下会在控制台中显示许多您可能不希望看到的内容,要更改这些内容,只需在您在main函数中使用的try-catch之前添加这些内容,如图所示(这还将关闭警告和错误消息,更多信息请参见此处):

//(From here)
Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
logger.setLevel(Level.OFF);
logger.setUseParentHandlers(false);
//(To there-^)
try {
    GlobalScreen.registerNativeHook();
}
catch (NativeHookException ex) {
    System.err.println("There was a problem registering the native hook.");
    System.err.println(ex.getMessage());
    System.exit(1);
}

免责声明:我知道这个问题在几年前就解决了,我只是希望有人觉得这个更容易找到/使用。

dhxwm5r4

dhxwm5r44#

有一个图书馆为您做着艰苦的工作:https://github.com/kwhat/jnativehook

hvvq6cgz

hvvq6cgz5#

这里有一个纯java的方法来解决您所描述的问题(不是keylistener问题。。。使用机器人问题时提前退出测试):
在整个测试过程中,将鼠标位置与测试最近设置的位置进行比较。如果不匹配,退出测试。注意:这个代码的重要部分是 testPosition 方法。下面是我最近使用的代码:

public void testSomething() throws Exception {
    try {
        // snip

        // you can even extract this into a method "clickAndTest" or something
        robot.mouseMove(x2, y2);
        click();
        testPosition(x2, y2);

        // snip
    } catch (ExitEarlyException e) {
        // handle early exit
    }
}

private static void click() throws InterruptedException {
    r.mousePress(InputEvent.BUTTON1_DOWN_MASK);
    Thread.sleep(30 + rand.nextInt(50));
    r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
    Thread.sleep(30 + rand.nextInt(50));
}

private static void testPosition(int x2, int y2) throws ExitEarlyException {
    Point p = MouseInfo.getPointerInfo().getLocation();
    if(p.x != x2 || p.y != y2) throw new ExitEarlyException();
}
ngynwnxp

ngynwnxp6#

我也有同样的问题。在我的例子中,机器人只是控制一个windows应用程序,这是最大化的。我把这些线放在驱动机器人的主回路的顶部:
color iconcentercolor=新颜色(255,0,0);//如果程序图标为红色
if(iconcentercolor.equals(robot.getpixelcolor(10,15)))抛出新的illegalstateexception(“robot没有与正确的应用程序交互。”);
要取消机器人,只需将tab键切换到另一个应用程序。适用于简单的单应用驱动机器人。

hjqgdpho

hjqgdpho7#

从终端中的命令行启动程序,并使用ctrl-c终止程序。

相关问题