Stisk tlačítka myši
Vždy, když uživatel stiskne některé tlačítko myši, vygeneruje SDL dvě události – SDL_MOUSEBUTTONDOWN a SDL_MOUSEBUTTONUP. První z nich je odeslána při stisku a druhá při uvolnění. V obou případech se podrobnosti o události hledají v podobjektu event.button, který byl odvozen ze struktury SDL_MouseButtonEvent.
typedef struct
{
Uint8 type;
Uint8 button;
Uint8 state;
Uint16 x, y;
} SDL_MouseButtonEvent;
Atribut type je klasicky nastaven na jméno události a proměnná button ukládá jméno tlačítka, což je jedna ze symbolických konstant SDL_BUTTON_LEFT, SDL_BUTTON_MIDDLE a SDL_BUTTON_RIGHT. Ve verzi 1.2.5 SDL dále přibyla jména SDL_BUTTON_WHEELUP a SDL_BUTTON_WHEELDOWN, která oznamují točení rolovacím kolečkem nahoru a dolů.
Stejně jako u klávesnice, i zde může být state nastaveno na SDL_PRESSED nebo SDL_RELEASED, tuto informaci však už máme k dispozici z parametru type. Proměnné x a y poskytují pozici myši v klientské oblasti okna při stisku, bod [0, 0] se nachází v levém horním rohu.
V následujícím příkladu program zachytává stisk levého tlačítka myši a jako reakci vypíše do konzole informaci o pozici v okně.
// Ošetření událostí
case SDL_MOUSEBUTTONDOWN:
switch(event.button.button)
{
case SDL_BUTTON_LEFT:
printf("BUTTON_LEFT - pos(%d,%d)\n",
event.button.x,
event.button.y);
fflush(stdout);
break;
default:
break;
}
break;
Výstup programu po dvou stisknutích levého tlačítka:
BUTTON_LEFT - pos(65,103)
BUTTON_LEFT - pos(91,104)
Událost pohybu myší
Pohyb myší oznamuje SDL zprávou SDL_MOUSEMOTION, podrobnosti se následně hledají v objektu event.motion odvozeném od SDL_MouseMotionEvent.
typedef struct
{
Uint8 type;
Uint8 state;
Uint16 x, y;
Sint16 xrel, yrel;
} SDL_MouseMotionEvent;
Proměnná state definuje stavy tlačítek při pohybu. Pro zjištění, které je stisknuté a které ne, může být výhodné použít makro SDL_BUTTON(). Parametry x a y specifikují pozici kurzoru myši v okně, xrel a yrel obsahují relativní hodnotu posunu.
Po příchodu události o pohybu myši v příkladu níže vypíše program absolutní polohu kurzoru v okně, změnu polohy od minula a případně informaci o stisku tlačítek.
// Ošetření událostí
case SDL_MOUSEMOTION:
printf("MOUSEMOTION - pos(%d,%d), relpos(%d,%d)%s%s%s\n",
event.motion.x, event.motion.y,
event.motion.xrel, event.motion.yrel,
(event.motion.state & SDL_BUTTON(SDL_BUTTON_LEFT))
? ", left" : "",
(event.motion.state & SDL_BUTTON(SDL_BUTTON_MIDDLE))
? ", middle" : "",
(event.motion.state & SDL_BUTTON(SDL_BUTTON_RIGHT))
? ", right" : "");
fflush(stdout);
break;
Pokud je program spuštěn, začnou se při pohybování myší generovat výpisy podobné následujícím.
MOUSEMOTION - pos(130,91), relpos(4,0)
MOUSEMOTION - pos(134,91), relpos(4,0)
MOUSEMOTION - pos(138,91), relpos(4,0)
MOUSEMOTION - pos(136,91), relpos(-2,0), left
MOUSEMOTION - pos(132,93), relpos(-4,2), left, right
MOUSEMOTION - pos(130,93), relpos(-2,0), left, right
MOUSEMOTION - pos(128,95), relpos(-2,2), left, right
„Přímý“ přístup k myši
Stejně jako u klávesnice je i u myši možné používat metody přímého přístupu. Lze se tedy kdekoli v programu dotázat na aktuální polohu kurzoru nebo stisk tlačítek.
Uint8 SDL_GetMouseState(int *x, int *y);
Tato funkce uloží na adresu ukazatelů v parametrech aktuální polohu myši v okně a vrátí bitové pole tlačítkových flagů. Pro rozlišení, které je stisknuté a které ne, je opět nejjednodušší použít bitový součin s makrem SDL_BUTTON(). Pokud nás zajímají pouze tlačítka, je možné předat do parametrů hodnoty NULL.
Před samotným přístupem k myši bývá vhodné zavolat funkci SDL_PumpEvents(), která aktualizuje informace v SDL.
Podobným způsobem se lze dotazovat i na relativní změny polohy od minulého volání této funkce nebo od zpracování události o pohybu myši.
Uint8 SDL_GetRelativeMouseState(int *x, int *y);
Do proměnných x a y bude v příkladu níže uložena aktuální poloha myši, kód v sekci if se provede jen tehdy, je-li stisknuto levé tlačítko.
// Kdekoli v programu
int x, y;
SDL_PumpEvents();
if(SDL_GetMouseState(&x, &y) & SDL_BUTTON(SDL_BUTTON_LEFT))
printf("Levé tlačítko na %d, %d.\n", x, y);
Ruční změna polohy myši
Novou polohu myši lze specifikovat voláním funkce SDL_WarpMouse(), do parametrů se předávají požadované x a y souřadnice.
void SDL_WarpMouse(Uint16 x, Uint16 y);
Tato funkce má jeden vedlejší efekt, způsobuje generování události SDL_MOUSEMOTION, což může být někdy, kvůli zacyklení, nežádoucí (v reakci na událost se ošetří změna polohy a myš se přesune na nové místo, tím se generuje další událost, která se opět ošetří, myš se přesune atd.). Asi nejjednodušší řešení spočívá v ignorování této „přebytečné“ události.
Při změnách natočení kamery ve 3D akčních hrách končí ošetření každého pohybu myši nastavením její polohy zpět na střed okna. Je to z důvodu, že kdyby opustila okno, mohlo by ztratit fokus (většinou po kliknutí na jiné okno při střelbě) a operační systém by v takovém případě přestal posílat zprávy. Hra by se každou chvíli stávala nehratelnou.
Implementace rotace kamery v závislosti na pohybech myši by mohla vypadat následovně.
// Ošetření událostí
case SDL_MOUSEMOTION:
// SDL_WarpMouse() generuje SDL_MOUSEMOTION,
// bez testu na střed okna by se aplikace zacyklila
if(event.motion.x != GetWinWidth() >> 1
|| event.motion.y != GetWinHeight() >> 1)
{
m_cam.Rotate(event.motion.xrel,
event.motion.yrel, GetFPS());
// Přesun zpět doprostřed okna
SDL_WarpMouse(GetWinWidth() >> 1,
GetWinHeight() >> 1);
}
break;
Všimněte si především ignorování událostí, které generuje funkce SDL_WarpMouse(). Mimochodem, tento kód jsme použili v příkladu Pohyb v mřížce z osmého dílu. Jedná se o metodu QGridApp::ProcessEvent(SDL_Event& event).
Další možností by mohl být zákaz pro myš opustit okno aplikace, zbavili bychom se tak neustálého měnění její polohy a následného rozlišování validity událostí. V SDL stačí zavolat funkci SDL_WM_GrabInput() s parametrem SDL_GRAB_ON (popsána v desátém dílu), v některých jiných knihovnách však takové vymoženosti nejsou.
Barevné kurzory
Ještě jedna specialitka na závěr. V sedmém dílu jsme si ukázali, jak požádat SDL, aby změnilo kurzor myši ze standardní šipky na jiný. Tato technika však měla tu nevýhodu, že kurzor mohl být pouze černobílý.
V tuto chvíli však už máme dostatek znalostí, abychom standardní kurzor myši vypnuli a vykreslovali si vlastní, na nějž už nejsou kladena žádná omezení.
// Pro vycentrování obrázku na aktivní bod kurzoru
// U šipek levý horní roh, u zaměřovačů střed apod.
#define POSUN_DOLEVA 0
#define POSUN_NAHORU 0
// Inicializace, skryje kurzor
SDL_ShowCursor(0);
// Vykreslování (kurzor by se měl vždy kreslit jako poslední)
SDL_Rect rect;
SDL_GetMouseState(&rect.x, &rect.y);
rect.x -= POSUN_DOLEVA;
rect.y -= POSUN_NAHORU;
SDL_BlitSurface(g_cur_press, NULL, g_screen, &rect);
Tento kód předpokládá, že se scéna periodicky překresluje, nejlépe v „klasické“ herní smyčce nebo v reakci na pohyb myši, a pokaždé se kreslí úplně všechno.
Ukázkové programy
Kostky
Program zobrazuje v dolní části okna spoustu kostiček, které lze kliknutím myši zachytit a následně s nimi pohybovat. Jsou implementovány i kolize a také vlastní barevný kurzor, jenž se po kliknutí na nějakou kostku změní na jiný. (Zdrojový kód se zvýrazněním syntaxe.)
![SDL 13](https://i.iinfo.cz/urs/13_prog_a-111623527592169.png)
Download
Pokračování
Minule klávesnice, teď myš, takže přístě bude na řadě joystick…