Mercurial > fife-parpg
diff engine/core/eventchannel/eventmanager.cpp @ 0:4a0efb7baf70
* Datasets becomes the new trunk and retires after that :-)
author | mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Sun, 29 Jun 2008 18:44:17 +0000 |
parents | |
children | e84dccee1bb7 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/engine/core/eventchannel/eventmanager.cpp Sun Jun 29 18:44:17 2008 +0000 @@ -0,0 +1,576 @@ +/*************************************************************************** + * Copyright (C) 2005-2008 by the FIFE team * + * http://www.fifengine.de * + * This file is part of FIFE. * + * * + * FIFE is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * + ***************************************************************************/ + +// Standard C++ library includes +#include <iostream> + +// 3rd party library includes + +// FIFE includes +// These includes are split up in two parts, separated by one empty line +// First block: files included from the FIFE root src directory +// Second block: files included from the same folder +#include "util/base/exception.h" +#include "eventchannel/key/ec_key.h" +#include "eventchannel/key/ec_keyevent.h" +#include "eventchannel/mouse/ec_mouseevent.h" +#include "eventchannel/widget/ec_widgetevent.h" +#include "eventchannel/command/ec_command.h" +#include "eventchannel/trigger/ec_trigger.h" + +#include "eventmanager.h" + +namespace FIFE { + + EventManager::EventManager(): + m_commandlisteners(), + m_keylisteners(), + m_mouselisteners(), + m_sdleventlisteners(), + m_widgetlisteners(), + m_pending_widgetlisteners(), + m_nonconsumablekeys(), + m_keystatemap(), + m_mousestate(0), + m_mostrecentbtn(MouseEvent::EMPTY) + { + } + + EventManager::~EventManager() { + } + + void EventManager::fillMouseEvent(const SDL_Event& sdlevt, MouseEvent& mouseevt) { + mouseevt.setX(sdlevt.button.x); + mouseevt.setY(sdlevt.button.y); + mouseevt.setButton(MouseEvent::EMPTY); + mouseevt.setType(MouseEvent::MOVED); + if ((sdlevt.type == SDL_MOUSEBUTTONUP) || (sdlevt.type == SDL_MOUSEBUTTONDOWN)) { + switch (sdlevt.button.button) { + case SDL_BUTTON_LEFT: + mouseevt.setButton(MouseEvent::LEFT); + break; + case SDL_BUTTON_RIGHT: + mouseevt.setButton(MouseEvent::RIGHT); + break; + case SDL_BUTTON_MIDDLE: + mouseevt.setButton(MouseEvent::MIDDLE); + break; + default: + mouseevt.setButton(MouseEvent::UNKNOWN_BUTTON); + break; + } + + + if (sdlevt.type == SDL_MOUSEBUTTONUP ) { + + mouseevt.setType(MouseEvent::RELEASED); + + } else { + mouseevt.setType(MouseEvent::PRESSED); + } + + switch (sdlevt.button.button) { + case SDL_BUTTON_WHEELDOWN: + mouseevt.setType(MouseEvent::WHEEL_MOVED_DOWN); + break; + case SDL_BUTTON_WHEELUP: + mouseevt.setType(MouseEvent::WHEEL_MOVED_UP); + break; + default: + break; + } + } + if ((mouseevt.getType() == MouseEvent::MOVED) && m_mousestate) { + mouseevt.setType(MouseEvent::DRAGGED); + mouseevt.setButton(m_mostrecentbtn); + } + } + + void EventManager::fillKeyEvent(const SDL_Event& sdlevt, KeyEvent& keyevt) { + if (sdlevt.type == SDL_KEYDOWN) { + keyevt.setType(KeyEvent::PRESSED); + } else if (sdlevt.type == SDL_KEYUP) { + keyevt.setType(KeyEvent::RELEASED); + } else { + throw EventException("Invalid event type in fillKeyEvent"); + } + keyevt.setShiftPressed(sdlevt.key.keysym.mod & KMOD_SHIFT); + keyevt.setControlPressed(sdlevt.key.keysym.mod & KMOD_CTRL); + keyevt.setAltPressed(sdlevt.key.keysym.mod & KMOD_ALT); + keyevt.setMetaPressed(sdlevt.key.keysym.mod & KMOD_META); + keyevt.setNumericPad(sdlevt.key.keysym.sym >= SDLK_KP0 + && sdlevt.key.keysym.sym <= SDLK_KP_EQUALS); + + SDL_keysym keysym = sdlevt.key.keysym; + Key::KeyType value = Key::INVALID_KEY; + std::string repr(""); + + if (keysym.unicode < 255) { + value = static_cast<Key::KeyType>(keysym.unicode); + repr.push_back(value); + } + + #define MAP_KEY(_orig, _new) case _orig: value = _new; repr = #_new; break; + switch (keysym.sym) { + MAP_KEY(SDLK_TAB, Key::TAB); + MAP_KEY(SDLK_LALT, Key::LEFT_ALT); + MAP_KEY(SDLK_RALT, Key::RIGHT_ALT); + MAP_KEY(SDLK_LSHIFT, Key::LEFT_SHIFT); + MAP_KEY(SDLK_RSHIFT, Key::RIGHT_SHIFT); + MAP_KEY(SDLK_LCTRL, Key::LEFT_CONTROL); + MAP_KEY(SDLK_RCTRL, Key::RIGHT_CONTROL); + MAP_KEY(SDLK_BACKSPACE, Key::BACKSPACE); + MAP_KEY(SDLK_PAUSE, Key::PAUSE); + MAP_KEY(SDLK_ESCAPE, Key::ESCAPE); + MAP_KEY(SDLK_DELETE, Key::DELETE_KEY); + MAP_KEY(SDLK_INSERT, Key::INSERT); + MAP_KEY(SDLK_HOME, Key::HOME); + MAP_KEY(SDLK_END, Key::END); + MAP_KEY(SDLK_PAGEUP, Key::PAGE_UP); + MAP_KEY(SDLK_PRINT, Key::PRINT_SCREEN); + MAP_KEY(SDLK_PAGEDOWN, Key::PAGE_DOWN); + MAP_KEY(SDLK_F1, Key::F1); + MAP_KEY(SDLK_F2, Key::F2); + MAP_KEY(SDLK_F3, Key::F3); + MAP_KEY(SDLK_F4, Key::F4); + MAP_KEY(SDLK_F5, Key::F5); + MAP_KEY(SDLK_F6, Key::F6); + MAP_KEY(SDLK_F7, Key::F7); + MAP_KEY(SDLK_F8, Key::F8); + MAP_KEY(SDLK_F9, Key::F9); + MAP_KEY(SDLK_F10, Key::F10); + MAP_KEY(SDLK_F11, Key::F11); + MAP_KEY(SDLK_F12, Key::F12); + MAP_KEY(SDLK_F13, Key::F13); + MAP_KEY(SDLK_F14, Key::F14); + MAP_KEY(SDLK_F15, Key::F15); + MAP_KEY(SDLK_NUMLOCK, Key::NUM_LOCK); + MAP_KEY(SDLK_CAPSLOCK, Key::CAPS_LOCK); + MAP_KEY(SDLK_SCROLLOCK, Key::SCROLL_LOCK); + MAP_KEY(SDLK_RMETA, Key::RIGHT_META); + MAP_KEY(SDLK_LMETA, Key::LEFT_META); + MAP_KEY(SDLK_LSUPER, Key::LEFT_SUPER); + MAP_KEY(SDLK_RSUPER, Key::RIGHT_SUPER); + MAP_KEY(SDLK_MODE, Key::ALT_GR); + MAP_KEY(SDLK_UP, Key::UP); + MAP_KEY(SDLK_DOWN, Key::DOWN); + MAP_KEY(SDLK_LEFT, Key::LEFT); + MAP_KEY(SDLK_RIGHT, Key::RIGHT); + MAP_KEY(SDLK_RETURN, Key::ENTER); + MAP_KEY(SDLK_KP_ENTER, Key::ENTER); + case SDLK_SPACE: + // Special characters like ~ (tilde) ends up with the keysym.sym SDLK_SPACE which + // without this check would be lost. The check is only valid on key down events in SDL. + if (sdlevt.type == SDL_KEYUP || keysym.unicode == ' ') { + value = Key::SPACE; + } + break; + default: + break; + } + + if (!(keysym.mod & KMOD_NUM)) { + switch (keysym.sym) { + MAP_KEY(SDLK_KP0, Key::INSERT); + MAP_KEY(SDLK_KP1, Key::END); + MAP_KEY(SDLK_KP2, Key::DOWN); + MAP_KEY(SDLK_KP3, Key::PAGE_DOWN); + MAP_KEY(SDLK_KP4, Key::LEFT); + MAP_KEY(SDLK_KP5, Key::INVALID_KEY); + MAP_KEY(SDLK_KP6, Key::RIGHT); + MAP_KEY(SDLK_KP7, Key::HOME); + MAP_KEY(SDLK_KP8, Key::UP); + MAP_KEY(SDLK_KP9, Key::PAGE_UP); + default: + break; + } + } + + keyevt.setKey(Key(value, repr)); + } + + template<typename T> + void removeListener(std::vector<T>& vec, T& listener) { + vec.push_back(listener); + } + + template<typename T> + void addListener(std::vector<T>& vec, T& listener) { + vec.push_back(listener); + } + + void EventManager::addCommandListener(ICommandListener* listener) { + addListener<ICommandListener*>(m_pending_commandlisteners, listener); + } + + void EventManager::removeCommandListener(ICommandListener* listener) { + removeListener<ICommandListener*>(m_pending_cldeletions, listener); + } + + void EventManager::addKeyListener(IKeyListener* listener) { + addListener<IKeyListener*>(m_pending_keylisteners, listener); + } + + void EventManager::removeKeyListener(IKeyListener* listener) { + removeListener<IKeyListener*>(m_pending_kldeletions, listener); + } + + void EventManager::addMouseListener(IMouseListener* listener) { + addListener<IMouseListener*>(m_pending_mouselisteners, listener); + } + + void EventManager::removeMouseListener(IMouseListener* listener) { + removeListener<IMouseListener*>(m_pending_mldeletions, listener); + } + + void EventManager::addSdlEventListener(ISdlEventListener* listener) { + addListener<ISdlEventListener*>(m_pending_sdleventlisteners, listener); + } + + void EventManager::removeSdlEventListener(ISdlEventListener* listener) { + removeListener<ISdlEventListener*>(m_pending_sdldeletions, listener); + } + + void EventManager::addWidgetListener(IWidgetListener* listener) { + addListener<IWidgetListener*>(m_pending_widgetlisteners, listener); + } + + void EventManager::removeWidgetListener(IWidgetListener* listener) { + removeListener<IWidgetListener*>(m_pending_wldeletions, listener); + } + + void EventManager::dispatchCommand(Command& command) { + if(!m_pending_commandlisteners.empty()) { + std::vector<ICommandListener*>::iterator i = m_pending_commandlisteners.begin(); + while (i != m_pending_commandlisteners.end()) { + m_commandlisteners.push_back(*i); + ++i; + } + m_pending_commandlisteners.clear(); + } + + if (!m_pending_cldeletions.empty()) { + std::vector<ICommandListener*>::iterator i = m_pending_cldeletions.begin(); + while (i != m_pending_cldeletions.end()) { + std::vector<ICommandListener*>::iterator j = m_commandlisteners.begin(); + while (j != m_commandlisteners.end()) { + if(*j == *i) { + m_commandlisteners.erase(j); + break; + } + ++j; + } + ++i; + } + m_pending_cldeletions.clear(); + } + + std::vector<ICommandListener*>::iterator i = m_commandlisteners.begin(); + while (i != m_commandlisteners.end()) { + (*i)->onCommand(command); + if (command.isConsumed()) { + break; + } + ++i; + } + } + + void EventManager::dispatchKeyEvent(KeyEvent& evt) { + bool nonconsumablekey = false; + for (std::vector<int>::iterator it = m_nonconsumablekeys.begin(); + it != m_nonconsumablekeys.end(); ++it) { + if (*it == evt.getKey().getValue()) { + nonconsumablekey = true; + break; + } + } + + if(!m_pending_keylisteners.empty()) { + std::vector<IKeyListener*>::iterator i = m_pending_keylisteners.begin(); + while (i != m_pending_keylisteners.end()) { + m_keylisteners.push_back(*i); + ++i; + } + m_pending_keylisteners.clear(); + } + + if (!m_pending_kldeletions.empty()) { + std::vector<IKeyListener*>::iterator i = m_pending_kldeletions.begin(); + while (i != m_pending_kldeletions.end()) { + std::vector<IKeyListener*>::iterator j = m_keylisteners.begin(); + while (j != m_keylisteners.end()) { + if(*j == *i) { + m_keylisteners.erase(j); + break; + } + ++j; + } + ++i; + } + m_pending_kldeletions.clear(); + } + + std::vector<IKeyListener*>::iterator i = m_keylisteners.begin(); + while (i != m_keylisteners.end()) { + switch (evt.getType()) { + case KeyEvent::PRESSED: + (*i)->keyPressed(evt); + break; + case KeyEvent::RELEASED: + (*i)->keyReleased(evt); + break; + default: + break; + } + if ((!nonconsumablekey) && (evt.isConsumed())) { + break; + } + ++i; + } + } + + void EventManager::fillModifiers(InputEvent& evt) { + evt.setAltPressed(m_keystatemap[Key::ALT_GR] | + m_keystatemap[Key::LEFT_ALT] | + m_keystatemap[Key::RIGHT_ALT]); + evt.setControlPressed(m_keystatemap[Key::LEFT_CONTROL] | + m_keystatemap[Key::RIGHT_CONTROL]); + evt.setMetaPressed(m_keystatemap[Key::LEFT_META] | + m_keystatemap[Key::RIGHT_META]); + evt.setShiftPressed(m_keystatemap[Key::LEFT_SHIFT] | + m_keystatemap[Key::RIGHT_SHIFT]); + } + + void EventManager::dispatchMouseEvent(MouseEvent& evt) { + if(!m_pending_mouselisteners.empty()) { + std::vector<IMouseListener*>::iterator i = m_pending_mouselisteners.begin(); + while (i != m_pending_mouselisteners.end()) { + m_mouselisteners.push_back(*i); + ++i; + } + m_pending_mouselisteners.clear(); + } + + if (!m_pending_mldeletions.empty()) { + std::vector<IMouseListener*>::iterator i = m_pending_mldeletions.begin(); + while (i != m_pending_mldeletions.end()) { + std::vector<IMouseListener*>::iterator j = m_mouselisteners.begin(); + while (j != m_mouselisteners.end()) { + if(*j == *i) { + m_mouselisteners.erase(j); + break; + } + ++j; + } + ++i; + } + m_pending_mldeletions.clear(); + } + + std::vector<IMouseListener*>::iterator i = m_mouselisteners.begin(); + while (i != m_mouselisteners.end()) { + switch (evt.getType()) { + case MouseEvent::MOVED: + (*i)->mouseMoved(evt); + break; + case MouseEvent::PRESSED: + (*i)->mousePressed(evt); + break; + case MouseEvent::RELEASED: + (*i)->mouseReleased(evt); + break; + case MouseEvent::WHEEL_MOVED_DOWN: + (*i)->mouseWheelMovedDown(evt); + break; + case MouseEvent::WHEEL_MOVED_UP: + (*i)->mouseWheelMovedUp(evt); + break; + case MouseEvent::CLICKED: + (*i)->mouseClicked(evt); + break; + case MouseEvent::ENTERED: + (*i)->mouseEntered(evt); + case MouseEvent::EXITED: + (*i)->mouseExited(evt); + break; + case MouseEvent::DRAGGED: + (*i)->mouseDragged(evt); + break; + default: + break; + } + if (evt.isConsumed()) { + break; + } + ++i; + } + } + + void EventManager::dispatchSdlEvent(SDL_Event& evt) { + if (!m_pending_sdleventlisteners.empty()) { + std::vector<ISdlEventListener*>::iterator i = m_pending_sdleventlisteners.begin(); + while(i != m_pending_sdleventlisteners.end()) { + m_sdleventlisteners.push_back(*i); + ++i; + } + m_pending_sdleventlisteners.clear(); + } + + if (!m_pending_sdldeletions.empty()) { + std::vector<ISdlEventListener*>::iterator i = m_pending_sdldeletions.begin(); + while (i != m_pending_sdldeletions.end()) { + std::vector<ISdlEventListener*>::iterator j = m_sdleventlisteners.begin(); + while (j != m_sdleventlisteners.end()) { + if(*j == *i) { + m_sdleventlisteners.erase(j); + break; + } + ++j; + } + ++i; + } + m_pending_sdldeletions.clear(); + } + + std::vector<ISdlEventListener*>::iterator i = m_sdleventlisteners.begin(); + while (i != m_sdleventlisteners.end()) { + (*i)->onSdlEvent(evt); + ++i; + } + } + + void EventManager::dispatchWidgetEvent(WidgetEvent& evt) { + if(!m_pending_widgetlisteners.empty()) { + std::vector<IWidgetListener*>::iterator i = m_pending_widgetlisteners.begin(); + while (i != m_pending_widgetlisteners.end()) { + m_widgetlisteners.push_back(*i); + ++i; + } + m_pending_widgetlisteners.clear(); + } + + if (!m_pending_wldeletions.empty()) { + std::vector<IWidgetListener*>::iterator i = m_pending_wldeletions.begin(); + while (i != m_pending_wldeletions.end()) { + std::vector<IWidgetListener*>::iterator j = m_widgetlisteners.begin(); + while (j != m_widgetlisteners.end()) { + if(*j == *i) { + m_widgetlisteners.erase(j); + break; + } + ++j; + } + ++i; + } + m_pending_wldeletions.clear(); + } + + std::vector<IWidgetListener*>::iterator i = m_widgetlisteners.begin(); + while (i != m_widgetlisteners.end()) { + (*i)->onWidgetAction(evt); + if (evt.isConsumed()) { + break; + } + ++i; + } + } + + void EventManager::onWidgetAction(WidgetEvent& evt) { + dispatchWidgetEvent(evt); + } + + void EventManager::processEvents(){ + SDL_Event event; + while (SDL_PollEvent(&event)) { + dispatchSdlEvent(event); + switch (event.type) { + case SDL_QUIT: { + Command cmd; + cmd.setSource(this); + cmd.setCommandType(CMD_QUIT_GAME); + dispatchCommand(cmd); + break; + } + case SDL_ACTIVEEVENT: + break; + case SDL_KEYDOWN: + case SDL_KEYUP: { + KeyEvent keyevt; + keyevt.setSource(this); + fillKeyEvent(event, keyevt); + m_keystatemap[keyevt.getKey().getValue()] = (keyevt.getType() == KeyEvent::PRESSED); + dispatchKeyEvent(keyevt); + } + break; + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEMOTION: + case SDL_MOUSEBUTTONDOWN: { + MouseEvent mouseevt; + mouseevt.setSource(this); + fillMouseEvent(event, mouseevt); + fillModifiers(mouseevt); + if (event.type == SDL_MOUSEBUTTONDOWN) { + m_mousestate |= static_cast<int>(mouseevt.getButton()); + m_mostrecentbtn = mouseevt.getButton(); + } else if (event.type == SDL_MOUSEBUTTONUP) { + m_mousestate &= ~static_cast<int>(mouseevt.getButton()); + } + // fire scrollwheel events only once + if (event.button.button == SDL_BUTTON_WHEELDOWN || event.button.button == SDL_BUTTON_WHEELUP) { + if (event.type == SDL_MOUSEBUTTONUP) { + break; + } + } + dispatchMouseEvent(mouseevt); + break; + } + } + } + + pollTriggers(); + } + + EventSourceType EventManager::getEventSourceType() { + return ES_ENGINE; + } + + void EventManager::setNonConsumableKeys(const std::vector<int>& keys) { + m_nonconsumablekeys = keys; + } + + std::vector<int> EventManager::getNonConsumableKeys() { + return m_nonconsumablekeys; + } + + void EventManager::registerTrigger(Trigger& trigger){ + m_triggers.push_back(&trigger); + } + + void EventManager::unregisterTrigger(Trigger& trigger){ + m_triggers.remove(&trigger); + } + + void EventManager::pollTriggers(){ + for (std::list<Trigger*>::iterator it = m_triggers.begin(); it!=m_triggers.end(); ++it) { + (*it)->pollTrigger(); + } + } +}