SDL3_API分类参考_触摸输入(CategoryTouch)

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

触摸输入子系统(CategoryTouch)

SDL 在支持触摸功能的平台上提供了完整的触摸输入处理能力,可管理多个触摸设备,并追踪每个设备上的多点触控(多手指触摸)操作。

核心交互方式

触摸操作主要通过事件系统传递:

  • SDL_EVENT_FINGER_DOWN:手指按下事件;
  • SDL_EVENT_FINGER_MOTION:手指移动事件;
  • SDL_EVENT_FINGER_UP:手指抬起事件。
    同时也提供了查询触摸硬件信息的辅助函数。

虚拟鼠标事件

SDL 触摸系统默认会将触摸操作转换为虚拟鼠标事件,这一特性可让桌面应用无需大幅修改代码就能在触屏手机上运行。

  • 若应用需要区分原生鼠标输入和触摸模拟的鼠标输入,需忽略 which 字段为 SDL_TOUCH_MOUSEID 的鼠标事件;
  • 反之,若只需基础交互,可直接使用鼠标事件处理逻辑,无需额外适配触摸。

函数

  • SDL_GetTouchDeviceName:根据触摸设备ID获取设备名称(如 "Touchscreen")
  • SDL_GetTouchDevices:枚举系统中所有已连接的触摸设备(返回触摸设备ID列表及数量)
  • SDL_GetTouchDeviceType:获取触摸设备的类型(如触摸屏、触摸板、手写板)
  • SDL_GetTouchFingers:获取指定触摸设备上所有活动的手指信息(返回手指ID列表及数量)

数据类型

  • SDL_FingerID:手指ID类型(标识触摸设备上的单个手指,多点触控时区分不同手指)
  • SDL_TouchID:触摸设备ID类型(标识系统中的单个触摸设备)

结构体

  • SDL_Finger:手指状态结构体(包含手指ID、归一化的触摸位置(x/y:0.0~1.0)、压力值(0.0~1.0))

枚举

  • SDL_TouchDeviceType:触摸设备类型枚举(SDL_TOUCH_DEVICE_TYPE_DIRECT 触摸屏(直接触摸)、SDL_TOUCH_DEVICE_TYPE_INDIRECT_ABS 绝对坐标触摸板、SDL_TOUCH_DEVICE_TYPE_INDIRECT_REL 相对坐标触摸板)

  • SDL_MOUSE_TOUCHID:鼠标事件关联的触摸设备ID标识(用于反向关联鼠标事件到触摸设备)
  • SDL_TOUCH_MOUSEID:触摸模拟鼠标事件的设备ID(用于区分原生鼠标和触摸模拟鼠标)

FreeBASIC 示例代码

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

' 辅助函数:打印触摸设备信息
Sub PrintTouchDeviceInfo(ByVal touchID As SDL_TouchID)
    Dim As ZString Ptr devName = SDL_GetTouchDeviceName(touchID)
    Dim As SDL_TouchDeviceType devType = SDL_GetTouchDeviceType(touchID)

    Dim As String typeStr = ""
    Select Case devType
        Case SDL_TOUCH_DEVICE_TYPE_DIRECT: typeStr = "触摸屏(直接触摸)"
        Case SDL_TOUCH_DEVICE_TYPE_INDIRECT_ABS: typeStr = "触摸板(绝对坐标)"
        Case SDL_TOUCH_DEVICE_TYPE_INDIRECT_REL: typeStr = "触摸板(相对坐标)"
        Case Else: typeStr = "未知设备类型"
    End Select

    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "==== 触摸设备信息 ====")
    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "设备ID:%llu | 名称:%s | 类型:%s", touchID, devName, typeStr)

    ' 获取设备上的活动手指数量
    Dim As Integer fingerCount = SDL_GetTouchFingers(touchID, NULL, 0)
    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "当前活动手指数量:%d", fingerCount)

    If (devName <> NULL) Then SDL_free(devName)
End Sub

' 主程序
Dim As SDL_Window Ptr window = NULL
Dim As SDL_Renderer Ptr renderer = NULL
Dim As SDL_TouchID Ptr touchIDs = NULL
Dim As Integer touchCount = 0
Dim As SDL_Event evt
Dim As Boolean quit = False

