JavaFX自定义虚拟键盘如何将按键事件转发给Windows外部程序
问题根因
JavaFX 内置的 KeyEvent 是UI框架内部的私有事件对象,仅在JavaFX自身的事件分发链路内传递,根本不会进入Windows系统的全局输入队列,外部程序(包括你的CNC原厂控制软件)完全无法感知这类事件,靠框架内手动派发事件的思路从原理上就无法实现跨程序输入。
实现方案
要模拟实体键盘的全局输入效果,必须调用操作系统层面的输入模拟接口,不能在JavaFX框架内部兜圈子,Windows平台下有两种成熟的落地方式:
方案1:集成JNativeHook快速实现
这个库封装了Windows全局输入的模拟/监听逻辑,不需要自己写JNI/JNA的原生调用,适配成本最低:
- 第一步:在项目中引入JNativeHook的依赖,选择和你设备上JRE架构(x86/x64)匹配的稳定版本即可。
- 第二步:替换原有内部派发事件的逻辑,调用库提供的全局事件投递方法,数字0按键的参考实现如下:
import org.jnativehook.GlobalScreen; import org.jnativehook.NativeHookException; import org.jnativehook.keyboard.NativeKeyEvent; import static org.jnativehook.GlobalScreen.postNativeEvent; import static org.jnativehook.keyboard.NativeKeyEvent.*; // 程序启动阶段初始化全局钩子,不要放在按钮点击回调里执行 static { try { GlobalScreen.registerNativeHook(); } catch (NativeHookException e) { e.printStackTrace(); } } @FXML void clickOnZero(TouchEvent event) { // 发送按键按下事件 NativeKeyEvent pressEvent = new NativeKeyEvent( NATIVE_KEY_PRESSED, VC_0, KEY_LOCATION_STANDARD ); postNativeEvent(pressEvent); // 必须发送按键释放事件,缺省这步多数程序会识别为按键长按 NativeKeyEvent releaseEvent = new NativeKeyEvent( NATIVE_KEY_RELEASED, VC_0, KEY_LOCATION_STANDARD ); postNativeEvent(releaseEvent); }
如果需要模拟Shift、Ctrl这类组合键,要先按下修饰键、再发送普通键事件,最后按逆序发送所有按键的释放事件即可。
方案2:JNA调用Windows原生API(稳定性最高)
如果不想引入第三方依赖,可以直接通过JNA调用Windows官方提供的SendInput接口实现输入模拟,这个接口是微软官方推荐的全局输入方案,兼容性最好,基本不会被工业软件拦截:
import com.sun.jna.platform.win32.User32; import com.sun.jna.platform.win32.WinUser.INPUT; import static com.sun.jna.platform.win32.WinUser.KEYEVENTF_KEYUP; import static com.sun.jna.platform.win32.WinUser.VK_0; @FXML void clickOnZero(TouchEvent event) { INPUT[] inputArr = new INPUT[2]; // 构造按键按下事件 inputArr[0] = new INPUT(); inputArr[0].type = INPUT.INPUT_KEYBOARD; inputArr[0].input.ki.wVk = VK_0; inputArr[0].input.ki.dwFlags = 0; // 构造按键释放事件 inputArr[1] = new INPUT(); inputArr[1].type = INPUT.INPUT_KEYBOARD; inputArr[1].input.ki.wVk = VK_0; inputArr[1].input.ki.dwFlags = KEYEVENTF_KEYUP; User32.INSTANCE.SendInput(inputArr.length, inputArr, inputArr[0].size()); }
CNC场景适配注意事项
- 焦点处理:点击JavaFX虚拟键盘按钮时,默认会把输入焦点抢到JavaFX窗口上,此时发送的全局按键会被JavaFX窗口接收,CNC程序无法响应。建议把JavaFX窗口设置为不获取焦点的工具窗口样式,或者每次发送按键前调用Windows API将焦点切回CNC控制程序窗口。
- 键码匹配:不要直接用JavaFX的
KeyCode枚举值对应系统键码,两者不是一一映射关系,要对照Windows虚拟键码表匹配原实体键盘的键值,尤其是CNC设备用到的自定义功能键。 - 事件完整性:必须成对发送按下、释放事件,多数工业控制软件对输入校验严格,缺失释放事件要么识别不到输入,要么会判定按键卡滞触发设备报警。
- 触摸适配:关闭JavaFX按钮的触摸点击延迟,避免快速操作时出现输入滞后,影响机床操作效率。
内容的提问来源于stack exchange,提问作者Armin Brkić
相关产品推荐
相关产品推荐

