Linux Game Programming for PC & Embedded Systems using SDL
Presented by
Fore June
Author of Windows Fan, Linux Fan

Games and SDL
SDL Installation
SDL for Embedded
SDL API
SDL Events
 SDL Graphics
SDL Threads
Thread Example
SDL Animation
SDL Sound
 Raw Video Player
Video Formats
Video Compression
 Game Trees
About The Author
@Copyright by Fore June, 2006

SDL Events

    Programs that operate in a GUI environment are event-driven. An event is an action that takes place within a program when something happens. Part of writing a GUI application is to create event listeners. An event listener is an object or a loop that triggers certain action when a specific event occurs. In the SDL programming environment, an event is produced whenever you move or click the mouse, press a key, or resize the SDL video window. Event handling allows your application to receive input from the user. SDL stores unprocessed events in an internal event queue which allows SDL to collect as many events as possible each time it updates an event. Using functions like SDL_PollEvent, SDL_PeepEvents and SDL_WaitEvent you can observe and handle waiting input events.

    There are four main categories of events: keyboard, mouse, window, and system-dependent events. Window events handle gaining and losing focus, as well as exit requests. System-dependent events process raw messages from the windowing system that SDL otherwise would ignore. Information of an event is stored in the structure type SDL_Event. The event queue itself is composed of a series of SDL_Event unions, one for each waiting event. SDL_Event unions are read from the queue with the SDL_PollEvent function and it is then up to the application to process the information stored with them.

    The SDL event subsystem is intertwined with the video subsystem. We basically cannot separate the use of them. Therefore, they are both initialized with SDL_INIT_VIDEO parameter to SDL_Init().

  1. Event Processing
    To process an event, you need to read the SDL_Event unions from the event queue using the SDL_PollEvent() or SDL_WaitEvent() function. You can also add events onto the event queue using SDL_PushEvent(), which returns 0 on success or -1 on failure. The following are some typical techniques that people use to handle events.
    Waiting for events

    You can wait for events to occur using the SDL_WaitEvent() function, which waits indefinitely and returns only if an event or an error has occurred.

    Synopsis     #include "SDL.h"
    int SDL_WaitEvent(SDL_Event *event);
    Description     Waits indefinitely for the next available event.
     
    Returns     0 if there was an error while waiting for events, 1 otherwise. Information of the event detected will be stored in the structure pointed by event and the event is removed from the event queue.
     

     
    Tip:
    SDL has international keyboard support, translating key events and placing the UNICODE equivalents into event.key.keysym.unicode. Since this has some processing overhead involved, it must be enabled using SDL_EnableUNICODE().

    Example:
    /*
    waitevent.cpp
    
    compile by: g++ -o waitevent waitevent.cpp -I/usr/include -L/usr/local/lib -lSDL
    executed by: ./waitevent
    */
    
    #include <SDL/SDL.h>
    #include <stdlib.h>
    
    bool wait_for_events ()
    {
      SDL_Event event;
      int status;
      char *key;
      bool quit = false;
    
      printf("waiting for events, press 'q' or 'ESC' to quit\n");
      while ( !quit ) {				
        status = SDL_WaitEvent(&event);	//wait indefinitely for an event to occur
    					//event will be removed from event queue
        if ( !status ) {			//Error has occurred while waiting
    	printf("SDL_WaitEvent error: %s\n", SDL_GetError());
    	return false;
        }
        switch (event.type) {		//check the event type
          case SDL_KEYDOWN:			//if a key has been pressed
    	key = SDL_GetKeyName(event.key.keysym.sym);
        	printf("The %s key was pressed!\n", key );
    	if ( event.key.keysym.sym == SDLK_ESCAPE )	//quit if 'ESC' pressed
    	  quit = true;
        	else if ( key[0] == 'q'  )	//quit if 'q'  pressed
    	  quit = true;			//same as "if ( event.key.keysym.sym == SDLK_q )"
        	break;
           case SDL_MOUSEMOTION:             //mouse moved
            printf("Mouse motion x:%d, y:%d\n", event.motion.x, event.motion.y );
            break;
          case SDL_MOUSEBUTTONUP:           //mouse button pressed
            printf("Mouse pressed x:%d, y:%d\n", event.button.x, event.button.y );
            break; 
         case SDL_QUIT:			//'x' of Window clicked
    	  exit ( 1 );
        	break;
        }
      } //while
      return true;
    }
    
    int main()
    {   
      SDL_Surface *screen;
    
      //initialize the event subsystem along with video system
      if ( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
            fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError());
            exit(1);
      }
      //ensure SDL_Quit is called when the program exits
      atexit(SDL_Quit);
       
      //set video mode of 640 x 480 with 16-bit pixels
      screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);
      if ( screen == NULL ) {
            fprintf(stderr, "Unable to set 640x480 video: %s\n", SDL_GetError());
            exit(1);
      }
      
      wait_for_events();
      
      return 0;
    }
    

    Keyboard and Mouse Events

    In the above example, it prints out the key you have pressed and exits if you have pressed 'ESC' or 'q'. The function SDL_GetKeyName() is used to get the name of the key being pressed. SDL assigns a virtual keysym to each key on the keyboard. A preprocessor symbol is used to map to each virtual keysym. For example, Escape key corresponds to the symbol SDLK_ESCAPE; key 'q' corresponds to SDLK_q. Virtual keysyms are of type SDLKey. Virtual keysyms treat the special keys like Ctrl, Alt, and Shift as ordinary keys. You can find their keysyms in the header file SDL_keysym.h. However, those keys are also considered as modifier keys which are represented by ORed bit flags. For example, the flag for a combination of right Ctrl and Alt keys would be ( KMOD_RCTRL | KMOD_RALT ).

    A mouse event is generated when you move the move or click on one of its buttons. A mouse reports changes in its position with respect to a fixed unit of measure, called a mickey. For example, a movement 1 inch right and two inches down may correspond to 200 horizontal mouse units and -400 vertical mouse units.

    The following are some often used events generated by a mouse or a keyboard.

    SDL_QUIT - user clicked little x button in the corner of a window mode.
    SDL_KEYDOWN - key pressed, stored in the key member of SDL_Event
    SDL_KEYUP - key released, stored in the key member of SDL_Event
    SDL_MOUSEDOWN - mouse button pressed, stored in button member of SDL_Event
    SDL_MOUSEUP - mouse button released, stored in button member of SDL_Event
    SDL_MOUSEMOTION - mouse moved, stored in motion member of SDL_Event

    For keyboard events, the data are stored in the key event of SDL_Event. A few of the more useful SDLKey's include

    SDLK_RETURN
    SDLK_ESCAPE
    SDLK_SPACE
    SDLK_0
    SDLK_1
    ...
    SDLK_9
    SDLK_a
    SDLK_b
    SDLK_c
    ...
    SDLK_z
    

    The button structure for Mouse up and down is a SDL_MouseButtonEvent structure and has 5 members. The x and y members store the coordinates for the cursor, with ( 0, 0 ) at the upper left corner and the screen is positive. The button member can be SDL_BUTTON_LEFT, SDL_BUTTON_MIDDLE, or SDL_BUTTON_RIGHT. The type member stores SDL_MOUSEBUTTONDOWN or SDL_MOUSEBUTTONUP and state stores SDL_PRESSED and SDL_RELEASED.

    The motion member is an SDL_MouseMotionEvent structure. This has the x and y coordinates of the mouse, and xrel and yrel as relative motion in the x and y direction. along with type (always SDL_MOUSEMOTION)

    Synopsis     SDL_MouseButtonEvent -- Mouse button event structure
    Definition    
    typedef struct{
      Uint8 type;		//SDL_MOUSEBUTTONDOWN or SDL_MOUSEBUTTONUP
      Uint8 button;		//Mouse button index (SDL_BUTTON_LEFT, SDL_BUTTON_MIDDLE,
     			//SDL_BUTTON_RIGHT, SDL_BUTTON_WHEELUP, SDL_BUTTON_WHEELDOWN)
      Uint8 state;		//SDL_PRESSED or SDL_RELEASED
      Uint16 x, y;		//The X/Y coordinates of the mouse at press/release time
    } SDL_MouseButtonEvent;
    
    Description     A member of the SDL_Event union and is used when an event of type SDL_MOUSEBUTTONDOWN or SDL_MOUSEBUTTONUP is reported.

    The following are some useful related functions.

    SDL_WarpMouse(Uint26 x, Uint16 y) warp the mouse to the given location and generate a SDL_MOUSEMOTION event.
    Uint8 *SDL_GetKeyState(int *numkeys) if numkeys is NULL, then all the keys will be returned, otherwise just the first numkeys. The return value is a pointer to an array of keystates, where the SDLKey values are the indexes (SDLK_RETURN, SDLK_p, ...)
    For example,
      Uint8 *keystate = SDL_GetKeyState(NULL);
      if (keystate[SDLK_RETURN]) { printf("Return Key Pressed"); }
    SDLMod SDL_GetModState() returns the current state of modifier keys (shift, alt, etc.) where SDLMod is an enum, some values including, KMOD_NONE, KMOD_LSHIFT, KMOD_RSHIFT, KMOD_LALT, KMOD_RALT, KMOD_CAPS. A complete list can be found from SDL_GetModState man page.
    char *SDL_GetKeyName ( SDLKey key ) returns a char pointer to the key.
    int SDL_EnableKeyRepeat ( int delay, int interval ) sets the key repeat rate. If idelay is 0, repeating is disabled. Two good values for this function are SDL_DEFAULT_REPEAT_DELAY and SDL_DEFAULT_REPEAT_INTERVAL. This returns 0 on success and -1 on failure.

    As we mentioned in an earlier chapter, SDL does not support USB devices. If you need to a USB keyboard or mouse for your embedded system, minor modifications of the SDL library are needed; we shall discuss the required modifications in a later chapter.

    Polling for events

    You can poll for events using the SDL_PollEvent() function.

      Tip:
    You can peek at events in the event queue without removing them by passing the SDL_PEEKEVENT action to SDL_PeepEvents().

    Example:
    {
      SDL_Event event;
    
      while ( SDL_PollEvent(&event) ) {
        switch (event.type) {
          case SDL_MOUSEMOTION:
    	printf("Mouse moved by %d,%d to (%d,%d)\n", 
    	       event.motion.xrel, event.motion.yrel,
    	       event.motion.x, event.motion.y);
    	break;
          case SDL_MOUSEBUTTONDOWN:
    	printf("Mouse button %d pressed at (%d,%d)\n",
    	       event.button.button, event.button.x, event.button.y);
    	break;
          case SDL_QUIT:
    	exit(0);
        }
      }
    } 

    Polling event state

    In addition to handling events directly, each type of event has a function which allows you to check the application event state. If you use this exclusively, you should ignore all events with the SDL_EventState() function, and call SDL_PumpEvents() periodically to update the application event state.

       

    Tip:
    You can hide or show the system mouse cursor using SDL_ShowCursor().

    Example:
    {
      SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
    }
    
    void CheckMouseHover(void)
    {
      int mouse_x, mouse_y;
    
      SDL_PumpEvents();
    
      SDL_GetMouseState(&mouse_x, &mouse_y);
      if ( (mouse_x < 32) && (mouse_y < 32) ) {
        printf("Mouse in upper left hand corner!\n");
      }
    }