java程序中注册设置全局系统级热键快捷键,支持Windows、Linux、Mac OSX
微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。
JNA vs JNI
JNA是建立在JNI技术基础之上的一个Java类库,它使您可以方便地使用java直接访问动态链接库中的函数。原来使用JNI,你必须手工用C写一个动态链接库,在C语言中映射Java的数据类型。JNA中,它提供了一个动态的C语言编写的转发器,可以自动实现Java和C的数据类型映射。你不再需要编写C动态链接库。当然,这也意味着,使用JNA技术比使用JNI技术调用动态链接库会有些微的性能损失。可能速度会降低十几倍。不管怎么样,即使Jna调用C函数效率比jni低,但jna不用自己用c写一系列动态库等配置,用法比较简单,对于很多人来说也是一个福音。
JNI的缺点:繁琐
我们知道,使用JNI调用.dll/.so共享类库是非常非常麻烦和痛苦的。
如果有一个现有的.dll/.so文件,如果使用JNI技术调用,我们首先需要另外使用C语言写一个.dll/.so共享库,使用SUN规定的数据结构替代C语言的数据结构,调用已有的 dll/so中公布的函数。
然后再在Java中载入这个适配器dll/so,再编写Java native函数作为dll中函数的代理。
经过2个繁琐的步骤才能在Java中调用本地代码。
因此,很少有Java程序员愿意编写调用dll/.so库中的原生函数的java程序。这也使Java语言在客户端上乏善可陈。可以说JNI是Java的一大弱点!
JNA优点:简单
JNA(Java Native Access )提供一组Java工具类用于在运行期动态访问系统本地库(native library:如Window的dll,Android的so)而不需要编写任何Native/JNI代码。开发人员只要在一个Java接口中描述目标native library的函数与结构,JNA将自动实现Java接口到native function的映射
性能方面
参考“JNI与JNA性能比较”,在Java端进行循环调用1000*1000次,结果是 JNI 16ms << JNA 2593ms!!!性能差距还蛮大的!!
JKeyMaster
这是一个Java库,它提供单个接口来注册多个平台的全局热键:
Windows
基于X11的系统(理论上仅在某些Linux发行版和PCBSD上进行了测试)
Mac OSX
Github:https://github.com/ivu4e/jkeymaster,forked from tulskiy/jkeymaster
构建JkeyMaster
需要 Java 1.6+ 和 Maven 用于构建
//克隆代码到本地 git clone https://github.com/tulskiy/jkeymaster //切换目录 cd jkeymaster/ //执行构建 mvn clean install //一次可能不成功,再执行一次 mvn clean install
测试
构建成功,就可以运行项目自带的测试类进行测试了。
//切换到构建输出目录
cd core/target/
//执行测试
java -cp jkeymaster-1.3-SNAPSHOT.jar com.tulskiy.keymaster.AWTTest
稍等一会儿,会弹出一个窗口,这时你按下想要测试的快捷键,窗口中就会显示出来,然后点击“Grab”按钮,热键就注册成功了。
将窗口最小化,再按下刚才的热键,就可以呼出窗口了,你会看到:
在终端下也会看到输出:我的测试环境是 iMac
$ 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包引入就可以了。
步骤:项目属性》Java Build Path》Libraries》Add External JARs》选择jkeymaster项目下的core/target目录生成的Jar包
如果你的是Maven类型的项目,参考下面的。
Maven
对于Maven类型的项目,可以省略构建的步骤,直接在pom.xml中添加依赖:
Release 版本:
<dependencies> <dependency> <groupId>com.github.tulskiy</groupId> <artifactId>jkeymaster</artifactId> <version>1.2</version> </dependency> </dependencies>
Snapshot 版本:
<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;
注册热键
在项目启动初始化时,如:
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();//在这里编写热键响应代码 } }); }
销毁热键
在关闭时,如:
//处理关闭事件 private void doClose(Component c){ Provider provider = Provider.getCurrentProvider(true); provider.reset(); provider.stop(); System.gc(); }
完整的示例的话,我近期在研究Java实现屏幕截图功能,后续会把完整代码上传到Github上。
小结
虽然JNA也是通过JNI的方式访问系统底层,但是JNA使用的JNI(.dll/.so)是JDK自带的,不需要我们考虑,也就不需要我们去解决不同平台(操作系统)的兼容性问题。如果用JNI方式的话,我们需要针对要支持的每一种操作系统写一个实现。JkeyMaster基于JNA来实现,也就解决了兼容性问题。既然使用 Java 来实现,就不应该丢失其一次编写,处处运行的特性,你们说是不是?不管你是什么类型的项目,也可以省略本地构建的步骤,Maven类型的添加依赖就可以了,普通项目下载到需要的Jar包,添加到依赖中也是可以的。
本文由 微wx笑 创作,采用 署名-非商业性使用-相同方式共享 4.0 许可协议,转载请附上原文出处链接及本声明。
原文链接:https://www.ivu4e.cn/blog/lang/2020-06-20/483.html