SDL3_API分类参考_鼠标(CategoryMouse)

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

鼠标子系统(CategoryMouse)

所有图形界面(GUI)应用都需要处理鼠标交互,SDL 提供了一套完整的函数集,用于管理鼠标输入、控制光标显示形态等核心功能。

核心交互方式

  • 事件驱动:鼠标操作主要通过事件子系统传递(如移动触发 SDL_EVENT_MOUSE_MOTION、按键按下触发 SDL_EVENT_MOUSE_BUTTON_DOWN);
  • 状态查询:也可通过 SDL_GetMouseState() 随时查询鼠标当前状态(位置、按键按下情况)。

特殊场景适配

  1. 相对鼠标模式:FPS 等游戏需解除光标与窗口边界的绑定(避免鼠标移到窗口边缘停止响应),可调用 SDL_SetWindowRelativeMouseMode()——隐藏光标、独占窗口输入、无边界读取鼠标移动;
  2. 自定义光标
    • 隐藏系统光标,自行绘制:SDL_HideCursor()/SDL_ShowCursor()
    • 更高效的方式:通过 SDL_CreateColorCursor() 创建自定义图像光标,或 SDL_CreateSystemCursor() 使用系统预设光标,再通过 SDL_SetCursor() 设置;
  3. 多鼠标设备:多数平台支持识别多个连接的鼠标,可通过 SDL_GetMice() 枚举设备,监听 SDL_EVENT_MOUSE_ADDED/SDL_EVENT_MOUSE_REMOVED 事件感知设备插拔;
  4. 虚拟鼠标:SDL 为触摸/手写笔输入提供虚拟鼠标设备,桌面应用无需修改代码即可在触屏手机上运行;若需区分原生鼠标和触摸/手写笔,可过滤 which 字段为 SDL_TOUCH_MOUSEID/SDL_PEN_MOUSEID 的事件。

函数

  • SDL_CaptureMouse:捕获/释放全局鼠标输入(让指定窗口接收所有鼠标事件,即使鼠标在窗口外)
  • SDL_CreateAnimatedCursor:创建动画光标(支持多帧切换)
  • SDL_CreateColorCursor:创建自定义颜色光标(从 SDL_Surface 生成光标图像)
  • SDL_CreateCursor:创建自定义光标(从像素数据生成,兼容旧版接口)
  • SDL_CreateSystemCursor:创建系统预设光标(如箭头、手型、等待光标等)
  • SDL_CursorVisible:检查光标当前是否可见(返回 1 可见,0 隐藏)
  • SDL_DestroyCursor:销毁自定义光标(释放光标资源)
  • SDL_GetCursor:获取当前设置的光标(返回 SDL_Cursor 指针)
  • SDL_GetDefaultCursor:获取系统默认光标
  • SDL_GetGlobalMouseState:获取鼠标的全局屏幕坐标及按键状态(不受窗口约束)
  • SDL_GetMice:枚举系统中所有已连接的鼠标设备(返回设备 ID 列表及数量)
  • SDL_GetMouseFocus:获取当前拥有鼠标焦点的 SDL 窗口
  • SDL_GetMouseNameForID:根据鼠标设备 ID 获取设备名称(如 "USB Optical Mouse")
  • SDL_GetMouseState:获取鼠标在指定窗口内的坐标及按键状态
  • SDL_GetRelativeMouseState:获取鼠标的相对移动量及按键状态(适用于相对鼠标模式)
  • SDL_GetWindowMouseGrab:检查窗口是否启用鼠标抓取(鼠标是否被限制在窗口内)
  • SDL_GetWindowMouseRect:获取窗口的鼠标活动区域(鼠标仅在该区域内响应)
  • SDL_GetWindowRelativeMouseMode:检查窗口是否启用相对鼠标模式
  • SDL_HasMouse:检查系统是否连接了至少一个鼠标设备(返回布尔值)
  • SDL_HideCursor:隐藏鼠标光标(全局生效)
  • SDL_SetCursor:设置当前使用的光标(切换自定义/系统光标)
  • SDL_SetRelativeMouseTransform:设置相对鼠标移动的变换回调(自定义鼠标移动的坐标转换规则)
  • SDL_SetWindowMouseGrab:启用/禁用窗口的鼠标抓取(限制鼠标在窗口内移动)
  • SDL_SetWindowMouseRect:设置窗口的鼠标活动区域(仅该区域内响应鼠标事件)
  • SDL_SetWindowRelativeMouseMode:启用/禁用窗口的相对鼠标模式(FPS 游戏核心接口)
  • SDL_ShowCursor:显示鼠标光标(全局生效)
  • SDL_WarpMouseGlobal:将鼠标移动到全局屏幕的指定坐标
  • SDL_WarpMouseInWindow:将鼠标移动到指定窗口内的指定坐标

