Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8765 was 8743, checked in by bensch, 18 years ago

gui: event-handler now supports retrieving key-states

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