编程语言您现在的位置是:首页 > 博客日志 > 编程语言

java程序中注册设置全局系统级热键快捷键,支持Windows、Linux、Mac OSX

<a href='mailto:'>微wx笑</a>的头像微wx笑 2020-06-20编程语言 6 0关键字: Java  热键  快捷键  JNI  JNA  jintellitype  JKeyMaster  

使用Java编写GUI程序时,想注册设置全局系统级热键快捷键是一件相对困难的事情,多数人的解决方法是使用JNI,以及相关的项目如“jintellitype”,但这些要么非常复杂麻烦,要么就只支

使用Java编写GUI程序时,想注册设置全局系统级热键快捷键是一件相对困难的事情,多数人的解决方法是使用JNI,以及相关的项目如“jintellitype”,但这些要么非常复杂麻烦,要么就只支持Windows,而这就失去了Java跨平台的特性!本文将介绍一种基于JNA的方法,不仅支持Windows,而且还支持Linux(基于X11的系统)和Mac OSX。4kS无知

JNA vs JNI

JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问动态链接库中的函数。原来使用JNI,你必须手工用C写一个动态链接库,在C语言中映射Java的数据类型。JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现Java和C的数据类型映射。你不再需要编写C动态链接库。当然,这也意味着,使用JNA技术比使用JNI技术调用动态链接库会有些微的性能损失。可能速度会降低十几倍。不管怎么样,即使Jna调用C函数效率比jni低,但jna不用自己用c写一系列动态库等配置,用法比较简单,对于很多人来说也是一个福音。4kS无知

4kS无知

JNI的缺点:繁琐

我们知道,使用JNI调用.dll/.so共享类库是非常非常麻烦和痛苦的。4kS无知

如果有一个现有的.dll/.so文件,如果使用JNI技术调用,我们首先需要另外使用C语言写一个.dll/.so共享库,使用SUN规定的数据结构替代C语言的数据结构,调用已有的  dll/so中公布的函数。4kS无知

然后再在Java中载入这个适配器dll/so,再编写Java   native函数作为dll中函数的代理。4kS无知

经过2个繁琐的步骤才能在Java中调用本地代码。4kS无知

因此,很少有Java程序员愿意编写调用dll/.so库中的原生函数的java程序。这也使Java语言在客户端上乏善可陈。可以说JNI是Java的一大弱点!4kS无知

JNA优点:简单

JNA(Java Native Access )提供一组Java工具类用于在运行期动态访问系统本地库(native library:如Window的dll,Android的so)而不需要编写任何Native/JNI代码。开发人员只要在一个Java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射4kS无知

性能方面

参考“JNI与JNA性能比较”,在Java端进行循环调用1000*1000次,结果是 JNI 16ms  << JNA 2593ms!!!性能差距还蛮大的!!4kS无知

JKeyMaster

4kS无知

这是一个Java库,它提供单个接口来注册多个平台的全局热键:4kS无知

  • Windows4kS无知

  • 基于X11的系统(理论上仅在某些Linux发行版和PCBSD上进行了测试)4kS无知

  • Mac OSX4kS无知

Github:https://github.com/ivu4e/jkeymasterforked from tulskiy/jkeymaster4kS无知

构建JkeyMaster

需要 Java 1.6+ 和 Maven 用于构建4kS无知

//克隆代码到本地
git clone https://github.com/tulskiy/jkeymaster
//切换目录
cd jkeymaster/
//执行构建
mvn clean install
//一次可能不成功,再执行一次
mvn clean install

测试

构建成功,就可以运行项目自带的测试类进行测试了。4kS无知

//切换到构建输出目录4kS无知

cd core/target/4kS无知

//执行测试4kS无知

java -cp jkeymaster-1.3-SNAPSHOT.jar com.tulskiy.keymaster.AWTTest4kS无知

稍等一会儿,会弹出一个窗口,这时你按下想要测试的快捷键,窗口中就会显示出来,然后点击“Grab”按钮,热键就注册成功了。4kS无知

image.png4kS无知

