10. díl - SDL - Události klávesnice

C a C++ SDL SDL - Události klávesnice

ONEbit hosting Unicorn College Tento obsah je dostupný zdarma v rámci projektu IT lidem. Vydávání, hosting a aktualizace umožňují jeho sponzoři.

V dnešním díle se podíváme na události, které může vyvolat klávesnice. Nejprve zjistíme, jak se s klávesnicí pracuje ve frontě událostí, a následně jak můžeme kdekoliv v programu zjistit aktuální stav klávesnice.

V úvodu bych měl zmínit, že všechny události jsou v SDL_Event uloženy pod svými atributy. Například k SDL_KeyboardEvent se dostaneme skrze event.key. Podobně k události upravující text (SDL_TextInputEvent) se dostaneme skrz event.text. Stejná pravidla platí pro každou událost, atribut je vždy uveden v dokumentaci a nebudu jej u každé události uvádět.

Scancode, Keycode a Keymod

SDL disponujeme dvěma enumerátory, které identifikují klávesu. Prvním je SDL_Scancode a druhý SDL_Keycode. Jejich přehled můžete vidět zde. Jsou téměř totožné, ale neplatí to vždy. SDL_Scancode je namapován na fyzické rozložení klávesnice, zatímco SDL_Keycode na aktuální rozvržení klávesnice určené operačním systémem. Rozdíl můžeme poznat, když budeme mít dvě rozvržení klávesnice, jedno QWERTZ a druhé QWERTY. SDL_Scancode bude mít pro klávesu Y v obou případech stejnou hodnotu, zatímco u SDL_Keycode se bude měnit podle toho, které rozvržení bude aktuálně aktivní (Y/Z). Podle toho bychom také měli zachytávat události. Například WSAD budeme chtít mít vždy na stejném místě, proto použijeme SDL_Scancode. Jestliže má klávesa „I“ otevřít inventář, měli bychom použít SDL_Keycode.

S enumerátorem SDL_Keymod je situace odlišná. Obsahuje hodnoty jako bitové flagy a můžeme hodnoty binárně ORovat nebo ANDovat. Flagy jsou určeny pro speciální klávesy, jako je Ctrl, Alt, Shift, ale také NumLock, Tab a další. Pro klávesy, které jsou duplicitní (například Ctrl je vpravo i vlevo), obsahuje jednotlivé flagy pro každou z těchto kláves (KMOD_LCTRL, KMOD_RCTRL), ale také ORovanou hodnotu pro obě klávesy (KMOD_CTRL = KMOD_LCTRL|KMOD_RCTRL). Vše je popsáno v dokumentaci.

SDL_KeyboardEvent

SDL_KeyboardEvent je základní struktura, ze které budeme vycházet.

typedef struct SDL_KeyboardEvent
{
    Uint32 type;
    Uint32 timestamp;
    Uint32 windowID;
    Uint8 state;
    Uint8 repeat;
    SDL_Keysym keysym;
} SDL_KeyboardEvent;
  • type může být SDL_KEYDOWN nebo SDL_KEYUP pro stisk nebo uvolnění klávesy.
  • timestamp je čas, ve kterém byla událost vyvolána.
  • windowsID je ID okna, které událost vyvolalo. Takové okno můžeme získat funkcí SDL_GetWindow­FromID.
  • state nabývá hodnot SDL_PRESSED a SDL_RELEASED. Jedná se vlastně o duplicitní informaci, kterou získáme i z type.
  • z keysym se dozvíme, o kterou klávesu se jednalo.

Úmyslně jsem vynechal repeat, protože tento atribut je komplikovanější. Operační systém Windows při stisku klávesy vygeneruje událost KEYDOWN. Jestliže klávesu držíme déle, začne po určité době opakovaně generovat KEYDOWN událost, která už bude mít nastavený atribut repeat na jinou hodnotu než je 0. Tím poznáme, že klávesa nebyla stisknuta, ale je držena. Protože je SDL multiplatformní, vývojáři se rozhodli, že i na jiných systémech než Windows se bude SDL chovat stejným způsobem a generovat opakovaně KEYDOWN událost. Je možné, že se to v dalších verzích SDL změní, proto se vyplatí kontrolovat dokumentaci.

Strukturu SDL_Keysym jsem už prakticky popsal. Obsahuje pouze SDL_Keycode, SDL_Scancode a SDL_Keymod, neměl by s ní být tedy problém.

Aktuální stav klávesnice

Někdy potřebujeme přímo v programu zjistit, která klávesa je stisknuta. Událost nám řekne pouze změnu klávesy (tedy jestli byla právě stisknuta nebo uvolněna). Někdy tedy můžeme vidět v programu konstrukce podobné této.

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í
}

Při stisku klávesy nějakým způsobem zaregistrujeme, že byla klávesa stisknuta, a obdobně se zachováme při uvolnění. Podobným konstrukcím se můžeme vyhnout použitím funkce SDL_GetKeyboar­dState, která nám vrátí pole aktuálního stavu. Indexy pole jsou scancode kláves. Jestliže budeme chtít zjistit, zda je aktuálně stisknuta šipka nahoru, použijeme tuto část programu.

