Windows 虚拟鼠标驱动

Windows virtual mouse driver

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

总体思路是一个 KMDF 根枚举非筛选器驱动程序,它将能够将输出报告发送到鼠标和键盘驱动程序堆栈。

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

报告类型和数据包格式在 Microsoft 资源中几乎没有记录。没有关于我需要发送哪些数据和发送到哪个设备的信息,以便移动鼠标指针、模拟点击(使用鼠标或键盘)。

只有关于 HID 客户端、驱动程序等的一般信息。它们的文档通常引用 Windows 驱动程序示例 git 存储库,但该存储库不包含与我的任务接近的任何源代码。驱动开发的人很少,所以也没有教程

如果能提示我在哪里可以找到更多关于我的任务的信息,我将不胜感激。

HID 是 USB 定义的标准。所以微软没有定义格式。其实HID的用途很广,格式应该自己定义在HID报告描述符中。

HID 描述符在 Device Class Definition HID and HID Usage Tables 中定义。

在“设备 Class 定义 HID”的第 61 页中有一个鼠标示例,它正是您想要的。 Usage Page (Generic Desktop), Usage (Mouse), Collection (Application), Usage (Pointer), Collection (Physical), Report Count (3), Report Size (1), Usage Page (Buttons), Usage Minimum (1), Usage Maximum (3), Logical Minimum (0), Logical Maximum (1), Input (Data, Variable, Absolute), Report Count (1), Report Size (5), Input (Constant), Report Size (8), Report Count (2), Usage Page (Generic Desktop), Usage (X), Usage (Y), Logical Minimum (-127), Logical Maximum (127), Input (Data, Variable, Relative), End Collection, End Collection

Jks Liu 的 已经指出了正确的方向。现在模拟鼠标的最佳方法是模拟 USB HID 硬件。

如果您的虚拟鼠标数据来自您可以控制的硬件,您也可以跳过驱动程序部分并使您的硬件 HID 兼容。

如果我们谈论的是纯软件模拟,我认为您最好的选择是模拟将自身标识为 HID 设备的 USB 设备。关于创建您自己的 USB 设备仿真,MSDN article 非常棒。好的是他们使用 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 鼠标的示例。一些例子:

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

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. 键盘输出(我用来向我的驱动程序发送键盘输入的设备)