Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/event/event_handler.cc @ 8599

Last change on this file since 8599 was 8490, checked in by patrick, 19 years ago

merged the bsp branche back to trunk

File size: 14.5 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Patrick Boenzli
13   co-programmer:
14*/
15
16#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_EVENT
17
18#include "event_handler.h"
19
20#include "event_listener.h"
21#include "event.h"
22#include "key_mapper.h"
23#include "key_names.h"
24
25#include "compiler.h"
26#include "debug.h"
27#include "class_list.h"
28
29#include <algorithm>
30
31/**
32 * @brief standard constructor
33 */
34EventHandler::EventHandler ()
35{
36  this->setClassID(CL_EVENT_HANDLER, "EventHandler");
37  this->setName("EventHandler");
38
39  SDL_InitSubSystem(SDL_INIT_JOYSTICK);
40  SDL_InitSubSystem(SDL_INIT_EVENTTHREAD);
41  SDL_SetEventFilter(EventHandler::eventFilter);
42
43
44  /* now initialize them all to zero */
45  for (unsigned int i = 0; i < ES_NUMBER; i++)
46    this->bUNICODE[i] = false;
47  this->grabEvents(false);
48
49  this->state = ES_GAME;
50  this->eventsGrabbed = false;
51}
52
53
54/**
55 * @brief the singleton reference to this class
56*/
57EventHandler* EventHandler::singletonRef = NULL;
58
59
60/**
61 * @brief standard deconstructor
62 */
63EventHandler::~EventHandler ()
64{
65  bool forgotToUnsubscribe = false;
66
67  for(int i = 0; i < ES_NUMBER; ++i)
68  {
69    for(int j = 0; j < EV_NUMBER; ++j)
70    {
71      if(!this->listeners[i][j].empty())
72      {
73        if (!forgotToUnsubscribe)
74        {
75          forgotToUnsubscribe = true;
76          PRINTF(2)("forgot to unsubscribe an EventListener!\n");// %s!\n", this->listeners[i][j]->getName());
77        }
78      }
79    }
80  }
81
82  if (forgotToUnsubscribe)
83  {
84    PRINTF(2)("Listing still subscribed EventListeners\n");
85    PRINTF(2)("========================================\n");
86    this->debug();
87    PRINTF(2)("========================================\n");
88  }
89
90  SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
91
92  EventHandler::singletonRef = NULL;
93}
94
95
96/**
97 * @brief initializes the event handler
98 *
99 * this has to be called before the use of the event handler
100*/
101void EventHandler::init()
102{
103  this->keyMapper.loadKeyBindings();
104}
105
106/**
107 * @param state: to which the event handler shall change
108 */
109void EventHandler::setState(elState state)
110{
111  if (state == this->state)
112    return;
113
114  PRINTF(4)("Switching to State %s\n", EventHandler::ELStateToString(state).c_str());
115
116  /// When Changing the State, all the keys will be released.
117  /// This is done by sending each eventListener, that still
118  /// has an Event subscribed, a Release Event.
119  int keyCount;
120  Uint8 * pressedKeys = SDL_GetKeyState(&keyCount);
121  for (unsigned int i = 0; i < SDLK_LAST; i++)
122  {
123    if (pressedKeys[i])
124    {
125      Event ev;
126      ev.bPressed = false;
127      ev.type = i;
128      if (unlikely(this->bUNICODE[this->state]))
129        ev.x = i;
130      this->dispachEvent(this->state, ev );
131    }
132  }
133
134  // switching to the new State.
135  elState oldState = this->state;
136  this->state = state;
137
138  // in the End the Corresponding handler will be notified.
139  Event stateSwitchEvent;
140  stateSwitchEvent.type = EV_LEAVE_STATE;
141  this->dispachEvent(oldState, stateSwitchEvent);
142
143  SDL_EnableUNICODE(this->bUNICODE[state]);
144};
145
146
147/**
148 * @brief pushes the current State in the State-stack, and selects state
149 * @param state the new State to set
150 */
151void EventHandler::pushState(elState state)
152{
153  if (likely(state != ES_NULL && state != ES_ALL ))
154  {
155    this->stateStack.push(this->state);
156    this->setState(state);
157  }
158  else
159  {
160    PRINTF(2)("unable to push State\n");
161  }
162}
163
164/**
165 * @brief this removes the topmost stack-entry and select the underlying one
166 * @returns the next stack-entry
167 */
168elState EventHandler::popState()
169{
170  if (stateStack.empty())
171    return ES_NULL;
172  elState state =  (elState)stateStack.top();
173  this->stateStack.pop();
174  if (state == ES_NULL)
175  {
176    PRINTF(2)("No more states availiable. (unable to pop state)\n");
177    return ES_NULL;
178  }
179  else
180  {
181    this->setState(state);
182    return state;
183  }
184}
185
186
187/**
188 * @brief subscribe to an event
189 * @param el: the event listener that wants to subscribe itself, the listener that will be called when the evetn occures
190 * @param state: for which the listener wants to receive events
191 * @param eventType: the event type that wants to be listened for.
192
193   This is one of the most important function of the EventHandler. If you would like to subscribe for more
194   than one state, you have to subscribe for each state again. If you want to subscribe for all states, use
195   state = ES_ALL, which will subscribe your listener for all states together.
196 */
197void EventHandler::subscribe(EventListener* el, elState state, int eventType)
198{
199  PRINTF(4)("Subscribing event type: %i\n", eventType);
200  if( state == ES_ALL )
201  {
202    for(unsigned int i = 0; i < ES_NUMBER; i++)
203      if (!this->findListener( NULL, (elState)i, eventType, el))
204        this->listeners[i][eventType].push_back(el);
205      else
206      {
207        PRINTF(2)("%s::%s was already subscribed to state %d event %d\n", el->getClassName(), el->getName(), i, eventType);
208      }
209  }
210  else
211  {
212    if (!this->findListener( NULL, state, eventType, el))
213      this->listeners[state][eventType].push_back(el);
214    else
215    {
216      PRINTF(2)("%s::%s was already subscribed to state %d event %d\n", el->getClassName(), el->getName(), state, eventType);
217    }
218  }
219}
220
221
222/**
223 * @brief unsubscribe from the EventHandler
224 * @param state: the stat in which it has been subscribed
225 * @param eventType: the event, that shall be unsubscribed
226 *
227 * if you want to unsubscribe an event listener from all subscribed events, just use the
228 * unsubscribe(EventListener* el, elState state) function
229 */
230void EventHandler::unsubscribe(EventListener* el, elState state, int eventType)
231{
232  PRINTF(4)("Unsubscribing event type nr: %i\n", eventType);
233  if (state == ES_ALL)
234    for (unsigned int i = 0; i < ES_NUMBER; i++)
235    {
236      std::vector<EventListener*>::iterator listener;
237      if (this->findListener(&listener, (elState)i, eventType, el))
238        this->listeners[i][eventType].erase(listener);
239    }
240  else
241  {
242    std::vector<EventListener*>::iterator listener;
243    if (this->findListener(&listener, state, eventType, el))
244      this->listeners[state][eventType].erase(listener);
245  }
246}
247
248
249/**
250 * @brief unsubscribe all events from a specific listener
251 * @param el: the listener that wants to unsubscribe itself
252 * @param state: the state in which the events shall be unsubscribed
253 */
254void EventHandler::unsubscribe(EventListener* el, elState state)
255{
256  assert( el != NULL && state < ES_NUMBER);
257  if( state == ES_ALL)
258  {
259    for(unsigned int i = 0; i < ES_NUMBER; i++)
260    {
261      for(unsigned int j = 0; j < EV_NUMBER; j++)
262      {
263        std::vector<EventListener*>::iterator deller = std::find (this->listeners[i][j].begin(), this->listeners[i][j].end(), el);
264        if( deller != this->listeners[i][j].end())
265          this->listeners[i][j].erase(deller);
266      }
267    }
268  }
269  else
270  {
271    for(int j = 0; j < EV_NUMBER; j++)
272    {
273      std::vector<EventListener*>::iterator deller =  std::find (this->listeners[state][j].begin(), this->listeners[state][j].end(), el);
274      if( deller != this->listeners[state][j].end())
275        this->listeners[state][j].erase(deller);
276    }
277  }
278}
279
280/**
281 * @brief returns true if at state and eventType there is something subscribed.
282 * @param state the state to check in.
283 * @param eventType the eventtype to check.
284 * @returns true if a event is subscibed.
285 */
286bool EventHandler::isSubscribed(elState state, int eventType)
287{
288  return(listeners[state][eventType].empty()) ? false : true;
289};
290
291
292
293/**
294 * @brief flush all registered events
295 * @param state: a specific state
296*/
297void EventHandler::flush(elState state)
298{
299  if( state == ES_ALL)
300  {
301    for(int i = 0; i < ES_NUMBER; ++i)
302    {
303      for(int j = 0; j < EV_NUMBER; ++j)
304      {
305        this->listeners[i][j].clear();
306      }
307    }
308  }
309  else
310  {
311    for(int j = 0; j < EV_NUMBER; ++j)
312    {
313      this->listeners[state][j].clear();
314    }
315  }
316}
317
318
319bool EventHandler::findListener(std::vector<EventListener*>::iterator* it, elState state, int eventType, EventListener* listener)
320{
321  std::vector<EventListener*>::iterator findIterator =
322    std::find(this->listeners[state][eventType].begin(), this->listeners[state][eventType].end(), listener);
323  if (it != NULL)
324    *it = findIterator;
325  return ( findIterator != this->listeners[state][eventType].end());
326
327}
328
329
330
331/**
332 * @brief if the unicode characters should be recorded.
333 * @param state the State in whitch to set the new Value.
334 * @param enableUNICODE: enabled, or disabled.
335 */
336void EventHandler::withUNICODE(elState state, bool enableUNICODE)
337{
338  this->bUNICODE[state] = enableUNICODE;
339  if (this->state == state)
340    SDL_EnableUNICODE(enableUNICODE);
341}
342
343/**
344 * @brief grabs InputEvents.
345 * @param grabEvents if the Events should be grabbed(true) or released(false)
346 */
347void EventHandler::grabEvents(bool grabEvents)
348{
349  this->eventsGrabbed = grabEvents;
350  if(!grabEvents)
351  {
352    SDL_ShowCursor(SDL_ENABLE);
353    SDL_WM_GrabInput(SDL_GRAB_OFF);
354  }
355  else
356  {
357    SDL_WM_GrabInput(SDL_GRAB_ON);
358    SDL_ShowCursor(SDL_DISABLE);
359  }
360}
361
362
363
364/**
365 * @brief core function of event handler: receives all events from SDL
366 *
367 * The event from the SDL framework are collected here and distributed to all listeners.
368 */
369void EventHandler::process() const
370{
371  SDL_Event event;
372  Event ev;
373  while( SDL_PollEvent (&event))
374  {
375    switch( event.type)
376    {
377      case SDL_KEYDOWN:
378        ev.bPressed = true;
379        ev.type = event.key.keysym.sym;
380        if (unlikely(this->bUNICODE[this->state]))
381          ev.x = event.key.keysym.unicode;
382        break;
383      case SDL_KEYUP:
384        ev.bPressed = false;
385        ev.type = event.key.keysym.sym;
386        if (unlikely(this->bUNICODE[this->state]))
387          ev.x = event.key.keysym.unicode;
388        break;
389      case SDL_MOUSEMOTION:
390        ev.bPressed = false;
391        ev.type = EV_MOUSE_MOTION;
392        ev.x = event.motion.x;
393        ev.y = event.motion.y;
394        ev.xRel = event.motion.xrel;
395        ev.yRel = event.motion.yrel;
396        break;
397      case SDL_MOUSEBUTTONUP:
398        ev.bPressed = false;
399        ev.x = event.motion.x;
400        ev.y = event.motion.y;
401        ev.type = event.button.button + SDLK_LAST;
402        break;
403      case SDL_MOUSEBUTTONDOWN:
404        ev.bPressed = true;
405        ev.x = event.motion.x;
406        ev.y = event.motion.y;
407        ev.type = event.button.button + SDLK_LAST;
408        break;
409      case SDL_JOYAXISMOTION:
410        ev.bPressed = false;
411        ev.type = EV_JOY_AXIS_MOTION;
412        break;
413      case SDL_JOYBALLMOTION:
414        ev.bPressed = false;
415        ev.type = EV_JOY_BALL_MOTION;
416        break;
417      case SDL_JOYHATMOTION:
418        ev.bPressed = false;
419        ev.type = EV_JOY_HAT_MOTION;
420        break;
421      case SDL_JOYBUTTONDOWN:
422        ev.bPressed = true;
423        ev.type = EV_JOY_BUTTON;
424        break;
425      case SDL_JOYBUTTONUP:
426        ev.bPressed = true;
427        ev.type = EV_JOY_BUTTON;
428        break;
429      case SDL_ACTIVEEVENT:
430        ev.type = EV_WINDOW_FOCUS;
431        ev.bPressed = (event.active.gain != 0);
432        break;
433      case SDL_VIDEORESIZE:
434        ev.resize = event.resize;
435        ev.type = EV_VIDEO_RESIZE;
436        break;
437      case SDL_QUIT:
438        ev.type = EV_MAIN_QUIT;
439        break;
440      default:
441        ev.type = EV_UNKNOWN;
442        break;
443    }
444    this->dispachEvent(this->state, ev);
445  }
446}
447
448
449/**
450 * @brief dispaches an Event.
451 * @param event the Event to dispach.
452 */
453void EventHandler::dispachEvent(elState state, const Event& event) const
454{
455  /* small debug routine: shows all events dispatched by the event handler */
456  PRINT(4)("\n==========================| EventHandler::process () |===\n");
457  PRINT(4)("=  Got Event nr %i, for state %i\n", event.type, state);
458
459  /// setting a temporary state in case of an EventListener's process changes the state.
460  for (unsigned int i = 0; i < this->listeners[state][event.type].size(); i++)
461  {
462    PRINT(4)("=  Event dispatcher msg: This event has been consumed\n");
463    PRINT(4)("=  Got Event nr %i, for state %i (%d registered) to %s::%s(%p)\n", event.type, i, state, this->listeners[state][event.type][i]->getClassName(), this->listeners[state][event.type][i]->getName(), this->listeners[state][event.type][i]);
464    PRINT(4)("=======================================================\n");
465    this->listeners[state][event.type][i]->process(event);
466  }
467  /*    else
468  {
469        PRINT(4)("=  Event dispatcher msg: This event has NOT been consumed\n");
470        PRINT(4)("=======================================================\n");
471  }*/
472}
473
474
475
476/**
477 * @brief An eventFilter.
478 * @param event the Event to be filtered.
479 * @returns 0 on filtered Event. 1 Otherwise.
480 */
481int EventHandler::eventFilter(const SDL_Event *event)
482{
483  if (likely(EventHandler::getInstance()->eventsGrabbed))
484  {
485    if (event->type == SDL_KEYDOWN &&  event->key.keysym.sym == SDLK_TAB && SDL_GetKeyState(NULL)[SDLK_LALT])
486    {
487      PRINTF(3)("Not sending event to the WindowManager\n");
488      EventHandler::getInstance()->grabEvents(false);
489      return 0;
490    }
491  }
492  else
493  {
494    if (event->type == SDL_MOUSEBUTTONDOWN)
495    {
496      EventHandler::getInstance()->grabEvents( true);
497      return 1;
498    }
499  }
500
501  return 1;
502}
503
504
505/**
506 * @param state The State to get the Name of.
507 * @returns the Name of the State.
508 */
509const std::string& EventHandler::ELStateToString(elState state)
510{
511  if (state < ES_NUMBER)
512    return EventHandler::stateNames[state];
513  else
514    return EventHandler::stateNames[5];
515}
516
517/**
518 * @param stateName the Name of the State to retrieve.
519 * @return the State given by the name
520 */
521elState EventHandler::StringToELState(const std::string& stateName)
522{
523  for (unsigned int i = 0 ; i < ES_NUMBER; i++)
524    if (stateName == EventHandler::stateNames[i])
525      return (elState)i;
526  return ES_NULL;
527}
528
529const std::string  EventHandler::stateNames[] =
530{
531  "game",
532  "game_menu",
533  "menu",
534  "shell",
535  "all",
536  "unknown",
537};
538
539
540/**
541 * @brief outputs some nice information about the EventHandler
542 */
543void EventHandler::debug() const
544{
545  PRINT(0)("===============================\n");
546  PRINT(0)(" EventHandle Debug Information \n");
547  PRINT(0)("===============================\n");
548  for(int i = 0; i < ES_NUMBER; ++i)
549  {
550    for(int j = 0; j < EV_NUMBER; ++j)
551      for (unsigned int evl = 0; evl < this->listeners[i][j].size(); evl++)
552        PRINT(0)("Event %s(%d) of State %s(%d) subscribed to %s (%p)\n",
553        EVToKeyName(j).c_str(), j,
554        ELStateToString((elState)i).c_str(), i,
555        this->listeners[i][j][evl]->getName(), this->listeners[i][j][evl]);
556  }
557  PRINT(0)("============================EH=\n");
558}
Note: See TracBrowser for help on using the repository browser.