SDL3_API分类参考_HIDAPI (CategoryHIDAPI)

2026-3-6 / 0 评论 / 3 阅读

HIDAPI 子系统(CategoryHIDAPI)

SDL HIDAPI 功能的头文件封装模块,适配了 Alan Ott 开发的原生 HIDAPI 接口,其源代码遵循以下许可协议:

HIDAPI - 用于与 HID 设备通信的跨平台库

版权所有 2009,Alan Ott,Signal 11 Software。
保留所有权利。

只要源文件中的版权声明保持完整,任何人可出于任何原因使用本软件。

注:该许可协议与 SDL zlib 许可协议的第三条内容一致,不会为使用者增加任何新的约束条件。

若你希望使用不含此模块的 SDL 版本,可在编译时将 SDL_HIDAPI_DISABLED 定义为 1。例如在 iOS 或 tvOS 平台上,关闭该模块可避免依赖 CoreBluetooth 框架。


函数

  • SDL_hid_ble_scan:扫描蓝牙低功耗(BLE)HID 设备(指定扫描时长,发现可用的 BLE HID 设备)
  • SDL_hid_close:关闭已打开的 HID 设备句柄(释放设备资源,终止与设备的通信)
  • SDL_hid_device_change_count:获取 HID 设备变更计数(用于检测设备的插拔事件)
  • SDL_hid_enumerate:枚举系统中所有 HID 设备(按厂商ID/产品ID筛选,返回设备信息链表)
  • SDL_hid_exit:退出 HIDAPI 子系统(释放全局资源,与 SDL_hid_init 配对使用)
  • SDL_hid_free_enumeration:释放枚举 HID 设备时分配的内存(避免内存泄漏)
  • SDL_hid_get_device_info:获取已打开 HID 设备的详细信息(返回 SDL_hid_device_info 结构体)
  • SDL_hid_get_feature_report:从 HID 设备读取特征报告(用于获取设备配置/状态信息)
  • SDL_hid_get_indexed_string:读取 HID 设备的索引字符串(获取设备的自定义描述字符串)
  • SDL_hid_get_input_report:从 HID 设备读取输入报告(获取设备的实时输入数据)
  • SDL_hid_get_manufacturer_string:读取 HID 设备的厂商名称字符串
  • SDL_hid_get_product_string:读取 HID 设备的产品名称字符串
  • SDL_hid_get_properties:获取 HID 设备的属性集合(如支持的报告类型、传输速率等)
  • SDL_hid_get_report_descriptor:获取 HID 设备的报告描述符(解析设备的输入/输出报告格式)
  • SDL_hid_get_serial_number_string:读取 HID 设备的序列号字符串
  • SDL_hid_init:初始化 HIDAPI 子系统(必须先调用,否则无法使用其他 HIDAPI 函数)
  • SDL_hid_open:通过厂商ID和产品ID打开 HID 设备(支持指定设备序列号区分同型号设备)
  • SDL_hid_open_path:通过设备路径打开 HID 设备(更精准的设备定位方式)
  • SDL_hid_read:从 HID 设备读取数据(阻塞式读取,直到有数据可用)
  • SDL_hid_read_timeout:带超时的 HID 设备数据读取(指定超时时间,避免永久阻塞)
  • SDL_hid_send_feature_report:向 HID 设备发送特征报告(用于配置设备参数)
  • SDL_hid_set_nonblocking:设置 HID 设备的非阻塞模式(影响 read/write 操作的阻塞行为)
  • SDL_hid_write:向 HID 设备写入数据(发送输出报告,控制设备行为)

数据类型

  • SDL_hid_device:HID 设备句柄类型(标识已打开的 HID 设备,用于后续读写操作)

结构体

  • SDL_hid_device_info:HID 设备信息结构体(包含厂商ID、产品ID、设备路径、名称、总线类型等)

枚举

  • SDL_hid_bus_type:HID 设备总线类型枚举(如 USB、蓝牙、I2C、SPI 等)

  • (无)

FreeBASIC 示例代码

' 引入 SDL 相关声明(需确保 FreeBASIC 已链接 SDL3 库,且启用 HIDAPI)
#Include "SDL.bi"

