如何用JavaFX制作Windows锁屏?需屏蔽Win键与Alt+Tab组合键
解决JavaFX全屏窗口屏蔽Windows键与Alt+Tab的方案
问题分析
你当前的JavaFX代码仅能拦截应用内普通按键,但Windows键、Alt+Tab这类系统级快捷键由Windows系统优先处理,JavaFX的事件过滤器无法直接捕获拦截,必须借助Windows原生API实现全局键盘钩子,或是调整窗口属性让它成为系统顶层锁定窗口。
实现方案
方案1:使用JNA调用Windows API(推荐)
通过JNA(Java Native Access)直接调用Windows的user32.dll函数,注册全局键盘钩子拦截指定系统快捷键。
添加JNA依赖
在Maven/Gradle中引入依赖:<!-- Maven 依赖 --> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> <version>5.13.0</version> </dependency> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> <version>5.13.0</version> </dependency>编写全局键盘钩子类
创建类处理全局键盘事件:import com.sun.jna.platform.win32.*; import com.sun.jna.win32.W32APIOptions; public class GlobalKeyHook implements WinUser.LowLevelKeyboardProc { private WinUser.HHOOK hHook; private final WinUser.LowLevelKeyboardProc keyboardProc = this; public GlobalKeyHook() { hHook = User32.INSTANCE.SetWindowsHookEx(WinUser.WH_KEYBOARD_LL, keyboardProc, Kernel32.INSTANCE.GetModuleHandle(null), 0); } @Override public WinDef.LRESULT callback(int nCode, WinDef.WPARAM wParam, WinUser.KBDLLHOOKSTRUCT lParam) { if (nCode >= 0) { int keyCode = lParam.vkCode; // 拦截左右Windows键、Alt+Tab、Alt+Esc、Ctrl+Esc boolean isWinKey = keyCode == WinUser.VK_LWIN || keyCode == WinUser.VK_RWIN; boolean isAltTab = (User32.INSTANCE.GetAsyncKeyState(WinUser.VK_MENU) < 0) && keyCode == WinUser.VK_TAB; boolean isAltEsc = (User32.INSTANCE.GetAsyncKeyState(WinUser.VK_MENU) < 0) && keyCode == WinUser.VK_ESCAPE; boolean isCtrlEsc = (User32.INSTANCE.GetAsyncKeyState(WinUser.VK_CONTROL) < 0) && keyCode == WinUser.VK_ESCAPE; if (isWinKey || isAltTab || isAltEsc || isCtrlEsc) { // 拦截该按键事件 return new WinDef.LRESULT(1); } } return User32.INSTANCE.CallNextHookEx(hHook, nCode, wParam, lParam.getPointer()); } public void unhook() { if (hHook != null) { User32.INSTANCE.UnhookWindowsHookEx(hHook); hHook = null; } } }集成到JavaFX启动类
修改start方法,添加钩子初始化与销毁逻辑:private GlobalKeyHook keyHook; @Override public void start(Stage primaryStage) { try { // 初始化全局键盘钩子 keyHook = new GlobalKeyHook(); FXMLLoader loader = new FXMLLoader(); loader.setLocation(Main.class.getResource("/vista/PantallaBloqueo.fxml")); Pane ventana = (Pane) loader.load(); Scene escena = new Scene(ventana); primaryStage.setScene(escena); primaryStage.setFullScreen(true); primaryStage.setOnCloseRequest(e -> e.consume()); primaryStage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH); // 全局钩子已处理Alt相关按键,移除原有局部拦截 primaryStage.setAlwaysOnTop(true); primaryStage.show(); // 程序退出时销毁钩子 Runtime.getRuntime().addShutdownHook(new Thread(keyHook::unhook)); } catch (IOException error) { error.printStackTrace(); } } @Override public void stop() throws Exception { super.stop(); if (keyHook != null) { keyHook.unhook(); } }
方案2:设置窗口为系统顶层锁定样式(进阶)
若要实现类似Windows登录界面的彻底锁定效果,可调用Windows API调整窗口扩展样式:
// 在窗口显示后执行 Platform.runLater(() -> { Window window = primaryStage.getScene().getWindow(); HWND hwnd = new HWND(Native.getComponentPointer(window)); // 设置窗口为工具窗口+顶层窗口,移除任务栏显示 int exStyle = User32.INSTANCE.GetWindowLong(hwnd, User32.GWL_EXSTYLE); exStyle |= WinUser.WS_EX_TOOLWINDOW | WinUser.WS_EX_TOPMOST; exStyle &= ~WinUser.WS_EX_APPWINDOW; User32.INSTANCE.SetWindowLong(hwnd, User32.GWL_EXSTYLE, exStyle); });
注意事项
- 全局键盘钩子需要程序以管理员权限运行,否则无法正常拦截系统快捷键。
- 务必保留退出机制(如登录验证通过后调用
keyHook.unhook()并关闭窗口),避免出现无法操作系统的情况。 - 建议使用最新稳定版JNA,避免兼容性问题。
内容的提问来源于stack exchange,提问作者David Tzintzun Gonzalez
相关产品推荐
相关产品推荐