数据类型

  • SDL_Cursor:光标句柄类型(标识自定义/系统光标)
  • SDL_MouseButtonFlags:鼠标按键标志类型(位掩码,标识哪些按键被按下,如 SDL_BUTTON_LMASK 左键、SDL_BUTTON_RMASK 右键)
  • SDL_MouseID:鼠标设备唯一标识类型(区分多个连接的鼠标)
  • SDL_MouseMotionTransformCallback:鼠标移动变换回调类型(自定义相对鼠标的坐标转换逻辑)

结构体

  • SDL_CursorFrameInfo:动画光标帧信息结构体(包含单帧图像、延迟时间等)

枚举

  • SDL_MouseWheelDirection:鼠标滚轮方向枚举(SDL_MOUSEWHEEL_NORMAL 正常方向、SDL_MOUSEWHEEL_FLIPPED 反转方向)
  • SDL_SystemCursor:系统预设光标类型枚举(如 SDL_SYSTEM_CURSOR_ARROW 箭头、SDL_SYSTEM_CURSOR_HAND 手型、SDL_SYSTEM_CURSOR_WAIT 等待)

  • SDL_TOUCH_MOUSEID:触摸输入对应的虚拟鼠标设备 ID(用于区分原生鼠标和触摸模拟鼠标)

FreeBASIC 示例代码

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

' 辅助函数:打印鼠标状态信息
Sub PrintMouseState(ByVal window As SDL_Window Ptr)
    Dim As Integer x, y
    Dim As Uint32 buttonState = SDL_GetMouseState(window, @x, @y)

    Dim As String btnStr = ""
    If (buttonState And SDL_BUTTON_LMASK) Then btnStr &= "左键 "
    If (buttonState And SDL_BUTTON_RMASK) Then btnStr &= "右键 "
    If (buttonState And SDL_BUTTON_MMASK) Then btnStr &= "中键 "

    If (btnStr = "") Then btnStr = "无按键"
    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "鼠标位置:(%d, %d) | 按键状态:%s", x, y, btnStr)
End Sub

' 主程序
Dim As SDL_Window Ptr window = NULL
Dim As SDL_Renderer Ptr renderer = NULL
Dim As SDL_Cursor Ptr customCursor = NULL, systemCursor = NULL
Dim As SDL_Event evt
Dim As SDL_MouseID Ptr mouseIDs = NULL
Dim As Integer mouseCount = 0
Dim As Boolean quit = False, relativeMode = False

' 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. 检查鼠标设备
If (Not SDL_HasMouse()) Then
    SDL_LogError(SDL_LOG_CATEGORY_INPUT, "系统未检测到鼠标设备")
    SDL_Quit()
    End 1
End If

' 枚举鼠标设备
mouseCount = SDL_GetMice(0, NULL)
If (mouseCount > 0) Then
    mouseIDs = Callocate(mouseCount * SizeOf(SDL_MouseID))
    mouseCount = SDL_GetMice(mouseCount, mouseIDs)
    SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "检测到 %d 个鼠标设备", mouseCount)
    For i As Integer = 0 To mouseCount - 1
        Dim As ZString Ptr mouseName = SDL_GetMouseNameForID(mouseIDs[i])
        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "鼠标 %d:%s", i, mouseName)
        SDL_free(mouseName)
    Next
End If

' 3. 创建窗口和渲染器
window = SDL_CreateWindow("SDL 鼠标示例", _
    SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _
    800, 600, SDL_WINDOW_SHOWN)
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED)
If (window = NULL Or renderer = NULL) Then
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口/渲染器失败:%s", SDL_GetError())
    SDL_Quit()
    End 1
End If

' 4. 创建系统预设光标(手型)
systemCursor = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_HAND)
If (systemCursor = NULL) Then
    SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, "创建系统光标失败:%s", SDL_GetError())
End If

SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== SDL 鼠标操作示例 ===")
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "F1:切换相对鼠标模式 | F2:切换系统光标(手型/默认) | F3:显示/隐藏光标 | ESC:退出")
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "鼠标移动/点击:打印状态 | 滚轮:打印方向")

