/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Patrick Boenzli co-programmer: */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_EVENT #include "event_handler.h" #include "event_listener.h" #include "event.h" #include "key_mapper.h" #include "compiler.h" #include "debug.h" #include "class_list.h" #include "t_stack.h" using namespace std; /** * standard constructor */ EventHandler::EventHandler () { this->setClassID(CL_EVENT_HANDLER, "EventHandler"); this->setName("EventHandler"); SDL_InitSubSystem(SDL_INIT_JOYSTICK); SDL_InitSubSystem(SDL_INIT_EVENTTHREAD); SDL_SetEventFilter(EventHandler::eventFilter); /* now initialize them all to zero */ this->flush(ES_ALL); this->withUNICODE(false); this->grabEvents(false); this->state = ES_GAME; this->keyMapper = NULL; this->stateStack = NULL; } /** * the singleton reference to this class */ EventHandler* EventHandler::singletonRef = NULL; /** * standard deconstructor */ EventHandler::~EventHandler () { for(int i = 0; i < ES_NUMBER; ++i) { for(int j = 0; j < EV_NUMBER; ++j) { if( this->listeners[i][j] != NULL) { PRINTF(2)("forgot to unsubscribe an EventListener!\n");// %s!\n", this->listeners[i][j]->getName()); } } } delete this->stateStack; delete this->keyMapper; SDL_QuitSubSystem(SDL_INIT_JOYSTICK); EventHandler::singletonRef = NULL; } /** * initializes the event handler * * this has to be called before the use of the event handler */ void EventHandler::init(IniParser* iniParser) { if (this->keyMapper == NULL) { this->keyMapper = new KeyMapper(); this->keyMapper->loadKeyBindings(iniParser); } if (this->stateStack == NULL) this->stateStack = new tStack; } /** * pushes the current State in the State-stack, and selects state * @param state the new State to set */ void EventHandler::pushState(elState state) { if (likely(state != ES_NULL && state != ES_ALL && this->stateStack != NULL)) { this->stateStack->push(this->state); this->setState(state); } else { PRINTF(2)("unable to push State\n"); } } /** * this removes the topmost stack-entry and select the underlying one * @returns the next stack-entry */ elState EventHandler::popState() { if (unlikely(this->stateStack == NULL)) return ES_NULL; elState state = (elState)this->stateStack->pop(); if (state == ES_NULL) { PRINTF(2)("No more states availiable. (unable to pop state)\n"); return ES_NULL; } else { this->setState(state); return state; } } /** * subscribe to an event * @param el: the event listener that wants to subscribe itself, the listener that will be called when the evetn occures * @param state: for which the listener wants to receive events * @param eventType: the event type that wants to be listened for. This is one of the most important function of the EventHandler. If you would like to subscribe for more than one state, you have to subscribe for each state again. If you want to subscribe for all states, use state = ES_ALL, which will subscribe your listener for all states together. */ void EventHandler::subscribe(EventListener* el, elState state, int eventType) { PRINTF(4)("Subscribing event type: %i\n", eventType); if( state == ES_ALL ) { for(unsigned int i = 0; i < ES_NUMBER; i++) if( likely(this->listeners[i][eventType] == NULL)) this->listeners[i][eventType] = el; else PRINTF(2)("%s of class %s tried to subscribe to event %i @ state %i but this event has already been subscribed\n", el->getName(), el->getClassName(), eventType, state); } else if( likely(this->listeners[state][eventType] == NULL)) { this->listeners[state][eventType] = el; } else PRINTF(2)("% of class %s tried to subscribe to event %i @ state %i but this event has already been subscribed\n", el->getName(), el->getClassName(), eventType, state); } /** * unsubscribe from the EventHandler * @param state: the stat in which it has been subscribed * @param eventType: the event, that shall be unsubscribed if you want to unsubscribe an event listener from all subscribed events, just use the unsubscribe(EventListener* el, elState state) function */ void EventHandler::unsubscribe(elState state, int eventType) { PRINTF(4)("Unsubscribing event type nr: %i\n", eventType); if (state == ES_ALL) for (unsigned int i = 0; i < ES_NUMBER; i++) this->listeners[i][eventType] = NULL; else this->listeners[state][eventType] = NULL; } /** * unsubscribe all events from a specific listener * @param el: the listener that wants to unsubscribe itself * @param state: the state in which the events shall be unsubscribed */ void EventHandler::unsubscribe(EventListener* el, elState state) { if( el == NULL || state >= ES_NUMBER) return; if( state == ES_ALL) { for(unsigned int i = 0; i < ES_NUMBER; i++) { for(unsigned int j = 0; j < EV_NUMBER; j++) { if( this->listeners[i][j] == el ) this->listeners[i][j] = NULL; } } } else { for(int j = 0; j < EV_NUMBER; j++) { if( this->listeners[state][j] == el ) this->listeners[state][j] = NULL; } } } /** * flush all registered events * @param state: a specific state */ void EventHandler::flush(elState state) { if( state == ES_ALL) { for(int i = 0; i < ES_NUMBER; ++i) { for(int j = 0; j < EV_NUMBER; ++j) { this->listeners[i][j] = NULL; } } } else { for(int j = 0; j < EV_NUMBER; ++j) { this->listeners[state][j] = NULL; } } } void EventHandler::withUNICODE(bool enableUNICODE) { SDL_EnableUNICODE(enableUNICODE); this->bUNICODE = enableUNICODE; } void EventHandler::grabEvents(bool grabEvents) { this->eventsGrabbed = grabEvents; if(!grabEvents) SDL_WM_GrabInput(SDL_GRAB_OFF); else SDL_WM_GrabInput(SDL_GRAB_ON); } /** * core function of event handler: receives all events from SDL The event from the SDL framework are collected here and distributed to all listeners. */ void EventHandler::process() { SDL_Event event; Event ev; EventListener* listener = NULL; while( SDL_PollEvent (&event)) { switch( event.type) { case SDL_KEYDOWN: ev.bPressed = true; ev.type = event.key.keysym.sym; if (unlikely(this->bUNICODE)) ev.x = event.key.keysym.unicode; break; case SDL_KEYUP: ev.bPressed = false; ev.type = event.key.keysym.sym; if (unlikely(this->bUNICODE)) ev.x = event.key.keysym.unicode; break; case SDL_MOUSEMOTION: ev.bPressed = false; ev.type = EV_MOUSE_MOTION; ev.x = event.motion.x; ev.y = event.motion.y; ev.xRel = event.motion.xrel; ev.yRel = event.motion.yrel; break; case SDL_MOUSEBUTTONUP: ev.bPressed = false; ev.type = event.button.button + SDLK_LAST; break; case SDL_MOUSEBUTTONDOWN: ev.bPressed = true; ev.type = event.button.button + SDLK_LAST; break; case SDL_JOYAXISMOTION: ev.bPressed = false; ev.type = EV_JOY_AXIS_MOTION; break; case SDL_JOYBALLMOTION: ev.bPressed = false; ev.type = EV_JOY_BALL_MOTION; break; case SDL_JOYHATMOTION: ev.bPressed = false; ev.type = EV_JOY_HAT_MOTION; break; case SDL_JOYBUTTONDOWN: ev.bPressed = true; ev.type = EV_JOY_BUTTON; break; case SDL_JOYBUTTONUP: ev.bPressed = true; ev.type = EV_JOY_BUTTON; break; case SDL_VIDEORESIZE: ev.resize = event.resize; ev.type = EV_VIDEO_RESIZE; break; case SDL_QUIT: ev.type = EV_MAIN_QUIT; break; default: ev.type = EV_UNKNOWN; break; } /* small debug routine: shows all events dispatched by the event handler */ PRINT(4)("\n==========================| EventHandler::process () |===\n"); PRINT(4)("= Got Event nr %i, for state %i", ev.type, this->state); listener = this->listeners[this->state][ev.type]; if( listener != NULL) { PRINT(4)("= Event dispatcher msg: This event has been consumed\n"); PRINT(4)("=======================================================\n"); listener->process(ev); } else { PRINT(4)("= Event dispatcher msg: This event has NOT been consumed\n"); PRINT(4)("=======================================================\n"); } } } int EventHandler::eventFilter(const SDL_Event *event) { if (event->type == SDL_KEYDOWN && event->key.keysym.sym == SDLK_TAB && SDL_GetKeyState(NULL)[SDLK_LALT]) { printf("Not sending event to the WindowManager\n"); return 0; } return 1; } /** * outputs some nice information about the EventHandler */ void EventHandler::debug() const { PRINT(0)("===============================\n"); PRINT(0)(" EventHandle Debug Information \n"); PRINT(0)("===============================\n"); for(int i = 0; i < ES_NUMBER; ++i) for(int j = 0; j < EV_NUMBER; ++j) if( this->listeners[i][j] != NULL) PRINT(0)("Event %d of State %d subscribed to %s (%p)\n", j, i, this->listeners[i][j]->getName(), this->listeners[i][j]); PRINT(0)("============================EH=\n"); }