SDL Events

October 25th, 2007 by Tim Jones Leave a reply »

Alongside the basics of game development is something called Events. All videogames, from basic free poker applications to the highly complex PC games and console titles, use events to interact with the player. These events can come from keyboards, mice, joysticks, gamepads, and so on, or events from our operating system. It’s important to understand how events work if we are to appropriately interact a user with a game. We’ve already been using events, but only for closing our window, now we’ll look at how to receive events from the user.

If you haven’t caught on, each tutorial builds off the previous, so we’ll be using the code from the previous lesson. In order to track all these events and throw them into nice functions, lets create a new class. Create two files called CEvent.h and CEvent.cpp. These two files will handle our events, and call the appropriate function. CApp will inherit this class, so when we need to catch an event we simply override a function.

Open up CEvent.h and add the following code:

#ifndef _CEVENT_H_
    #define _CEVENT_H_

#include <SDL.h>

class CEvent {
    public:
        CEvent();

        virtual ~CEvent();

        virtual void OnEvent(SDL_Event* Event);

        virtual void OnInputFocus();

        virtual void OnInputBlur();

        virtual void OnKeyDown(SDLKey sym, SDLMod mod, Uint16 unicode);

        virtual void OnKeyUp(SDLKey sym, SDLMod mod, Uint16 unicode);

        virtual void OnMouseFocus();

        virtual void OnMouseBlur();

        virtual void OnMouseMove(int mX, int mY, int relX, int relY, bool Left,bool Right,bool Middle);

        virtual void OnMouseWheel(bool Up, bool Down)//Not implemented

        virtual void OnLButtonDown(int mX, int mY);

        virtual void OnLButtonUp(int mX, int mY);

        virtual void OnRButtonDown(int mX, int mY);

        virtual void OnRButtonUp(int mX, int mY);

        virtual void OnMButtonDown(int mX, int mY);

        virtual void OnMButtonUp(int mX, int mY);

        virtual void OnJoyAxis(Uint8 which, Uint8 axis, Sint16 value);

        virtual void OnJoyButtonDown(Uint8 which, Uint8 button);

        virtual void OnJoyButtonUp(Uint8 which, Uint8 button);

        virtual void OnJoyHat(Uint8 which, Uint8 hat, Uint8 value);

        virtual void OnJoyBall(Uint8 which, Uint8 ball, Sint16 xrel, Sint16 yrel);

        virtual void OnMinimize();

        virtual void OnRestore();

        virtual void OnResize(int w,int h);

        virtual void OnExpose();

        virtual void OnExit();

        virtual void OnUser(Uint8 type, int code, void* data1, void* data2);
};

#endif

Pretty hefty class right? Alright, open up CEvent.cpp, and add the following code:

#include "CEvent.h"

CEvent::CEvent() {
}

CEvent::~CEvent() {
    //Do nothing
}

