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

基于Java实现Windows进程监听与自动按键组合发送的技术求助

Hey there! 既然你已经搞定了进程监测的部分,那咱们直接聚焦在Windows下Java模拟按键组合这个核心需求上。下面给你两种可行的方案,从简单到精准,你可以根据需求选择:

方案1:用Java自带的java.awt.Robot快速实现

Java标准库的Robot类是最省事的选择,适合不需要精准定位到特定窗口的场景(比如只要全局发送按键)。它能模拟键盘的按下/释放动作,实现组合键非常直观。

代码示例(发送CTRL+F1)

import java.awt.AWTException;
import java.awt.Robot;
import java.awt.event.KeyEvent;

public class KeySender {
    public static void sendCtrlF1() throws AWTException {
        Robot robot = new Robot();
        
        // 按下Ctrl键
        robot.keyPress(KeyEvent.VK_CONTROL);
        // 按下并释放F1键
        robot.keyPress(KeyEvent.VK_F1);
        robot.keyRelease(KeyEvent.VK_F1);
        // 松开Ctrl键
        robot.keyRelease(KeyEvent.VK_CONTROL);
        
        // 可选:添加短暂延迟,确保按键序列被系统正确识别
        robot.delay(100);
    }

    public static void main(String[] args) {
        try {
            sendCtrlF1();
        } catch (AWTException e) {
            e.printStackTrace();
        }
    }
}

注意点

  • Robot类依赖AWT环境,所以如果你的程序是控制台应用,可能需要确保AWT线程正常初始化。
  • 它发送的按键会作用于当前拥有焦点的窗口,如果需要把按键精准发送到目标进程的窗口,这个方案就不够用了,得看下面的方案。

方案2:用JNA调用Windows API(精准发送到目标进程窗口)

如果需要确保按键只发送给你监测到的目标进程窗口,就得借助Windows原生API。JNA(Java Native Access)可以让你直接在Java代码里调用Windows的user32.dll,不用写C/C++的JNI代码,非常方便。

步骤1:引入JNA依赖

如果用Maven,在pom.xml里添加:

<dependencies>
    <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>
</dependencies>

步骤2:实现按键发送到目标窗口

核心思路是:先找到目标进程对应的窗口句柄,把窗口切换到前台,再用SendInput模拟按键(或者用SendMessage直接给窗口发消息)。

import com.sun.jna.Native;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef;
import com.sun.jna.platform.win32.WinUser;

public class TargetWindowKeySender {

    public static void sendCtrlF1ToWindow(WinDef.HWND hwnd) {
        User32 user32 = User32.INSTANCE;
        
        // 把目标窗口切换到前台(确保按键能发送过去)
        user32.SetForegroundWindow(hwnd);
        // 短暂延迟,等待窗口激活
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 构造CTRL+F1的按键序列:按下Ctrl → 按下F1 → 释放F1 → 释放Ctrl
        WinUser.INPUT ctrlDown = new WinUser.INPUT();
        ctrlDown.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD);
        ctrlDown.input.setKeyboard(new WinUser.KEYBDINPUT());
        ctrlDown.input.keyboard.wVk = new WinDef.WORD(WinUser.VK_CONTROL);

        WinUser.INPUT f1Down = new WinUser.INPUT();
        f1Down.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD);
        f1Down.input.setKeyboard(new WinUser.KEYBDINPUT());
        f1Down.input.keyboard.wVk = new WinDef.WORD(WinUser.VK_F1);

        WinUser.INPUT f1Up = new WinUser.INPUT();
        f1Up.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD);
        f1Up.input.setKeyboard(new WinUser.KEYBDINPUT());
        f1Up.input.keyboard.wVk = new WinDef.WORD(WinUser.VK_F1);
        f1Up.input.keyboard.dwFlags = new WinDef.DWORD(WinUser.KEYBDINPUT.KEYEVENTF_KEYUP);

        WinUser.INPUT ctrlUp = new WinUser.INPUT();
        ctrlUp.type = new WinDef.DWORD(WinUser.INPUT.INPUT_KEYBOARD);
        ctrlUp.input.setKeyboard(new WinUser.KEYBDINPUT());
        ctrlUp.input.keyboard.wVk = new WinDef.WORD(WinUser.VK_CONTROL);
        ctrlUp.input.keyboard.dwFlags = new WinDef.DWORD(WinUser.KEYBDINPUT.KEYEVENTF_KEYUP);

        WinUser.INPUT[] sequence = {ctrlDown, f1Down, f1Up, ctrlUp};
        user32.SendInput(new WinDef.DWORD(sequence.length), sequence, sequence[0].size());
    }

    // 根据窗口标题找句柄(你也可以结合进程ID来查找,更精准)
    public static WinDef.HWND findWindowByTitle(String title) {
        return User32.INSTANCE.FindWindow(null, title);
    }

    public static void main(String[] args) {
        // 示例:找到标题为"Notepad"的记事本窗口,发送CTRL+F1
        WinDef.HWND notepadHwnd = findWindowByTitle("Notepad");
        if (notepadHwnd != null) {
            sendCtrlF1ToWindow(notepadHwnd);
        } else {
            System.out.println("目标窗口未找到");
        }
    }
}

关键说明

  • FindWindow可以根据窗口标题找句柄,如果你有目标进程的PID,也可以用EnumWindows遍历窗口,匹配对应的进程ID,这样更精准(避免同标题的多个窗口)。
  • SetForegroundWindow是必须的,因为Windows的按键输入默认会发送到前台窗口。
  • SendInput是Windows推荐的模拟输入的API,比旧的keybd_event更可靠。

总结

  • 如果你只需要全局发送按键,用Robot类最快,代码量少,不需要额外依赖。
  • 如果需要精准控制按键发送到目标进程窗口,JNA+Windows API是更可靠的选择。

内容的提问来源于stack exchange,提问作者Domenico Verde

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:51:27