' 存储触摸点状态(最多支持5点触控)
Type TouchPoint
    active As Boolean
    x As Double
    y As Double
    pressure As Double
End Type
Dim As TouchPoint touchPoints(0 To 4)

' 1. 初始化 SDL
If (SDL_Init(SDL_INIT_VIDEO) < 0) Then
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL 初始化失败:%s", SDL_GetError())
    End 1
End If

' 2. 创建窗口(全屏模式更适合触摸演示)
window = SDL_CreateWindow("SDL 触摸输入示例", _
    SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _
    800, 600, SDL_WINDOW_SHOWN Or SDL_WINDOW_RESIZABLE)
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED Or SDL_RENDERER_PRESENTVSYNC)
If (window = NULL Or renderer = NULL) Then
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口/渲染器失败:%s", SDL_GetError())
    SDL_Quit()
    End 1
End If

' 3. 枚举触摸设备
touchCount = SDL_GetTouchDevices(0, NULL)
If (touchCount > 0) Then
    touchIDs = Callocate(touchCount * SizeOf(SDL_TouchID))
    touchCount = SDL_GetTouchDevices(touchCount, touchIDs)
    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "检测到 %d 个触摸设备", touchCount)

    ' 打印第一个触摸设备信息
    PrintTouchDeviceInfo(touchIDs[0])
Else
    SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "系统未检测到触摸设备,仍可测试虚拟鼠标事件")
End If

SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== SDL 触摸输入示例 ===")
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "触摸屏幕:显示触摸点 | 鼠标操作:区分原生/模拟 | ESC:退出")

' 4. 主循环
While (Not quit)
    ' 清屏(黑色背景)
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
    SDL_RenderClear(renderer)

    ' 绘制触摸点
    For i As Integer = 0 To 4
        If (touchPoints(i).active) Then
            ' 获取窗口尺寸,将归一化坐标转换为像素坐标
            Dim As Integer winW, winH
            SDL_GetWindowSize(window, @winW, @winH)

            Dim As Integer px = touchPoints(i).x * winW
            Dim As Integer py = touchPoints(i).y * winH
            Dim As Integer size = 50 + touchPoints(i).pressure * 50 ' 压力越大,触摸点越大

            ' 绘制彩色触摸点(不同手指不同颜色)
            Select Case i
                Case 0: SDL_SetRenderDrawColor(renderer, 255, 0, 0, 200) ' 红色
                Case 1: SDL_SetRenderDrawColor(renderer, 0, 255, 0, 200) ' 绿色
                Case 2: SDL_SetRenderDrawColor(renderer, 0, 0, 255, 200) ' 蓝色
                Case 3: SDL_SetRenderDrawColor(renderer, 255, 255, 0, 200) ' 黄色
                Case 4: SDL_SetRenderDrawColor(renderer, 255, 0, 255, 200) ' 紫色
            End Select

            ' 绘制圆形触摸点(简化为矩形)
            Dim As SDL_Rect touchRect = (px - size\2, py - size\2, size, size)
            SDL_RenderFillRect(renderer, @touchRect)
        End If
    Next

    ' 刷新画面
    SDL_RenderPresent(renderer)

    ' 处理事件队列
    While (SDL_PollEvent(@evt))
        Select Case evt.type
            Case SDL_QUITEVENT
                quit = True

            ' 键盘事件
            Case SDL_EVENT_KEY_DOWN
                If (evt.key.scancode = SDL_SCANCODE_ESCAPE) Then
                    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按下 ESC,退出程序")
                    quit = True
                End If

            ' 触摸事件处理
            Case SDL_EVENT_FINGER_DOWN
                SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, _
                    "手指按下 | 设备ID:%llu | 手指ID:%llu | 位置:(%.2f, %.2f) | 压力:%.2f", _
                    evt.tfinger.touchId, evt.tfinger.fingerId, _
                    evt.tfinger.x, evt.tfinger.y, evt.tfinger.pressure)

                ' 记录触摸点状态(简化:按手指ID索引存储)
                Dim As Integer idx = evt.tfinger.fingerId Mod 5
                touchPoints(idx).active = True
                touchPoints(idx).x = evt.tfinger.x
                touchPoints(idx).y = evt.tfinger.y
                touchPoints(idx).pressure = evt.tfinger.pressure

            Case SDL_EVENT_FINGER_MOTION
                SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, _
                    "手指移动 | 设备ID:%llu | 手指ID:%llu | 位置:(%.2f, %.2f) | 相对偏移:(%.4f, %.4f)", _
                    evt.tfinger.touchId, evt.tfinger.fingerId, _
                    evt.tfinger.x, evt.tfinger.y, evt.tfinger.dx, evt.tfinger.dy)

                ' 更新触摸点位置
                Dim As Integer idx = evt.tfinger.fingerId Mod 5
                touchPoints(idx).x = evt.tfinger.x
                touchPoints(idx).y = evt.tfinger.y
                touchPoints(idx).pressure = evt.tfinger.pressure

            Case SDL_EVENT_FINGER_UP
                SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, _
                    "手指抬起 | 设备ID:%llu | 手指ID:%llu | 位置:(%.2f, %.2f)", _
                    evt.tfinger.touchId, evt.tfinger.fingerId, evt.tfinger.x, evt.tfinger.y)

                ' 清除触摸点状态
                Dim As Integer idx = evt.tfinger.fingerId Mod 5
                touchPoints(idx).active = False

            ' 区分原生鼠标和触摸模拟鼠标
            Case SDL_EVENT_MOUSE_BUTTON_DOWN
                If (evt.button.which = SDL_TOUCH_MOUSEID) Then
                    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "鼠标点击(触摸模拟):位置(%d, %d)", evt.button.x, evt.button.y)
                Else
                    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "鼠标点击(原生):位置(%d, %d)", evt.button.x, evt.button.y)
                End If
        End Select
    Wend

    SDL_Delay(16) ' 约60FPS