将窗口最小化,再按下刚才的热键,就可以呼出窗口了,你会看到:
4kS无知

image.png4kS无知

在终端下也会看到输出:我的测试环境是 iMac4kS无知

$ java -cp jkeymaster-1.3-SNAPSHOT.jar com.tulskiy.keymaster.AWTTest
六月 20, 2020 5:25:15 下午 com.tulskiy.keymaster.osx.CarbonProvider$1 run
信息: Installing Event Handler
六月 20, 2020 5:26:00 下午 com.tulskiy.keymaster.osx.CarbonProvider resetAll
信息: Resetting hotkeys
六月 20, 2020 5:26:00 下午 com.tulskiy.keymaster.osx.CarbonProvider register
信息: Registered hotkey: shift ctrl pressed A
六月 20, 2020 5:27:50 下午 com.tulskiy.keymaster.osx.CarbonProvider$EventHandler callback
信息: Received event id: 1

引用

对于普通Java项目,把上面构建出来的Jar包引入就可以了。
4kS无知

步骤:项目属性》Java Build Path》Libraries》Add External JARs》选择jkeymaster项目下的core/target目录生成的Jar包4kS无知

image.png4kS无知

如果你的是Maven类型的项目,参考下面的。4kS无知

Maven

对于Maven类型的项目,可以省略构建的步骤,直接在pom.xml中添加依赖:4kS无知

4kS无知

Release 版本:4kS无知

<dependencies>
    <dependency>
        <groupId>com.github.tulskiy</groupId>
        <artifactId>jkeymaster</artifactId>
        <version>1.2</version>
    </dependency>
</dependencies>

Snapshot 版本:4kS无知

<dependencies>
    <dependency>
        <groupId>com.github.tulskiy</groupId>
        <artifactId>jkeymaster</artifactId>
        <version>1.3-SNAPSHOT</version>
    </dependency>
</dependencies>

<repositories>
    <repository>
        <id>snapshots-repo</id>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    </repository>
</repositories>

应用示例:

引用

import com.tulskiy.keymaster.common.HotKey;
import com.tulskiy.keymaster.common.HotKeyListener;
import com.tulskiy.keymaster.common.Provider;

注册热键

在项目启动初始化时,如:4kS无知

    private void initWindow(){
        //主类是Provider,获取当前平台(操作系统)的提供者
        //Provider provider = Provider.getCurrentProvider(useSwingEventQueue);
        Provider provider = Provider.getCurrentProvider(true);
        //注册热键,键值是以字符串的形式传递的
        provider.register(KeyStroke.getKeyStroke("control shift A"), new HotKeyListener() {
			@Override
			public void onHotKey(HotKey arg0) {
				doStart();//在这里编写热键响应代码
			}
		});
    }

销毁热键

在关闭时,如:4kS无知

    //处理关闭事件
    private void doClose(Component c){
        Provider provider = Provider.getCurrentProvider(true);
        provider.reset();
        provider.stop();
        System.gc();
    }

完整的示例的话,我近期在研究Java实现屏幕截图功能,后续会把完整代码上传到Github上。
4kS无知

小结

虽然JNA也是通过JNI的方式访问系统底层,但是JNA使用的JNI(.dll/.so)是JDK自带的,不需要我们考虑,也就不需要我们去解决不同平台(操作系统)的兼容性问题。如果用JNI方式的话,我们需要针对要支持的每一种操作系统写一个实现。JkeyMaster基于JNA来实现,也就解决了兼容性问题。既然使用 Java 来实现,就不应该丢失其一次编写,处处运行的特性,你们说是不是?不管你是什么类型的项目,也可以省略本地构建的步骤,Maven类型的添加依赖就可以了,普通项目下载到需要的Jar包,添加到依赖中也是可以的。4kS无知


4kS无知


4kS无知


4kS无知

本文由 微wx笑 创作,采用 署名-非商业性使用-相同方式共享 4.0 许可协议,转载请附上原文出处链接及本声明。
原文链接:https://www.ivu4e.cn/blog/lang/2020-06-20/483.html

很赞哦! () 有话说 ()