' 5. 主循环
While (Not quit)
    ' 每帧打印鼠标状态
    PrintMouseState(window)

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

            ' 键盘事件(功能切换)
            Case SDL_EVENT_KEY_DOWN
                Select Case evt.key.scancode
                    Case SDL_SCANCODE_ESCAPE
                        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按下 ESC,退出程序")
                        quit = True

                    ' F1:切换相对鼠标模式(FPS 模式)
                    Case SDL_SCANCODE_F1
                        relativeMode = Not relativeMode
                        SDL_SetWindowRelativeMouseMode(window, relativeMode)
                        SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "相对鼠标模式:%s", IIf(relativeMode, "启用", "禁用"))

                    ' F2:切换系统光标(手型/默认)
                    Case SDL_SCANCODE_F2
                        Static As Boolean useCustom = False
                        useCustom = Not useCustom
                        If (useCustom And systemCursor <> NULL) Then
                            SDL_SetCursor(systemCursor)
                            SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "切换为手型光标")
                        Else
                            SDL_SetCursor(SDL_GetDefaultCursor())
                            SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "切换为默认箭头光标")
                        End If

                    ' F3:显示/隐藏光标
                    Case SDL_SCANCODE_F3
                        Static As Boolean cursorVisible = True
                        cursorVisible = Not cursorVisible
                        If (cursorVisible) Then
                            SDL_ShowCursor(SDL_ENABLE)
                            SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "显示光标")
                        Else
                            SDL_HideCursor()
                            SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "隐藏光标")
                        End If
                End Select

            ' 鼠标移动事件
            Case SDL_EVENT_MOUSE_MOTION
                SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "鼠标移动:相对偏移 (%d, %d)", evt.motion.xrel, evt.motion.yrel)

            ' 鼠标按键事件
            Case SDL_EVENT_MOUSE_BUTTON_DOWN
                Select Case evt.button.button
                    Case SDL_BUTTON_LEFT: SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "左键按下")
                    Case SDL_BUTTON_RIGHT: SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "右键按下")
                    Case SDL_BUTTON_MIDDLE: SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "中键按下")
                    Case Else: SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "额外按键 %d 按下", evt.button.button)
                End Select

            ' 鼠标滚轮事件
            Case SDL_EVENT_MOUSE_WHEEL
                Dim As String dir = IIf(evt.wheel.y > 0, "上", "下")
                SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "鼠标滚轮:%s | 水平偏移:%d", dir, evt.wheel.x)

            ' 鼠标设备插拔事件
            Case SDL_EVENT_MOUSE_ADDED
                SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "检测到新鼠标设备(ID:%d)", evt.mouse.device)
            Case SDL_EVENT_MOUSE_REMOVED
                SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "鼠标设备断开(ID:%d)", evt.mouse.device)
        End Select
    Wend

    ' 清屏(黑色背景)
    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)
    SDL_RenderClear(renderer)
    SDL_RenderPresent(renderer)

    SDL_Delay(50)  ' 降低日志输出频率
Wend

' 6. 清理资源
If (systemCursor <> NULL) Then
    SDL_DestroyCursor(systemCursor)
End If
If (mouseIDs <> NULL) Then
    Deallocate(mouseIDs)
End If
SDL_DestroyRenderer(renderer)
SDL_DestroyWindow(window)
SDL_Quit()

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

核心知识点补充

  1. 鼠标按键标识

    • SDL_BUTTON_LEFT:左键(1)
    • SDL_BUTTON_RIGHT:右键(3)
    • SDL_BUTTON_MIDDLE:中键/滚轮键(2)
    • SDL_BUTTON_X1/SDL_BUTTON_X2:额外侧键(4/5)
  2. 相对鼠标模式核心优势

    • 光标隐藏,不会被窗口边界限制;
    • 鼠标移动以「相对偏移量」返回,而非绝对坐标;
    • 适用于 FPS 游戏视角控制、3D 场景旋转等场景。
  3. 自定义光标注意事项

    • SDL_CreateColorCursor 需传入 32 位 RGBA 格式的 SDL_Surface;
    • 光标热点(hotspot)决定光标图像的「点击点」(如箭头光标的尖端);
    • 使用完自定义光标后必须调用 SDL_DestroyCursor 释放资源。

总结

  1. 核心交互模式
    • 基础交互:通过 SDL_GetMouseState 查询状态,或监听 SDL_EVENT_MOUSE_* 事件;
    • 游戏场景:启用相对鼠标模式(SDL_SetWindowRelativeMouseMode)实现无边界鼠标控制;
    • 界面定制:通过 SDL_CreateSystemCursor/SDL_CreateColorCursor 自定义光标样式;
  2. 关键区分
    • SDL_GetMouseState:窗口内绝对坐标;
    • SDL_GetRelativeMouseState:相对移动量(相对模式专用);
    • SDL_GetGlobalMouseState:全局屏幕坐标;
  3. 多设备支持:通过 SDL_GetMice 枚举鼠标设备,监听插拔事件实现多鼠标差异化处理。

评论一下?

OωO
取消