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

如何模拟USB键盘向Windows 11发送按键指令?

USB键盘数据包重放问题解答

1. 如何将数据包发送至PC的USB集线器?

首先纠正一个关键误解:USB是主从架构,PC作为主机,键盘是从设备(向主机发送数据)。你不能直接从PC向USB集线器发送键盘数据包来模拟按键——Windows只接受USB从设备发送的HID输入报告,而非主机侧主动发送的数据包。

根据你使用的两个库,具体实现思路如下:

用pywinusb(Windows专用,更简单)

pywinusb针对Windows HID设备做了封装,无需直接操作USB集线器,核心是模拟HID键盘的输入报告:

  • 第一步:找到你抓包的真实键盘的VID(厂商ID)和PID(产品ID),或者提取它的HID报告描述符(Wireshark抓包中可找到)。Windows需要匹配报告描述符才会识别为合法键盘。
  • 第二步:通过pywinusb打开HID设备(或模拟设备),构造对应的按键输入报告并发送。

用pyusb(底层通用,需驱动)

pyusb更贴近USB协议底层,但Windows下需要额外配置:

  • 先安装libusb驱动(用Zadig工具将目标设备的驱动替换为libusb-win32)。
  • 你需要一个支持USB HID模拟的硬件(比如Arduino Leonardo,它自带USB HID模拟功能),因为纯软件无法在Windows上模拟USB从设备(Windows USB栈要求硬件存在)。
  • 枚举设备、找到对应的中断端点,然后向端点发送HID输入报告。

2. 待发送数据包的结构:需要剔除哪些字节?

Wireshark捕获的USB数据包包含USB总线协议层字节(比如令牌包、URB头、地址/端点标识等),这些都要剔除,只保留HID输入报告的有效载荷。

标准键盘HID报告结构

普通USB键盘的输入报告通常是6-8字节,格式如下:

  • 第1字节:修饰键位(比如Ctrl=0x01、Shift=0x02,无修饰键则为0x00)
  • 第2字节:保留位(固定为0x00)
  • 第3-8字节:按键扫描码(按下某键时填入对应扫描码,松开时填0x00)

示例:

  • 按下W键的报告(6字节):[0x00, 0x00, 0x1A, 0x00, 0x00, 0x00](W的扫描码是0x1A)
  • 松开W键的报告:[0x00, 0x00, 0x00, 0x00, 0x00, 0x00]

从Wireshark抓包提取有效数据

在Wireshark中找到标记为URB_INTERRUPT in的数据包(键盘向PC发送的中断包),展开Urb -> Data字段,里面的字节就是你需要的HID输入报告,直接提取这部分即可,无需添加其他字节。


关键注意事项

  • 必须匹配目标键盘的HID报告描述符:不同键盘的报告长度、格式可能有差异(比如带多媒体键的键盘报告更长),如果报告格式不匹配,Windows无法正确识别按键。
  • 模拟按键需要成对发送:按下报告后必须发送松开报告,否则系统会认为按键一直被按住。
  • 纯软件模拟限制:Windows不允许主机侧程序直接模拟USB从设备,必须借助支持HID模拟的硬件(如Arduino、USB HID模拟模块)。

代码示例

pywinusb示例(模拟W键按下松开)

import pywinusb.hid as hid

def simulate_key_press(vid, pid, scan_code):
    # 筛选目标HID设备(替换为你抓包的键盘VID/PID)
    devices = hid.HidDeviceFilter(vendor_id=vid, product_id=pid).get_devices()
    if not devices:
        print("未找到目标设备")
        return
    
    device = devices[0]
    device.open()
    
    # 构造按下W的报告(以8字节标准报告为例)
    press_report = [0x00, 0x00, scan_code, 0x00, 0x00, 0x00, 0x00, 0x00]
    device.send_input_report(press_report)
    
    # 构造松开报告
    release_report = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
    device.send_input_report(release_report)
    
    device.close()

# 替换为你的键盘VID、PID,W键扫描码0x1A
simulate_key_press(0xXXXX, 0xXXXX, 0x1A)

pyusb示例(基于Arduino Leonardo模拟)

import usb.core
import usb.util

# Arduino Leonardo的VID/PID
VID = 0x2341
PID = 0x8036

def send_key_report(scan_code):
    dev = usb.core.find(idVendor=VID, idProduct=PID)
    if not dev:
        raise ValueError("未找到Arduino设备")
    
    # 配置设备
    dev.set_configuration()
    cfg = dev.get_active_configuration()
    intf = cfg[(0, 0)]
    
    # 找到中断输出端点(向PC发送数据的端点)
    ep = usb.util.find_descriptor(
        intf,
        custom_match=lambda e: usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT
    )
    
    # 发送按下报告
    ep.write([0x00, 0x00, scan_code, 0x00, 0x00, 0x00])
    # 发送松开报告
    ep.write([0x00, 0x00, 0x00, 0x00, 0x00, 0x00])

# 模拟W键按下松开
send_key_report(0x1A)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:51:37