Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8336 was 8316, checked in by bensch, 18 years ago

trunk: fixed most -Wall warnings… but there are still many missing :/

File size: 14.4 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  /// When Changing the State, all the keys will be released.
115  /// This is done by sending each eventListener, that still
116  /// has an Event subscribed, a Release Event.
117  int keyCount;
118  Uint8 * pressedKeys = SDL_GetKeyState(&keyCount);
119  for (unsigned int i = 0; i < SDLK_LAST; i++)
120  {
121    if (pressedKeys[i])
122    {
123      Event ev;
124      ev.bPressed = false;
125      ev.type = i;
126      if (unlikely(this->bUNICODE[this->state]))
127        ev.x = i;
128      this->dispachEvent(this->state, ev );
129    }
130  }
131
132  // switching to the new State.
133  elState oldState = this->state;
134  this->state = state;
135
136  // in the End the Corresponding handler will be notified.
137  Event stateSwitchEvent;
138  stateSwitchEvent.type = EV_LEAVE_STATE;
139  this->dispachEvent(oldState, stateSwitchEvent);
140
141  SDL_EnableUNICODE(this->bUNICODE[state]);
142};
143
144
145/**
146 * @brief pushes the current State in the State-stack, and selects state
147 * @param state the new State to set
148 */
149void EventHandler::pushState(elState state)
150{
151  if (likely(state != ES_NULL && state != ES_ALL ))
152  {
153    this->stateStack.push(this->state);
154    this->setState(state);
155  }
156  else
157  {
158    PRINTF(2)("unable to push State\n");
159  }
160}
161
162/**
163 * @brief this removes the topmost stack-entry and select the underlying one
164 * @returns the next stack-entry
165 */
166elState EventHandler::popState()
167{
168  if (stateStack.empty())
169    return ES_NULL;
170  elState state =  (elState)stateStack.top();
171  this->stateStack.pop();
172  if (state == ES_NULL)
173  {
174    PRINTF(2)("No more states availiable. (unable to pop state)\n");
175    return ES_NULL;
176  }
177  else
178  {
179    this->setState(state);
180    return state;
181  }
182}
183
184
185/**
186 * @brief subscribe to an event
187 * @param el: the event listener that wants to subscribe itself, the listener that will be called when the evetn occures
188 * @param state: for which the listener wants to receive events
189 * @param eventType: the event type that wants to be listened for.
190
191   This is one of the most important function of the EventHandler. If you would like to subscribe for more
192   than one state, you have to subscribe for each state again. If you want to subscribe for all states, use
193   state = ES_ALL, which will subscribe your listener for all states together.
194 */
195void EventHandler::subscribe(EventListener* el, elState state, int eventType)
196{
197  PRINTF(4)("Subscribing event type: %i\n", eventType);
198  if( state == ES_ALL )
199  {
200    for(unsigned int i = 0; i < ES_NUMBER; i++)
201      if (!this->findListener( NULL, (elState)i, eventType, el))
202        this->listeners[i][eventType].push_back(el);
203      else
204      {
205        PRINTF(2)("%s::%s was already subscribed to state %d event %d\n", el->getClassName(), el->getName(), i, eventType);
206      }
207  }
208  else
209  {
210    if (!this->findListener( NULL, state, eventType, el))
211      this->listeners[state][eventType].push_back(el);
212    else
213    {
214      PRINTF(2)("%s::%s was already subscribed to state %d event %d\n", el->getClassName(), el->getName(), state, eventType);
215    }
216  }
217}
218
219
220/**
221 * @brief unsubscribe from the EventHandler
222 * @param state: the stat in which it has been subscribed
223 * @param eventType: the event, that shall be unsubscribed
224 *
225 * if you want to unsubscribe an event listener from all subscribed events, just use the
226 * unsubscribe(EventListener* el, elState state) function
227 */
228void EventHandler::unsubscribe(EventListener* el, elState state, int eventType)
229{
230  PRINTF(4)("Unsubscribing event type nr: %i\n", eventType);
231  if (state == ES_ALL)
232    for (unsigned int i = 0; i < ES_NUMBER; i++)
233    {
234      std::vector<EventListener*>::iterator listener;
235      if (this->findListener(&listener, (elState)i, eventType, el))
236        this->listeners[i][eventType].erase(listener);
237    }
238  else
239  {
240    std::vector<EventListener*>::iterator listener;
241    if (this->findListener(&listener, state, eventType, el))
242      this->listeners[state][eventType].erase(listener);
243  }
244}
245
246
247/**
248 * @brief unsubscribe all events from a specific listener
249 * @param el: the listener that wants to unsubscribe itself
250 * @param state: the state in which the events shall be unsubscribed
251 */
252void EventHandler::unsubscribe(EventListener* el, elState state)
253{
254  assert( el != NULL && state < ES_NUMBER);
255  if( state == ES_ALL)
256  {
257    for(unsigned int i = 0; i < ES_NUMBER; i++)
258    {
259      for(unsigned int j = 0; j < EV_NUMBER; j++)
260      {
261        std::vector<EventListener*>::iterator deller = std::find (this->listeners[i][j].begin(), this->listeners[i][j].end(), el);
262        if( deller != this->listeners[i][j].end())
263          this->listeners[i][j].erase(deller);
264      }
265    }
266  }
267  else
268  {
269    for(int j = 0; j < EV_NUMBER; j++)
270    {
271      std::vector<EventListener*>::iterator deller =  std::find (this->listeners[state][j].begin(), this->listeners[state][j].end(), el);
272      if( deller != this->listeners[state][j].end())
273        this->listeners[state][j].erase(deller);
274    }
275  }
276}
277
278/**
279 * @brief returns true if at state and eventType there is something subscribed.
280 * @param state the state to check in.
281 * @param eventType the eventtype to check.
282 * @returns true if a event is subscibed.
283 */
284bool EventHandler::isSubscribed(elState state, int eventType)
285{
286  return(listeners[state][eventType].empty()) ? false : true;
287};
288
289
290
291/**
292 * @brief flush all registered events
293 * @param state: a specific state
294*/
295void EventHandler::flush(elState state)
296{
297  if( state == ES_ALL)
298  {
299    for(int i = 0; i < ES_NUMBER; ++i)
300    {
301      for(int j = 0; j < EV_NUMBER; ++j)
302      {
303        this->listeners[i][j].clear();
304      }
305    }
306  }
307  else
308  {
309    for(int j = 0; j < EV_NUMBER; ++j)
310    {
311      this->listeners[state][j].clear();
312    }
313  }
314}
315
316
317bool EventHandler::findListener(std::vector<EventListener*>::iterator* it, elState state, int eventType, EventListener* listener)
318{
319  std::vector<EventListener*>::iterator findIterator =
320    std::find(this->listeners[state][eventType].begin(), this->listeners[state][eventType].end(), listener);
321  if (it != NULL)
322    *it = findIterator;
323  return ( findIterator != this->listeners[state][eventType].end());
324
325}
326
327
328
329/**
330 * @brief if the unicode characters should be recorded.
331 * @param state the State in whitch to set the new Value.
332 * @param enableUNICODE: enabled, or disabled.
333 */
334void EventHandler::withUNICODE(elState state, bool enableUNICODE)
335{
336  this->bUNICODE[state] = enableUNICODE;
337  if (this->state == state)
338    SDL_EnableUNICODE(enableUNICODE);
339}
340
341/**
342 * @brief grabs InputEvents.
343 * @param grabEvents if the Events should be grabbed(true) or released(false)
344 */
345void EventHandler::grabEvents(bool grabEvents)
346{
347  this->eventsGrabbed = grabEvents;
348  if(!grabEvents)
349  {
350    SDL_ShowCursor(SDL_ENABLE);
351    SDL_WM_GrabInput(SDL_GRAB_OFF);
352  }
353  else
354  {
355    SDL_WM_GrabInput(SDL_GRAB_ON);
356    SDL_ShowCursor(SDL_DISABLE);
357  }
358}
359
360
361
362/**
363 * @brief core function of event handler: receives all events from SDL
364 *
365 * The event from the SDL framework are collected here and distributed to all listeners.
366 */
367void EventHandler::process() const
368{
369  SDL_Event event;
370  Event ev;
371  while( SDL_PollEvent (&event))
372  {
373    switch( event.type)
374    {
375      case SDL_KEYDOWN:
376        ev.bPressed = true;
377        ev.type = event.key.keysym.sym;
378        if (unlikely(this->bUNICODE[this->state]))
379          ev.x = event.key.keysym.unicode;
380        break;
381      case SDL_KEYUP:
382        ev.bPressed = false;
383        ev.type = event.key.keysym.sym;
384        if (unlikely(this->bUNICODE[this->state]))
385          ev.x = event.key.keysym.unicode;
386        break;
387      case SDL_MOUSEMOTION:
388        ev.bPressed = false;
389        ev.type = EV_MOUSE_MOTION;
390        ev.x = event.motion.x;
391        ev.y = event.motion.y;
392        ev.xRel = event.motion.xrel;
393        ev.yRel = event.motion.yrel;
394        break;
395      case SDL_MOUSEBUTTONUP:
396        ev.bPressed = false;
397        ev.x = event.motion.x;
398        ev.y = event.motion.y;
399        ev.type = event.button.button + SDLK_LAST;
400        break;
401      case SDL_MOUSEBUTTONDOWN:
402        ev.bPressed = true;
403        ev.x = event.motion.x;
404        ev.y = event.motion.y;
405        ev.type = event.button.button + SDLK_LAST;
406        break;
407      case SDL_JOYAXISMOTION:
408        ev.bPressed = false;
409        ev.type = EV_JOY_AXIS_MOTION;
410        break;
411      case SDL_JOYBALLMOTION:
412        ev.bPressed = false;
413        ev.type = EV_JOY_BALL_MOTION;
414        break;
415      case SDL_JOYHATMOTION:
416        ev.bPressed = false;
417        ev.type = EV_JOY_HAT_MOTION;
418        break;
419      case SDL_JOYBUTTONDOWN:
420        ev.bPressed = true;
421        ev.type = EV_JOY_BUTTON;
422        break;
423      case SDL_JOYBUTTONUP:
424        ev.bPressed = true;
425        ev.type = EV_JOY_BUTTON;
426        break;
427      case SDL_ACTIVEEVENT:
428        ev.type = EV_WINDOW_FOCUS;
429        ev.bPressed = (event.active.gain != 0);
430        break;
431      case SDL_VIDEORESIZE:
432        ev.resize = event.resize;
433        ev.type = EV_VIDEO_RESIZE;
434        break;
435      case SDL_QUIT:
436        ev.type = EV_MAIN_QUIT;
437        break;
438      default:
439        ev.type = EV_UNKNOWN;
440        break;
441    }
442    this->dispachEvent(this->state, ev);
443  }
444}
445
446
447/**
448 * @brief dispaches an Event.
449 * @param event the Event to dispach.
450 */
451void EventHandler::dispachEvent(elState state, const Event& event) const
452{
453  /* small debug routine: shows all events dispatched by the event handler */
454  PRINT(4)("\n==========================| EventHandler::process () |===\n");
455  PRINT(4)("=  Got Event nr %i, for state %i\n", event.type, state);
456
457  /// setting a temporary state in case of an EventListener's process changes the state.
458  for (unsigned int i = 0; i < this->listeners[state][event.type].size(); i++)
459  {
460    PRINT(4)("=  Event dispatcher msg: This event has been consumed\n");
461    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]);
462    PRINT(4)("=======================================================\n");
463    this->listeners[state][event.type][i]->process(event);
464  }
465  /*    else
466  {
467        PRINT(4)("=  Event dispatcher msg: This event has NOT been consumed\n");
468        PRINT(4)("=======================================================\n");
469  }*/
470}
471
472
473
474/**
475 * @brief An eventFilter.
476 * @param event the Event to be filtered.
477 * @returns 0 on filtered Event. 1 Otherwise.
478 */
479int EventHandler::eventFilter(const SDL_Event *event)
480{
481  if (likely(EventHandler::getInstance()->eventsGrabbed))
482  {
483    if (event->type == SDL_KEYDOWN &&  event->key.keysym.sym == SDLK_TAB && SDL_GetKeyState(NULL)[SDLK_LALT])
484    {
485      PRINTF(3)("Not sending event to the WindowManager\n");
486      EventHandler::getInstance()->grabEvents(false);
487      return 0;
488    }
489  }
490  else
491  {
492    if (event->type == SDL_MOUSEBUTTONDOWN)
493    {
494      EventHandler::getInstance()->grabEvents( true);
495      return 1;
496    }
497  }
498
499  return 1;
500}
501
502
503/**
504 * @param state The State to get the Name of.
505 * @returns the Name of the State.
506 */
507const std::string& EventHandler::ELStateToString(elState state)
508{
509  if (state < ES_NUMBER)
510    return EventHandler::stateNames[state];
511  else
512    return EventHandler::stateNames[5];
513}
514
515/**
516 * @param stateName the Name of the State to retrieve.
517 * @return the State given by the name
518 */
519elState EventHandler::StringToELState(const std::string& stateName)
520{
521  for (unsigned int i = 0 ; i < ES_NUMBER; i++)
522    if (stateName == EventHandler::stateNames[i])
523      return (elState)i;
524  return ES_NULL;
525}
526
527const std::string  EventHandler::stateNames[] =
528{
529  "game",
530  "game_menu",
531  "menu",
532  "shell",
533  "all",
534  "unknown",
535};
536
537
538/**
539 * @brief outputs some nice information about the EventHandler
540 */
541void EventHandler::debug() const
542{
543  PRINT(0)("===============================\n");
544  PRINT(0)(" EventHandle Debug Information \n");
545  PRINT(0)("===============================\n");
546  for(int i = 0; i < ES_NUMBER; ++i)
547  {
548    for(int j = 0; j < EV_NUMBER; ++j)
549      for (unsigned int evl = 0; evl < this->listeners[i][j].size(); evl++)
550        PRINT(0)("Event %s(%d) of State %s(%d) subscribed to %s (%p)\n",
551        EVToKeyName(j).c_str(), j,
552        ELStateToString((elState)i).c_str(), i,
553        this->listeners[i][j][evl]->getName(), this->listeners[i][j][evl]);
554  }
555  PRINT(0)("============================EH=\n");
556}
Note: See TracBrowser for help on using the repository browser.