SDL: Events
Events
BearbeitenEvents sind das Herzstück von SDL. Jedes Mal, wenn eine Taste betätigt wird, der Joystick bewegt wird oder der Programmierer es einfach so wünscht, wird ein Ereignis generiert und in eine Datenstruktur eingetragen. Auf dieses Ereignis kann das Programm dann so reagieren, dass das Fahrzeug nach links fährt, wenn sich der Joystick nach links bewegt. Um Events zu benutzen muss SDL_Init mit SDL_INIT_VIDEO aufgerufen werden, Sie haben also nur dann Zugriff auf Events, wenn Ihr Video-System erfolgreich eingebunden wird.
Events abfragen
BearbeitenIn diesem Kapitel geht es um die verschiedenen Möglichkeiten, Events abzufragen. Grundsätzlich kann nur dauernd abgefragt werden (das nennt sich Pollen), ob Ereignisse anliegen oder so lange gewartet werden, bis ein Ereignis anliegt.
Pollen
Bearbeitenint SDL_PollEvent (SDL_Event *event);
Gibt 1 zurück, wenn Events in der Eventqueue (eine Datenstruktur, in der SDL_Events aufbewahrt werden) vorhanden sind. Das älteste Event wird in event zurückgegeben und anschließend aus der Eventqueue entfernt. Beispiel:
SDL_Event event; /* Struktur eines Events */ int ende = 0; ... while (!ende) /* Schau nach, ob Events anliegen */ while (SDL_PollEvent (&event)) { /* Solange noch Events vorhanden sind */ switch (event.type) { /* Schau nach, welcher Event eingetroffen ist */ case SDL_KEYDOWN: /* Tastaturevent */ ende = 1; break; case SDL_MOUSEMOTION: /* Mausevent */ ... break; ... default: /* unbeachteter Event */ break; } }
Warten
Bearbeitenint SDL_WaitEvent (SDL_Event *event);
Diese Funktion wartet beliebig lange auf ein Event. Sie gibt 0 zurück, wenn ein Fehler passierte, sonst 1. Beispiel:
SDL_Event event; ... /* Warte, bis Events anliegen */ while (SDL_WaitEvent (&event)) { switch (event.type) { /* Schau nach, welcher Event eingetroffen ist */ case SDL_KEYDOWN: /* Tastaturevent */ ... break; case SDL_MOUSEMOTION: /* Mausevent */ ... break; ... default: /* unbeachteter Event */ break; } }
Vielfalt der Events
BearbeitenJeder Event ist eine Vereinheitlichung aller Events. Das gemeinte Event ist abgelegt im Parameter type.
typedef union { Uint8 type; SDL_ActiveEvent active; SDL_KeyboardEvent key; SDL_MouseMotionEvent motion; SDL_MouseButtonEvent button; SDL_JoyAxisEvent jaxis; SDL_JoyBallEvent jball; SDL_JoyHatEvent jhat; SDL_JoyButtonEvent jbutton; SDL_ResizeEvent resize; SDL_ExposeEvent expose; SDL_QuitEvent quit; SDL_UserEvent user; SDL_SysWMEvent syswm; } SDL_Event;
Liste wichtiger Events
BearbeitenHier ist eine alphabetisch sortierte Liste einiger Event-Typen. Folgende Konstanten können im type-Parameter des Events verwendet werden:
- SDL_JOYAXISMOTION -- Die Axen des Joysticks werden bewegt
- SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP -- Knöpfe des Joysticks werden betätigt
- SDL_KEYDOWN, SDL_KEYUP -- Tasten an der Tastatur werden betätigt
- SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP -- Mausknöpfe werden betätigt
- SDL_MOUSEMOTION -- die Maus wird bewegt
- SDL_QUIT -- Anwendung wird beendet
- SDL_USEREVENT -- ausschließlich für selbstgenerierte Ereignisse
Struktur einiger Events und wie man sie auswertet
BearbeitenDie Erläuterungen sind geordnet nach Event-Typ.
SDL_JOYAXISMOTION
BearbeitenDieses Event ist folgendermaßen aufgebaut:
typedef struct { Uint8 type; Uint8 which; Uint8 axis; Sint16 value; } SDL_JoyAxisEvent;
type ist immer SDL_JOYAXISMOTION, which ist die Nummer des Joysticks, axis die Nummer der Joystickachse, value ein vorzeichenbehafteter Wert, dessen Vorzeichen die Richtung der Bewegung angibt und dessen absolute Zahl bei manchen Joysticks die Auslenkung angibt.
SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP
BearbeitenWerden die Knöpfe eines Joysticks bewegt, so wird ein Event folgender Struktur generiert:
typedef struct { Uint8 type; Uint8 which; Uint8 button; Uint8 state; } SDL_JoyButtonEvent;
type ist entweder SDL_JOYBUTTONDOWN oder SDL_JOYBUTTONUP. which ist die Nummer des Joysticks, button die Knopfnummer. state ist SDL_PRESSED oder SDL_RELEASED, enthält also dieselbe Information wie type.
SDL_KEYDOWN, SDL_KEYUP
BearbeitenDer SDL_KeyboardEvent ist folgendermaßen aufgebaut:
typedef struct { Uint8 type; Uint8 state; SDL_keysym keysym; } SDL_KeyboardEvent;
Das type-Feld enthält die Art des Events, nämlich SDL_KEYDOWN oder SDL_KEYUP. state ist ein Feld, welches die Werte SDL_PRESSED und SDL_RELEASED annehmen kann. Die Felder type und state enthalten also immer dieselbe Information. keysym ist selbst eine Struktur, welche die aktuell gedrückte oder losgelassene Taste enthält. Mit
if (event.key.keysym.sym == SDLK_q) /* "q"-Taste wurde gedrückt */
können Sie eine solche Taste abfragen. Mehr über Tasten erfahren Sie im Kapitel SDL:_Tastatur.
SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP
BearbeitenDas SDL_MouseButtonEvent ist folgendermassen aufgebaut:
typedef struct { Uint8 type; Uint8 button; Uint8 state; Uint16 x, y; } SDL_MouseButtonEvent;
type kann die Werte SDL_MOUSEBUTTONDOWN und SDL_MOUSEBUTTONUP annehmen, button ist der zur Zeit gedrückte Mausknopf (SDL_BUTTON_LEFT, SDL_BUTTON_MIDDLE, SDL_BUTTON_RIGHT, SDL_BUTTON_WHEELUP, SDL_BUTTON_WHEELDOWN). state kann die Werte SDL_PRESSED und SDL_RELEASED annehmen, enthält also die identische Information wie type. Die aktuellen Koordinaten der Maus werden in den Feldern x, y gemeldet. Scrollt man am Mausrad, so werden nacheinander SDL_MOUSEBUTTONDOWN- und SDL_MOUSEBUTTONUP-Events generiert:
case SDL_MOUSEBUTTONDOWN: printf ("Knopf Runter: %d\n", event.button.button); break; case SDL_MOUSEBUTTONUP: printf ("Knopf Hoch: %d\n", event.button.button); break;
SDL_MOUSEMOTION
BearbeitenMausbewegungen werden mit einem eigenen Ereignis angezeigt. Alternativ lässt sich dieses Ereignis auch mit der Funktion SDL_WarpMouse erzeugen. Das SDL_MouseMotionEvent ist folgendermassen aufgebaut:
typedef struct { Uint8 type; Uint8 state; Uint16 x, y; Sint16 xrel, yrel; } SDL_MouseMotionEvent;
type enthält immer SDL_MOUSEMOTION. state ist der Status der Mausknöpfe. x, y sind die aktuellen Koordinaten der Maus, xrel, yrel sind die relativen Koordinaten seit dem letzten SDL_MOUSEMOTION-Event. Unter Linux und Windows gibt es noch eine Besonderheit: Wird der Mauszeiger versteckt (SDL_ShowCursor (SDL_DISABLE)) und die gesamte Eingabe auf das Fenster fokussiert (SDL_WM_GrabInput (SDL_GRAB_ON)), dann werden relative Mauskoordinaten auch dann gemeldet, wenn die Maus über die Fenstergrenzen hinweg bewegt wird. Beispiel:
SDL_ShowCursor (SDL_DISABLE); SDL_WM_GrabInput (SDL_GRAB_ON); while (SDL_WaitEvent (&event)) switch (event.type) { case SDL_MOUSEMOTION: printf ("Absolut: (%d, %d), Relativ: (%d, %d)\n", event.motion.x, event.motion.y, event.motion.xrel, event.motion.yrel); break; ... }
Bitte seien Sie beim Testen dieser Zeilen vorsichtig. SDL_WM_GrabInput (SDL_GRAB_ON) nimmt jeden Event entgegen. Wenn Sie keine Möglichkeit vorsehen, die Event-Schleife abzubrechen, können Sie unter Umständen das Programm nicht beenden...
SDL_QUIT
BearbeitenEin SDL_QUIT-Event wird generiert, wenn entweder das Fenster per Schließen-Knopf in der Titelzeile geschlossen wird oder die Anwendung per SIGTERM beendet wird (kill -15 Prozessnummer, getestet unter Linux). Das SDL_QuitEvent hat folgende Struktur:
typedef struct { Uint8 type } SDL_QuitEvent;
Das Feld type ist hierbei immer SDL_QUIT.
switch (event.type) { case SDL_QUIT: printf ("quit\n"); exit (0); break; ... }
Bitte beachten Sie, dass im Vollbild-Modus kein Schließen-Knopf vorhanden ist. Sie müssen für das Beenden Ihrer Anwendung also auf anderem Wege sorgen, z. B. durch ein Tastaturereignis.
SDL_USEREVENT
BearbeitenSDL_USEREVENT werden ausschließlich vom Programmierer einer SDL-Anwendung, niemals von internen Bereichen der SDL generiert. Sie sind komplett verantwortlich für alle Teile dieses Events. Die Struktur eines SDL_UserEvent ist wie folgt:
typedef struct { Uint8 type; int code; void *data1; void *data2; } SDL_UserEvent;
type kann Werte zwischen SDL_USEREVENT und SDL_NUMEVENTS-1 annehmen. Das ist, je nachdem was Sie vorhaben, eine relativ kleine Spanne von zur Zeit sieben möglichen Events. Viel interessanter ist es da, die frei definierbaren Felder code, data1 und data2 zu benutzen.
Events generieren
BearbeitenEinen Event kann man mit der Funktion
int SDL_PushEvent (SDL_Event *event);
in die Event-Queue einfügen. Diese Funktion erwartet einen Zeiger auf einen ausgefüllten Event und gibt 0 bei Erfolg zurück, sonst -1. Ein Beispiel finden Sie im Kapitel Timer.
Events filtern
BearbeitenMit Hilfe der Funktion
void SDL_SetEventFilter (SDL_EventFilter filter);
können Sie Events bearbeiten, bevor sie in der Event-Queue eintreffen. SDL_EventFilter ist hierbei von funktionalem Typ:
typedef int (*SDL_EventFilter) (const SDL_Event *event);
Wenn Ihre selbstgebaute Event-Filter-Funktion 0 zurückliefert, wird das Event nicht in die Event-Queue eingefügt. Die Funktion kann andernfalls 1 zurückliefern. Events, die mit der Funktion SDL_PushEvent in die Queue eingefügt werden, sind vom Event-Filter nicht betroffen. Das SDL_QUITEVENT wird nur dann bearbeitet, wenn es durch den Schließen-Knopf generiert wurde. Soll das Programm per Interrupt beendet werden, so wie es der Befehl kill tun würde, so wird der Event-Filter umgangen.