10. diel - SDĽ - Udalosti klávesnice
V dnešnom diele sa pozrieme na udalosti, ktoré môže vyvolať klávesnice. Najprv zistíme, ako sa s klávesnicou pracuje vo fronte udalostí, a následne ako môžeme kdekoľvek v programe zistiť aktuálny stav klávesnice.
V úvode by som mal spomenúť, že všetky udalosti sú v
SDL_Event
uložené pod svojimi atribúty. Napríklad k
SDL_KeyboardEvent
sa dostaneme skrze event.key
.
Podobne k udalosti upravujúce text (SDL_TextInputEvent
) sa
dostaneme skrz event.text
. Rovnaké pravidlá platia pre každú
udalosť, atribút je vždy uvedený v dokumentácii a nebudem ho pri každej
udalosti uvádzať.
Scancode, keycode a Keymod
SDL disponujeme dvoma enumerátory, ktoré identifikujú kláves. Prvým je
SDL_Scancode
a druhý SDL_Keycode
. Ich prehľad
môžete vidieť tu.
Sú takmer totožné, ale neplatí to vždy. SDL_Scancode
je
priradené na fyzické rozloženie klávesnice, zatiaľ čo
SDL_Keycode
na aktuálne rozloženie klávesnice určené
operačným systémom. Rozdiel môžeme spoznať, keď budeme mať dve
rozloženie klávesnice, jedno QWERTZ a druhé QWERTY. SDL_Scancode
bude mať pre kláves Y v oboch prípadoch rovnakú hodnotu, zatiaľ čo u
SDL_Keycode
sa bude meniť podľa toho, ktoré rozvrhnutie bude
aktuálne aktívny (Y / Z). Podľa toho by sme tiež mali zachytávať udalosti.
Napríklad WSAD budeme chcieť mať vždy na rovnakom mieste, preto použijeme
SDL_Scancode
. Ak má klávesa "I" otvoriť inventár, mali by sme
použiť SDL_Keycode
.
S Enumerátor SDL_Keymod je situácia odlišná. Obsahuje hodnoty
ako bitové flagy a môžeme hodnoty binárne ORovat alebo Andová. Flagy sú
určené pre špeciálne klávesy, ako je Ctrl, Alt, Shift, ale aj NumLock, Tab
a ďalšie. Pre klávesy, ktoré sú duplicitné (napríklad Ctrl je vpravo i
vľavo), obsahuje jednotlivé flagy pre každú z týchto klávesov
(KMOD_LCTRL
, KMOD_RCTRL
), ale aj ORovanou hodnotu pre
obe klávesy (KMOD_CTRL
= KMOD_LCTRL|KMOD_RCTRL
).
Všetko je popísané v dokumentácii.
SDL_KeyboardEvent
SDL_KeyboardEvent je základná štruktúra, z ktorej budeme vychádzať.
typedef struct SDL_KeyboardEvent { Uint32 type; Uint32 timestamp; Uint32 windowID; Uint8 state; Uint8 repeat; SDL_Keysym keysym; } SDL_KeyboardEvent;
type
môže byťSDL_KEYDOWN
aleboSDL_KEYUP
pre stlačenie alebo uvoľnenie klávesy.timestamp
je čas, v ktorom bola udalosť vyvolaná.windowsID
je ID okná, ktoré udalosť vyvolalo. Takéto okno môžeme získať funkcií SDL_GetWindowFromID.state
nadobúda hodnôtSDL_PRESSED
aSDL_RELEASED
. Jedná sa vlastne o duplicitné informáciu, ktorú získame aj ztype
.- z
keysym
sa dozvieme, o ktorú kláves sa jednalo.
Úmyselne som vynechal repeat
, pretože tento atribút je
komplikovanejšia. Operačný systém Windows pri stlačení klávesy vygeneruje
udalosť KEYDOWN
. Ak kláves držíme dlhšie, začne po určitej
dobe opakovane generovať KEYDOWN
udalosť, ktorá už bude mať
nastavený atribút repeat
na inú hodnotu ako je 0. Tým
spoznáme, že klávesa nebola stlačená, ale je držaná. Pretože je SDL
multiplatformový, vývojári sa rozhodli, že aj na iných systémoch ako
Windows sa bude SDL správať rovnakým spôsobom a generovať opakovane
KEYDOWN
udalosť. Je možné, že sa to v ďalších verziách SDL
zmení, preto sa oplatí kontrolovať dokumentáciu.
Štruktúru SDL_Keysym som už prakticky opísal. Obsahuje iba
SDL_Keycode
, SDL_Scancode
a SDL_Keymod
,
nemal by s ňou byť teda problém.
Aktuálny stav klávesnice
Niekedy potrebujeme priamo v programe zistiť, ktorá klávesa je stlačená. Udalosť nám povie iba zmenu klávesy (teda či bola práve stlačená alebo uvoľnená). Niekedy teda môžeme vidieť v programe konštrukcie podobnej tejto.
bool PPressed = false; bool End = false; while (!End) { while (SDL_PollEvent(event)) { if (event->type == SDL_QUIT) End = true; if (event->type == SDL_KEYDOWN && event->key.keysym.scancode == SDL_SCANCODE_P) PPressed = true; if (event->type == SDL_KEYUP && event->key.keysym.scancode == SDL_SCANCODE_P) PPressed = false; } //vykreslení }
Pri stlačení klávesy nejakým spôsobom zaregistrujeme, že bola klávesa stlačená, a obdobne sa zachováme pri uvoľnení. Podobným konštrukciám sa môžeme vyhnúť použitím funkcie SDL_GetKeyboardState, ktorá nám vráti pole aktuálneho stavu. Indexy polia sú scancode klávesov. Ak budeme chcieť zistiť, či je aktuálne stlačená šípka hore, použijeme túto časť programu.
const Uint8 *state = SDL_GetKeyboardState(NULL); if (state[SDL_SCANCODE_UP]) { //šipka nahoru je stisknutá }
Do funkcie môžeme podľa potreby vložiť ukazovateľ na int
,
v ktorom nám SDL vráti dĺžku poľa.
Vyššie spomenutá funkcia prepadla klávesy ako Shift, Ctrl a podobné. K tomu slúži funkcia SDL_GetModState, ktorá ale na rozdiel od predchádzajúcej funkcie nevracia poľa, ale ORované hodnoty jednotlivých kláves. Pre vykonanie kódu pri stlačenom Ctrl použijeme tento kód.
SDL_Keymod mod=SDL_GetModState(); if (mod & KMOD_CTRL) { //jedno z Ctrl je stisknuté }
Môžeme aj ručne nastaviť, ktoré z týchto klávesov sa budú tváriť
ako stlačené. Použijeme na to funkciu SDL_SetModState. Funkcia
prijíma ako parameter binárne ORované hodnoty z SDL_Keysym
.
Klávesy, ktoré nastavíme, budú pri najbližšom volaní
SDL_GetModState
zahrnuté v návratovej hodnote.
Posledná funkcia, ktorú môžeme niečo zistiť o aktuálnej situácii, je
funkcia SDL_GetKeyboardFocus. Vracia SDL_Window
, ktoré
je aktuálne aktívny, a prijíma udalosti vyvolané klávesnicou.
Text
SDL poskytuje aj rozhranie pre zachytávanie textu. Prečo potrebujeme separátne rozhranie pre text, keď vieme, ktorá klávesa bola stlačená? Pre text je nepreberné množstvo kombinácií a klávesnica samotná môže mať niekoľko rozvrhnutie. Ak by sme chceli každý znak vytvárať ručne, bola by to veľa práce (v súčasnosti existuje približne 110 000 znakov). Toto rozhranie nás od konkrétnej implementácie utlmia a môžeme pracovať len so samotným textom.
Základné funkcie sú SDL_StartTextInput a
SDL_StopTextInput. Po zavolaní prvá funkcia SDL začne generovať
udalosti typu SDL_TEXTINPUT
, poprípade
SDL_TEXTEDITING
. SDL_TextInputEvent má okrem
základných atribútov iba jeden vlastný, a tým je text
. Ten je
ukazovateľ typu char
a je v ňom uložený reťazec formátu UTF-8
ukončený nulovým znakom. SDL_TextEditingEvent je o niečo
rozsiahlejšie, preto si ho ukážeme.
typedef struct SDL_TextEditingEvent { Uint32 type; Uint32 timestamp; Uint32 windowID; char text[SDL_TEXTEDITINGEVENT_TEXT_SIZE]; Sint32 start; Sint32 length; } SDL_TextEditingEvent;
Okrem základných atribútov obsahuje atribút text
, ktorý
obsahuje nový text. Ďalej atribút start
(kde editácia začína)
a length
(dĺžka editovaného textu). Taká je aspoň predstava. Z
pokusov na Windows som zistil, že SDL_TextEditingEvent
sa generuje
z neznámeho dôvodu iba pri zmene okna, ale neodovzdáva žiadne informácie.
text
, start
i length
sú 0. Vôbec
nezohľadňuje backspace, o tom, že by som sa chcel v texte posúvať pomocou
šípok ani nehovoriac. Neviem aká je situácia na Linuxe a poprípade na
ďalších systémoch, ak niekto bude skúšať program spustiť aj pod iným
operačným systémom, prosím dajte vedieť, ako program reaguje.
Klávesnica na obrazovke
Pretože je SDL multiplatformový, a to vrátane platformy Android a iOS,
môže nastať situácia, keď nebudeme mať pripojenú fyzickú klávesnicu. U
tabletov a mobilných telefónov si musíme vystačiť so softvérovou
klávesnicou, ktorú nám poskytuje operačný systém. Funkciou
SDL_HasScreenKeyboardSuppor zistíme, či aktuálne platforma
podporuje klávesnicu na obrazovke. Druhou funkciou, ktorá sa môže hodiť, je
SDL_IsScreenKeyboardShown, ktorá vráti SDL_bool
, ak je
klávesnica zobrazená. Klávesnica by sa mala automaticky zobraziť pri volaní
SDL_StartTextInput
a pri SDL_StopTextInput
by sa mala
opäť skryť.
Na Windows 8.1 mi funkcionalita opäť nefungovala. Aj keď som zapol klávesnicu na obrazovke, klávesnica sa nie a nie zobraziť. Pravdepodobne sa opäť jedná o záležitosť konkrétnej platformy.
Príklad
V dnešnom príklade som pripravil ukážku, ako zachytávať práve textový vstup. Pri stlačení klávesy nahor sa vstup aktivuje, pri stlačení klávesy dole sa text prestane zapisovať.
V budúcom dieli sa pozrieme bližšie na myš a jej udalosti.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkamiStiahnuté 698x (9.51 MB)