You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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ć

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 11:42:16