13. diel - SDĽ - Vlastné udalosti a filtrovanie
V aplikácii často potrebujeme vlastné udalosti. Môže sa jednať o základné veci, ako vznik kolízie, spustenie určitého zvuku a ďalej. Všetky tieto veci možno (ale nie je nutné) riešiť cez udalosti. Preto si dnes ukážeme, ako môžeme vytvoriť vlastné udalosť a vložiť ju do fronty.
Vytvorenie vlastných udalostí
K vytvoreniu vlastnej udalosti budeme potrebovať vlastný typ. type je
Uint32
, to znamená, že môže nadobúdať celkovo 0xFFFF = 65535
hodnôt. Konštanta SDL_USEREVENT
, od ktorej by mali druhy
vlastných udalostí začínať, má hodnotu 0x8000 = 32768. Sami teda môžeme
vytvoriť celkom 32767 udalostí - máme dostatok priestoru pre vlastné
udalosti. Tým by som našu matematickú vložku ukončil a pozrieme sa na
praktickú časť.
Najjednoduchšie je si pre každú udalosť vytvoriť konštantu v
hlavičkovom súbore. Neskôr nebudeme musieť riešiť kolízie, až sa počet
udalostí zväčší nad únosnú mieru. Druhou možnosťou je typy udalostí
generovať za behu programu pomocou funkcie SDL_RegisterEvents. Ak
už nebudú k dispozícii ďalšie voľné udalosti, program vráti
(Uint32)-1
. Osobne sa prikláňam ku konštantám v hlavičkových
súboroch. Bohužiaľ nie sú oba postupy navzájom kompatibilné.
Pre užívateľské udalosti máme k dispozícii SDL_UserEvent, ku
ktorému pristupuje skrz user
atribút. Štruktúra má dva
ukazovatele typu void
, to znamená, že môžeme preniesť
prakticky ľubovoľné dáta, respektíve ukazovatele na ne. Nakoniec musíme
udalosť vložiť do fronty funkcií SDL_PushEvent
alebo
SDL_PeepEvents
.
Filtrovanie udalostí
Všetky filtrovacie funkcie pracujú s internou frontom - prebieha počas
hovoru SDL_PumpEvents
. Ako už bolo poznamenané na začiatku, v
aplikácii sa nedozvieme o tom, že používateľ práve teraz niečo vykonáva.
Vždy sa dozvieme len to, že niečo vykonal. Okamžitá spätná väzba nie je
možná. To je dôvod, prečo filtrovanie prebieha až počas prenášania
udalostí z externej frontu do internej.
Prvá možnosť je zablokovať všetky udalosti určitého typu. Použijeme
na to funkciu SDL_EventState. V prvom parametri odovzdáme typ
udalosti, ktorú nechceme v aplikácii získavať. Druhým parametrom je jedna z
hodnôt SDL_QUERY
pre opýtaní na aktuálny stav,
SDL_IGNORE
pre ignorovanie udalosti a SDL_ENABLE
pre
opätovné získavanie udalosti.
Ďalší v rade sú funkcie SDL_SetEventFilter a SDL_GetEventFilter. Nižšie uvádzam definícia každej funkcie.
int YourEventFilter(void* userdata, SDL_Event* event); void SDL_SetEventFilter(SDL_EventFilter filter, void* userdata); SDL_bool SDL_GetEventFilter(SDL_EventFilter* filter, void** userdata);
Pri nastavení filtra môžeme druhým parametrom odovzdať ľubovoľný objekt, ktorý dostane filtrovacie funkcie pri jej zavolanie. Ak filtrovacie funkcie vráti hodnotu 0, udalosť nebude do internej fronty pridaná. Naopak pri hodnote 1 pridaná bude. Funkcia by mala byť skutočne použitá pre filtrovanie. Ak nás bude zaujímať iba vnútorný stav udalosti, použijeme Event Watch.
Event Watch pridáme funkcií SDL_AddEventWatch a zmažeme funkcií SDL_DelEventWatch.
int YourEventFilter(void* userdata, SDL_Event* event); void SDL_AddEventWatch(SDL_EventFilter filter, void* userdata); void SDL_DelEventWatch(SDL_EventFilter filter, void* userdata);
Vidíme, že callback je rovnaký ako pre filter. Na rozdiel od neho, vrátená hodnota callbacku je ignorovaná a ako je podľa pomenovania funkcií zrejmé, callback môže byť niekoľko. Môžeme mať samostatný callback pre každý typ udalosti, ale bude potreba na začiatku každého callbacku overiť, či ide o správny typ. Nie je možné nikde nastaviť, pre ktorý typ udalosti je callback určený - je volaný pre všetky typy.
Použitie filtra a Event Watch nie je tak jednoduché, ako by sa na prvý
pohľad mohlo zdať. Obaja Callback môžu bežať v samostatnom vlákne.
Problematika viacvláknových aplikácií je mimo rozsah tohto tutoriálu. Tu
platí iba jednoduché pravidlo - dáta odovzdané pri vytváraní callbacku by
sa nemala v žiadnej časti aplikácie meniť. Potom bude všetko fungovať, ako
má. Callback sa volajú aj pre udalosti vložené do fronty funkcií
SDL_PushEvent
, ale už nie pre funkciu SDL_PeepEvents
.
Pri návrhu programu je s tým potrebné počítať.
Posledná funkcia je SDL_FilterEvents. V tomto prípade prebehne odovzdaný callback pre každú udalosť v internej fronte. Ide o jednorazovú záležitosť na aktuálne interné fronte.
Funkcie sú zoradené tak, ako prebiehajú za sebou. Ak funkcie spomínaná
vyššie odfiltruje udalosť, funkcie alebo callback spomínaný pod ňou už
neprebehne. Ak nastavíme SDL_KEYDOWN
state na
SDL_IGNORE
, Event Watch sa nezavolá. Pre prehľadnosť uvádzam
graf (prvý prebehne funkcia vľavo).
SDL_EventState -> SDL_ SetEventFilter -> SDL_AddEventWatch -> SDL_FilterEvents
Príklad
Priložený program obsahuje aj prvky z minulej lekcie a demonštruje
vytvorenie vlastnej udalosti, filtrovanie a zmazanie udalosti po
SDL_WarpMouseInWindow
. V budúcom diele už opustíme udalosti a
pozrieme sa na zvyšok veci, ktoré nám ešte chýba. Bude to napríklad
abstrakcie súborov alebo viacvláknové programovanie.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkamiStiahnuté 645x (11.77 MB)