const Uint8 *state = SDL_GetKeyboardState(NULL);
if (state[SDL_SCANCODE_UP])
{
   //šipka nahoru je stisknutá
}

Do funkce můžeme podle potřeby vložit ukazatel na int, ve kterém nám SDL vrátí délku pole.

Výše zmíněná funkce nebere v potaz klávesy jako Shift, Ctrl a podobné. K tomu slouží funkce SDL_GetModState, která ale na rozdíl od předchozí funkce nevrací pole, ale ORované hodnoty jednotlivých kláves. Pro vykonání kódu při stisknutém Ctrl použijeme tento kód.

SDL_Keymod mod=SDL_GetModState();
if (mod & KMOD_CTRL)
{
        //jedno z Ctrl je stisknuté
}

Můžeme i ručně nastavit, které z těchto kláves se budou tvářit jako stisknuté. Použijeme k tomu funkci SDL_SetModState. Funkce přijímá jako parametr binárně ORované hodnoty z SDL_Keysym. Klávesy, které nastavíme, budou při příštím volání SDL_GetModState zahrnuty v návratové hodnotě.

Poslední funkcí, kterou můžeme něco zjistit o aktuální situaci, je funkce SDL_GetKeyboar­dFocus. Vrací SDL_Window, které je aktuálně aktivní, a přijímá události vyvolané klávesnicí.

Text

SDL poskytuje i rozhraní pro zachytávání textu. Proč potřebujeme separátní rozhraní pro text, když víme, která klávesa byla stisknuta? Pro text je nepřeberné množství kombinací a klávesnice samotná může mít několik rozvržení. Pokud bychom chtěli každý znak vytvářet ručně, byla by to spousta práce (v současnosti existuje přibližně 110 000 znaků). Toto rozhraní nás od konkrétní implementace odstíní a můžeme pracovat pouze se samotným textem.

Základní funkce jsou SDL_StartTextIn­put a SDL_StopTextIn­put. Po zavolání první funkce SDL začne generovat události typu SDL_TEXTINPUT, popřípadě SDL_TEXTEDITING. SDL_TextInputE­vent má kromě základních atributů pouze jeden vlastní, a tím je text. Ten je ukazatel typu char a je v něm uložený řetězec formátu UTF-8 ukončený nulovým znakem. SDL_TextEditin­gEvent je o něco rozsáhlejší, proto si jej ukážeme.

typedef struct SDL_TextEditingEvent
{
    Uint32 type;
    Uint32 timestamp;
    Uint32 windowID;
    char text[SDL_TEXTEDITINGEVENT_TEXT_SIZE];
    Sint32 start;
    Sint32 length;
} SDL_TextEditingEvent;

Kromě základních atributů obsahuje atribut text, který obsahuje nový text. Dále atribut start (kde editace začíná) a length (délka editovaného textu). Taková je alespoň představa. Z pokusů na Windows jsem zjistil, že SDL_TextEditingEvent se generuje z neznámého důvodu pouze při změně okna, ale nepředává žádné informace. text, start i length jsou 0. Vůbec nebere v potaz backspace, o tom, že bych se chtěl v textu posouvat pomocí šipek ani nemluvě. Nevím jaká je situace na Linuxu a popřípadě na dalších systémech, pokud někdo bude zkoušet program spustit i pod jiným operačním systémem, prosím dejte vědět, jak program reaguje.

Klávesnice na obrazovce

Protože je SDL multiplatformní, a to včetně platformy Android a iOS, může nastat situace, kdy nebudeme mít připojenou fyzickou klávesnici. U tabletů a mobilních telefonů si musíme vystačit se softwarovou klávesnicí, kterou nám poskytuje operační systém. Funkcí SDL_HasScreen­KeyboardSuppor zjistíme, jestli aktuální platforma podporuje klávesnici na obrazovce. Druhou funkcí, která se může hodit, je SDL_IsScreenKe­yboardShown, která vrátí SDL_bool, pokud je klávesnice zobrazena. Klávesnice by se měla automaticky zobrazit při volání SDL_StartTextInput a při SDL_StopTextInput by se měla opět skrýt.

Na Windows 8.1 mi funkcionalita opět nefungovala. I když jsem zapnul klávesnici na obrazovce, klávesnice se ne a ne zobrazit. Pravděpodobně se opět jedná o záležitost konkrétní platformy.

Příklad

V dnešním příkladu jsem připravil ukázku, jak zachytávat právě textový vstup. Při stisku klávesy nahoru se vstup aktivuje, při stisku klávesy dolů se text přestane zapisovat.

V příštím díle se podíváme blíže na myš a její události.


 

Stáhnout

Staženo 209x (9.51 MB)

 

  Aktivity (1)

Článek pro vás napsal patrik.valkovic
Avatar
Věnuji se programování v C++ a C#. Kromě toho také programuji v PHP (Nette) a JavaScriptu.

Jak se ti líbí článek?
Celkem (1 hlasů) :
55555


 


Miniatura
Předchozí článek
SDL - Práce s časovačem
Miniatura
Všechny články v sekci
SDL
Miniatura
Následující článek
SDL - Události myši

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!