SDL3_API分类参考_事件(CategoryEvents)

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

事件子系统(CategoryEvents)

SDL 事件队列的管理核心模块,是应用与「外部交互」的核心通道——几乎所有和现实世界的交互信息(用户操作、硬件插拔、系统状态变化等)都会流经事件队列。

核心使用方式

应用通常在「新帧开始」时处理事件队列:

  • 最常用:循环调用 SDL_PollEvent() 直到返回 false(无事件),逐个处理或忽略事件;
  • 回调模式:若使用主回调函数,事件会在 SDL_AppIterate() 调用前通过 SDL_AppEvent() 逐个传入,此时无需调用 SDL_PollEvent()
  • 其他控制方式:
    • SDL_PeepEvents():功能更丰富,但使用复杂度更高;
    • SDL_WaitEvent():阻塞进程直到有事件发生(低功耗硬件场景更友好);
    • SDL_AddEventWatch():注册回调,有新事件时触发。

自定义事件

应用也可主动生成事件:

  • SDL_PushEvent():将自定义事件推入队列,供后续读取;
  • SDL_RegisterEvents():注册自定义事件类型,确保其 ID 不与系统内置类型冲突。

函数

  • SDL_AddEventWatch:注册事件监听回调(有新事件加入队列时触发该回调)
  • SDL_EventEnabled:检查指定类型的事件是否被启用(返回布尔值)
  • SDL_FilterEvents:对事件队列中的事件批量应用过滤器(筛选/修改事件)
  • SDL_FlushEvent:清空事件队列中指定类型的单个事件
  • SDL_FlushEvents:清空事件队列中指定类型范围的所有事件
  • SDL_GetEventDescription:获取指定事件类型的文本描述(如 "SDL_QUIT" 对应 "Quit requested")
  • SDL_GetEventFilter:获取当前设置的全局事件过滤器
  • SDL_GetWindowFromEvent:从事件对象中提取关联的 SDL_Window 指针
  • SDL_HasEvent:检查事件队列中是否存在指定类型的单个事件(返回布尔值)
  • SDL_HasEvents:检查事件队列中是否存在指定类型范围的任意事件(返回布尔值)
  • SDL_PeepEvents:从事件队列中读取/移除事件(支持批量操作,比 PollEvent 更灵活)
  • SDL_PollEvent:从事件队列中取出一个事件(非阻塞,无事件时返回 false)
  • SDL_PumpEvents:强制更新事件队列(收集系统输入事件,SDL 内部自动调用,一般无需手动调用)
  • SDL_PushEvent:将自定义事件推入事件队列(返回是否成功)
  • SDL_RegisterEvents:注册自定义事件类型(指定数量,返回起始事件 ID,避免类型冲突)
  • SDL_RemoveEventWatch:移除已注册的事件监听回调
  • SDL_SetEventEnabled:启用/禁用指定类型的事件(禁用后该事件不会进入队列)
  • SDL_SetEventFilter:设置全局事件过滤器(可拦截/修改所有事件)
  • SDL_WaitEvent:阻塞等待事件队列中有事件(直到有事件时取出并返回)
  • SDL_WaitEventTimeout:带超时的阻塞等待事件(超时后返回 false,避免永久阻塞)

数据类型

  • SDL_EventFilter:事件过滤器回调类型(用于拦截/修改事件,返回布尔值表示是否保留事件)

