Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/gui/src/lib/event/event_handler.cc @ 7908

Last change on this file since 7908 was 7905, checked in by bensch, 19 years ago

borders

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