void CEvent::OnEvent(SDL_Event* Event) {
    switch(Event->type) {
        case SDL_ACTIVEEVENT: {
            switch(Event->active.state) {
                case SDL_APPMOUSEFOCUS: {
                    if ( Event->active.gain )   OnMouseFocus();
                    else                OnMouseBlur();

                    break;
                }
                case SDL_APPINPUTFOCUS: {
                    if ( Event->active.gain )   OnInputFocus();
                    else                OnInputBlur();

                    break;
                }
                case SDL_APPACTIVE: {
                    if ( Event->active.gain )   OnRestore();
                    else                OnMinimize();

                    break;
                }
            }
            break;
        }

        case SDL_KEYDOWN: {
            OnKeyDown(Event->key.keysym.sym,Event->key.keysym.mod,Event->key.keysym.unicode);
            break;
        }

        case SDL_KEYUP: {
            OnKeyUp(Event->key.keysym.sym,Event->key.keysym.mod,Event->key.keysym.unicode);
            break;
        }

        case SDL_MOUSEMOTION: {
            OnMouseMove(Event->motion.x,Event->motion.y,Event->motion.xrel,Event->motion.yrel,(Event->motion.state&SDL_BUTTON(SDL_BUTTON_LEFT))!=0,(Event->motion.state&SDL_BUTTON(SDL_BUTTON_RIGHT))!=0,(Event->motion.state&SDL_BUTTON(SDL_BUTTON_MIDDLE))!=0);
            break;
        }

        case SDL_MOUSEBUTTONDOWN: {
            switch(Event->button.button) {
                case SDL_BUTTON_LEFT: {
                    OnLButtonDown(Event->button.x,Event->button.y);
                    break;
                }
                case SDL_BUTTON_RIGHT: {
                    OnRButtonDown(Event->button.x,Event->button.y);
                    break;
                }
                case SDL_BUTTON_MIDDLE: {
                    OnMButtonDown(Event->button.x,Event->button.y);
                    break;
                }
            }
            break;
        }

        case SDL_MOUSEBUTTONUP: {
            switch(Event->button.button) {
                case SDL_BUTTON_LEFT: {
                    OnLButtonUp(Event->button.x,Event->button.y);
                    break;
                }
                case SDL_BUTTON_RIGHT: {
                    OnRButtonUp(Event->button.x,Event->button.y);
                    break;
                }
                case SDL_BUTTON_MIDDLE: {
                    OnMButtonUp(Event->button.x,Event->button.y);
                    break;
                }
            }
            break;
        }

        case SDL_JOYAXISMOTION: {
            OnJoyAxis(Event->jaxis.which,Event->jaxis.axis,Event->jaxis.value);
            break;
        }

        case SDL_JOYBALLMOTION: {
            OnJoyBall(Event->jball.which,Event->jball.ball,Event->jball.xrel,Event->jball.yrel);
            break;
        }

        case SDL_JOYHATMOTION: {
            OnJoyHat(Event->jhat.which,Event->jhat.hat,Event->jhat.value);
            break;
        }
        case SDL_JOYBUTTONDOWN: {
            OnJoyButtonDown(Event->jbutton.which,Event->jbutton.button);
            break;
        }

        case SDL_JOYBUTTONUP: {
            OnJoyButtonUp(Event->jbutton.which,Event->jbutton.button);
            break;
        }

        case SDL_QUIT: {
            OnExit();
            break;
        }

        case SDL_SYSWMEVENT: {
            //Ignore
            break;
        }

        case SDL_VIDEORESIZE: {
            OnResize(Event->resize.w,Event->resize.h);
            break;
        }

        case SDL_VIDEOEXPOSE: {
            OnExpose();
            break;
        }

        default: {
            OnUser(Event->user.type,Event->user.code,Event->user.data1,Event->user.data2);
            break;
        }
    }
}

void CEvent::OnInputFocus() {
    //Pure virtual, do nothing
}

void CEvent::OnInputBlur() {
    //Pure virtual, do nothing
}

void CEvent::OnKeyDown(SDLKey sym, SDLMod mod, Uint16 unicode) {
    //Pure virtual, do nothing
}

void CEvent::OnKeyUp(SDLKey sym, SDLMod mod, Uint16 unicode) {
    //Pure virtual, do nothing
}

void CEvent::OnMouseFocus() {
    //Pure virtual, do nothing
}

void CEvent::OnMouseBlur() {
    //Pure virtual, do nothing
}

void CEvent::OnMouseMove(int mX, int mY, int relX, int relY, bool Left,bool Right,bool Middle) {
    //Pure virtual, do nothing
}

void CEvent::OnMouseWheel(bool Up, bool Down) {
    //Pure virtual, do nothing
}

