diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 255bbbec1a..4053208814 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 inputmanagerimp mousemanager sdlmappings sensormanager + actions actionmanager controllermanager inputmanagerimp mousemanager sdlmappings sensormanager ) add_openmw_dir (mwgui diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp new file mode 100644 index 0000000000..ec687ed7b1 --- /dev/null +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -0,0 +1,409 @@ +#include "controllermanager.hpp" + +#include +#include +#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 "actions.hpp" +#include "actionmanager.hpp" +#include "mousemanager.hpp" + +namespace MWInput +{ + static const int sFakeDeviceID = 1; + + ControllerManager::ControllerManager(ICS::InputControlSystem* inputBinder, + SDLUtil::InputWrapper* inputWrapper, + ActionManager* actionManager, + MouseManager* mouseManager, + const std::string& userControllerBindingsFile, + const std::string& controllerBindingsFile) + : mInputBinder(inputBinder) + , mInputWrapper(inputWrapper) + , mActionManager(actionManager) + , mMouseManager(mouseManager) + , mJoystickEnabled (Settings::Manager::getBool("enable controller", "Input")) + , mGamepadCursorSpeed(Settings::Manager::getFloat("gamepad cursor speed", "Input")) + , mInvUiScalingFactor(1.f) + , mSneakToggleShortcutTimer(0.f) + , mGamepadZoom(0) + , mGamepadGuiCursorEnabled(true) + , mControlsDisabled(false) + , mJoystickLastUsed(false) + , mSneakGamepadShortcut(false) + , mGamepadPreviewMode(false) + { + if(!controllerBindingsFile.empty()) + { + SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.c_str()); + } + if(!userControllerBindingsFile.empty()) + { + SDL_GameControllerAddMappingsFromFile(userControllerBindingsFile.c_str()); + } + + // Open all presently connected sticks + int numSticks = SDL_NumJoysticks(); + for(int i = 0; i < numSticks; i++) + { + if(SDL_IsGameController(i)) + { + SDL_ControllerDeviceEvent evt; + evt.which = i; + controllerAdded(sFakeDeviceID, evt); + Log(Debug::Info) << "Detected game controller: " << SDL_GameControllerNameForIndex(i); + } + else + { + Log(Debug::Info) << "Detected unusable controller: " << SDL_JoystickNameForIndex(i); + } + } + + float uiScale = Settings::Manager::getFloat("scaling factor", "GUI"); + if (uiScale != 0.f) + mInvUiScalingFactor = 1.f / uiScale; + } + + void ControllerManager::clear() + { + } + + void ControllerManager::processChangedSettings(const Settings::CategorySettingVector& changed) + { + for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) + { + if (it->first == "Input" && it->second == "enable controller") + mJoystickEnabled = Settings::Manager::getBool("enable controller", "Input"); + } + } + + bool ControllerManager::actionIsActive (int id) + { + return (mInputBinder->getChannel (id)->getValue ()==1.0); + } + + void ControllerManager::update(float dt, bool disableControls, bool gamepadPreviewMode) + { + mControlsDisabled = disableControls; + mGamepadPreviewMode = gamepadPreviewMode; + + if (mGuiCursorEnabled && !(mJoystickLastUsed && !mGamepadGuiCursorEnabled)) + { + float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue()*2.0f-1.0f; + float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue()*2.0f-1.0f; + float zAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; + + xAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue()); + yAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue()); + + // We keep track of our own mouse position, so that moving the mouse while in + // game mode does not move the position of the GUI cursor + float xMove = xAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed; + float yMove = yAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed; + if (xMove != 0 || yMove != 0 || zAxis != 0) + { + int mouseWheelMove = static_cast(-zAxis * dt * 1500.0f); + + mMouseManager->injectMouseMove(xMove, yMove, mouseWheelMove); + mMouseManager->warpMouse(); + MWBase::Environment::get().getWindowManager()->setCursorActive(true); + } + } + + 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; + } + + // Configure player movement according to keyboard 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) + { + triedToMove = true; + player.setLeftRight((xAxis - 0.5f) * 2); + } + + if (yAxis != .5) + { + triedToMove = true; + player.setAutoMove (false); + player.setForwardBackward((yAxis - 0.5f) * 2 * -1); + } + + if (triedToMove) + mJoystickLastUsed = true; + + if(triedToMove) MWBase::Environment::get().getInputManager()->resetIdleTime(); + + static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input"); + if (!isToggleSneak) + { + if(mJoystickLastUsed) + { + if(actionIsActive(A_Sneak)) + { + if(mSneakToggleShortcutTimer) // New Sneak Button Press + { + if(mSneakToggleShortcutTimer <= 0.3f) + { + mSneakGamepadShortcut = true; + mActionManager->toggleSneaking(); + } + else + mSneakGamepadShortcut = false; + } + + if(!mActionManager->isSneaking()) + mActionManager->toggleSneaking(); + mSneakToggleShortcutTimer = 0.f; + } + else + { + if(!mSneakGamepadShortcut && mActionManager->isSneaking()) + mActionManager->toggleSneaking(); + if(mSneakToggleShortcutTimer <= 0.3f) + mSneakToggleShortcutTimer += dt; + } + } + else + player.setSneak(actionIsActive(A_Sneak)); + } + } + + if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch")) + { + if (!actionIsActive(A_TogglePOV)) + mGamepadZoom = 0; + + if(mGamepadZoom) + { + MWBase::Environment::get().getWorld()->changeVanityModeScale(mGamepadZoom); + MWBase::Environment::get().getWorld()->setCameraDistance(mGamepadZoom, true, true); + } + } + } + + void ControllerManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg ) + { + if (!mJoystickEnabled || mInputBinder->detectingBindingState()) + return; + + mJoystickLastUsed = true; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + if (gamepadToGuiControl(arg)) + return; + if (mGamepadGuiCursorEnabled) + { + // Temporary mouse binding until keyboard controls are available: + if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. + { + bool mousePressSuccess = mMouseManager->injectMouseButtonPress(SDL_BUTTON_LEFT); + if (MyGUI::InputManager::getInstance().getMouseFocusWidget()) + { + MyGUI::Button* b = MyGUI::InputManager::getInstance().getMouseFocusWidget()->castType(false); + if (b && b->getEnabled()) + MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); + } + + MWBase::Environment::get().getInputManager()->setPlayerControlsEnabled(!mousePressSuccess); + } + } + } + else + MWBase::Environment::get().getInputManager()->setPlayerControlsEnabled(true); + + //esc, to leave initial movie screen + auto kc = mInputWrapper->sdl2OISKeyCode(SDLK_ESCAPE); + MWBase::Environment::get().getInputManager()->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0)); + + if (!mControlsDisabled) + mInputBinder->buttonPressed(deviceID, arg); + } + + void ControllerManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg ) + { + if(mInputBinder->detectingBindingState()) + { + mInputBinder->buttonReleased(deviceID, arg); + return; + } + if (!mJoystickEnabled || mControlsDisabled) + return; + + mJoystickLastUsed = true; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + if (mGamepadGuiCursorEnabled) + { + // Temporary mouse binding until keyboard controls are available: + if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. + { + bool mousePressSuccess = mMouseManager->injectMouseButtonRelease(SDL_BUTTON_LEFT); + if (mInputBinder->detectingBindingState()) // If the player just triggered binding, don't let button release bind. + return; + + MWBase::Environment::get().getInputManager()->setPlayerControlsEnabled(!mousePressSuccess); + } + } + } + else + MWBase::Environment::get().getInputManager()->setPlayerControlsEnabled(true); + + //esc, to leave initial movie screen + auto kc = mInputWrapper->sdl2OISKeyCode(SDLK_ESCAPE); + MWBase::Environment::get().getInputManager()->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); + + mInputBinder->buttonReleased(deviceID, arg); + } + + void ControllerManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg) + { + if(!mJoystickEnabled || mControlsDisabled) + return; + + mJoystickLastUsed = true; + if (MWBase::Environment::get().getWindowManager()->isGuiMode()) + { + gamepadToGuiControl(arg); + } + else + { + if(mGamepadPreviewMode && arg.value) // Preview Mode Gamepad Zooming + { + if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) + { + mGamepadZoom = arg.value * 0.85f / 1000.f; + return; // Do not propagate event. + } + else if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT) + { + mGamepadZoom = -arg.value * 0.85f / 1000.f; + return; // Do not propagate event. + } + } + } + mInputBinder->axisMoved(deviceID, arg); + } + + void ControllerManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) + { + mInputBinder->controllerAdded(deviceID, arg); + } + + void ControllerManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg) + { + mInputBinder->controllerRemoved(arg); + } + + bool ControllerManager::gamepadToGuiControl(const SDL_ControllerButtonEvent &arg) + { + // Presumption of GUI mode will be removed in the future. + // MyGUI KeyCodes *may* change. + + MyGUI::KeyCode key = MyGUI::KeyCode::None; + switch (arg.button) + { + case SDL_CONTROLLER_BUTTON_DPAD_UP: + key = MyGUI::KeyCode::ArrowUp; + break; + case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: + key = MyGUI::KeyCode::ArrowRight; + break; + case SDL_CONTROLLER_BUTTON_DPAD_DOWN: + key = MyGUI::KeyCode::ArrowDown; + break; + case SDL_CONTROLLER_BUTTON_DPAD_LEFT: + key = MyGUI::KeyCode::ArrowLeft; + break; + case SDL_CONTROLLER_BUTTON_A: + // If we are using the joystick as a GUI mouse, A must be handled via mouse. + if (mGamepadGuiCursorEnabled) + return false; + key = MyGUI::KeyCode::Space; + break; + case SDL_CONTROLLER_BUTTON_B: + if (MyGUI::InputManager::getInstance().isModalAny()) + MWBase::Environment::get().getWindowManager()->exitCurrentModal(); + else + MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); + return true; + case SDL_CONTROLLER_BUTTON_X: + key = MyGUI::KeyCode::Semicolon; + break; + case SDL_CONTROLLER_BUTTON_Y: + key = MyGUI::KeyCode::Apostrophe; + break; + case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: + key = MyGUI::KeyCode::Period; + break; + case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: + key = MyGUI::KeyCode::Slash; + break; + case SDL_CONTROLLER_BUTTON_LEFTSTICK: + mGamepadGuiCursorEnabled = !mGamepadGuiCursorEnabled; + MWBase::Environment::get().getWindowManager()->setCursorActive(mGamepadGuiCursorEnabled); + return true; + default: + return false; + } + + // Some keys will work even when Text Input windows/modals are in focus. + if (SDL_IsTextInputActive()) + return false; + + MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); + return true; + } + + bool ControllerManager::gamepadToGuiControl(const SDL_ControllerAxisEvent &arg) + { + switch (arg.axis) + { + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + if (arg.value == 32767) // Treat like a button. + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Minus, 0, false); + break; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + if (arg.value == 32767) // Treat like a button. + MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Equals, 0, false); + break; + case SDL_CONTROLLER_AXIS_LEFTX: + case SDL_CONTROLLER_AXIS_LEFTY: + case SDL_CONTROLLER_AXIS_RIGHTX: + case SDL_CONTROLLER_AXIS_RIGHTY: + // If we are using the joystick as a GUI mouse, process mouse movement elsewhere. + if (mGamepadGuiCursorEnabled) + return false; + break; + default: + return false; + } + + return true; + } +} diff --git a/apps/openmw/mwinput/controllermanager.hpp b/apps/openmw/mwinput/controllermanager.hpp new file mode 100644 index 0000000000..2343cab397 --- /dev/null +++ b/apps/openmw/mwinput/controllermanager.hpp @@ -0,0 +1,77 @@ +#ifndef MWINPUT_MWCONTROLLERMANAGER_H +#define MWINPUT_MWCONTROLLERMANAGER_H + +#include + +#include +#include +#include + +namespace ICS +{ + class InputControlSystem; +} + +namespace MWInput +{ + class ActionManager; + class MouseManager; + + class ControllerManager : public SDLUtil::ControllerListener + { + public: + ControllerManager(ICS::InputControlSystem* inputBinder, + SDLUtil::InputWrapper* inputWrapper, + ActionManager* actionManager, + MouseManager* mouseManager, + const std::string& userControllerBindingsFile, + const std::string& controllerBindingsFile); + + virtual ~ControllerManager() = default; + + void clear(); + + void 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); + virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg); + virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg); + virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg); + + void processChangedSettings(const Settings::CategorySettingVector& changed); + + void setJoystickLastUsed(bool enabled) { mJoystickLastUsed = enabled; } + bool joystickLastUsed() { return mJoystickLastUsed; } + + void setGuiCursorEnabled(bool enabled) { mGuiCursorEnabled = enabled; } + + void setGamepadGuiCursorEnabled(bool enabled) { mGamepadGuiCursorEnabled = enabled; } + bool gamepadGuiCursorEnabled() { return mGamepadGuiCursorEnabled; } + + private: + // Return true if GUI consumes input. + bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg); + bool gamepadToGuiControl(const SDL_ControllerAxisEvent &arg); + + bool actionIsActive(int id); + + ICS::InputControlSystem* mInputBinder; + SDLUtil::InputWrapper* mInputWrapper; + ActionManager* mActionManager; + MouseManager* mMouseManager; + + bool mJoystickEnabled; + float mGamepadCursorSpeed; + float mInvUiScalingFactor; + float mSneakToggleShortcutTimer; + float mGamepadZoom; + bool mGamepadGuiCursorEnabled; + bool mControlsDisabled; + bool mJoystickLastUsed; + bool mGuiCursorEnabled; + bool mSneakGamepadShortcut; + bool mGamepadPreviewMode; + }; +} +#endif diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4376951b5c..a647aac20e 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -31,6 +31,7 @@ #include "../mwmechanics/actorutil.hpp" #include "actionmanager.hpp" +#include "controllermanager.hpp" #include "mousemanager.hpp" #include "sdlmappings.hpp" #include "sensormanager.hpp" @@ -46,31 +47,23 @@ namespace MWInput const std::string& controllerBindingsFile, bool grab) : mWindow(window) , mWindowVisible(true) - , mJoystickLastUsed(false) , mInputManager(nullptr) , mVideoWrapper(nullptr) , mUserFile(userFile) , mDragDrop(false) , mGrabCursor (Settings::Manager::getBool("grab cursor", "Input")) , mControlsDisabled(false) - , mJoystickEnabled (Settings::Manager::getBool("enable controller", "Input")) , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) , mGuiCursorEnabled(true) - , mGamepadGuiCursorEnabled(true) , mDetectingKeyboard(false) , mOverencumberedMessageDelay(0.f) - , mGamepadZoom(0) - , mSneakToggleShortcutTimer(0.f) - , mSneakGamepadShortcut(false) , mAttemptJump(false) - , mGamepadCursorSpeed(Settings::Manager::getFloat("gamepad cursor speed", "Input")) , mFakeDeviceID(1) { mInputManager = new SDLUtil::InputWrapper(window, viewer, grab); mInputManager->setKeyboardEventCallback (this); mInputManager->setWindowEventCallback(this); - mInputManager->setControllerEventCallback(this); mVideoWrapper = new SDLUtil::VideoWrapper(window, viewer); mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"), @@ -95,42 +88,16 @@ namespace MWInput mControlSwitch["playerviewswitch"] = true; mControlSwitch["vanitymode"] = true; - /* Joystick Init */ - - // Load controller mappings - if(!controllerBindingsFile.empty()) - { - SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.c_str()); - } - if(!userControllerBindingsFile.empty()) - { - SDL_GameControllerAddMappingsFromFile(userControllerBindingsFile.c_str()); - } - - // Open all presently connected sticks - int numSticks = SDL_NumJoysticks(); - for(int i = 0; i < numSticks; i++) - { - if(SDL_IsGameController(i)) - { - SDL_ControllerDeviceEvent evt; - evt.which = i; - controllerAdded(mFakeDeviceID, evt); - Log(Debug::Info) << "Detected game controller: " << SDL_GameControllerNameForIndex(i); - } - else - { - Log(Debug::Info) << "Detected unusable controller: " << SDL_JoystickNameForIndex(i); - } - } - - mSensorManager = new SensorManager(); - mInputManager->setSensorEventCallback (mSensorManager); + mActionManager = new ActionManager(mInputBinder, screenCaptureOperation, viewer, screenCaptureHandler); mMouseManager = new MouseManager(mInputBinder, mInputManager, window); mInputManager->setMouseEventCallback (mMouseManager); - mActionManager = new ActionManager(mInputBinder, screenCaptureOperation, viewer, screenCaptureHandler); + mControllerManager = new ControllerManager(mInputBinder, mInputManager, mActionManager, mMouseManager, userControllerBindingsFile, controllerBindingsFile); + mInputManager->setControllerEventCallback(mControllerManager); + + mSensorManager = new SensorManager(); + mInputManager->setSensorEventCallback (mSensorManager); } void InputManager::clear() @@ -140,6 +107,7 @@ namespace MWInput it->second = true; mActionManager->clear(); + mControllerManager->clear(); mSensorManager->clear(); mMouseManager->clear(); } @@ -149,6 +117,7 @@ namespace MWInput mInputBinder->save (mUserFile); delete mActionManager; + delete mControllerManager; delete mMouseManager; delete mSensorManager; @@ -178,93 +147,6 @@ namespace MWInput } } - bool InputManager::gamepadToGuiControl(const SDL_ControllerButtonEvent &arg) - { - // Presumption of GUI mode will be removed in the future. - // MyGUI KeyCodes *may* change. - - MyGUI::KeyCode key = MyGUI::KeyCode::None; - switch (arg.button) - { - case SDL_CONTROLLER_BUTTON_DPAD_UP: - key = MyGUI::KeyCode::ArrowUp; - break; - case SDL_CONTROLLER_BUTTON_DPAD_RIGHT: - key = MyGUI::KeyCode::ArrowRight; - break; - case SDL_CONTROLLER_BUTTON_DPAD_DOWN: - key = MyGUI::KeyCode::ArrowDown; - break; - case SDL_CONTROLLER_BUTTON_DPAD_LEFT: - key = MyGUI::KeyCode::ArrowLeft; - break; - case SDL_CONTROLLER_BUTTON_A: - // If we are using the joystick as a GUI mouse, A must be handled via mouse. - if (mGamepadGuiCursorEnabled) - return false; - key = MyGUI::KeyCode::Space; - break; - case SDL_CONTROLLER_BUTTON_B: - if (MyGUI::InputManager::getInstance().isModalAny()) - MWBase::Environment::get().getWindowManager()->exitCurrentModal(); - else - MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); - return true; - case SDL_CONTROLLER_BUTTON_X: - key = MyGUI::KeyCode::Semicolon; - break; - case SDL_CONTROLLER_BUTTON_Y: - key = MyGUI::KeyCode::Apostrophe; - break; - case SDL_CONTROLLER_BUTTON_LEFTSHOULDER: - key = MyGUI::KeyCode::Period; - break; - case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER: - key = MyGUI::KeyCode::Slash; - break; - case SDL_CONTROLLER_BUTTON_LEFTSTICK: - mGamepadGuiCursorEnabled = !mGamepadGuiCursorEnabled; - MWBase::Environment::get().getWindowManager()->setCursorActive(mGamepadGuiCursorEnabled); - return true; - default: - return false; - } - - // Some keys will work even when Text Input windows/modals are in focus. - if (SDL_IsTextInputActive()) - return false; - - MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false); - return true; - } - - bool InputManager::gamepadToGuiControl(const SDL_ControllerAxisEvent &arg) - { - switch (arg.axis) - { - case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: - if (arg.value == 32767) // Treat like a button. - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Minus, 0, false); - break; - case SDL_CONTROLLER_AXIS_TRIGGERLEFT: - if (arg.value == 32767) // Treat like a button. - MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Equals, 0, false); - break; - case SDL_CONTROLLER_AXIS_LEFTX: - case SDL_CONTROLLER_AXIS_LEFTY: - case SDL_CONTROLLER_AXIS_RIGHTX: - case SDL_CONTROLLER_AXIS_RIGHTY: - // If we are using the joystick as a GUI mouse, process mouse movement elsewhere. - if (mGamepadGuiCursorEnabled) - return false; - break; - default: - return false; - } - - return true; - } - void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue) { resetIdleTime (); @@ -297,12 +179,13 @@ namespace MWInput if (mControlSwitch["playercontrols"]) { + bool joystickUsed = mControllerManager->joystickLastUsed(); if (action == A_Use) { - if(mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon)) + if(joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon)) action = A_CycleWeaponRight; - else if (mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell)) + else if (joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell)) action = A_CycleSpellRight; else @@ -314,10 +197,10 @@ namespace MWInput } else if (action == A_Jump) { - if(mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon)) + if(joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon)) action = A_CycleWeaponLeft; - else if (mJoystickLastUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell)) + else if (joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell)) action = A_CycleSpellLeft; else @@ -371,28 +254,7 @@ namespace MWInput updateCursorMode(); - if (mGuiCursorEnabled && !(mJoystickLastUsed && !mGamepadGuiCursorEnabled)) - { - float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue()*2.0f-1.0f; - float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue()*2.0f-1.0f; - float zAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f; - - xAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue()); - yAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue()); - - // We keep track of our own mouse position, so that moving the mouse while in - // game mode does not move the position of the GUI cursor - float xMove = xAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed; - float yMove = yAxis * dt * 1500.0f * mInvUiScalingFactor * mGamepadCursorSpeed; - if (xMove != 0|| yMove != 0 || zAxis != 0) - { - int mouseWheelMove = static_cast(-zAxis * dt * 1500.0f); - - mMouseManager->injectMouseMove(xMove, yMove, mouseWheelMove); - mMouseManager->warpMouse(); - MWBase::Environment::get().getWindowManager()->setCursorActive(true); - } - } + mControllerManager->update(dt, disableControls, mPreviewPOVDelay == 1.f); if (mMouseManager->update(dt, disableControls)) resetIdleTime(); @@ -414,28 +276,10 @@ namespace MWInput bool isRunning = false; bool alwaysRunAllowed = false; - // joystick movement + // keyboard movement float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue(); float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue(); - if (xAxis != .5) - { - triedToMove = true; - player.setLeftRight((xAxis - 0.5f) * 2); - } - - if (yAxis != .5) - { - triedToMove = true; - player.setAutoMove (false); - player.setForwardBackward((yAxis - 0.5f) * 2 * -1); - } - - if (triedToMove) - mJoystickLastUsed = true; - - // keyboard movement isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25; - if(triedToMove) resetIdleTime(); if (actionIsActive(A_MoveLeft) != actionIsActive(A_MoveRight)) { @@ -462,34 +306,7 @@ namespace MWInput static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input"); if (!isToggleSneak) { - if(mJoystickLastUsed) - { - if(actionIsActive(A_Sneak)) - { - if(mSneakToggleShortcutTimer) // New Sneak Button Press - { - if(mSneakToggleShortcutTimer <= 0.3f) - { - mSneakGamepadShortcut = true; - mActionManager->toggleSneaking(); - } - else - mSneakGamepadShortcut = false; - } - - if(!mActionManager->isSneaking()) - mActionManager->toggleSneaking(); - mSneakToggleShortcutTimer = 0.f; - } - else - { - if(!mSneakGamepadShortcut && mActionManager->isSneaking()) - mActionManager->toggleSneaking(); - if(mSneakToggleShortcutTimer <= 0.3f) - mSneakToggleShortcutTimer += dt; - } - } - else + if(!mControllerManager->joystickLastUsed()) player.setSneak(actionIsActive(A_Sneak)); } @@ -537,13 +354,6 @@ namespace MWInput MWBase::Environment::get().getWorld()->togglePOV(); } mPreviewPOVDelay = 0.f; - mGamepadZoom = 0; - } - - if(mGamepadZoom) - { - MWBase::Environment::get().getWorld()->changeVanityModeScale(mGamepadZoom); - MWBase::Environment::get().getWorld()->setCameraDistance(mGamepadZoom, true, true); } } } @@ -562,8 +372,6 @@ namespace MWInput updateIdleTime(dt); } } - else - mGamepadZoom = 0; mAttemptJump = false; // Can only jump on first frame input is on } @@ -574,17 +382,18 @@ namespace MWInput void InputManager::setGamepadGuiCursorEnabled(bool enabled) { - mGamepadGuiCursorEnabled = enabled; + mControllerManager->setGamepadGuiCursorEnabled(enabled); } void InputManager::changeInputMode(bool guiMode) { mGuiCursorEnabled = guiMode; - mMouseManager->setGuiCursorEnabled(guiMode); - mMouseManager->setMouseLookEnabled(!guiMode); + mControllerManager->setGuiCursorEnabled(mGuiCursorEnabled); + mMouseManager->setGuiCursorEnabled(mGuiCursorEnabled); + mMouseManager->setMouseLookEnabled(!mGuiCursorEnabled); if (guiMode) MWBase::Environment::get().getWindowManager()->showCrosshair(false); - MWBase::Environment::get().getWindowManager()->setCursorVisible(guiMode && (!mJoystickLastUsed || mGamepadGuiCursorEnabled)); + MWBase::Environment::get().getWindowManager()->setCursorVisible(guiMode && (!mControllerManager->joystickLastUsed() || mControllerManager->gamepadGuiCursorEnabled())); // if not in gui mode, the camera decides whether to show crosshair or not. } @@ -598,9 +407,6 @@ namespace MWInput if (it->first == "Input" && it->second == "grab cursor") mGrabCursor = Settings::Manager::getBool("grab cursor", "Input"); - if (it->first == "Input" && it->second == "enable controller") - mJoystickEnabled = Settings::Manager::getBool("enable controller", "Input"); - if (it->first == "Video" && ( it->second == "resolution x" || it->second == "resolution y" @@ -686,7 +492,7 @@ namespace MWInput if (!mControlsDisabled && !consumed) mInputBinder->keyPressed (arg); - mJoystickLastUsed = false; + mControllerManager->setJoystickLastUsed(false); } void InputManager::textInput(const SDL_TextInputEvent &arg) @@ -699,7 +505,7 @@ namespace MWInput void InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { - mJoystickLastUsed = false; + mControllerManager->setJoystickLastUsed(false); OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); if (!mInputBinder->detectingBindingState()) @@ -707,118 +513,6 @@ namespace MWInput mInputBinder->keyReleased (arg); } - void InputManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg ) - { - if (!mJoystickEnabled || mInputBinder->detectingBindingState()) - return; - - mJoystickLastUsed = true; - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - if (gamepadToGuiControl(arg)) - return; - if (mGamepadGuiCursorEnabled) - { - // Temporary mouse binding until keyboard controls are available: - if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. - { - bool mousePressSuccess = mMouseManager->injectMouseButtonPress(SDL_BUTTON_LEFT); - if (MyGUI::InputManager::getInstance().getMouseFocusWidget()) - { - MyGUI::Button* b = MyGUI::InputManager::getInstance().getMouseFocusWidget()->castType(false); - if (b && b->getEnabled()) - MWBase::Environment::get().getWindowManager()->playSound("Menu Click"); - } - - setPlayerControlsEnabled(!mousePressSuccess); - } - } - } - else - setPlayerControlsEnabled(true); - - //esc, to leave initial movie screen - OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0)); - - if (!mControlsDisabled) - mInputBinder->buttonPressed(deviceID, arg); - } - - void InputManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg ) - { - if(mInputBinder->detectingBindingState()) - { - mInputBinder->buttonReleased(deviceID, arg); - return; - } - if (!mJoystickEnabled || mControlsDisabled) - return; - - mJoystickLastUsed = true; - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - if (mGamepadGuiCursorEnabled) - { - // Temporary mouse binding until keyboard controls are available: - if (arg.button == SDL_CONTROLLER_BUTTON_A) // We'll pretend that A is left click. - { - bool mousePressSuccess = mMouseManager->injectMouseButtonRelease(SDL_BUTTON_LEFT); - if (mInputBinder->detectingBindingState()) // If the player just triggered binding, don't let button release bind. - return; - - setPlayerControlsEnabled(!mousePressSuccess); - } - } - } - else - setPlayerControlsEnabled(true); - - //esc, to leave initial movie screen - OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE); - setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc))); - - mInputBinder->buttonReleased(deviceID, arg); - } - - void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg ) - { - if(!mJoystickEnabled || mControlsDisabled) - return; - - mJoystickLastUsed = true; - if (MWBase::Environment::get().getWindowManager()->isGuiMode()) - { - gamepadToGuiControl(arg); - } - else - { - if(mPreviewPOVDelay == 1.f && arg.value) // Preview Mode Gamepad Zooming - { - if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT) - { - mGamepadZoom = arg.value * 0.85f / 1000.f; - return; // Do not propagate event. - } - else if(arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT) - { - mGamepadZoom = -arg.value * 0.85f / 1000.f; - return; // Do not propagate event. - } - } - } - mInputBinder->axisMoved(deviceID, arg); - } - - void InputManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg) - { - mInputBinder->controllerAdded(deviceID, arg); - } - void InputManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg) - { - mInputBinder->controllerRemoved(arg); - } - void InputManager::windowFocusChange(bool have_focus) { } @@ -1398,4 +1092,14 @@ namespace MWInput { loadControllerDefaults(true); } + + void InputManager::setJoystickLastUsed(bool enabled) + { + mControllerManager->setJoystickLastUsed(enabled); + } + + bool InputManager::joystickLastUsed() + { + return mControllerManager->joystickLastUsed(); + } } diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index da7075e4e0..93bcf13ee2 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -22,6 +22,7 @@ namespace MWInput { class ActionManager; + class ControllerManager; class MouseManager; class SensorManager; } @@ -63,7 +64,6 @@ namespace MWInput public MWBase::InputManager, public SDLUtil::KeyListener, public SDLUtil::WindowListener, - public SDLUtil::ControllerListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { @@ -106,19 +106,13 @@ namespace MWInput virtual void resetToDefaultKeyBindings(); virtual void resetToDefaultControllerBindings(); - virtual void setJoystickLastUsed(bool enabled) { mJoystickLastUsed = enabled; } - virtual bool joystickLastUsed() {return mJoystickLastUsed;} + 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 buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg); - virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg); - virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg); - virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg); - virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg); - virtual void windowVisibilityChange( bool visible ); virtual void windowFocusChange( bool have_focus ); virtual void windowResized (int x, int y); @@ -159,9 +153,6 @@ namespace MWInput SDL_Window* mWindow; bool mWindowVisible; - bool mJoystickLastUsed; - MWWorld::Player* mPlayer; - ICS::InputControlSystem* mInputBinder; SDLUtil::InputWrapper* mInputManager; @@ -174,30 +165,22 @@ namespace MWInput bool mGrabCursor; bool mControlsDisabled; - bool mJoystickEnabled; float mPreviewPOVDelay; float mTimeIdle; bool mGuiCursorEnabled; - bool mGamepadGuiCursorEnabled; bool mDetectingKeyboard; float mOverencumberedMessageDelay; - float mGamepadZoom; - bool mSneakToggles; - float mSneakToggleShortcutTimer; - bool mSneakGamepadShortcut; bool mAttemptJump; std::map mControlSwitch; - float mInvUiScalingFactor; - float mGamepadCursorSpeed; - ActionManager* mActionManager; + ControllerManager* mControllerManager; MouseManager* mMouseManager; SensorManager* mSensorManager; @@ -206,9 +189,6 @@ namespace MWInput void updateIdleTime(float dt); void handleGuiArrowKey(int action); - // Return true if GUI consumes input. - bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg); - bool gamepadToGuiControl(const SDL_ControllerAxisEvent &arg); void updateCursorMode(); diff --git a/apps/openmw/mwinput/mousemanager.hpp b/apps/openmw/mwinput/mousemanager.hpp index c0a9408c68..f4517da47d 100644 --- a/apps/openmw/mwinput/mousemanager.hpp +++ b/apps/openmw/mwinput/mousemanager.hpp @@ -1,8 +1,6 @@ #ifndef MWINPUT_MWMOUSEMANAGER_H #define MWINPUT_MWMOUSEMANAGER_H -#include - #include #include