' 定义常用常量(示例:通用 USB HID 设备的厂商/产品ID,可替换为实际设备值)
Const VENDOR_ID As UShort = &H1234    ' 厂商ID(示例值,需替换为实际设备ID)
Const PRODUCT_ID As UShort = &H5678   ' 产品ID(示例值,需替换为实际设备ID)
Const REPORT_SIZE As Integer = 64     ' HID 报告长度(根据设备协议调整)

' 枚举并打印所有 HID 设备信息
Sub EnumerateAndPrintHIDDevices()
    ' 枚举所有 HID 设备(vendor_id=0, product_id=0 表示枚举全部)
    Dim As SDL_hid_device_info Ptr devs = SDL_hid_enumerate(0, 0)
    If (devs = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_INPUT, "枚举 HID 设备失败:%s", SDL_GetError())
        Return
    End If

    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "==== 系统中所有 HID 设备 ====")

    ' 遍历设备链表
    Dim As SDL_hid_device_info Ptr dev = devs
    Dim As Integer devCount = 0
    While (dev <> NULL)
        devCount += 1

        ' 获取总线类型描述
        Dim As String busType = ""
        Select Case dev->bus_type
            Case SDL_HID_BUS_USB: busType = "USB"
            Case SDL_HID_BUS_BLUETOOTH: busType = "蓝牙(BLE)"
            Case SDL_HID_BUS_I2C: busType = "I2C"
            Case SDL_HID_BUS_SPI: busType = "SPI"
            Case Else: busType = "未知总线"
        End Select

        ' 打印设备信息
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "设备 %d:", devCount)
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "  厂商ID: 0x%04X", dev->vendor_id)
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "  产品ID: 0x%04X", dev->product_id)
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "  设备路径: %s", dev->path)
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "  厂商名称: %s", IIf(dev->manufacturer_string, dev->manufacturer_string, "未知"))
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "  产品名称: %s", IIf(dev->product_string, dev->product_string, "未知"))
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "  序列号: %s", IIf(dev->serial_number, dev->serial_number, "无"))
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "  总线类型: %s", busType)
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "------------------------")

        dev = dev->next
    Wend

    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "共发现 %d 个 HID 设备", devCount)

    ' 释放枚举内存
    SDL_hid_free_enumeration(devs)
End Sub

' 打开指定 HID 设备并测试读写
Function OpenAndTestHIDDevice(ByVal vendorID As UShort, ByVal productID As UShort) As Boolean
    ' 初始化 HIDAPI
    Dim As Integer initResult = SDL_hid_init()
    If (initResult < 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_INPUT, "初始化 HIDAPI 失败:%s", SDL_GetError())
        Return False
    End If

    ' 打开 HID 设备
    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "尝试打开 HID 设备 (VID:0x%04X, PID:0x%04X)...", vendorID, productID)
    Dim As SDL_hid_device Ptr dev = SDL_hid_open(vendorID, productID, NULL)
    If (dev = NULL) Then
        SDL_LogError(SDL_LOG_CATEGORY_INPUT, "打开 HID 设备失败:%s", SDL_GetError())
        SDL_hid_exit()
        Return False
    End If

    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "成功打开 HID 设备")

    ' 获取设备信息
    Dim As ZString * 256 manufacturer, product, serial
    If (SDL_hid_get_manufacturer_string(dev, @manufacturer, 256) = 0) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "厂商名称:%s", manufacturer)
    End If
    If (SDL_hid_get_product_string(dev, @product, 256) = 0) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "产品名称:%s", product)
    End If
    If (SDL_hid_get_serial_number_string(dev, @serial, 256) = 0) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "序列号:%s", serial)
    End If

    ' 设置非阻塞模式
    SDL_hid_set_nonblocking(dev, 1)

    ' 测试:发送输出报告(示例数据,需根据设备协议调整)
    Dim As UByte outputReport(0 To REPORT_SIZE-1) = {0}
    outputReport(0) = 0x01 ' 报告ID(根据设备协议)
    outputReport(1) = 0x02 ' 数据1
    outputReport(2) = 0x03 ' 数据2

    Dim As Integer writeResult = SDL_hid_write(dev, @outputReport(0), REPORT_SIZE)
    If (writeResult < 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_INPUT, "写入 HID 设备失败:%s", SDL_GetError())
    Else
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "成功写入 %d 字节到 HID 设备", writeResult)
    End If

    ' 测试:读取输入报告(超时 1000ms)
    Dim As UByte inputReport(0 To REPORT_SIZE-1) = {0}
    Dim As Integer readResult = SDL_hid_read_timeout(dev, @inputReport(0), REPORT_SIZE, 1000)
    If (readResult < 0) Then
        SDL_LogError(SDL_LOG_CATEGORY_INPUT, "读取 HID 设备失败:%s", SDL_GetError())
    ElseIf (readResult = 0) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "读取超时(1000ms),无数据返回")
    Else
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "成功读取 %d 字节:", readResult)
        ' 打印读取到的数据(十六进制)
        Dim As String hexStr = ""
        For i As Integer = 0 To readResult-1
            hexStr += SDL_Format("0x%02X ", inputReport(i))
        Next
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "  数据:%s", hexStr)
    End If

    ' 关闭设备
    SDL_hid_close(dev)
    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "已关闭 HID 设备")

    ' 退出 HIDAPI
    SDL_hid_exit()

    Return True
