diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 405320881..97cc9b035 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -25,7 +25,7 @@ add_openmw_dir (mwrender ) add_openmw_dir (mwinput - actions actionmanager controllermanager inputmanagerimp mousemanager sdlmappings sensormanager + actions actionmanager controllermanager inputmanagerimp mousemanager keyboardmanager sdlmappings sensormanager ) add_openmw_dir (mwgui diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index ec687ed7b..209800bd6 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -94,7 +94,7 @@ namespace MWInput return (mInputBinder->getChannel (id)->getValue ()==1.0); } - void ControllerManager::update(float dt, bool disableControls, bool gamepadPreviewMode) + bool ControllerManager::update(float dt, bool disableControls, bool gamepadPreviewMode) { mControlsDisabled = disableControls; mGamepadPreviewMode = gamepadPreviewMode; @@ -122,23 +122,21 @@ namespace MWInput } } - MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); - // Disable movement in Gui mode if (MWBase::Environment::get().getWindowManager()->isGuiMode() || MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running) { mGamepadZoom = 0; - return; + return false; } - // Configure player movement according to keyboard input. Actual movement will + MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); + bool triedToMove = false; + + // Configure player movement according to controller input. Actual movement will // be done in the physics system. if (MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols")) { - bool triedToMove = false; - - // joystick movement float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue(); float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue(); if (xAxis != .5) @@ -157,7 +155,8 @@ namespace MWInput if (triedToMove) mJoystickLastUsed = true; - if(triedToMove) MWBase::Environment::get().getInputManager()->resetIdleTime(); + if (triedToMove) + MWBase::Environment::get().getInputManager()->resetIdleTime(); static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input"); if (!isToggleSneak) @@ -205,6 +204,8 @@ namespace MWInput MWBase::Environment::get().getWorld()->setCameraDistance(mGamepadZoom, true, true); } } + + return triedToMove; } void ControllerManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg ) diff --git a/apps/openmw/mwinput/controllermanager.hpp b/apps/openmw/mwinput/controllermanager.hpp index 2343cab39..77b68be54 100644 --- a/apps/openmw/mwinput/controllermanager.hpp +++ b/apps/openmw/mwinput/controllermanager.hpp @@ -31,7 +31,7 @@ namespace MWInput void clear(); - void update(float dt, bool disableControls, bool gamepadPreviewMode); + bool update(float dt, bool disableControls, bool gamepadPreviewMode); virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg); virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index ca07f6645..d176ba480 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -32,6 +32,7 @@ #include "actionmanager.hpp" #include "controllermanager.hpp" +#include "keyboardmanager.hpp" #include "mousemanager.hpp" #include "sdlmappings.hpp" #include "sensormanager.hpp" @@ -47,12 +48,9 @@ namespace MWInput const std::string& controllerBindingsFile, bool grab) : mWindow(window) , mWindowVisible(true) - , mInputWrapper(nullptr) - , mVideoWrapper(nullptr) , mUserFile(userFile) , mDragDrop(false) , mGrabCursor (Settings::Manager::getBool("grab cursor", "Input")) - , mControlsDisabled(false) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) , mGuiCursorEnabled(true) @@ -62,7 +60,6 @@ namespace MWInput , mFakeDeviceID(1) { mInputWrapper = new SDLUtil::InputWrapper(window, viewer, grab); - mInputWrapper->setKeyboardEventCallback (this); mInputWrapper->setWindowEventCallback(this); mVideoWrapper = new SDLUtil::VideoWrapper(window, viewer); @@ -90,14 +87,17 @@ namespace MWInput mActionManager = new ActionManager(mInputBinder, screenCaptureOperation, viewer, screenCaptureHandler); + mKeyboardManager = new KeyboardManager(mInputBinder, mInputWrapper, mActionManager); + mInputWrapper->setKeyboardEventCallback(mKeyboardManager); + mMouseManager = new MouseManager(mInputBinder, mInputWrapper, window); - mInputWrapper->setMouseEventCallback (mMouseManager); + mInputWrapper->setMouseEventCallback(mMouseManager); mControllerManager = new ControllerManager(mInputBinder, mInputWrapper, mActionManager, mMouseManager, userControllerBindingsFile, controllerBindingsFile); mInputWrapper->setControllerEventCallback(mControllerManager); mSensorManager = new SensorManager(); - mInputWrapper->setSensorEventCallback (mSensorManager); + mInputWrapper->setSensorEventCallback(mSensorManager); } void InputManager::clear() @@ -118,6 +118,7 @@ namespace MWInput delete mActionManager; delete mControllerManager; + delete mKeyboardManager; delete mMouseManager; delete mSensorManager; @@ -236,13 +237,11 @@ namespace MWInput void InputManager::update(float dt, bool disableControls, bool disableEvents) { - mControlsDisabled = disableControls; - mInputWrapper->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible()); mInputWrapper->capture(disableEvents); - if (mControlsDisabled) + if (disableControls) { updateCursorMode(); return; @@ -253,7 +252,8 @@ namespace MWInput updateCursorMode(); - mControllerManager->update(dt, disableControls, mPreviewPOVDelay == 1.f); + bool controllerMove = mControllerManager->update(dt, disableControls, mPreviewPOVDelay == 1.f); + bool keyboardMove = mKeyboardManager->update(dt, disableControls); if (mMouseManager->update(dt, disableControls)) resetIdleTime(); @@ -265,64 +265,20 @@ namespace MWInput if (!(MWBase::Environment::get().getWindowManager()->isGuiMode() || MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)) { - // Configure player movement according to keyboard input. Actual movement will - // be done in the physics system. if (mControlSwitch["playercontrols"]) { MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); - bool triedToMove = false; - bool isRunning = false; - bool alwaysRunAllowed = false; - - // keyboard movement - float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue(); - float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue(); - isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25; - - if (actionIsActive(A_MoveLeft) != actionIsActive(A_MoveRight)) - { - alwaysRunAllowed = true; - triedToMove = true; - player.setLeftRight (actionIsActive(A_MoveRight) ? 1 : -1); - } - - if (actionIsActive(A_MoveForward) != actionIsActive(A_MoveBackward)) - { - alwaysRunAllowed = true; - triedToMove = true; - player.setAutoMove (false); - player.setForwardBackward (actionIsActive(A_MoveForward) ? 1 : -1); - } - - if (player.getAutoMove()) - { - alwaysRunAllowed = true; - triedToMove = true; - player.setForwardBackward (1); - } - - static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input"); - if (!isToggleSneak) - { - if(!mControllerManager->joystickLastUsed()) - player.setSneak(actionIsActive(A_Sneak)); - } - + bool attemptToJump = false; if (mAttemptJump && mControlSwitch["playerjumping"]) { - player.setUpDown (1); - triedToMove = true; + player.setUpDown(1); + attemptToJump = true; mOverencumberedMessageDelay = 0.f; } - if ((mActionManager->isAlwaysRunActive() && alwaysRunAllowed) || isRunning) - player.setRunState(!actionIsActive(A_Run)); - else - player.setRunState(actionIsActive(A_Run)); - // if player tried to start moving, but can't (due to being overencumbered), display a notification. - if (triedToMove) + if (controllerMove || keyboardMove || attemptToJump) { MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); mOverencumberedMessageDelay -= dt; @@ -466,52 +422,6 @@ namespace MWInput mControlSwitch[sw] = value; } - void InputManager::keyPressed( const SDL_KeyboardEvent &arg ) - { - // HACK: to make Morrowind's default keybinding for the console work without printing an extra "^" upon closing - // This assumes that SDL_TextInput events always come *after* the key event - // (which is somewhat reasonable, and hopefully true for all SDL platforms) - OIS::KeyCode kc = mInputWrapper->sdl2OISKeyCode(arg.keysym.sym); - if (mInputBinder->getKeyBinding(mInputBinder->getControl(A_Console), ICS::Control::INCREASE) - == arg.keysym.scancode - && MWBase::Environment::get().getWindowManager()->isConsoleMode()) - SDL_StopTextInput(); - - bool consumed = false; - if (kc != OIS::KC_UNASSIGNED && !mInputBinder->detectingBindingState()) - { - consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0, arg.repeat); - if (SDL_IsTextInputActive() && // Little trick to check if key is printable - ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym))) - consumed = true; - setPlayerControlsEnabled(!consumed); - } - if (arg.repeat) - return; - - if (!mControlsDisabled && !consumed) - mInputBinder->keyPressed (arg); - mControllerManager->setJoystickLastUsed(false); - } - - void InputManager::textInput(const SDL_TextInputEvent &arg) - { - MyGUI::UString ustring(&arg.text[0]); - MyGUI::UString::utf32string utf32string = ustring.asUTF32(); - for (MyGUI::UString::utf32string::const_iterator it = utf32string.begin(); it != utf32string.end(); ++it) - MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it); - } - - void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) - { - mControllerManager->setJoystickLastUsed(false); - OIS::KeyCode kc = mInputWrapper->sdl2OISKeyCode(arg.keysym.sym); - - if (!mInputBinder->detectingBindingState()) - setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); - mInputBinder->keyReleased (arg); - } - void InputManager::windowFocusChange(bool have_focus) { } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index e6c084a64..ff0c43a82 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -23,6 +23,7 @@ namespace MWInput { class ActionManager; class ControllerManager; + class KeyboardManager; class MouseManager; class SensorManager; } @@ -62,7 +63,6 @@ namespace MWInput */ class InputManager : public MWBase::InputManager, - public SDLUtil::KeyListener, public SDLUtil::WindowListener, public ICS::ChannelListener, public ICS::DetectingBindingListener @@ -109,10 +109,6 @@ namespace MWInput virtual void setJoystickLastUsed(bool enabled); virtual bool joystickLastUsed(); - virtual void keyPressed(const SDL_KeyboardEvent &arg ); - virtual void keyReleased( const SDL_KeyboardEvent &arg ); - virtual void textInput (const SDL_TextInputEvent &arg); - virtual void windowVisibilityChange( bool visible ); virtual void windowFocusChange( bool have_focus ); virtual void windowResized (int x, int y); @@ -164,8 +160,6 @@ namespace MWInput bool mGrabCursor; - bool mControlsDisabled; - float mPreviewPOVDelay; float mTimeIdle; @@ -181,6 +175,7 @@ namespace MWInput ActionManager* mActionManager; ControllerManager* mControllerManager; + KeyboardManager* mKeyboardManager; MouseManager* mMouseManager; SensorManager* mSensorManager; diff --git a/apps/openmw/mwinput/keyboardmanager.cpp b/apps/openmw/mwinput/keyboardmanager.cpp new file mode 100644 index 000000000..f56246716 --- /dev/null +++ b/apps/openmw/mwinput/keyboardmanager.cpp @@ -0,0 +1,146 @@ +#include "keyboardmanager.hpp" + +#include + +#include + +#include + +#include "../mwbase/environment.hpp" +#include "../mwbase/inputmanager.hpp" +#include "../mwbase/statemanager.hpp" +#include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" + +#include "../mwworld/player.hpp" + +#include "actionmanager.hpp" +#include "actions.hpp" + +namespace MWInput +{ + KeyboardManager::KeyboardManager(ICS::InputControlSystem* inputBinder, SDLUtil::InputWrapper* inputWrapper, ActionManager* actionManager) + : mInputBinder(inputBinder) + , mInputWrapper(inputWrapper) + , mActionManager(actionManager) + , mControlsDisabled(false) + { + } + + bool KeyboardManager::update(float dt, bool disableControls) + { + mControlsDisabled = disableControls; + + // Disable movement in Gui mode + if (MWBase::Environment::get().getWindowManager()->isGuiMode() + || MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running) + { + return false; + } + + // Configure player movement according to keyboard input. Actual movement will + // be done in the physics system. + if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols")) + { + return false; + } + + bool triedToMove = false; + bool alwaysRunAllowed = false; + + MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); + + if (actionIsActive(A_MoveLeft) != actionIsActive(A_MoveRight)) + { + alwaysRunAllowed = true; + triedToMove = true; + player.setLeftRight (actionIsActive(A_MoveRight) ? 1 : -1); + } + + if (actionIsActive(A_MoveForward) != actionIsActive(A_MoveBackward)) + { + alwaysRunAllowed = true; + triedToMove = true; + player.setAutoMove (false); + player.setForwardBackward (actionIsActive(A_MoveForward) ? 1 : -1); + } + + if (player.getAutoMove()) + { + alwaysRunAllowed = true; + triedToMove = true; + player.setForwardBackward (1); + } + + if (triedToMove) + MWBase::Environment::get().getInputManager()->resetIdleTime(); + + static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input"); + if (!isToggleSneak) + { + if(!MWBase::Environment::get().getInputManager()->joystickLastUsed()) + player.setSneak(actionIsActive(A_Sneak)); + } + + float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue(); + float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue(); + bool isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25; + if ((mActionManager->isAlwaysRunActive() && alwaysRunAllowed) || isRunning) + player.setRunState(!actionIsActive(A_Run)); + else + player.setRunState(actionIsActive(A_Run)); + + return triedToMove; + } + + bool KeyboardManager::actionIsActive (int id) + { + return (mInputBinder->getChannel(id)->getValue ()==1.0); + } + + void KeyboardManager::textInput(const SDL_TextInputEvent &arg) + { + MyGUI::UString ustring(&arg.text[0]); + MyGUI::UString::utf32string utf32string = ustring.asUTF32(); + for (MyGUI::UString::utf32string::const_iterator it = utf32string.begin(); it != utf32string.end(); ++it) + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it); + } + + void KeyboardManager::keyPressed(const SDL_KeyboardEvent &arg) + { + // HACK: to make Morrowind's default keybinding for the console work without printing an extra "^" upon closing + // This assumes that SDL_TextInput events always come *after* the key event + // (which is somewhat reasonable, and hopefully true for all SDL platforms) + OIS::KeyCode kc = mInputWrapper->sdl2OISKeyCode(arg.keysym.sym); + if (mInputBinder->getKeyBinding(mInputBinder->getControl(A_Console), ICS::Control::INCREASE) + == arg.keysym.scancode + && MWBase::Environment::get().getWindowManager()->isConsoleMode()) + SDL_StopTextInput(); + + bool consumed = false; + if (kc != OIS::KC_UNASSIGNED && !mInputBinder->detectingBindingState()) + { + consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0, arg.repeat); + if (SDL_IsTextInputActive() && // Little trick to check if key is printable + ( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym))) + consumed = true; + MWBase::Environment::get().getInputManager()->setJoystickLastUsed(!consumed); + } + if (arg.repeat) + return; + + if (!mControlsDisabled && !consumed) + mInputBinder->keyPressed(arg); + MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false); + } + + void KeyboardManager::keyReleased(const SDL_KeyboardEvent &arg) + { + MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false); + OIS::KeyCode kc = mInputWrapper->sdl2OISKeyCode(arg.keysym.sym); + + if (!mInputBinder->detectingBindingState()) + MWBase::Environment::get().getInputManager()->setJoystickLastUsed(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + mInputBinder->keyReleased(arg); + } +} diff --git a/apps/openmw/mwinput/keyboardmanager.hpp b/apps/openmw/mwinput/keyboardmanager.hpp new file mode 100644 index 000000000..590241bc7 --- /dev/null +++ b/apps/openmw/mwinput/keyboardmanager.hpp @@ -0,0 +1,45 @@ +#ifndef MWINPUT_MWKEYBOARDMANAGER_H +#define MWINPUT_MWKEYBOARDMANAGER_H + +#include +#include + +namespace SDLUtil +{ + class InputWrapper; +} + +namespace ICS +{ + class InputControlSystem; +} + +namespace MWInput +{ + class ActionManager; + + class KeyboardManager : public SDLUtil::KeyListener + { + public: + KeyboardManager(ICS::InputControlSystem* inputBinder, SDLUtil::InputWrapper* inputWrapper, ActionManager* actionManager); + + virtual ~KeyboardManager() = default; + + bool update(float dt, bool disableControls); + + virtual void textInput(const SDL_TextInputEvent &arg); + virtual void keyPressed(const SDL_KeyboardEvent &arg); + virtual void keyReleased(const SDL_KeyboardEvent &arg); + + private: + bool actionIsActive(int id); + + ICS::InputControlSystem* mInputBinder; + SDLUtil::InputWrapper* mInputWrapper; + + ActionManager* mActionManager; + + bool mControlsDisabled; + }; +} +#endif diff --git a/apps/openmw/mwinput/sensormanager.hpp b/apps/openmw/mwinput/sensormanager.hpp index d655e9c07..51225e381 100644 --- a/apps/openmw/mwinput/sensormanager.hpp +++ b/apps/openmw/mwinput/sensormanager.hpp @@ -31,7 +31,6 @@ namespace MWInput bool update(float dt, bool isCursorEnabled, bool isTurningEnabled); - public: virtual void sensorUpdated(const SDL_SensorEvent &arg); virtual void displayOrientationChanged(); void processChangedSettings(const Settings::CategorySettingVector& changed); @@ -48,6 +47,11 @@ namespace MWInput Minus_Z = -3 }; + void updateSensors(); + void correctGyroscopeAxes(); + GyroscopeAxis mapGyroscopeAxis(const std::string& axis); + float getGyroAxisSpeed(GyroscopeAxis axis, const SDL_SensorEvent &arg) const; + bool mInvertX; bool mInvertY; @@ -61,12 +65,6 @@ namespace MWInput GyroscopeAxis mGyroVAxis; float mGyroInputThreshold; - private: - - void updateSensors(); - void correctGyroscopeAxes(); - GyroscopeAxis mapGyroscopeAxis(const std::string& axis); - float getGyroAxisSpeed(GyroscopeAxis axis, const SDL_SensorEvent &arg) const; SDL_Sensor* mGyroscope; }; }