FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
eventmanager.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2008 by the FIFE team *
3  * http://www.fifengine.de *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 #include <iostream>
24 
25 // 3rd party library includes
26 
27 // FIFE includes
28 // These includes are split up in two parts, separated by one empty line
29 // First block: files included from the FIFE root src directory
30 // Second block: files included from the same folder
31 #include "util/base/exception.h"
32 #include "util/log/logger.h"
33 #include "util/math/fife_math.h"
34 #include "eventchannel/key/ec_key.h"
35 #include "eventchannel/key/ec_keyevent.h"
36 #include "eventchannel/key/ec_ikeyfilter.h"
37 #include "eventchannel/mouse/ec_mouseevent.h"
38 #include "eventchannel/command/ec_command.h"
39 #include "video/renderbackend.h"
40 
41 #include "eventmanager.h"
42 
43 namespace FIFE {
44  static Logger _log(LM_EVTCHANNEL);
45 
47  m_commandlisteners(),
48  m_keylisteners(),
49  m_mouselisteners(),
50  m_sdleventlisteners(),
51  m_keystatemap(),
52  m_keyfilter(0),
53  m_mousestate(0),
54  m_mostrecentbtn(MouseEvent::EMPTY),
55  m_mousesensitivity(0.0),
56  m_acceleration(false),
57  m_warp(false),
58  m_enter(false),
59  m_oldx(0),
60  m_oldy(0),
61  m_lastticks(0),
62  m_oldvelocity(0.0) {
63  }
64 
66  }
67 
68  template<typename T>
69  void removeListener(std::deque<T>& vec, T& listener) {
70  vec.push_back(listener);
71  }
72 
73  template<typename T>
74  void addListener(std::deque<T>& vec, T& listener) {
75  vec.push_back(listener);
76  }
77 
79  addListener<ICommandListener*>(m_pending_commandlisteners, listener);
80  }
81 
83  addListener<ICommandListener*>(m_pending_commandlisteners, listener);
84  }
85 
87  removeListener<ICommandListener*>(m_pending_cldeletions, listener);
88  }
89 
91  addListener<IKeyListener*>(m_pending_keylisteners, listener);
92  }
93 
95  addListener<IKeyListener*>(m_pending_keylisteners_front, listener);
96  }
97 
99  removeListener<IKeyListener*>(m_pending_kldeletions, listener);
100  }
101 
103  addListener<IMouseListener*>(m_pending_mouselisteners, listener);
104  }
105 
107  addListener<IMouseListener*>(m_pending_mouselisteners, listener);
108  }
109 
111  removeListener<IMouseListener*>(m_pending_mldeletions, listener);
112  }
113 
115  addListener<ISdlEventListener*>(m_pending_sdleventlisteners, listener);
116  }
117 
119  addListener<ISdlEventListener*>(m_pending_sdleventlisteners, listener);
120  }
121 
123  removeListener<ISdlEventListener*>(m_pending_sdldeletions, listener);
124  }
125 
127  if(!m_pending_commandlisteners.empty()) {
128  std::deque<ICommandListener*>::iterator i = m_pending_commandlisteners.begin();
129  while (i != m_pending_commandlisteners.end()) {
130  m_commandlisteners.push_back(*i);
131  ++i;
132  }
133  m_pending_commandlisteners.clear();
134  }
135 
136  if(!m_pending_commandlisteners_front.empty()) {
137  std::deque<ICommandListener*>::iterator i = m_pending_commandlisteners_front.begin();
138  while (i != m_pending_commandlisteners_front.end()) {
139  m_commandlisteners.push_front(*i);
140  ++i;
141  }
142  m_pending_commandlisteners_front.clear();
143  }
144 
145  if (!m_pending_cldeletions.empty()) {
146  std::deque<ICommandListener*>::iterator i = m_pending_cldeletions.begin();
147  while (i != m_pending_cldeletions.end()) {
148  std::deque<ICommandListener*>::iterator j = m_commandlisteners.begin();
149  while (j != m_commandlisteners.end()) {
150  if(*j == *i) {
151  m_commandlisteners.erase(j);
152  break;
153  }
154  ++j;
155  }
156  ++i;
157  }
158  m_pending_cldeletions.clear();
159  }
160 
161  std::deque<ICommandListener*>::iterator i = m_commandlisteners.begin();
162  while (i != m_commandlisteners.end()) {
163  (*i)->onCommand(command);
164  if (command.isConsumed()) {
165  break;
166  }
167  ++i;
168  }
169  }
170 
171  void EventManager::dispatchKeyEvent(KeyEvent& evt) {
172  if(!m_pending_keylisteners.empty()) {
173  std::deque<IKeyListener*>::iterator i = m_pending_keylisteners.begin();
174  while (i != m_pending_keylisteners.end()) {
175  m_keylisteners.push_back(*i);
176  ++i;
177  }
178  m_pending_keylisteners.clear();
179  }
180 
181  if(!m_pending_keylisteners_front.empty()) {
182  std::deque<IKeyListener*>::iterator i = m_pending_keylisteners_front.begin();
183  while (i != m_pending_keylisteners_front.end()) {
184  m_keylisteners.push_front(*i);
185  ++i;
186  }
187  m_pending_keylisteners_front.clear();
188  }
189 
190  if (!m_pending_kldeletions.empty()) {
191  std::deque<IKeyListener*>::iterator i = m_pending_kldeletions.begin();
192  while (i != m_pending_kldeletions.end()) {
193  std::deque<IKeyListener*>::iterator j = m_keylisteners.begin();
194  while (j != m_keylisteners.end()) {
195  if(*j == *i) {
196  m_keylisteners.erase(j);
197  break;
198  }
199  ++j;
200  }
201  ++i;
202  }
203  m_pending_kldeletions.clear();
204  }
205 
206  std::deque<IKeyListener*>::iterator i = m_keylisteners.begin();
207  while (i != m_keylisteners.end()) {
208  switch (evt.getType()) {
209  case KeyEvent::PRESSED:
210  (*i)->keyPressed(evt);
211  break;
212  case KeyEvent::RELEASED:
213  (*i)->keyReleased(evt);
214  break;
215  default:
216  break;
217  }
218  ++i;
219  }
220  }
221 
222  void EventManager::dispatchMouseEvent(MouseEvent& evt) {
223  if(!m_pending_mouselisteners.empty()) {
224  std::deque<IMouseListener*>::iterator i = m_pending_mouselisteners.begin();
225  while (i != m_pending_mouselisteners.end()) {
226  m_mouselisteners.push_back(*i);
227  ++i;
228  }
229  m_pending_mouselisteners.clear();
230  }
231 
232  if(!m_pending_mouselisteners_front.empty()) {
233  std::deque<IMouseListener*>::iterator i = m_pending_mouselisteners_front.begin();
234  while (i != m_pending_mouselisteners_front.end()) {
235  m_mouselisteners.push_front(*i);
236  ++i;
237  }
238  m_pending_mouselisteners_front.clear();
239  }
240 
241  if (!m_pending_mldeletions.empty()) {
242  std::deque<IMouseListener*>::iterator i = m_pending_mldeletions.begin();
243  while (i != m_pending_mldeletions.end()) {
244  std::deque<IMouseListener*>::iterator j = m_mouselisteners.begin();
245  while (j != m_mouselisteners.end()) {
246  if(*j == *i) {
247  m_mouselisteners.erase(j);
248  break;
249  }
250  ++j;
251  }
252  ++i;
253  }
254  m_pending_mldeletions.clear();
255  }
256 
257  std::deque<IMouseListener*>::iterator i = m_mouselisteners.begin();
258  while (i != m_mouselisteners.end()) {
259  switch (evt.getType()) {
260  case MouseEvent::MOVED:
261  (*i)->mouseMoved(evt);
262  break;
263  case MouseEvent::PRESSED:
264  (*i)->mousePressed(evt);
265  break;
266  case MouseEvent::RELEASED:
267  (*i)->mouseReleased(evt);
268  break;
269  case MouseEvent::WHEEL_MOVED_DOWN:
270  (*i)->mouseWheelMovedDown(evt);
271  break;
272  case MouseEvent::WHEEL_MOVED_UP:
273  (*i)->mouseWheelMovedUp(evt);
274  break;
275  case MouseEvent::CLICKED:
276  (*i)->mouseClicked(evt);
277  break;
278  case MouseEvent::ENTERED:
279  (*i)->mouseEntered(evt);
280  break;
281  case MouseEvent::EXITED:
282  (*i)->mouseExited(evt);
283  break;
284  case MouseEvent::DRAGGED:
285  (*i)->mouseDragged(evt);
286  break;
287  default:
288  break;
289  }
290  if (evt.isConsumed()) {
291  break;
292  }
293  ++i;
294  }
295  }
296 
297  bool EventManager::dispatchSdlEvent(SDL_Event& evt) {
298  bool ret = false;
299  if (!m_pending_sdleventlisteners.empty()) {
300  std::deque<ISdlEventListener*>::iterator i = m_pending_sdleventlisteners.begin();
301  while(i != m_pending_sdleventlisteners.end()) {
302  m_sdleventlisteners.push_back(*i);
303  ++i;
304  }
305  m_pending_sdleventlisteners.clear();
306  }
307 
308  if (!m_pending_sdleventlisteners_front.empty()) {
309  std::deque<ISdlEventListener*>::iterator i = m_pending_sdleventlisteners_front.begin();
310  while(i != m_pending_sdleventlisteners_front.end()) {
311  m_sdleventlisteners.push_front(*i);
312  ++i;
313  }
314  m_pending_sdleventlisteners_front.clear();
315  }
316 
317  if (!m_pending_sdldeletions.empty()) {
318  std::deque<ISdlEventListener*>::iterator i = m_pending_sdldeletions.begin();
319  while (i != m_pending_sdldeletions.end()) {
320  std::deque<ISdlEventListener*>::iterator j = m_sdleventlisteners.begin();
321  while (j != m_sdleventlisteners.end()) {
322  if(*j == *i) {
323  m_sdleventlisteners.erase(j);
324  break;
325  }
326  ++j;
327  }
328  ++i;
329  }
330  m_pending_sdldeletions.clear();
331  }
332 
333  std::deque<ISdlEventListener*>::iterator i = m_sdleventlisteners.begin();
334  while (i != m_sdleventlisteners.end()) {
335  ret = ret || (*i)->onSdlEvent(evt);
336  ++i;
337  }
338  return ret;
339  }
340 
341  bool EventManager::combineEvents(SDL_Event& event1, const SDL_Event& event2) {
342  if(event1.type == event2.type) {
343  switch (event1.type) {
344  case SDL_MOUSEMOTION:
345  if(event1.motion.state == event2.motion.state) {
346  event1.motion.x = event2.motion.x;
347  event1.motion.y = event2.motion.y;
348  event1.motion.xrel += event2.motion.xrel;
349  event1.motion.yrel += event2.motion.yrel;
350  return true;
351  }
352  return false;
353  }
354  }
355  return false;
356  }
357 
359  // The double SDL_PollEvent calls don't throw away events,
360  // but try to combine (mouse motion) events.
361  SDL_Event event, next_event;
362  bool has_next_event = (SDL_PollEvent(&event) != 0);
363  while (has_next_event) {
364  has_next_event = (SDL_PollEvent(&next_event) != 0);
365  if(has_next_event && combineEvents(event, next_event))
366  continue;
367 
368  switch (event.type) {
369  case SDL_QUIT: {
370  Command cmd;
371  cmd.setSource(this);
372  cmd.setCommandType(CMD_QUIT_GAME);
373  dispatchCommand(cmd);
374  }
375  break;
376 
377  case SDL_ACTIVEEVENT:
378  processActiveEvent(event);
379  break;
380 
381  case SDL_KEYDOWN:
382  case SDL_KEYUP:
383  processKeyEvent(event);
384  break;
385 
386  case SDL_MOUSEBUTTONUP:
387  case SDL_MOUSEMOTION:
388  case SDL_MOUSEBUTTONDOWN:
389  processMouseEvent(event);
390  break;
391  }
392  if(has_next_event)
393  event = next_event;
394  }
395  }
396 
397  void EventManager::processActiveEvent(SDL_Event event) {
398  if (dispatchSdlEvent(event)) {
399  return;
400  }
401 
402  SDL_ActiveEvent actevt = event.active;
403  std::vector<Command*> commands;
404 
405  if (actevt.state & SDL_APPMOUSEFOCUS) {
406  Command* cmd = new Command();
407  if (actevt.gain) {
408  cmd->setCommandType(CMD_MOUSE_FOCUS_GAINED);
409  m_enter = true;
410  } else {
411  cmd->setCommandType(CMD_MOUSE_FOCUS_LOST);
412  }
413  commands.push_back(cmd);
414  }
415  if (actevt.state & SDL_APPINPUTFOCUS) {
416  Command* cmd = new Command();
417  if (actevt.gain) {
418  cmd->setCommandType(CMD_INPUT_FOCUS_GAINED);
419  } else {
420  cmd->setCommandType(CMD_INPUT_FOCUS_LOST);
421  }
422  commands.push_back(cmd);
423  }
424  if (actevt.state & SDL_APPACTIVE) {
425  Command* cmd = new Command();
426  if (actevt.gain) {
427  cmd->setCommandType(CMD_APP_RESTORED);
428  } else {
429  cmd->setCommandType(CMD_APP_ICONIFIED);
430  }
431  commands.push_back(cmd);
432  }
433 
434  std::vector<Command*>::iterator it = commands.begin();
435  for (; it != commands.end(); ++it) {
436  dispatchCommand(**it);
437  delete *it;
438  }
439  }
440 
441  void EventManager::processKeyEvent(SDL_Event event) {
442  KeyEvent keyevt;
443  keyevt.setSource(this);
444  fillKeyEvent(event, keyevt);
445  m_keystatemap[keyevt.getKey().getValue()] = (keyevt.getType() == KeyEvent::PRESSED);
446 
447  bool dispatchAsSdl = !keyevt.getKey().isFunctionKey();
448  if( dispatchAsSdl && m_keyfilter ) {
449  dispatchAsSdl = !m_keyfilter->isFiltered(keyevt);
450  }
451 
452  if( dispatchAsSdl ) {
453  if( dispatchSdlEvent(event) )
454  return;
455  }
456 
457  dispatchKeyEvent(keyevt);
458  }
459 
460  void EventManager::processMouseEvent(SDL_Event event) {
461  if (event.type == SDL_MOUSEMOTION && (!Mathf::Equal(m_mousesensitivity, 0.0) || m_acceleration)) {
462  uint16_t tmp_x = event.motion.x;
463  uint16_t tmp_y = event.motion.y;
464  if (m_enter) {
465  m_oldx = tmp_x;
466  m_oldy = tmp_y;
467  m_oldvelocity = 0.0;
468  m_enter = false;
469  }
470 
471  float modifier;
472  if (m_acceleration) {
473  uint32_t ticks = SDL_GetTicks();
474  float difference = static_cast<float>((ticks - m_lastticks) + 1);
475  m_lastticks = ticks;
476  float dx = static_cast<float>(tmp_x - m_oldx);
477  float dy = static_cast<float>(tmp_y - m_oldy);
478  float distance = Mathf::Sqrt(dx * dx + dy * dy);
479  float acceleration = static_cast<float>((distance / difference) / difference);
480  float velocity = (m_oldvelocity + acceleration * difference)/2;
481  if (velocity > m_mousesensitivity+1) {
482  velocity = m_mousesensitivity+1;
483  }
484  m_oldvelocity = velocity;
485  modifier = velocity;
486  } else {
487  modifier = m_mousesensitivity;
488  }
489 
490  int16_t tmp_xrel = static_cast<int16_t>(tmp_x - m_oldx);
491  int16_t tmp_yrel = static_cast<int16_t>(tmp_y - m_oldy);
492  if ((tmp_xrel != 0) || (tmp_yrel != 0)) {
493  Rect screen = RenderBackend::instance()->getArea();
494  int16_t x_fact = static_cast<int16_t>(round(static_cast<float>(tmp_xrel * modifier)));
495  int16_t y_fact = static_cast<int16_t>(round(static_cast<float>(tmp_yrel * modifier)));
496  if ((tmp_x + x_fact) > screen.w) {
497  tmp_x = screen.w;
498  } else if ((tmp_x + x_fact) < screen.x) {
499  tmp_x = screen.x;
500  } else {
501  tmp_x += x_fact;
502  }
503 
504  if (tmp_y + y_fact > screen.h) {
505  tmp_y = screen.h;
506  } else if ((tmp_y + y_fact) < screen.y) {
507  tmp_y = screen.y;
508  } else {
509  tmp_y += y_fact;
510  }
511  m_oldx = tmp_x;
512  m_oldy = tmp_y;
513  event.motion.x = tmp_x;
514  event.motion.y = tmp_y;
515  m_warp = true; //don't trigger an event handler when warping
516  SDL_WarpMouse(tmp_x, tmp_y);
517  m_warp = false;
518  }
519 
520  }
521  if (dispatchSdlEvent(event)) {
522  return;
523  }
524  MouseEvent mouseevt;
525  mouseevt.setSource(this);
526  fillMouseEvent(event, mouseevt);
527  fillModifiers(mouseevt);
528  if (event.type == SDL_MOUSEBUTTONDOWN) {
529  m_mousestate |= static_cast<int32_t>(mouseevt.getButton());
530  m_mostrecentbtn = mouseevt.getButton();
531  } else if (event.type == SDL_MOUSEBUTTONUP) {
532  m_mousestate &= ~static_cast<int32_t>(mouseevt.getButton());
533  }
534  // fire scrollwheel events only once
535  if (event.button.button == SDL_BUTTON_WHEELDOWN || event.button.button == SDL_BUTTON_WHEELUP) {
536  if (event.type == SDL_MOUSEBUTTONUP) {
537  return;
538  }
539  }
540  dispatchMouseEvent(mouseevt);
541  }
542 
543 
544  void EventManager::fillMouseEvent(const SDL_Event& sdlevt, MouseEvent& mouseevt) {
545  if (m_warp) {
546  return;
547  }
548 
549  mouseevt.setX(sdlevt.button.x);
550  mouseevt.setY(sdlevt.button.y);
551 
552  mouseevt.setButton(MouseEvent::EMPTY);
553  mouseevt.setType(MouseEvent::MOVED);
554  if ((sdlevt.type == SDL_MOUSEBUTTONUP) || (sdlevt.type == SDL_MOUSEBUTTONDOWN)) {
555  switch (sdlevt.button.button) {
556  case SDL_BUTTON_LEFT:
557  mouseevt.setButton(MouseEvent::LEFT);
558  break;
559  case SDL_BUTTON_RIGHT:
560  mouseevt.setButton(MouseEvent::RIGHT);
561  break;
562  case SDL_BUTTON_MIDDLE:
563  mouseevt.setButton(MouseEvent::MIDDLE);
564  break;
565  default:
566  mouseevt.setButton(MouseEvent::UNKNOWN_BUTTON);
567  break;
568  }
569 
570  if (sdlevt.type == SDL_MOUSEBUTTONUP ) {
571  mouseevt.setType(MouseEvent::RELEASED);
572  } else {
573  mouseevt.setType(MouseEvent::PRESSED);
574  }
575 
576  switch (sdlevt.button.button) {
577  case SDL_BUTTON_WHEELDOWN:
578  mouseevt.setType(MouseEvent::WHEEL_MOVED_DOWN);
579  break;
580  case SDL_BUTTON_WHEELUP:
581  mouseevt.setType(MouseEvent::WHEEL_MOVED_UP);
582  break;
583  default:
584  break;
585  }
586  }
587  if ((mouseevt.getType() == MouseEvent::MOVED) && m_mousestate) {
588  mouseevt.setType(MouseEvent::DRAGGED);
589  mouseevt.setButton(m_mostrecentbtn);
590  }
591  }
592 
593  void EventManager::fillKeyEvent(const SDL_Event& sdlevt, KeyEvent& keyevt) {
594  if (sdlevt.type == SDL_KEYDOWN) {
595  keyevt.setType(KeyEvent::PRESSED);
596  } else if (sdlevt.type == SDL_KEYUP) {
597  keyevt.setType(KeyEvent::RELEASED);
598  } else {
599  FL_WARN(_log, LMsg("fillKeyEvent()")
600  << " Invalid key event type of " << sdlevt.type << ". Ignoring event.");
601  return;
602  }
603  SDL_keysym keysym = sdlevt.key.keysym;
604 
605  keyevt.setShiftPressed((keysym.mod & KMOD_SHIFT) != 0);
606  keyevt.setControlPressed((keysym.mod & KMOD_CTRL) != 0);
607  keyevt.setAltPressed((keysym.mod & KMOD_ALT) != 0);
608  keyevt.setMetaPressed((keysym.mod & KMOD_META) != 0);
609  keyevt.setNumericPad(keysym.sym >= SDLK_KP0 && keysym.sym <= SDLK_KP_EQUALS);
610  keyevt.setKey(Key(static_cast<Key::KeyType>(keysym.sym), keysym.unicode));
611  }
612 
613  void EventManager::fillModifiers(InputEvent& evt) {
614  evt.setAltPressed(m_keystatemap[Key::ALT_GR] |
615  m_keystatemap[Key::LEFT_ALT] |
616  m_keystatemap[Key::RIGHT_ALT]);
617  evt.setControlPressed(m_keystatemap[Key::LEFT_CONTROL] |
618  m_keystatemap[Key::RIGHT_CONTROL]);
619  evt.setMetaPressed(m_keystatemap[Key::LEFT_META] |
620  m_keystatemap[Key::RIGHT_META]);
621  evt.setShiftPressed(m_keystatemap[Key::LEFT_SHIFT] |
622  m_keystatemap[Key::RIGHT_SHIFT]);
623  }
624 
626  return ES_ENGINE;
627  }
628 
629  void EventManager::setKeyFilter(IKeyFilter* keyFilter) {
630  m_keyfilter = keyFilter;
631  }
632 
633  void EventManager::setMouseSensitivity(float sensitivity) {
634  if (sensitivity < -0.99) {
635  sensitivity = -0.99;
636  } else if (sensitivity > 10.0) {
637  sensitivity = 10.0;
638  }
639  m_mousesensitivity = sensitivity;
640  }
641 
643  return m_mousesensitivity;
644  }
645 
646  void EventManager::setMouseAcceleration(bool acceleration) {
647  m_acceleration = acceleration;
648  }
649 
651  return m_acceleration;
652  }
653 }