Wend

' 5. 清理资源
If (touchIDs <> NULL) Then
    Deallocate(touchIDs)
End If
SDL_DestroyRenderer(renderer)
SDL_DestroyWindow(window)
SDL_Quit()

SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "程序正常退出")
End 0

核心知识点补充

  1. 触摸坐标归一化

    • SDL 触摸事件中的 x/y 坐标为归一化值(0.0 ~ 1.0),对应触摸设备的左上角到右下角;
    • 需转换为窗口像素坐标时,公式:像素坐标 = 归一化坐标 × 窗口尺寸
    • 压力值(pressure)同样为 0.0 ~ 1.0,仅部分触摸设备支持(如电容屏)。
  2. 多点触控处理

    • 每个手指有唯一的 SDL_FingerID,可通过该ID区分不同手指的操作;
    • 示例中简化为最多支持5点触控,实际可根据需求扩展;
    • 常见多点触控手势(缩放、旋转)需通过多个手指的位置变化计算实现。
  3. 跨平台注意事项

    • 桌面平台(Windows/macOS)的触摸板会被识别为 SDL_TOUCH_DEVICE_TYPE_INDIRECT_ABS
    • 移动平台(Android/iOS)的触摸屏会被识别为 SDL_TOUCH_DEVICE_TYPE_DIRECT
    • 虚拟鼠标事件在移动平台默认启用,桌面平台可通过 SDL 提示关闭。

总结

  1. 核心特性
    • SDL 触摸系统提供标准化的多点触控事件,无需关注底层平台差异;
    • 虚拟鼠标事件机制大幅降低跨平台适配成本;
    • 通过 SDL_TOUCH_MOUSEID 可灵活区分原生鼠标和触摸模拟输入;
  2. 使用场景
    • 简单适配:直接使用鼠标事件处理触摸输入;
    • 精细控制:监听 SDL_EVENT_FINGER_* 事件,处理多点触控、压力感应等高级功能;
  3. 关键接口
    • 设备枚举:SDL_GetTouchDevices/SDL_GetTouchDeviceName
    • 事件处理:SDL_EVENT_FINGER_DOWN/MOTION/UP
    • 输入区分:SDL_TOUCH_MOUSEID 宏。

评论一下?

OωO
取消