1. jintellitype
-
pom
xml<!-- 不能注册多个组合键比如alt+abc --> <!-- https://mvnrepository.com/artifact/com.melloware/jintellitype --> <dependency> <groupId>com.melloware</groupId> <artifactId>jintellitype</artifactId> <version>1.4.1</version> </dependency>
-
代码
javapackage com.hotkey.app; import cn.hutool.core.date.DateUtil; import com.melloware.jintellitype.JIntellitype; public class IntelApplication { public static void main(String[] args) { // 添加全局热键 JIntellitype instance = JIntellitype.getInstance(); instance.registerHotKey(0, JIntellitype.MOD_ALT + JIntellitype.MOD_SHIFT, 'B'); instance.registerHotKey(2, 20, 'B'); instance.registerHotKey(1, "CTRL+SHIFT+X+V"); instance.registerHotKey(3, "CTRL+SHIFT+ALT+WIN+DELETE+B"); // 添加热键监听器 instance.addHotKeyListener(hotkey -> { System.out.println(DateUtil.now() + " Hotkey pressed: " + hotkey); // 在这里处理你的逻辑 }); } }
-
缺点: 对于ctrl a b 按ctrl b也可以触发
2. jkeymaster
-
pom
xml<!-- https://mvnrepository.com/artifact/com.github.tulskiy/jkeymaster --> <dependency> <groupId>com.github.tulskiy</groupId> <artifactId>jkeymaster</artifactId> <version>1.3</version> </dependency> <!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna --> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.12.1</version> </dependency>
-
代码
javaimport com.tulskiy.keymaster.common.Provider; import javax.swing.*; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; public class KeyApplication { public static void main(String[] args) { Provider provider = Provider.getCurrentProvider(true); provider.register( KeyStroke.getKeyStroke(KeyEvent.CTRL_MASK, InputEvent.ALT_MASK), x -> System.err.println(x)); } }
-
缺点: 对于+ = [ ]特殊按键识别不到; 不能注册类似ctrl a b会报错
3. jnativehook(推荐)
-
pom
xml<!-- https://mvnrepository.com/artifact/com.1stleg/jnativehook --> <dependency> <groupId>com.1stleg</groupId> <artifactId>jnativehook</artifactId> <version>2.1.0</version> </dependency>
-
代码
javaimport cn.hutool.core.collection.CollUtil; import org.jnativehook.GlobalScreen; import org.jnativehook.NativeHookException; import org.jnativehook.keyboard.NativeKeyEvent; import org.jnativehook.keyboard.NativeKeyListener; import javax.swing.*; import java.awt.*; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; /** * 监听键盘和鼠标按键, 这个是强制顺序和不支持重复的 * 如果要支持重复就得使用List保存快捷键, 并给每个编键去配置标志位, 或者快捷键数组使用对象数组 * 如果要不要求顺序, 就按下时候直接标志位变成true即可 * * @author codor * @date 2023/12/08 16:23 * @see org.jnativehook.example.NativeHookDemo */ public class NativeApplication extends JFrame implements NativeKeyListener { // ----------------------------------------------------------------------------------------------------------------- 逻辑使用 /** * 快捷键组合 * 名字也可以不写上去, 使用NativeKeyEvent.getKeyText(event.getKeyCode())获取 */ private Map<Integer, String> hotKeys; /** * 键编码的列表, 因为要保证顺序 */ private List<Integer> codes; /** * 快捷键是否按下标标志位 */ private Map<Integer, Boolean> flags; /** * 窗口是否展示出来了 */ private boolean isWindowShow = false; // ---------------------------------------------------------------------------------------------------------------- 界面使用 /** * 倒计时 */ private Timer countdownTimer; /** * 倒计时事件 */ private final static Integer COUNT_DOWN_SECONDS = 10; /** * 初始化标志位 * * @see org.jnativehook.keyboard.NativeKeyEvent */ public void initHotKeys() { this.hotKeys = new LinkedHashMap<>(); this.hotKeys.put(29, "Ctrl"); this.hotKeys.put(46, "C"); this.hotKeys.put(45, "X"); this.hotKeys.put(47, "V"); // 初始化键编码 this.codes = new ArrayList<>(); this.hotKeys.forEach((k, v) -> this.codes.add(k)); // 初始化标指位 this.initFlags(); } /** * 初始化标志位 */ public void initFlags() { if (this.hotKeys == null) { this.initHotKeys(); } this.flags = new HashMap<>(); for (Integer code : this.codes) { this.flags.put(code, false); } } /** * 按下键时候, 强制要求顺序 * * @param code 键编码 * @return 是否全部按下了, true是, 反之false */ public boolean pressedKey(int code) { // 如果未在内, 重置标志位 if (!this.codes.contains(code)) { this.initFlags(); return false; } for (Integer k : this.codes) { // 循环到 第一个非按下状态的就跳出循环或退出方法 if (!this.flags.get(k)) { // 并且等于按下的键, 设置按下成功 if (k.equals(code)) { this.flags.put(code, true); break; } else { // 不是不等于按下的, 说明按了后面的, this.initFlags(); return false; } } } // 只有break时候到这里, 判断是否循环完, 也即code是否最后一个 return code == this.codes.get(this.codes.size() - 1); } /** * 松开键 */ public void releaseKey(int code) { this.flags.put(code, false); } public String getKeyTexts() { if (CollUtil.isEmpty(this.codes)) { return ""; } StringBuilder resB = new StringBuilder(" "); for (Integer code : this.codes) { resB.append(NativeKeyEvent.getKeyText(code)).append(" "); } return resB.toString(); } public void showWindow(String hotKeyTexts) { setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); setUndecorated(true); // 窗口无装饰, 但是标题也会干掉 setTitle("倒计时窗口"); setLayout(new BorderLayout()); JLabel countdownLabel = new JLabel("倒计时: " + COUNT_DOWN_SECONDS + " 秒", JLabel.CENTER); JButton cancelButton = new JButton("取消"); cancelButton.addActionListener(e -> { // 点击取消按钮时的处理 if (countdownTimer != null) { // 重置标志位 this.initFlags(); // 关闭窗口 this.closeWindow(); } }); add(countdownLabel, BorderLayout.CENTER); add(cancelButton, BorderLayout.SOUTH); setSize(300, 150); setLocationRelativeTo(null); // 将窗口置于屏幕中央 setVisible(true); AtomicInteger second = new AtomicInteger(COUNT_DOWN_SECONDS); countdownTimer = new Timer(1000, e -> { second.getAndDecrement(); if (second.get() >= 0) { countdownLabel.setText("倒计时: " + second.get() + " 秒"); } else { // 关闭窗口 this.closeWindow(); // 触发成功后发送指令 // 指令发送成功后重置标志位 this.initFlags(); } }); countdownTimer.start(); } public void closeWindow() { countdownTimer.stop(); dispose(); // 关闭窗口 setVisible(false); // 设置窗口不可见 getContentPane().removeAll(); // 移除所有组件 revalidate(); // 重新验证布局 repaint(); // 重绘窗口 // 关闭窗口时候重置 isWindowShow = false; } // ---------------------------------------------------------------------------------------------------------------- Override Method @Override public void nativeKeyTyped(NativeKeyEvent nativeKeyEvent) { } @Override public void nativeKeyPressed(NativeKeyEvent event) { boolean isHotKey = this.pressedKey(event.getKeyCode()); // 成功并且窗口未展示时候 if (isHotKey && !isWindowShow) { System.err.println("触发快捷组合键成功..."); // 窗口标志位设置成功 isWindowShow = true; this.showWindow(this.getKeyTexts()); } } @Override public void nativeKeyReleased(NativeKeyEvent event) { this.releaseKey(event.getKeyCode()); } public static void main(String[] args) { try { // 设置日志级别,避免 JNativeHook 的日志输出 Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName()); logger.setLevel(Level.OFF); // 注册全局键盘事件 GlobalScreen.registerNativeHook(); } catch (NativeHookException ex) { ex.printStackTrace(); System.err.println("Failed to initialize native hook. Exiting."); System.exit(1); } // 添加 NativeKeyListener NativeApplication application = new NativeApplication(); application.initFlags(); GlobalScreen.addNativeKeyListener(application); } }