作者:星隕
來源:
音視訊開發進階在前面的文章中已經建立了一個 SDL 視窗并且顯示指定的顔色。
為了讓視窗顯示出來,在程式中寫了一個死循環,這幾行代碼就是 SDL 消息循環和事件響應的核心縮影了。
SDL_Event windowEvent;
while (true){
if (SDL_PollEvent(&windowEvent)){
if (SDL_QUIT == windowEvent.type){
break;
}
}
}
SDL 消息循環和事件響應
和 Android 中的 Handler 機制有些類似,Handler 會關聯一個線程,線程内部維護一個消息隊列 MessageQueue,通過 Handler 像 MessageQueue 發送消息,然後再從 MessageQueue 中取出 Message 進行處理。
在 SDL 中通過
SDL_PollEvent
從消息隊列取出消息,如果有則傳回 1,沒用則傳回 0。
SDL_Event
結構體代表消息事件,其中的
type
指定具體的事件類型,在
SDL_events.h
檔案中能看到所有的事件類型,抄錄一些比較典型的:
typedef enum
{
/* Application events */
SDL_QUIT = 0x100, /**< User-requested quit */
/* Keyboard events */
SDL_KEYDOWN = 0x300, /**< Key pressed */
SDL_KEYUP, /**< Key released */
/* Mouse events */
SDL_MOUSEMOTION = 0x400, /**< Mouse moved */
SDL_MOUSEBUTTONDOWN, /**< Mouse button pressed */
SDL_MOUSEBUTTONUP, /**< Mouse button released */
SDL_MOUSEWHEEL, /**< Mouse wheel motion */
/* Window events */
SDL_WINDOWEVENT = 0x200, /**< Window state change */
SDL_SYSWMEVENT, /**< System specific event */
} SDL_EventType;
如上所示,有鍵盤、滑鼠事件還有視窗事件和應用退出的事件,基本上也就用到這些了。
當使用者點選了視窗左上角
叉
的時候,對應 SDL_Event 的 type 就是
SDL_QUIT
,這個 type 是一定要添加處理的,不然點叉就關閉不了視窗了。
bool bQuit = false;
while (!bQuit){
while (SDL_PollEvent(&windowEvent)){
switch (windowEvent.type){
case SDL_QUIT:
bQuit = true;
break;
default:
break;
}
}
}
除了
SDL_PollEvent
方法去取消息外,還有
SDL_WaitEvent
方法。顧名思義,該方法會阻塞目前調用的線程,直到取出一個消息為止。
bool bQuit = false;
while (!bQuit){
SDL_WaitEvent(&windowEvent);
if (windowEvent.type == SDL_QUIT){
bQuit = true;
break;
} else{
cout << "get event" << endl;
}
}
使用方法如上所示,但實際上程式不會一直卡在
SDL_WaitEvent
上,因為它沒有限制監聽的事件類型,是以隻要有視窗在運作顯示,哪怕你滑鼠在視窗上滑過、或者按下了鍵盤,都能算是收到了消息事件,
cout
方法列印的 log 日志會不斷出現的。
同樣的,在
SDL_WaitEvent
方法中監聽了
SDL_QUIT
類型的事件,當點選視窗左上角的叉時,也要退出循環,結束程式。
鍵盤響應
現在可以通過
SDL_Event
的事件類型來監聽特定的鍵盤事件了。
鍵盤事件有
SDL_KEYDOWN
按下和
SDL_KEYUP
擡起兩種類型,按需監聽。
而具體使用者點選鍵盤上什麼按鍵,這個資訊就在 SDL_Event 的
SDL_KeyboardEvent
中。
對于不同類型的事件所包含的具體資訊,SDL_Event 都有對應的結構體去存儲。
typedef union SDL_Event
{
Uint32 type; /**< Event type, shared with all events */
SDL_CommonEvent common; /**< Common event data */
SDL_DisplayEvent display; /**< Window event data */
SDL_WindowEvent window; /**< Window event data */
// 鍵盤事件的資訊
SDL_KeyboardEvent key; /**< Keyboard event data */
// 滑鼠事件的資訊
SDL_MouseButtonEvent button; /**< Mouse button event data */
SDL_MouseMotionEvent motion; /**< Mouse motion event data */
}
是以想要知道使用者點選了哪個按鍵,去找
SDL_KeyboardEvent
對應的資訊就好了。
bool bQuit = false;
while (!bQuit){
while (SDL_PollEvent(&windowEvent)){
switch (windowEvent.type){
case SDL_QUIT:
bQuit = true;
break;
case SDL_KEYDOWN:
if (windowEvent.key.keysym.sym == SDLK_SPACE){
cout << "user click space \n" ;
}
break;
default:
break;
}
}
}
以上代碼監聽使用者是否點選空格鍵,如果是就輸出對應的 log 。
滑鼠響應
除此之外還可以監聽滑鼠事件,比如滑鼠是否按下、擡起、移動和坐标之類的。
對應的事件類型是
SDL_MOUSEMOTION
、
SDL_MOUSEBUTTONDOWN
SDL_MOUSEBUTTONUP
SDL_MOUSEBUTTONUP
,按自己的需求去監聽了。
事件包含的具體資訊在
SDL_MouseMotionEvent
SDL_MouseButtonEvent
和
SDL_MouseWheelEvent
裡面。
bool bQuit = false;
while (!bQuit){
while (SDL_PollEvent(&windowEvent)){
switch (windowEvent.type){
case SDL_QUIT:
bQuit = true;
break;
case SDL_MOUSEBUTTONDOWN:
printf("button index is %d\n",windowEvent.button.button);
break;
default:
break;
}
}
}
以上代碼就是監聽滑鼠點選事件,并且列印出點選按鍵的 index ,滑鼠的左鍵、右鍵和中間滾輪按下去對應的 index 不同。
自定義事件響應
除了系統事件,還可以自定義事件。
首先定義一個事件類型的宏:
#define SDL_CUSTOM_EVENT (SDL_USEREVENT + 1)
其次,要建立一個線程,讓它延時五秒後,發送自定義事件,在主線程中去接收到這個事件。
// 線程運作函數
int sdl_thread_custom_event(void *){
// 延時 5 秒
SDL_Delay(5000);
// 建立自定義事件并發送到消息隊列中去
SDL_Event sdlEvent;
sdlEvent.type = SDL_CUSTOM_EVENT;
SDL_PushEvent(&sdlEvent);
}
// 建立線程并運作
SDL_CreateThread(sdl_thread_custom_event, "custom_event", nullptr);
線程運作函數如上所示,定義一個 SDL_Event ,把它的 type 指派為自定義的類型,然後通過
SDL_PushEvent
方法把該消息事件放到消息隊列中去。
bool bQuit = false;
while (!bQuit){
while (SDL_PollEvent(&windowEvent)){
switch (windowEvent.type){
case SDL_QUIT:
bQuit = true;
break;
case SDL_CUSTOM_EVENT:
cout << "receive user custom event\n";
break;
default:
break;
}
}
}
SDL_PollEvent 方法會從消息隊列中取到我們自定義的消息事件,這時候就能做一些想要的操作呢,比如列印 log 之類的。
總結
以上就是關于 SDL 消息循環和事件響應的學習連載
003
篇。基本上後續所有的 SDL 代碼都會有這樣一個消息循環作為程式的主架構,是以這個時候弄明白了,方面後面代碼的學習。
具體的代碼見倉庫:
https://github.com/glumes/av-beginner本篇文章對應的送出
tag
為
av-beginner-003
,可切換至對應源碼檢視。
能力有限,文中有不對之處,歡迎加我微信 ezglumes 進行交流~~
SDL 系列文章「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。