End Function

' 主程序
Sub Main()
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== SDL HIDAPI 示例程序 ===")

    ' 1. 枚举并打印所有 HID 设备
    EnumerateAndPrintHIDDevices()

    ' 2. 尝试打开指定 HID 设备(替换为实际设备的 VID/PID)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, vbCrLf & "==== 测试指定 HID 设备 ====")
    Dim As Boolean testResult = OpenAndTestHIDDevice(VENDOR_ID, PRODUCT_ID)

    If (testResult) Then
        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "HID 设备测试成功")
    Else
        SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "HID 设备测试失败(请检查 VID/PID 是否正确)")
    End If

    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序结束")
End Sub

' 运行主程序
Main()

' 辅助函数:格式化字符串(模拟 SDL 格式化输出)
Function SDL_Format(ByVal fmt As String, ...) As String
    Dim As Any Ptr args = va_start()
    Dim As ZString * 1024 buffer
    vsprintf(@buffer, fmt, args)
    va_end(args)
    Return buffer
End Function

核心知识点补充

  1. HID 设备基础概念

    • VID/PID:厂商ID(Vendor ID)和产品ID(Product ID)是识别 USB/HID 设备的唯一标识,由 USB-IF 分配;
    • 报告(Report):HID 设备通过报告传输数据,分为输入报告(设备→主机)、输出报告(主机→设备)、特征报告(配置/状态);
    • 报告描述符:定义设备支持的报告格式、数据长度、用途,是解析 HID 数据的关键。
  2. 开发注意事项

    • 权限问题:Linux/macOS 平台访问 HID 设备可能需要 root 权限或自定义 udev 规则;
    • 跨平台兼容:Windows 需注意设备路径格式,macOS/iOS 需处理蓝牙 HID 设备的扫描逻辑;
    • 非阻塞模式:设置非阻塞模式后,SDL_hid_read 会立即返回,避免主线程阻塞。
  3. 调试技巧

    • 使用 SDL_hid_enumerate(0, 0) 枚举所有设备,确认目标设备的 VID/PID 和路径;
    • 通过 SDL_hid_get_report_descriptor 获取报告描述符,解析设备的数据格式;
    • 移动平台(Android/iOS)需配置权限(如蓝牙权限)才能访问 BLE HID 设备。

总结

  1. 核心优势
    • SDL HIDAPI 封装了原生 HIDAPI,提供跨平台的 HID 设备访问接口,无需关注底层系统差异;
    • 支持 USB、蓝牙等多种总线类型的 HID 设备,涵盖键鼠、手柄、传感器、自定义 HID 设备;
    • 许可协议宽松,可自由使用且无额外约束;
  2. 使用建议
    • 必须先调用 SDL_hid_init 初始化,使用完调用 SDL_hid_exit 释放资源;
    • 枚举设备后务必调用 SDL_hid_free_enumeration 释放内存,避免泄漏;
    • 实际开发中需根据设备的 HID 协议解析读写数据,示例中的报告格式仅为参考;
  3. 关键接口
    • 设备枚举:SDL_hid_enumerate/SDL_hid_free_enumeration
    • 设备操作:SDL_hid_open/SDL_hid_close/SDL_hid_init/SDL_hid_exit
    • 数据读写:SDL_hid_read/SDL_hid_write/SDL_hid_read_timeout

评论一下?

OωO
取消