Java系统范围内的键盘快捷键

28

是否有任何方法或库可以在Java应用程序中获取系统范围(全局)的键盘快捷方式来执行操作?

7个回答

19

我是JIntellitype的作者,我可以告诉你,这必须在DLL中本地完成并从Java JNI调用,就像JIntellitype一样。这是一个未在JDK中实现的操作系统级钩子,因此必须使用类似于JIntellitype和jxGrabKey的库。据我所知,目前还没有人为OSX编写过一个。

JIntellitype在Github上是开放源代码的,如果想了解它的工作原理,请查看源代码


JNA 中是否有任何内置的功能可用? - Johnydep

15

我刚刚发现了https://github.com/kwhat/jnativehook

它似乎是跨平台的。

这里是他们用于监听按键的示例代码:

import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
import org.jnativehook.keyboard.NativeKeyEvent;
import org.jnativehook.keyboard.NativeKeyListener;

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

        if (e.getKeyCode() == NativeKeyEvent.VC_ESCAPE) {
            GlobalScreen.unregisterNativeHook();
        }
    }

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

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

    public static void main(String[] args) {
        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 GlobalKeyListenerExample());
    }
}

检查修饰符基于位掩码(我们所有人都应该知道但总是忘记的东西 :-P):
    boolean isAltPressed = (e.getModifiers() & NativeKeyEvent.ALT_MASK) != 0;
    boolean isShiftPressed = (e.getModifiers() & NativeKeyEvent.SHIFT_MASK) != 0;

你可以将这个与 KeyCode 结合起来:

if (e.getKeyCode() == NativeKeyEvent.VK_2 && isShiftPressed && isAltPressed){...}

这是从这里修改的示例。

您还应该修改默认的日志记录行为,否则它会在控制台上生成垃圾信息:

// Get the logger for "org.jnativehook" and set the level to warning.
Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
logger.setLevel(Level.WARNING);

// Don't forget to disable the parent handlers.
logger.setUseParentHandlers(false);

代码示例来自这里


我从2017年开始使用这个库,一段时间后,我意识到波浪键在整个系统中都被禁用了。我还观察到很少的硬件崩溃,当我停止使用这个库时,这些崩溃也停止了。这并不是一个明确的陈述,但我的个人结论是将应用程序的默认热键功能设置为可选,这样除非绝对必要,否则不会激活该库。现在我正准备使用https://github.com/melloware/jintellitype尝试同样的事情,让我们看看我能做到什么。 - Dreamspace President
1
@DreamspacePresident 我使用这个没有任何问题。我使用 "Escape" 键来将我的应用程序最小化(到系统托盘),并与 "Ctrl"、"Alt" 一起组合以再次打开它。其他按键是普通字符。但我从未更新库 - 仍在使用2.1.0版本(2.2.2是当前版本)。 - dermoritz

13

目前来看,没有适用于Linux和OSX的解决方案,但在Windows中可以使用此方法:

jintellitype

不幸的是,我并不知道其他平台是否有类似的解决方案,这也许是为什么java不会自带该功能的原因。

如果你发现了其他平台的解决方法,请在这里分享一下 :)

只是出于好奇,您是想要做些什么呢?


感谢您的回复。我想要这个功能,这样用户就可以从系统的任何地方带出一个弹出窗口。在Windows应用程序中,这是非常常见的事情,但我想要跨平台支持。 - fabiopedrosa
是的,我想我们必须等待。我听说在Linux和OSX中这很容易实现,我不知道为什么半路上的第三方已经编码了。当然,Sun不会支持它。 - OscarRyz
1
Jintellitype提到了JxGrabKey(http://sourceforge.net/projects/jxgrabkey/)项目,该项目为Linux提供了相同的功能。 - Domchi

2
对于 Windows,您需要一个键盘钩子 DLL。您可以从 Java 中初始化您的 DLL,这将导致它注册监听器。您将得到所需的内容。请查看 MSDN 以获取有关 DLL 钩子或键盘钩子的信息。其中之一应该可以帮助您设置。
对于 Linux,我认为这应该更容易,但我从未自己尝试过。

http://ubuntuforums.org/showthread.php?t=864566

Google的第一个搜索结果为“linux listen for global key presses”(不加引号),返回了我认为对于X11环境将会对您有所帮助的内容。
OSX可能只需使用接近这个解决方案的方法即可。 但最终,除非JNA可以毫无问题地完成此操作,否则您可能需要为每个平台都需要一个dll文件,那么最糟糕的情况就已经发生了。

2

更新:我不知道是否可以从JVM外部钩取事件。我认为Swing/AWT组件必须具有焦点才能正常工作。

您需要钩取Java AWT事件队列,以确保您可以获得全局(jvm范围内)按键。

使用

EventQueue ev = Toolkit.getSystemEventQueue();
// MyCustomEventQueue extends EventQueue and processes keyboard events in the dispatch
ev.push(new MyCustomEventQueue());

class MyEventQueue extends EventQueue
{
    protected void dispatchEvent(AWTEvent event)
    {
       // all AWTEvents can be indentified by type, KeyEvent, MouseEvent, etc
       // look for KeyEvents and match against you hotkeys / callbacks
    }
}

我认为有其他方法可以使用动作映射来完成全局按键。实际上,我已经使用了上述方法。


@basszero:关于你的更新,是的,这个Java应用程序必须具有焦点才能正常工作。 - OscarRyz

1

JDIC(Java桌面集成)可以帮助
https://jdic.dev.java.net/

对我来说似乎有点不维护。 我不确定。
如果有人知道更多,请报告!
我也非常感兴趣这个功能。


1

现在您可以使用JNA - 请参见https://github.com/tulskiy/jkeymaster

我已经在Windows 10笔记本电脑上轻松测试过,但我个人没有在其他平台上进行过测试 - 显然它也适用于MacOS和“基于X11的系统(理论上仅在某些Linux发行版和PCBSD上进行了测试)”。

设置不应该很困难 - 您需要slf4j才能使其运行。

您不需要构建jar文件。

例如,此代码有效地禁用了“f”键并记录了您按下它的事实。

import com.tulskiy.keymaster.common.Provider;
import com.tulskiy.keymaster.common.HotKeyListener;
import com.tulskiy.keymaster.common.HotKey;
import javax.swing.*;

// ...          

Provider provider = Provider.getCurrentProvider(false); 
    provider.register(KeyStroke.getKeyStroke("F"), new HotKeyListener() {
            public void onHotKey(HotKey hotKey) {
                System.out.println(hotKey);
            }
        });

我希望这能帮到某个人。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接