void CEvent::OnLButtonDown(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnLButtonUp(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnRButtonDown(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnRButtonUp(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnMButtonDown(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnMButtonUp(int mX, int mY) {
    //Pure virtual, do nothing
}

void CEvent::OnJoyAxis(Uint8 which,Uint8 axis,Sint16 value) {
    //Pure virtual, do nothing
}

void CEvent::OnJoyButtonDown(Uint8 which,Uint8 button) {
    //Pure virtual, do nothing
}

void CEvent::OnJoyButtonUp(Uint8 which,Uint8 button) {
    //Pure virtual, do nothing
}

void CEvent::OnJoyHat(Uint8 which,Uint8 hat,Uint8 value) {
    //Pure virtual, do nothing
}

void CEvent::OnJoyBall(Uint8 which,Uint8 ball,Sint16 xrel,Sint16 yrel) {
    //Pure virtual, do nothing
}

void CEvent::OnMinimize() {
    //Pure virtual, do nothing
}

void CEvent::OnRestore() {
    //Pure virtual, do nothing
}

void CEvent::OnResize(int w,int h) {
    //Pure virtual, do nothing
}

void CEvent::OnExpose() {
    //Pure virtual, do nothing
}

void CEvent::OnExit() {
    //Pure virtual, do nothing
}

void CEvent::OnUser(Uint8 type, int code, void* data1, void* data2) {
    //Pure virtual, do nothing
}
 

Lots of code, but all the SDL events should be covered. What we basically are doing is taking an SDL_Event pointer, and switching through the types, and then calling the appropriate function. It just looks like a lot since they are quite a bit of events.

Now that this has been all setup, let’s jump over to CApp.h and link the two together:

#ifndef _CAPP_H_
    #define _CAPP_H_

#include <SDL.h>

#include "CEvent.h"
#include "CSurface.h"

class CApp : public CEvent {
    private:
        bool            Running;

        SDL_Surface*    Surf_Display;

        SDL_Surface*    Surf_Test;

    public:
        CApp();

        int OnExecute();

    public:
        bool OnInit();

        void OnEvent(SDL_Event* Event);

        void OnLoop();

        void OnRender();

        void OnCleanup();
};

#endif
 

Everything should compile just fine. We have the event class setup, now lets actually link events to our new class structure. Open up CApp_OnEvent.cpp and edit the following function:

#include "CApp.h"

void CApp::OnEvent(SDL_Event* Event) {
    CEvent::OnEvent(Event);
}
 

We’re passing the Event structure to our class now, it will take care of the correct function calls. Now when we want to check for an event, we override the function. Since we got rid of checking for the SDL_QUIT event, lets use the function instead. Open up CApp.h again, and add the following function:

#ifndef _CAPP_H_
    #define _CAPP_H_

#include <SDL.h>

#include "CEvent.h"
#include "CSurface.h"

class CApp : public CEvent {
    private:
        bool            Running;

        SDL_Surface*    Surf_Display;

        SDL_Surface*    Surf_Test;

    public:
        CApp();

        int OnExecute();

    public:
        bool OnInit();

        void OnEvent(SDL_Event* Event);

        void OnExit();

        void OnLoop();

        void OnRender();

        void OnCleanup();
};

#endif
 

The OnExit function handles the SDL_QUIT events. Now that we have the prototype, lets define what it does. Open up CApp_OnEvent.cpp, and add the following:

#include "CApp.h"

void CApp::OnEvent(SDL_Event* Event) {
    CEvent::OnEvent(Event);
}

void CApp::OnExit() {
    Running = false;
}
 

Recompile, and try it out. You should be able to close the application just like before.

I encourage you to look through some of the various events that we can check. Later on we’ll use some of these events in our games, but for now try to familiarize yourself with them.

Jump on over to the next tutorial to take a look at creating our first game, Tic-Tac-Toe.

SDL Events – Tutorial Files:
Win32: Zip, Rar
Linux: Tar (Thanks Gaten)

Share and Enjoy:
  • Digg
  • del.icio.us
  • DZone
  • MisterWong
  • Reddit
  • StumbleUpon
  • Technorati
  • Slashdot
  • LinkedIn
  • MySpace
  • Yahoo! Buzz

Did you like this tutorial/blog post? Feel free to donate to keep more comin', and have more contests.

Advertisement

54 comments

  1. DarkGlitch says:

    Uhh..is there a glitch on this tutorial?

    I keep getting an “illegal call of non-static member” error from VC++ 2008 when I attempt to call CEvent::OnEvent(Event)

    Anyone else having this problem?

  2. Pedro says:

    Never mind, I got it fixed. Thanks anyways.

  3. Pedro says:

    Hello Tim, excellent tutorials for guys like me who are looking for an intuitive and easy-to-follow approach to learning the SDL library with C++. I do have a concern, so here it is.

    I followed this 3rd event tutorial that you showed me and I was able to load my bitmap images just fine until I had to make the change in code…

    From this:

    #include “CApp.h”

    void CApp::OnEvent(SDL_Event* Event) {
    if(Event->type == SDL_QUIT) {
    Running = false;
    }
    }

    To this:

    void CApp::OnEvent(SDL_Event* Event) {
    CEvent::OnEvent(Event);
    }

    Once I changed the code within the OnEvent function from CApp, then “instead” of seeing the window with my picture and the “part” of the picture, the program opens and closes the window immediately. I don’t know what went wrong as I followed your code to the letter. Any help at your earliest convenience would be great!

    Adios!

    –Pedro

  4. Rai says:

    I was thinking that the CEvent::OnEvent call could be refactored to use a Command pattern. Something like storing each handler (one for each SDL_Event) into a hash on creation of CApp and then performing a lookup into that hash using the Event->type as a key. So then your switch/case would be reduced to something like:

    Handler h = lookupHandler(Event->type);
    handler.execute();

    Is there much to gain doing that? I think it might be useful if other events make their way into CEvent.

    • Tim Jones says:

      Hrm – not really sure what you would gain by doing that. If you had other events coming in (not SDL related) – then this would allow you to combine the two under a single system (which is what I assume you meant by “other events make their way into CEvent”). But, you could always push your own custom events into the SDL_Event queue. Perhaps it would be something worthy of exploring and you might find some uses for it.

  5. atctex says:

    In some situations we also can explicitely specify in which ?::OnEvent method we want to use [inside CApp.cpp ]


    while(SDL_PollEvent(&event)) {
    SdlApp::OnEvent(&Event);

  6. ill says:

    uh.. why does the program end (or crash maybe ) when minimized?

Trackbacks /
Pingbacks

Leave a Reply