博客源码下载 : https://download.csdn.net/download/han1202012/89432451
SDL 事件处理代码执行效果如下 :
SDL , Simple DirectMedia Layer , 是 跨平台的多媒体开发库 , 用于开发 跨平台 的 多媒体应用程序 , 可开发 WIndows / Linux / MacOS 多媒体应用 , 编写一次代码 , 可以在多个平台运行 ;
使用 SDL 多媒体库开发的 应用 有如下功能 :
其中的 事件处理 , 就是处理 外设 ( 键盘 / 鼠标 ) 传入的事件 , 如 鼠标移动 , 鼠标点击 , 键盘按键 等事件 ;
SDL 事件处理步骤 :
// 初始化 SDL 环境
SDL_Init(SDL_INIT_VIDEO);
// 创建 SDL_Window 窗口
SDL_Window* window = SDL_CreateWindow(
"SDL Event Handling",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
800, 600, SDL_WINDOW_SHOWN);
// 事件循环
while (1) {
// 检查是否有事件发生
if (SDL_PollEvent(&event)) {
// 检测事件类型 , 执行不同的操作
// event.type
}
}
// 退出SDL
SDL_DestroyWindow(window);
SDL_Quit();
代码示例 :
#include <stdio.h>
#include <SDL.h>
#undef main
int main(int argc, char* argv[])
{
printf("Hello World!\n");
// SDL 窗口
SDL_Window* window = NULL;
// SDL 事件
SDL_Event event;
// 1. 初始化SDL
SDL_Init(SDL_INIT_VIDEO);
// 2. 创建窗口
window = SDL_CreateWindow("SDL 事件处理",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
800, 600, SDL_WINDOW_SHOWN);
// 3. 事件循环
while (1) {
// 检查是否有事件发生
if (SDL_PollEvent(&event)) {
// 退出事件 : 鼠标点击右上角的 x 关闭按钮
if (event.type == SDL_QUIT) {
printf("SDL_QUIT Event\n");
break;
}
}
}
// 4. 退出SDL
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
return 0;
}
执行结果 : 运行程序后 , 弹出窗口 ,
此时开启循环 , 监听事件 , 每次循环时有事件发生 , 就会进入 if (event.type == SDL_QUIT)
分支语句 ,
点击窗口中右上角的 x 关闭按钮 , 会触发 SDL_QUIT
事件 , 此时退出事件循环 ,
继续执行代码就会关闭窗口 , 释放 SDL 资源 , 程序运行结束 ;
运行程序后弹出事件窗口 :
点击 窗口中的 关闭按钮 , 就会触发 SDL_QUIT 事件 ;
SDL_Event 用于存储各种事件 , 事件有如下类型 :
具体类型 , 在下面的 SDL_Event 联合体的代码注释中有详细说明 ;
SDL_Event 是一个联合体 定义在 SDL_event.h 头文件中 , 该 SDL_Event 联合体是一种特殊的数据结构 , 允许在相同的内存位置存储不同类型的数据 ;
完整的 SDL_Event 联合体 union 内容如下 :
typedef union SDL_Event {
Uint32 type; /**< 事件类型,与所有事件共享 */
SDL_CommonEvent common; /**< 通用事件数据 */
SDL_DisplayEvent display; /**< 显示事件数据 */
SDL_WindowEvent window; /**< 窗口事件数据 */
SDL_KeyboardEvent key; /**< 键盘事件数据 */
SDL_TextEditingEvent edit; /**< 文本编辑事件数据 */
SDL_TextInputEvent text; /**< 文本输入事件数据 */
SDL_MouseMotionEvent motion; /**< 鼠标移动事件数据 */
SDL_MouseButtonEvent button; /**< 鼠标按钮事件数据 */
SDL_MouseWheelEvent wheel; /**< 鼠标滚轮事件数据 */
SDL_JoyAxisEvent jaxis; /**< 游戏手柄轴事件数据 */
SDL_JoyBallEvent jball; /**< 游戏手柄球事件数据 */
SDL_JoyHatEvent jhat; /**< 游戏手柄帽事件数据 */
SDL_JoyButtonEvent jbutton; /**< 游戏手柄按钮事件数据 */
SDL_JoyDeviceEvent jdevice; /**< 游戏手柄设备变更事件数据 */
SDL_ControllerAxisEvent caxis; /**< 游戏控制器轴事件数据 */
SDL_ControllerButtonEvent cbutton; /**< 游戏控制器按钮事件数据 */
SDL_ControllerDeviceEvent cdevice; /**< 游戏控制器设备事件数据 */
SDL_AudioDeviceEvent adevice; /**< 音频设备事件数据 */
SDL_TouchFingerEvent tfinger; /**< 触摸手指事件数据 */
SDL_MultiGestureEvent mgesture; /**< 多指手势事件数据 */
SDL_DollarGestureEvent dgesture; /**< 手势事件数据 */
SDL_DropEvent drop; /**< 拖放事件数据 */
SDL_SensorEvent sensor; /**< 传感器事件数据 */
SDL_QuitEvent quit; /**< 退出请求事件数据 */
SDL_OSEvent user; /**< 用户自定义事件数据 */
Uint8 padding[56];
} SDL_Event;
代码位置 :
SDL_Event 联合体设计很巧妙 , 其第一个类型成员 Uint32 type
与 其它 25 个结构体类型成员 共同占用同一个内存空间 , 这 25 个结构体 的第一个参数也都是 Uint32 type
成员 ;
因此 , 不管是什么类型的 事件 , 都可以通过 获取 Uint32 type
成员 , 获得该成员的类型 , 然后根据该类型 , 就知道这是什么事件 , 直接调用该事件对应的结构体即可 ;
举例说明 : 获取的 SDL_Event
事件对象 的 Uint32 type
类型是键盘事件 SDL_KEYDOWN
, 那么就使用 SDL_KeyboardEvent
结构体的 数据格式 访问该 SDL_Event
事件 ;
SDL_KeyboardEvent 结构体内容如下 :
/**
* \brief 键盘按键事件结构体 (event.key.*)
*/
typedef struct SDL_KeyboardEvent
{
Uint32 type; /**< ::SDL_KEYDOWN or ::SDL_KEYUP */
Uint32 timestamp; /**< 毫秒级时间戳,使用 SDL_GetTicks() 填充 */
Uint32 windowID; /**< 拥有键盘焦点的窗口,如果有的话 */
Uint8 state; /**< ::SDL_PRESSED 或 ::SDL_RELEASED */
Uint8 repeat; /**< 如果这是一个键重复事件,则非零 */
Uint8 padding2;
Uint8 padding3;
SDL_Keysym keysym; /**< 被按下或释放的按键 */
} SDL_KeyboardEvent;
解析键盘事件的代码示例如下 : 调用 SDL_WaitEvent 函数 , 阻塞等待事件到来 , 事件到来后 ,
event.type
, 先看是哪种类型的事件 , 选择使用哪种结构体数据格式访问改事件数据 ;event.key.keysym.sym
成员 , 获取按下的是哪个按键 , 根据不同的按键 , 进行不同的操作 ;// 3. 事件循环
while (1) {
SDL_WaitEvent(&event);
// 获取事件的类型
switch (event.type)
{
case SDL_KEYDOWN: // 事件类型为键盘事件
// 获取键盘按键
switch (event.key.keysym.sym)
{
case SDLK_a: // 按下 A 键
printf("Press A\n");
break;
case SDLK_s: // 按下 S 键
printf("Press S\n");
break;
case SDLK_d: // 按下 D 键
printf("Press D\n");
break;
case SDLK_w: // 按下 W 键
printf("Press W\n");
break;
default:
printf("Press 0x%x\n", event.key.keysym.sym);
break;
}
break;
case SDL_MOUSEBUTTONDOWN: // 鼠标点击事件
break;
case SDL_MOUSEMOTION: // 鼠标移动事件
break;
}
}
在上面的示例中 , 使用了 SDL_PollEvent 函数 , 检测是否有事件发生 ,
SDL_PollEvent 函数 是 非阻塞函数 , 如果没有事件发生 , 则立刻返回 , 不会阻塞程序执行 ; 与之相对的是 SDL_WaitEvent 函数 , 该函数会阻塞程序 , 等待事件发生 ;
SDL_PollEvent 函数原型如下 :
int SDL_PollEvent(SDL_Event *event);
代码示例 : 使用 SDL_PollEvent 函数时 ,
// 声明 SDL_Event 变量
SDL_Event event;
// 将 SDL_Event 变量地址传入 SDL_PollEvent 函数
// 如果返回 1 , 则处理事件
// 如果返回 0 , 则不处理事件
if (SDL_PollEvent(&event)) {
// 处理事件
}
SDL_WaitEvent 函数 的作用是 阻塞等待事件发生 , 如果没有事件发生 , 则程序会一直阻塞等待下去 , 当有事件发生时 , 再继续向下执行 ;
SDL_WaitEvent 函数原型如下 :
int SDL_WaitEvent(SDL_Event *event);
如果没有事件发生 , 则程序会一直阻塞下去 ;
代码示例 : 使用 SDL_WaitEvent 函数的流程如下 :
调用了 SDL_WaitEvent 函数后 , 会阻塞当前的程序 , 直到 事件发生 , 解除阻塞继续执行 ;
SDL_Event event;
// 调用后会阻塞等待事件到来
SDL_WaitEvent(&event);
// 事件到来 , 解除阻塞 , 开始处理事件
// ...
博客源码下载 : https://download.csdn.net/download/han1202012/89432451
代码示例 :
#include <stdio.h>
#include <SDL.h>
#define MY_QUIT_EVENT (SDL_USEREVENT + 2) // 用户自定义事件
#undef main
int main(int argc, char* argv[])
{
printf("Hello World!\n");
// SDL 窗口
SDL_Window* window = NULL;
// SDL 事件
SDL_Event event;
// 事件循环退出标志位
int event_exit = 0;
// 1. 初始化SDL
SDL_Init(SDL_INIT_VIDEO);
// 2. 创建窗口
window = SDL_CreateWindow("SDL 事件处理",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
800, 600, SDL_WINDOW_SHOWN);
// 3. 事件循环
while (1) {
SDL_WaitEvent(&event);
// 获取事件的类型
switch (event.type)
{
case SDL_KEYDOWN: // 事件类型为键盘事件
// 获取键盘按键
switch (event.key.keysym.sym)
{
case SDLK_a: // 按下 A 键
printf("Press A\n");
break;
case SDLK_s: // 按下 S 键
printf("Press S\n");
break;
case SDLK_d: // 按下 D 键
printf("Press D\n");
break;
case SDLK_w: // 按下 W 键
printf("Press W\n");
break;
case SDLK_q:
printf("Press Q\n");
// 生成自定义事件
SDL_Event event_q;
event_q.type = MY_QUIT_EVENT;
SDL_PushEvent(&event_q);
break;
default:
printf("Press 0x%x\n", event.key.keysym.sym);
break;
}
break;
case SDL_MOUSEBUTTONDOWN: // 鼠标事件
if (event.button.button == SDL_BUTTON_LEFT)
{
// 按下鼠标左键
printf("SDL_BUTTON_LEFT\n");
}
else if(event.button.button == SDL_BUTTON_RIGHT)
{
printf("SDL_BUTTON_RIGHT\n");
}
else
{
printf("Press Mouse Button %d\n", event.button.button);
}
break;
case SDL_MOUSEMOTION: // 鼠标点击事件
printf("Mouse Moved To (%d,%d)\n", event.button.x, event.button.y);
break;
case MY_QUIT_EVENT:
printf("MY_QUIT_EVENT\n");
event_exit = 1;
break;
}
if(event_exit)
break;
}
// 4. 退出SDL
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
return 0;
}
执行结果 :
鼠标移动 , 触发的事件 :
键盘按键 , 触发的事件 :
鼠标点击触发的事件 :