Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8204 was 8148, checked in by bensch, 19 years ago

trunk: output of EventListener Nicer

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  EventListener* listener = NULL;
372  while( SDL_PollEvent (&event))
373  {
374    switch( event.type)
375    {
376      case SDL_KEYDOWN:
377        ev.bPressed = true;
378        ev.type = event.key.keysym.sym;
379        if (unlikely(this->bUNICODE[this->state]))
380          ev.x = event.key.keysym.unicode;
381        break;
382      case SDL_KEYUP:
383        ev.bPressed = false;
384        ev.type = event.key.keysym.sym;
385        if (unlikely(this->bUNICODE[this->state]))
386          ev.x = event.key.keysym.unicode;
387        break;
388      case SDL_MOUSEMOTION:
389        ev.bPressed = false;
390        ev.type = EV_MOUSE_MOTION;
391        ev.x = event.motion.x;
392        ev.y = event.motion.y;
393        ev.xRel = event.motion.xrel;
394        ev.yRel = event.motion.yrel;
395        break;
396      case SDL_MOUSEBUTTONUP:
397        ev.bPressed = false;
398        ev.x = event.motion.x;
399        ev.y = event.motion.y;
400        ev.type = event.button.button + SDLK_LAST;
401        break;
402      case SDL_MOUSEBUTTONDOWN:
403        ev.bPressed = true;
404        ev.x = event.motion.x;
405        ev.y = event.motion.y;
406        ev.type = event.button.button + SDLK_LAST;
407        break;
408      case SDL_JOYAXISMOTION:
409        ev.bPressed = false;
410        ev.type = EV_JOY_AXIS_MOTION;
411        break;
412      case SDL_JOYBALLMOTION:
413        ev.bPressed = false;
414        ev.type = EV_JOY_BALL_MOTION;
415        break;
416      case SDL_JOYHATMOTION:
417        ev.bPressed = false;
418        ev.type = EV_JOY_HAT_MOTION;
419        break;
420      case SDL_JOYBUTTONDOWN:
421        ev.bPressed = true;
422        ev.type = EV_JOY_BUTTON;
423        break;
424      case SDL_JOYBUTTONUP:
425        ev.bPressed = true;
426        ev.type = EV_JOY_BUTTON;
427        break;
428      case SDL_ACTIVEEVENT:
429        ev.type = EV_WINDOW_FOCUS;
430        ev.bPressed = (event.active.gain != 0);
431        break;
432      case SDL_VIDEORESIZE:
433        ev.resize = event.resize;
434        ev.type = EV_VIDEO_RESIZE;
435        break;
436      case SDL_QUIT:
437        ev.type = EV_MAIN_QUIT;
438        break;
439      default:
440        ev.type = EV_UNKNOWN;
441        break;
442    }
443    this->dispachEvent(this->state, ev);
444  }
445}
446
447
448/**
449 * @brief dispaches an Event.
450 * @param event the Event to dispach.
451 */
452void EventHandler::dispachEvent(elState state, const Event& event) const
453{
454  /* small debug routine: shows all events dispatched by the event handler */
455  PRINT(4)("\n==========================| EventHandler::process () |===\n");
456  PRINT(4)("=  Got Event nr %i, for state %i\n", event.type, state);
457
458  /// setting a temporary state in case of an EventListener's process changes the state.
459  for (unsigned int i = 0; i < this->listeners[state][event.type].size(); i++)
460  {
461    PRINT(4)("=  Event dispatcher msg: This event has been consumed\n");
462    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]);
463    PRINT(4)("=======================================================\n");
464    this->listeners[state][event.type][i]->process(event);
465  }
466  /*    else
467  {
468        PRINT(4)("=  Event dispatcher msg: This event has NOT been consumed\n");
469        PRINT(4)("=======================================================\n");
470  }*/
471}
472
473
474
475/**
476 * @brief An eventFilter.
477 * @param event the Event to be filtered.
478 * @returns 0 on filtered Event. 1 Otherwise.
479 */
480int EventHandler::eventFilter(const SDL_Event *event)
481{
482  if (likely(EventHandler::getInstance()->eventsGrabbed))
483  {
484    if (event->type == SDL_KEYDOWN &&  event->key.keysym.sym == SDLK_TAB && SDL_GetKeyState(NULL)[SDLK_LALT])
485    {
486      PRINTF(3)("Not sending event to the WindowManager\n");
487      EventHandler::getInstance()->grabEvents(false);
488      return 0;
489    }
490  }
491  else
492  {
493    if (event->type == SDL_MOUSEBUTTONDOWN)
494    {
495      EventHandler::getInstance()->grabEvents( true);
496      return 1;
497    }
498  }
499
500  return 1;
501}
502
503
504/**
505 * @param state The State to get the Name of.
506 * @returns the Name of the State.
507 */
508const std::string& EventHandler::ELStateToString(elState state)
509{
510  if (state < ES_NUMBER)
511    return EventHandler::stateNames[state];
512  else
513    return EventHandler::stateNames[5];
514}
515
516/**
517 * @param stateName the Name of the State to retrieve.
518 * @return the State given by the name
519 */
520elState EventHandler::StringToELState(const std::string& stateName)
521{
522  for (unsigned int i = 0 ; i < ES_NUMBER; i++)
523    if (stateName == EventHandler::stateNames[i])
524      return (elState)i;
525  return ES_NULL;
526}
527
528const std::string  EventHandler::stateNames[] =
529{
530  "game",
531  "game_menu",
532  "menu",
533  "shell",
534  "all",
535  "unknown",
536};
537
538
539/**
540 * @brief outputs some nice information about the EventHandler
541 */
542void EventHandler::debug() const
543{
544  PRINT(0)("===============================\n");
545  PRINT(0)(" EventHandle Debug Information \n");
546  PRINT(0)("===============================\n");
547  for(int i = 0; i < ES_NUMBER; ++i)
548  {
549    for(int j = 0; j < EV_NUMBER; ++j)
550      for (unsigned int evl = 0; evl < this->listeners[i][j].size(); evl++)
551        PRINT(0)("Event %s(%d) of State %s(%d) subscribed to %s (%p)\n",
552        EVToKeyName(j).c_str(), j,
553        ELStateToString((elState)i).c_str(), i,
554        this->listeners[i][j][evl]->getName(), this->listeners[i][j][evl]);
555  }
556  PRINT(0)("============================EH=\n");
557}
Note: See TracBrowser for help on using the repository browser.