结构体

  • SDL_AudioDeviceEvent:音频设备事件(设备添加/移除)
  • SDL_CameraDeviceEvent:摄像头设备事件(设备添加/移除/授权)
  • SDL_ClipboardEvent:剪贴板事件(内容变化)
  • SDL_CommonEvent:所有事件的公共基结构体(包含时间戳、事件类型等通用字段)
  • SDL_DisplayEvent:显示设备事件(分辨率变化、显示连接/断开)
  • SDL_DropEvent:拖放事件(文件拖入窗口)
  • SDL_Event:核心事件联合体(包含所有类型的事件结构体)
  • SDL_GamepadAxisEvent:游戏手柄轴事件(摇杆/扳机移动)
  • SDL_GamepadButtonEvent:游戏手柄按键事件(按下/释放)
  • SDL_GamepadDeviceEvent:游戏手柄设备事件(连接/断开)
  • SDL_GamepadSensorEvent:游戏手柄传感器事件(陀螺仪/加速度计数据)
  • SDL_GamepadTouchpadEvent:游戏手柄触摸板事件
  • SDL_JoyAxisEvent:摇杆轴事件(传统摇杆设备)
  • SDL_JoyBallEvent:摇杆轨迹球事件
  • SDL_JoyBatteryEvent:摇杆电池事件(电量变化)
  • SDL_JoyButtonEvent:摇杆按键事件
  • SDL_JoyDeviceEvent:摇杆设备事件(连接/断开)
  • SDL_JoyHatEvent:摇杆方向键事件
  • SDL_KeyboardDeviceEvent:键盘设备事件(连接/断开)
  • SDL_KeyboardEvent:键盘事件(按键按下/释放)
  • SDL_MouseButtonEvent:鼠标按键事件(按下/释放)
  • SDL_MouseDeviceEvent:鼠标设备事件(连接/断开)
  • SDL_MouseMotionEvent:鼠标移动事件
  • SDL_MouseWheelEvent:鼠标滚轮事件
  • SDL_PenAxisEvent:手写笔轴事件(压力/倾斜变化)
  • SDL_PenButtonEvent:手写笔按键事件
  • SDL_PenMotionEvent:手写笔移动事件
  • SDL_PenProximityEvent:手写笔接近/离开事件
  • SDL_PenTouchEvent:手写笔触摸事件
  • SDL_PinchFingerEvent:捏合手势事件(多点触控)
  • SDL_QuitEvent:退出事件(用户请求关闭应用)
  • SDL_RenderEvent:渲染事件(渲染目标刷新)
  • SDL_SensorEvent:传感器事件(加速度计/陀螺仪等)
  • SDL_TextEditingCandidatesEvent:文本编辑候选词事件(输入法候选词)
  • SDL_TextEditingEvent:文本编辑事件(输入法正在输入)
  • SDL_TextInputEvent:文本输入事件(完成的文本输入)
  • SDL_TouchFingerEvent:触摸手指事件(按下/移动/抬起)
  • SDL_UserEvent:自定义用户事件(可携带自定义数据)
  • SDL_WindowEvent:窗口事件(大小变化、移动、最小化、关闭等)

枚举

  • SDL_EventAction:事件操作枚举(用于 SDL_PeepEvents,如 SDL_ADDEVENT/SDL_PEEKEVENT/SDL_GETEVENT)
  • SDL_EventType:事件类型枚举(所有内置事件的类型 ID,如 SDL_QUIT/SDL_KEYDOWN 等)

  • (无)

FreeBASIC 示例代码

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

' 自定义事件类型 ID
Dim As Uint32 CUSTOM_EVENT_ID

' 事件过滤器回调:拦截并打印键盘事件
Function EventFilter Cdecl (ByVal userdata As Any Ptr, ByVal evt As SDL_Event Ptr) As Integer
    Select Case evt->type
        Case SDL_KEYDOWN
            SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "过滤器拦截:按键 %d 按下", evt->key.keysym.sym)
            ' 返回 1 保留事件,返回 0 丢弃事件
            Return 1
        Case SDL_KEYUP
            SDL_LogInfo(SDL_LOG_CATEGORY_INPUT, "过滤器拦截:按键 %d 释放", evt->key.keysym.sym)
            Return 1
        Case Else
            Return 1  ' 保留其他事件
    End Select
End Function

' 事件监听回调:打印所有新事件
Sub EventWatchCallback Cdecl (ByVal userdata As Any Ptr, ByVal evt As SDL_Event Ptr)
    Dim As ZString Ptr evtDesc = SDL_GetEventDescription(evt->type)
    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "事件监听:%s (类型 ID: %d)", evtDesc, evt->type)
End Sub

