Windows虚拟鼠标驱动程序

6

我正在开发一个KMDF虚拟鼠标驱动程序。

总体思路是创建一个KMDF根枚举的非过滤驱动程序,它能够向鼠标和键盘驱动程序堆栈发送输出报告。

我的驱动程序已经可以工作并向其他驱动程序堆栈发送请求,但没有结果。

关于报告类型和数据包格式,在Microsoft资源中几乎没有详细说明。没有信息说明我需要向哪个设备发送哪些数据以移动鼠标指针,模拟点击(无论是用鼠标还是键盘)。

只有关于HID客户端、驱动程序等方面的一般性说明。他们的文档通常引用Windows Driver Samples git存储库,但该存储库不包含任何与我的任务相关的源代码。由于从事驱动程序开发的人很少,因此也没有教程。

我希望您能给我指点一下,我在哪里可以找到有关我的任务更多的信息。

3个回答

4
Jks Liu的答案已经指出了正确方向。如今模拟鼠标的最佳方法是模拟USB HID硬件。
如果您的虚拟鼠标数据来自您可以控制的硬件,那么您也可以跳过驱动程序部分,使您的硬件符合HID规范。
如果我们正在谈论纯软件仿真,我认为您最好的选择是仿真一个将自身标识为HID设备的USB设备。有一篇很棒的MSDN文章介绍了如何创建自己的USB设备仿真。好处在于它们使用HID作为示例USB描述符。
const UCHAR g_UsbDeviceDescriptor[] = {
    // Device Descriptor
    0x12, // Descriptor Size
    0x01, // Device Descriptor Type
    0x00, 0x03, // USB 3.0
    0x00, // Device class
    0x00, // Device sub-class
    0x00, // Device protocol
    0x09, // Maxpacket size for EP0 : 2^9
    0x5E, 0x04, // Vendor ID
    0x39, 0x00, // Product ID 
    0x00, // LSB of firmware version
    0x03, // MSB of firmware version
    0x01, // Manufacture string index
    0x03, // Product string index
    0x00, // Serial number string index
    0x01 // Number of configurations
};

要知道需要发送哪些端点和HID数据,您可以阅读HID规范,但更容易的方法是查看现有的微控制器实现。许多微控制器品牌都有示例,说明如何使用其USB堆栈模拟USB HID鼠标。一些示例:

事实上,在Windows上,HID与USB是独立的。要使虚拟HID设备(鼠标)工作,只需响应相应的内部IOCTL即可。来自Microsoft的mshidkmdf.sys将有助于完成其余工作。 - Jks Liu

2
HID是USB定义的标准,因此Microsoft不定义其格式。实际上,HID非常灵活,应该由用户在HID报告描述符中定义格式。
HID描述符在设备类别定义HIDHID使用表中定义。
在“设备类定义HID”第61页中,有一个鼠标的示例,正是您所需要的。 使用页面(通用桌面), 使用(鼠标), 集合(应用程序), 使用(指针), 集合(物理), 报告计数(3), 报告大小(1), 使用页面(按钮), 使用最小值(1), 使用最大值(3), 逻辑最小值(0), 逻辑最大值(1), 输入(数据,变量,绝对值), 报告计数(1), 报告大小(5), 输入(常量), 报告大小(8), 报告计数(2), 使用页面(通用桌面), 使用(X), 使用(Y), 逻辑最小值(-127), 逻辑最大值(127), 输入(数据,变量,相对值), 结束集合, 结束集合

谢谢。我已经开发并测试了驱动程序(在MSDN上得到了一个提示)。你的答案最接近实际情况,所以奖励归你。 - hedgar2017

0

这是我工作驱动程序的报告描述符集。