' 发送自定义事件的线程函数
Sub SendCustomEventThread Cdecl (ByVal data As Any Ptr)
    Dim As Integer i = 0
    While (i < 5)
        ' 构造自定义事件
        Dim As SDL_Event customEvt
        customEvt.type = CUSTOM_EVENT_ID
        customEvt.user.code = 100 + i
        customEvt.user.data1 = Cast(Any Ptr, i)
        customEvt.user.data2 = NULL

        ' 推入事件队列
        If (SDL_PushEvent(@customEvt) > 0) Then
            SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "线程:发送自定义事件 %d", i)
        End If

        SDL_Delay(1000)
        i += 1
    Wend
End Sub

' 主程序
Dim As SDL_Window Ptr window = NULL
Dim As SDL_Event evt
Dim As SDL_Thread Ptr thread = NULL
Dim As Integer quit = 0

' 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. 注册自定义事件类型(1 个自定义类型)
CUSTOM_EVENT_ID = SDL_RegisterEvents(1)
If (CUSTOM_EVENT_ID = SDL_INVALID_EVENT) Then
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "注册自定义事件失败")
    SDL_Quit()
    End 1
End If
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "自定义事件 ID:%d", CUSTOM_EVENT_ID)

' 3. 创建窗口
window = SDL_CreateWindow("SDL 事件系统示例", _
    SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, _
    600, 400, SDL_WINDOW_SHOWN)
If (window = NULL) Then
    SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "创建窗口失败:%s", SDL_GetError())
    SDL_Quit()
    End 1
End If

' 4. 设置事件过滤器和监听回调
SDL_SetEventFilter(@EventFilter, NULL)
SDL_AddEventWatch(@EventWatchCallback, NULL)

' 5. 创建线程发送自定义事件
thread = SDL_CreateThread(@SendCustomEventThread, "CustomEventThread", NULL)
If (thread = NULL) Then
    SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, "创建线程失败:%s", SDL_GetError())
End If

SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "=== 事件处理示例 ===")
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "按 ESC 退出 | 按任意键触发键盘事件 | 等待自定义事件...")

' 6. 主事件循环
While (quit = 0)
    ' 非阻塞读取事件
    While (SDL_PollEvent(@evt))
        Select Case evt.type
            ' 窗口关闭事件
            Case SDL_QUITEVENT
                SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "收到退出事件")
                quit = 1

            ' 键盘事件
            Case SDL_KEYDOWN
                If (evt.key.keysym.sym = SDLK_ESCAPE) Then
                    SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "ESC 键按下,退出程序")
                    quit = 1
                End If

            ' 窗口事件
            Case SDL_WINDOWEVENT
                Select Case evt.window.event
                    Case SDL_WINDOWEVENT_RESIZED
                        SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "窗口大小变化:%dx%d", _
                            evt.window.data1, evt.window.data2)
                End Select

            ' 自定义事件
            Case CUSTOM_EVENT_ID
                SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "收到自定义事件:code=%d, data1=%d", _
                    evt.user.code, Cast(Integer, evt.user.data1))

            ' 其他事件
            Case Else
                ' 忽略
        End Select
    Wend

    SDL_Delay(10)  ' 降低 CPU 占用
Wend

' 7. 清理资源
SDL_RemoveEventWatch(@EventWatchCallback, NULL)
If (thread <> NULL) Then
    SDL_WaitThread(thread, NULL)
End If
SDL_DestroyWindow(window)
SDL_Quit()

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

总结

  1. SDL 事件子系统是应用交互的核心,SDL_PollEvent 是最常用的事件读取接口(非阻塞),SDL_WaitEvent 适用于低功耗场景(阻塞);
  2. FreeBASIC 中使用时需注意:
    • 自定义事件需通过 SDL_RegisterEvents 注册 ID,避免冲突;
    • 事件过滤器(SDL_SetEventFilter)可全局拦截事件,监听回调(SDL_AddEventWatch)仅监听不拦截;
    • SDL_PushEvent 可跨线程发送事件,是线程间通信的常用方式;
  3. 核心流程:初始化 → 注册自定义事件(可选)→ 设置过滤器/监听(可选)→ 事件循环处理 → 清理资源。

评论一下?

OωO
取消