HID_REPORT_DESCRIPTOR g_reportDescriptor[] = {
    0x05, 0x01,     // USAGE_PAGE (Generic Desktop)
    0x09, 0x02,     // USAGE (Mouse)
    0xA1, 0x01,     // COLLECTION (Application)
    0x85,               REPORT_ID_MOUSE_INPUT,
    0x09, 0x01,         // USAGE_PAGE (Pointer)
    0xA1, 0x00,         // COLLECTION (Physical)
    0x05, 0x09,             // USAGE_PAGE (Buttons)
    0x19, 0x01,             // USAGE_MINIMUM (1)
    0x29, 0x03,             // USAGE_MAXIMUM (3)
    0x15, 0x00,             // LOGICAL_MINIMUM (0)
    0x25, 0x01,             // LOGICAL_MAXIMUM (1)
    0x95, 0x03,             // REPORT_COUNT (3)
    0x75, 0x01,             // REPORT_SIZE (1)
    0x81, 0x02,             // INPUT (Data, Variable, Absolute)
    0x95, 0x01,             // REPORT_COUNT (1)
    0x75, 0x05,             // REPORT_SIZE (5)
    0x81, 0x01,             // INPUT (Constant)
    0x05, 0x01,             // USAGE_PAGE (Generic Desktop)
    0x09, 0x30,             // USAGE (X)
    0x09, 0x31,             // USAGE (Y)
    0x15, 0x81,             // LOGICAL_MINIMUM (-127)
    0x25, 0x7F,             // LOGICAL_MAXIMUM (127)
    0x75, 0x08,             // REPORT_SIZE (8)
    0x95, 0x02,             // REPORT_COUNT (2)
    0x81, 0x06,             // Input (Data, Variable, Relative)
    0xC0,               // END_COLLECTION
    0xC0,           // END_COLLECTION

    0x05, 0x01,     // USAGE_PAGE (Generic Desktop)
    0x09, 0x00,     // USAGE (Undefined)
    0xa1, 0x01,     // COLLECTION (Application)
    0x85,               REPORT_ID_MOUSE_OUTPUT,
    0x09, 0x00,         // USAGE (Undefined)
    0x15, 0x00,         // LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,   // LOGICAL_MAXIMUM (255)
    0x95, 0x03,         // REPORT_COUNT (3)
    0x75, 0x08,         // REPORT_SIZE (8)
    0x91, 0x02,         // OUTPUT (Data, Variable, Absolute)
    0xc0,           // END_COLLECTION

    0x05, 0x01,     // USAGE_PAGE (Generic Desktop)
    0x09, 0x06,     // USAGE (Keyboard)
    0xA1, 0x01,     // COLLECTION (Application)
    0x85,               REPORT_ID_KEYBOARD_INPUT,
    0x05, 0x07,         // USAGE_PAGE (Keyboard Key Codes)
    0x19, 0xE0,         // USAGE_MINIMUM (224)
    0x29, 0xE7,         // USAGE_MAXIMUM (231)
    0x15, 0x00,         // LOGICAL_MINIMUM (0)
    0x25, 0x01,         // LOGICAL_MAXIMUM (1)
    0x75, 0x01,         // REPORT_SIZE (1)
    0x95, 0x08,         // REPORT_COUNT (8)
    0x81, 0x02,         // INPUT (Data, Variable, Absolute)
    0x95, 0x01,         // REPORT_COUNT (1)
    0x75, 0x08,         // REPORT_SIZE (8)
    0x81, 0x01,         // INPUT (Constant)
    0x19, 0x00,         // USAGE_MINIMUM (0)
    0x29, 0x65,         // USAGE_MAXIMUM (101)
    0x15, 0x00,         // LOGICAL_MINIMUM (0)
    0x25, 0x65,         // LOGICAL_MAXIMUM (101)
    0x95, 0x06,         // REPORT_COUNT (6)
    0x75, 0x08,         // REPORT_SIZE (8)
    0x81, 0x00,         // INPUT (Data, Array, Absolute)
    0x05, 0x08,         // USAGE_PAGE (LEDs)
    0x19, 0x01,         // USAGE_MINIMUM (Num Lock)
    0x29, 0x05,         // USAGE_MAXIMUM (Kana)
    0x95, 0x05,         // REPORT_COUNT (5)
    0x75, 0x01,         // REPORT_SIZE (1)
    0x91, 0x02,         // OUTPUT (Data, Variable, Absolute)
    0x95, 0x01,         // REPORT_COUNT (1)
    0x75, 0x03,         // REPORT_SIZE (3)
    0x91, 0x01,         // OUTPUT (Constant)
    0xC0,           // END_COLLECTION

    0x05, 0x01,     // USAGE_PAGE (Generic Desktop)
    0x09, 0x00,     // USAGE (Undefined)
    0xa1, 0x01,     // COLLECTION (Application)
    0x85,               REPORT_ID_KEYBOARD_OUTPUT,
    0x09, 0x00,         // USAGE (Undefined)
    0x15, 0x00,         // LOGICAL_MINIMUM (0)
    0x26, 0xff, 0x00,   // LOGICAL_MAXIMUM (255)
    0x95, 0x08,         // REPORT_COUNT (8)
    0x75, 0x08,         // REPORT_SIZE (8)
    0x91, 0x02,         // OUTPUT (Data, Variable, Absolute)
    0xc0            // END_COLLECTION
};

它包括:

  1. 鼠标输入(向Windows鼠标堆栈发送数据的设备)
  2. 鼠标输出(我用来向我的驱动程序发送鼠标输入的设备)
  3. 键盘输入(向Windows键盘堆栈发送数据的设备)
  4. 键盘输出(我用来向我的驱动程序发送键盘输入的设备)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接