Add OpenMW commits up to 16 May 2020
# Conflicts: # CI/before_script.linux.sh # apps/openmw/mwbase/world.hpp # apps/openmw/mwinput/inputmanagerimp.cpp # apps/openmw/mwscript/globalscripts.cpp # apps/openmw/mwscript/interpretercontext.cpp # apps/openmw/mwworld/cellstore.cpp # apps/openmw/mwworld/cellstore.hpp # apps/openmw/mwworld/worldimp.cpp # apps/openmw/mwworld/worldimp.hpp # components/interpreter/context.hpppull/593/head
commit
62df188fd4
@ -0,0 +1,665 @@
|
|||||||
|
#include "actionmanager.hpp"
|
||||||
|
|
||||||
|
#include <MyGUI_InputManager.h>
|
||||||
|
|
||||||
|
#include <SDL_keyboard.h>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Include additional headers for multiplayer purposes
|
||||||
|
*/
|
||||||
|
#include "../mwmp/Main.hpp"
|
||||||
|
#include "../mwmp/LocalPlayer.hpp"
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/statemanager.hpp"
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/mechanicsmanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
#include "../mwworld/class.hpp"
|
||||||
|
#include "../mwworld/inventorystore.hpp"
|
||||||
|
#include "../mwworld/esmstore.hpp"
|
||||||
|
|
||||||
|
#include "../mwmechanics/npcstats.hpp"
|
||||||
|
#include "../mwmechanics/actorutil.hpp"
|
||||||
|
|
||||||
|
#include "actions.hpp"
|
||||||
|
#include "bindingsmanager.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
const float ZOOM_SCALE = 120.f; /// Used for scrolling camera in and out
|
||||||
|
|
||||||
|
ActionManager::ActionManager(BindingsManager* bindingsManager,
|
||||||
|
osgViewer::ScreenCaptureHandler::CaptureOperation* screenCaptureOperation,
|
||||||
|
osg::ref_ptr<osgViewer::Viewer> viewer,
|
||||||
|
osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler)
|
||||||
|
: mBindingsManager(bindingsManager)
|
||||||
|
, mViewer(viewer)
|
||||||
|
, mScreenCaptureHandler(screenCaptureHandler)
|
||||||
|
, mScreenCaptureOperation(screenCaptureOperation)
|
||||||
|
, mAlwaysRunActive(Settings::Manager::getBool("always run", "Input"))
|
||||||
|
, mSneaking(false)
|
||||||
|
, mAttemptJump(false)
|
||||||
|
, mOverencumberedMessageDelay(0.f)
|
||||||
|
, mPreviewPOVDelay(0.f)
|
||||||
|
, mTimeIdle(0.f)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::update(float dt, bool triedToMove)
|
||||||
|
{
|
||||||
|
// Disable movement in Gui mode
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()
|
||||||
|
|| MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)
|
||||||
|
{
|
||||||
|
mAttemptJump = false;
|
||||||
|
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 alwaysRunAllowed = false;
|
||||||
|
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
|
||||||
|
if (mBindingsManager->actionIsActive(A_MoveLeft) != mBindingsManager->actionIsActive(A_MoveRight))
|
||||||
|
{
|
||||||
|
alwaysRunAllowed = true;
|
||||||
|
triedToMove = true;
|
||||||
|
player.setLeftRight(mBindingsManager->actionIsActive(A_MoveRight) ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBindingsManager->actionIsActive(A_MoveForward) != mBindingsManager->actionIsActive(A_MoveBackward))
|
||||||
|
{
|
||||||
|
alwaysRunAllowed = true;
|
||||||
|
triedToMove = true;
|
||||||
|
player.setAutoMove (false);
|
||||||
|
player.setForwardBackward(mBindingsManager->actionIsActive(A_MoveForward) ? 1 : -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.getAutoMove())
|
||||||
|
{
|
||||||
|
alwaysRunAllowed = true;
|
||||||
|
triedToMove = true;
|
||||||
|
player.setForwardBackward (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mAttemptJump && MWBase::Environment::get().getInputManager()->getControlSwitch("playerjumping"))
|
||||||
|
{
|
||||||
|
player.setUpDown(1);
|
||||||
|
triedToMove = true;
|
||||||
|
mOverencumberedMessageDelay = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if player tried to start moving, but can't (due to being overencumbered), display a notification.
|
||||||
|
if (triedToMove)
|
||||||
|
{
|
||||||
|
MWWorld::Ptr playerPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
||||||
|
mOverencumberedMessageDelay -= dt;
|
||||||
|
if (playerPtr.getClass().getEncumbrance(playerPtr) > playerPtr.getClass().getCapacity(playerPtr))
|
||||||
|
{
|
||||||
|
player.setAutoMove (false);
|
||||||
|
if (mOverencumberedMessageDelay <= 0)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage59}");
|
||||||
|
mOverencumberedMessageDelay = 1.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch"))
|
||||||
|
{
|
||||||
|
if (mBindingsManager->actionIsActive(A_TogglePOV))
|
||||||
|
{
|
||||||
|
if (mPreviewPOVDelay <= 0.5 &&
|
||||||
|
(mPreviewPOVDelay += dt) > 0.5)
|
||||||
|
{
|
||||||
|
mPreviewPOVDelay = 1.f;
|
||||||
|
MWBase::Environment::get().getWorld()->togglePreviewMode(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//disable preview mode
|
||||||
|
MWBase::Environment::get().getWorld()->togglePreviewMode(false);
|
||||||
|
if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.5)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->togglePOV();
|
||||||
|
}
|
||||||
|
mPreviewPOVDelay = 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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(mBindingsManager->actionIsActive(A_Sneak));
|
||||||
|
}
|
||||||
|
|
||||||
|
float xAxis = mBindingsManager->getActionValue(A_MoveLeftRight);
|
||||||
|
float yAxis = mBindingsManager->getActionValue(A_MoveForwardBackward);
|
||||||
|
bool isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25;
|
||||||
|
if ((mAlwaysRunActive && alwaysRunAllowed) || isRunning)
|
||||||
|
player.setRunState(!mBindingsManager->actionIsActive(A_Run));
|
||||||
|
else
|
||||||
|
player.setRunState(mBindingsManager->actionIsActive(A_Run));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mBindingsManager->actionIsActive(A_MoveForward) ||
|
||||||
|
mBindingsManager->actionIsActive(A_MoveBackward) ||
|
||||||
|
mBindingsManager->actionIsActive(A_MoveLeft) ||
|
||||||
|
mBindingsManager->actionIsActive(A_MoveRight) ||
|
||||||
|
mBindingsManager->actionIsActive(A_Jump) ||
|
||||||
|
mBindingsManager->actionIsActive(A_Sneak) ||
|
||||||
|
mBindingsManager->actionIsActive(A_TogglePOV) ||
|
||||||
|
mBindingsManager->actionIsActive(A_ZoomIn) ||
|
||||||
|
mBindingsManager->actionIsActive(A_ZoomOut))
|
||||||
|
{
|
||||||
|
resetIdleTime();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updateIdleTime(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
mAttemptJump = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::resetIdleTime()
|
||||||
|
{
|
||||||
|
if (mTimeIdle < 0)
|
||||||
|
MWBase::Environment::get().getWorld()->toggleVanityMode(false);
|
||||||
|
mTimeIdle = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::updateIdleTime(float dt)
|
||||||
|
{
|
||||||
|
static const float vanityDelay = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
||||||
|
.find("fVanityDelay")->mValue.getFloat();
|
||||||
|
if (mTimeIdle >= 0.f)
|
||||||
|
mTimeIdle += dt;
|
||||||
|
if (mTimeIdle > vanityDelay)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->toggleVanityMode(true);
|
||||||
|
mTimeIdle = -1.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::executeAction(int action)
|
||||||
|
{
|
||||||
|
// trigger action activated
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case A_GameMenu:
|
||||||
|
toggleMainMenu ();
|
||||||
|
break;
|
||||||
|
case A_Screenshot:
|
||||||
|
screenshot();
|
||||||
|
break;
|
||||||
|
case A_Inventory:
|
||||||
|
toggleInventory ();
|
||||||
|
break;
|
||||||
|
case A_Console:
|
||||||
|
toggleConsole ();
|
||||||
|
break;
|
||||||
|
case A_Activate:
|
||||||
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
activate();
|
||||||
|
break;
|
||||||
|
case A_MoveLeft:
|
||||||
|
case A_MoveRight:
|
||||||
|
case A_MoveForward:
|
||||||
|
case A_MoveBackward:
|
||||||
|
handleGuiArrowKey(action);
|
||||||
|
break;
|
||||||
|
case A_Journal:
|
||||||
|
toggleJournal();
|
||||||
|
break;
|
||||||
|
case A_AutoMove:
|
||||||
|
toggleAutoMove();
|
||||||
|
break;
|
||||||
|
case A_AlwaysRun:
|
||||||
|
toggleWalking();
|
||||||
|
break;
|
||||||
|
case A_ToggleWeapon:
|
||||||
|
toggleWeapon();
|
||||||
|
break;
|
||||||
|
case A_Rest:
|
||||||
|
rest();
|
||||||
|
break;
|
||||||
|
case A_ToggleSpell:
|
||||||
|
toggleSpell();
|
||||||
|
break;
|
||||||
|
case A_QuickKey1:
|
||||||
|
quickKey(1);
|
||||||
|
break;
|
||||||
|
case A_QuickKey2:
|
||||||
|
quickKey(2);
|
||||||
|
break;
|
||||||
|
case A_QuickKey3:
|
||||||
|
quickKey(3);
|
||||||
|
break;
|
||||||
|
case A_QuickKey4:
|
||||||
|
quickKey(4);
|
||||||
|
break;
|
||||||
|
case A_QuickKey5:
|
||||||
|
quickKey(5);
|
||||||
|
break;
|
||||||
|
case A_QuickKey6:
|
||||||
|
quickKey(6);
|
||||||
|
break;
|
||||||
|
case A_QuickKey7:
|
||||||
|
quickKey(7);
|
||||||
|
break;
|
||||||
|
case A_QuickKey8:
|
||||||
|
quickKey(8);
|
||||||
|
break;
|
||||||
|
case A_QuickKey9:
|
||||||
|
quickKey(9);
|
||||||
|
break;
|
||||||
|
case A_QuickKey10:
|
||||||
|
quickKey(10);
|
||||||
|
break;
|
||||||
|
case A_QuickKeysMenu:
|
||||||
|
showQuickKeysMenu();
|
||||||
|
break;
|
||||||
|
case A_ToggleHUD:
|
||||||
|
MWBase::Environment::get().getWindowManager()->toggleHud();
|
||||||
|
break;
|
||||||
|
case A_ToggleDebug:
|
||||||
|
MWBase::Environment::get().getWindowManager()->toggleDebugWindow();
|
||||||
|
break;
|
||||||
|
case A_ZoomIn:
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch") && MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols") && !MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
MWBase::Environment::get().getWorld()->setCameraDistance(ZOOM_SCALE, true, true);
|
||||||
|
break;
|
||||||
|
case A_ZoomOut:
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch") && MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols") && !MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
MWBase::Environment::get().getWorld()->setCameraDistance(-ZOOM_SCALE, true, true);
|
||||||
|
break;
|
||||||
|
case A_QuickSave:
|
||||||
|
quickSave();
|
||||||
|
break;
|
||||||
|
case A_QuickLoad:
|
||||||
|
quickLoad();
|
||||||
|
break;
|
||||||
|
case A_CycleSpellLeft:
|
||||||
|
if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic))
|
||||||
|
MWBase::Environment::get().getWindowManager()->cycleSpell(false);
|
||||||
|
break;
|
||||||
|
case A_CycleSpellRight:
|
||||||
|
if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Magic))
|
||||||
|
MWBase::Environment::get().getWindowManager()->cycleSpell(true);
|
||||||
|
break;
|
||||||
|
case A_CycleWeaponLeft:
|
||||||
|
if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
|
||||||
|
MWBase::Environment::get().getWindowManager()->cycleWeapon(false);
|
||||||
|
break;
|
||||||
|
case A_CycleWeaponRight:
|
||||||
|
if (checkAllowedToUseItems() && MWBase::Environment::get().getWindowManager()->isAllowed(MWGui::GW_Inventory))
|
||||||
|
MWBase::Environment::get().getWindowManager()->cycleWeapon(true);
|
||||||
|
break;
|
||||||
|
case A_Sneak:
|
||||||
|
static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input");
|
||||||
|
if (isToggleSneak)
|
||||||
|
{
|
||||||
|
toggleSneaking();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ActionManager::checkAllowedToUseItems() const
|
||||||
|
{
|
||||||
|
MWWorld::Ptr player = MWMechanics::getPlayer();
|
||||||
|
if (player.getClass().getNpcStats(player).isWerewolf())
|
||||||
|
{
|
||||||
|
// Cannot use items or spells while in werewolf form
|
||||||
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sWerewolfRefusal}");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::screenshot()
|
||||||
|
{
|
||||||
|
bool regularScreenshot = true;
|
||||||
|
|
||||||
|
std::string settingStr;
|
||||||
|
|
||||||
|
settingStr = Settings::Manager::getString("screenshot type","Video");
|
||||||
|
regularScreenshot = settingStr.size() == 0 || settingStr.compare("regular") == 0;
|
||||||
|
|
||||||
|
if (regularScreenshot)
|
||||||
|
{
|
||||||
|
mScreenCaptureHandler->setFramesToCapture(1);
|
||||||
|
mScreenCaptureHandler->captureNextFrame(*mViewer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
osg::ref_ptr<osg::Image> screenshot (new osg::Image);
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWorld()->screenshot360(screenshot.get(), settingStr))
|
||||||
|
{
|
||||||
|
(*mScreenCaptureOperation) (*(screenshot.get()), 0);
|
||||||
|
// FIXME: mScreenCaptureHandler->getCaptureOperation() causes crash for some reason
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleMainMenu()
|
||||||
|
{
|
||||||
|
if (MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->exitCurrentModal();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->toggleConsole();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!MWBase::Environment::get().getWindowManager()->isGuiMode()) //No open GUIs, open up the MainMenu
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
|
||||||
|
}
|
||||||
|
else //Close current GUI
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleSpell()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
||||||
|
|
||||||
|
// Not allowed before the magic window is accessible
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playermagic") || !MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!checkAllowedToUseItems())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Not allowed if no spell selected
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
MWWorld::InventoryStore& inventory = player.getPlayer().getClass().getInventoryStore(player.getPlayer());
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->getSelectedSpell().empty() &&
|
||||||
|
inventory.getSelectedEnchantItem() == inventory.end())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(player.getPlayer()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
MWMechanics::DrawState_ state = player.getDrawState();
|
||||||
|
if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing)
|
||||||
|
player.setDrawState(MWMechanics::DrawState_Spell);
|
||||||
|
else
|
||||||
|
player.setDrawState(MWMechanics::DrawState_Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::quickLoad()
|
||||||
|
{
|
||||||
|
if (!MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
MWBase::Environment::get().getStateManager()->quickLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::quickSave()
|
||||||
|
{
|
||||||
|
if (!MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
MWBase::Environment::get().getStateManager()->quickSave();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleWeapon()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
||||||
|
|
||||||
|
// Not allowed before the inventory window is accessible
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playerfighting") || !MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
// We want to interrupt animation only if attack is preparing, but still is not triggered
|
||||||
|
// Otherwise we will get a "speedshooting" exploit, when player can skip reload animation by hitting "Toggle Weapon" key twice
|
||||||
|
if (MWBase::Environment::get().getMechanicsManager()->isAttackPreparing(player.getPlayer()))
|
||||||
|
player.setAttackingOrSpell(false);
|
||||||
|
else if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(player.getPlayer()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
MWMechanics::DrawState_ state = player.getDrawState();
|
||||||
|
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
|
||||||
|
player.setDrawState(MWMechanics::DrawState_Weapon);
|
||||||
|
else
|
||||||
|
player.setDrawState(MWMechanics::DrawState_Nothing);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::rest()
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!MWBase::Environment::get().getWindowManager()->getRestEnabled() || MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Ignore attempts to rest if the player has not logged in on the server yet
|
||||||
|
|
||||||
|
Set LocalPlayer's isUsingBed to be able to distinguish bed use from regular rest
|
||||||
|
menu use
|
||||||
|
*/
|
||||||
|
if (!mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||||
|
return;
|
||||||
|
|
||||||
|
mwmp::Main::get().getLocalPlayer()->isUsingBed = false;
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Rest); //Open rest GUI
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleInventory()
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Ignore attempts to open inventory if the player has not logged in on the server yet
|
||||||
|
*/
|
||||||
|
if (!mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Toggle between game mode and inventory mode
|
||||||
|
if(!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Inventory);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MWGui::GuiMode mode = MWBase::Environment::get().getWindowManager()->getMode();
|
||||||
|
if(mode == MWGui::GM_Inventory || mode == MWGui::GM_Container)
|
||||||
|
MWBase::Environment::get().getWindowManager()->popGuiMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
// .. but don't touch any other mode, except container.
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleConsole()
|
||||||
|
{
|
||||||
|
if (MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
If a player's console is disabled by the server, go no further
|
||||||
|
*/
|
||||||
|
if (!mwmp::Main::get().getLocalPlayer()->consoleAllowed)
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->toggleConsole();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleJournal()
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
return;
|
||||||
|
if (MyGUI::InputManager::getInstance ().isModalAny())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Journal
|
||||||
|
&& MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_MainMenu
|
||||||
|
&& MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Settings
|
||||||
|
&& MWBase::Environment::get().getWindowManager ()->getJournalAllowed())
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Journal);
|
||||||
|
}
|
||||||
|
else if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Journal))
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_Journal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::quickKey (int index)
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols") || !MWBase::Environment::get().getInputManager()->getControlSwitch("playerfighting") || !MWBase::Environment::get().getInputManager()->getControlSwitch("playermagic"))
|
||||||
|
return;
|
||||||
|
if (!checkAllowedToUseItems())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")!=-1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
MWBase::Environment::get().getWindowManager()->activateQuickKey (index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::showQuickKeysMenu()
|
||||||
|
{
|
||||||
|
if (!MWBase::Environment::get().getWindowManager()->isGuiMode ()
|
||||||
|
&& MWBase::Environment::get().getWorld()->getGlobalFloat ("chargenstate")==-1)
|
||||||
|
{
|
||||||
|
if (!checkAllowedToUseItems())
|
||||||
|
return;
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_QuickKeysMenu);
|
||||||
|
}
|
||||||
|
else if (MWBase::Environment::get().getWindowManager()->getMode () == MWGui::GM_QuickKeysMenu)
|
||||||
|
{
|
||||||
|
while (MyGUI::InputManager::getInstance().isModalAny())
|
||||||
|
{ //Handle any open Modal windows
|
||||||
|
MWBase::Environment::get().getWindowManager()->exitCurrentModal();
|
||||||
|
}
|
||||||
|
MWBase::Environment::get().getWindowManager()->exitCurrentGuiMode(); //And handle the actual main window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::activate()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
||||||
|
{
|
||||||
|
bool joystickUsed = MWBase::Environment::get().getInputManager()->joystickLastUsed();
|
||||||
|
if (!SDL_IsTextInputActive() && !mBindingsManager->isLeftOrRightButton(A_Activate, joystickUsed))
|
||||||
|
MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0, false);
|
||||||
|
}
|
||||||
|
else if (MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleAutoMove()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.setAutoMove (!player.getAutoMove());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleWalking()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode() || SDL_IsTextInputActive()) return;
|
||||||
|
mAlwaysRunActive = !mAlwaysRunActive;
|
||||||
|
|
||||||
|
Settings::Manager::setBool("always run", "Input", mAlwaysRunActive);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::toggleSneaking()
|
||||||
|
{
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
||||||
|
if (!MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols")) return;
|
||||||
|
mSneaking = !mSneaking;
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.setSneak(mSneaking);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ActionManager::handleGuiArrowKey(int action)
|
||||||
|
{
|
||||||
|
bool joystickUsed = MWBase::Environment::get().getInputManager()->joystickLastUsed();
|
||||||
|
// This is currently keyboard-specific code
|
||||||
|
// TODO: see if GUI controls can be refactored into a single function
|
||||||
|
if (joystickUsed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (SDL_IsTextInputActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mBindingsManager->isLeftOrRightButton(action, joystickUsed))
|
||||||
|
return;
|
||||||
|
|
||||||
|
MyGUI::KeyCode key;
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case A_MoveLeft:
|
||||||
|
key = MyGUI::KeyCode::ArrowLeft;
|
||||||
|
break;
|
||||||
|
case A_MoveRight:
|
||||||
|
key = MyGUI::KeyCode::ArrowRight;
|
||||||
|
break;
|
||||||
|
case A_MoveForward:
|
||||||
|
key = MyGUI::KeyCode::ArrowUp;
|
||||||
|
break;
|
||||||
|
case A_MoveBackward:
|
||||||
|
default:
|
||||||
|
key = MyGUI::KeyCode::ArrowDown;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->injectKeyPress(key, 0, false);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
#ifndef MWINPUT_ACTIONMANAGER_H
|
||||||
|
#define MWINPUT_ACTIONMANAGER_H
|
||||||
|
|
||||||
|
#include <osg/ref_ptr>
|
||||||
|
#include <osgViewer/ViewerEventHandlers>
|
||||||
|
|
||||||
|
namespace osgViewer
|
||||||
|
{
|
||||||
|
class Viewer;
|
||||||
|
class ScreenCaptureHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class BindingsManager;
|
||||||
|
|
||||||
|
class ActionManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ActionManager(BindingsManager* bindingsManager,
|
||||||
|
osgViewer::ScreenCaptureHandler::CaptureOperation* screenCaptureOperation,
|
||||||
|
osg::ref_ptr<osgViewer::Viewer> viewer,
|
||||||
|
osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler);
|
||||||
|
|
||||||
|
void update(float dt, bool triedToMove);
|
||||||
|
|
||||||
|
void executeAction(int action);
|
||||||
|
|
||||||
|
bool checkAllowedToUseItems() const;
|
||||||
|
|
||||||
|
void toggleMainMenu();
|
||||||
|
void toggleSpell();
|
||||||
|
void toggleWeapon();
|
||||||
|
void toggleInventory();
|
||||||
|
void toggleConsole();
|
||||||
|
void screenshot();
|
||||||
|
void toggleJournal();
|
||||||
|
void activate();
|
||||||
|
void toggleWalking();
|
||||||
|
void toggleSneaking();
|
||||||
|
void toggleAutoMove();
|
||||||
|
void rest();
|
||||||
|
void quickLoad();
|
||||||
|
void quickSave();
|
||||||
|
|
||||||
|
void quickKey (int index);
|
||||||
|
void showQuickKeysMenu();
|
||||||
|
|
||||||
|
void resetIdleTime();
|
||||||
|
|
||||||
|
bool isAlwaysRunActive() const { return mAlwaysRunActive; };
|
||||||
|
bool isSneaking() const { return mSneaking; };
|
||||||
|
|
||||||
|
void setAttemptJump(bool enabled) { mAttemptJump = enabled; }
|
||||||
|
|
||||||
|
float getPreviewDelay() const { return mPreviewPOVDelay; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
void handleGuiArrowKey(int action);
|
||||||
|
|
||||||
|
void updateIdleTime(float dt);
|
||||||
|
|
||||||
|
BindingsManager* mBindingsManager;
|
||||||
|
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
||||||
|
osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler;
|
||||||
|
osgViewer::ScreenCaptureHandler::CaptureOperation* mScreenCaptureOperation;
|
||||||
|
|
||||||
|
bool mAlwaysRunActive;
|
||||||
|
bool mSneaking;
|
||||||
|
bool mAttemptJump;
|
||||||
|
|
||||||
|
float mOverencumberedMessageDelay;
|
||||||
|
float mPreviewPOVDelay;
|
||||||
|
float mTimeIdle;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,79 @@
|
|||||||
|
#ifndef MWINPUT_ACTIONS_H
|
||||||
|
#define MWINPUT_ACTIONS_H
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
enum Actions
|
||||||
|
{
|
||||||
|
// please add new actions at the bottom, in order to preserve the channel IDs in the key configuration files
|
||||||
|
|
||||||
|
A_GameMenu,
|
||||||
|
|
||||||
|
A_Unused,
|
||||||
|
|
||||||
|
A_Screenshot, // Take a screenshot
|
||||||
|
|
||||||
|
A_Inventory, // Toggle inventory screen
|
||||||
|
|
||||||
|
A_Console, // Toggle console screen
|
||||||
|
|
||||||
|
A_MoveLeft, // Move player left / right
|
||||||
|
A_MoveRight,
|
||||||
|
A_MoveForward, // Forward / Backward
|
||||||
|
A_MoveBackward,
|
||||||
|
|
||||||
|
A_Activate,
|
||||||
|
|
||||||
|
A_Use, //Use weapon, spell, etc.
|
||||||
|
A_Jump,
|
||||||
|
A_AutoMove, //Toggle Auto-move forward
|
||||||
|
A_Rest, //Rest
|
||||||
|
A_Journal, //Journal
|
||||||
|
A_Weapon, //Draw/Sheath weapon
|
||||||
|
A_Spell, //Ready/Unready Casting
|
||||||
|
A_Run, //Run when held
|
||||||
|
A_CycleSpellLeft, //cycling through spells
|
||||||
|
A_CycleSpellRight,
|
||||||
|
A_CycleWeaponLeft, //Cycling through weapons
|
||||||
|
A_CycleWeaponRight,
|
||||||
|
A_ToggleSneak, //Toggles Sneak
|
||||||
|
A_AlwaysRun, //Toggle Walking/Running
|
||||||
|
A_Sneak,
|
||||||
|
|
||||||
|
A_QuickSave,
|
||||||
|
A_QuickLoad,
|
||||||
|
A_QuickMenu,
|
||||||
|
A_ToggleWeapon,
|
||||||
|
A_ToggleSpell,
|
||||||
|
|
||||||
|
A_TogglePOV,
|
||||||
|
|
||||||
|
A_QuickKey1,
|
||||||
|
A_QuickKey2,
|
||||||
|
A_QuickKey3,
|
||||||
|
A_QuickKey4,
|
||||||
|
A_QuickKey5,
|
||||||
|
A_QuickKey6,
|
||||||
|
A_QuickKey7,
|
||||||
|
A_QuickKey8,
|
||||||
|
A_QuickKey9,
|
||||||
|
A_QuickKey10,
|
||||||
|
|
||||||
|
A_QuickKeysMenu,
|
||||||
|
|
||||||
|
A_ToggleHUD,
|
||||||
|
|
||||||
|
A_ToggleDebug,
|
||||||
|
|
||||||
|
A_LookUpDown, //Joystick look
|
||||||
|
A_LookLeftRight,
|
||||||
|
A_MoveForwardBackward,
|
||||||
|
A_MoveLeftRight,
|
||||||
|
|
||||||
|
A_ZoomIn,
|
||||||
|
A_ZoomOut,
|
||||||
|
|
||||||
|
A_Last // Marker for the last item
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,746 @@
|
|||||||
|
#include "bindingsmanager.hpp"
|
||||||
|
|
||||||
|
#include <MyGUI_EditBox.h>
|
||||||
|
|
||||||
|
#include <extern/oics/ICSChannelListener.h>
|
||||||
|
#include <extern/oics/ICSInputControlSystem.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Include additional headers for multiplayer purposes
|
||||||
|
*/
|
||||||
|
#include "../mwmp/Main.hpp"
|
||||||
|
#include "../mwmp/GUIController.hpp"
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
#include "actions.hpp"
|
||||||
|
#include "sdlmappings.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
static const int sFakeDeviceId = 1; //As we only support one controller at a time, use a fake deviceID so we don't lose bindings when switching controllers
|
||||||
|
|
||||||
|
void clearAllKeyBindings(ICS::InputControlSystem* inputBinder, ICS::Control* control)
|
||||||
|
{
|
||||||
|
// right now we don't really need multiple bindings for the same action, so remove all others first
|
||||||
|
if (inputBinder->getKeyBinding(control, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN)
|
||||||
|
inputBinder->removeKeyBinding(inputBinder->getKeyBinding(control, ICS::Control::INCREASE));
|
||||||
|
if (inputBinder->getMouseButtonBinding(control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS)
|
||||||
|
inputBinder->removeMouseButtonBinding(inputBinder->getMouseButtonBinding(control, ICS::Control::INCREASE));
|
||||||
|
if (inputBinder->getMouseWheelBinding(control, ICS::Control::INCREASE) != ICS::InputControlSystem::MouseWheelClick::UNASSIGNED)
|
||||||
|
inputBinder->removeMouseWheelBinding(inputBinder->getMouseWheelBinding(control, ICS::Control::INCREASE));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearAllControllerBindings(ICS::InputControlSystem* inputBinder, ICS::Control* control)
|
||||||
|
{
|
||||||
|
// right now we don't really need multiple bindings for the same action, so remove all others first
|
||||||
|
if (inputBinder->getJoystickAxisBinding(control, sFakeDeviceId, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN)
|
||||||
|
inputBinder->removeJoystickAxisBinding(sFakeDeviceId, inputBinder->getJoystickAxisBinding(control, sFakeDeviceId, ICS::Control::INCREASE));
|
||||||
|
if (inputBinder->getJoystickButtonBinding(control, sFakeDeviceId, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS)
|
||||||
|
inputBinder->removeJoystickButtonBinding(sFakeDeviceId, inputBinder->getJoystickButtonBinding(control, sFakeDeviceId, ICS::Control::INCREASE));
|
||||||
|
}
|
||||||
|
|
||||||
|
class InputControlSystem : public ICS::InputControlSystem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InputControlSystem(const std::string& bindingsFile)
|
||||||
|
: ICS::InputControlSystem(bindingsFile, true, nullptr, nullptr, A_Last)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BindingsListener :
|
||||||
|
public ICS::ChannelListener,
|
||||||
|
public ICS::DetectingBindingListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BindingsListener(ICS::InputControlSystem* inputBinder, BindingsManager* bindingsManager)
|
||||||
|
: mInputBinder(inputBinder)
|
||||||
|
, mBindingsManager(bindingsManager)
|
||||||
|
, mDetectingKeyboard(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~BindingsListener() = default;
|
||||||
|
|
||||||
|
virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue)
|
||||||
|
{
|
||||||
|
int action = channel->getNumber();
|
||||||
|
mBindingsManager->actionValueChanged(action, currentValue, previousValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void keyBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
||||||
|
, SDL_Scancode key, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
//Disallow binding escape key
|
||||||
|
if (key==SDL_SCANCODE_ESCAPE)
|
||||||
|
{
|
||||||
|
//Stop binding if esc pressed
|
||||||
|
mInputBinder->cancelDetectingBindingState();
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disallow binding reserved keys
|
||||||
|
if (key == SDL_SCANCODE_F3 || key == SDL_SCANCODE_F4 || key == SDL_SCANCODE_F10)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#ifndef __APPLE__
|
||||||
|
// Disallow binding Windows/Meta keys
|
||||||
|
if (key == SDL_SCANCODE_LGUI || key == SDL_SCANCODE_RGUI)
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!mDetectingKeyboard)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clearAllKeyBindings(mInputBinder, control);
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
ICS::DetectingBindingListener::keyBindingDetected(ICS, control, key, direction);
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
||||||
|
, ICS::InputControlSystem::NamedAxis axis, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
// we don't want mouse movement bindings
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
||||||
|
, unsigned int button, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
if (!mDetectingKeyboard)
|
||||||
|
return;
|
||||||
|
clearAllKeyBindings(mInputBinder, control);
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
ICS::DetectingBindingListener::mouseButtonBindingDetected(ICS, control, button, direction);
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void mouseWheelBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
||||||
|
, ICS::InputControlSystem::MouseWheelClick click, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
if (!mDetectingKeyboard)
|
||||||
|
return;
|
||||||
|
clearAllKeyBindings(mInputBinder, control);
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
ICS::DetectingBindingListener::mouseWheelBindingDetected(ICS, control, click, direction);
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control
|
||||||
|
, int axis, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
//only allow binding to the trigers
|
||||||
|
if (axis != SDL_CONTROLLER_AXIS_TRIGGERLEFT && axis != SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
|
||||||
|
return;
|
||||||
|
if (mDetectingKeyboard)
|
||||||
|
return;
|
||||||
|
|
||||||
|
clearAllControllerBindings(mInputBinder, control);
|
||||||
|
control->setValue(0.5f); //axis bindings must start at 0.5
|
||||||
|
control->setInitialValue(0.5f);
|
||||||
|
ICS::DetectingBindingListener::joystickAxisBindingDetected(ICS, deviceID, control, axis, direction);
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control
|
||||||
|
, unsigned int button, ICS::Control::ControlChangingDirection direction)
|
||||||
|
{
|
||||||
|
if (mDetectingKeyboard)
|
||||||
|
return;
|
||||||
|
clearAllControllerBindings(mInputBinder,control);
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, deviceID, control, button, direction);
|
||||||
|
MWBase::Environment::get().getWindowManager()->notifyInputActionBound();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setDetectingKeyboard(bool detecting)
|
||||||
|
{
|
||||||
|
mDetectingKeyboard = detecting;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ICS::InputControlSystem* mInputBinder;
|
||||||
|
BindingsManager* mBindingsManager;
|
||||||
|
bool mDetectingKeyboard;
|
||||||
|
};
|
||||||
|
|
||||||
|
BindingsManager::BindingsManager(const std::string& userFile, bool userFileExists)
|
||||||
|
: mUserFile(userFile)
|
||||||
|
, mDragDrop(false)
|
||||||
|
{
|
||||||
|
std::string file = userFileExists ? userFile : "";
|
||||||
|
mInputBinder = new InputControlSystem(file);
|
||||||
|
mListener = new BindingsListener(mInputBinder, this);
|
||||||
|
mInputBinder->setDetectingBindingListener(mListener);
|
||||||
|
|
||||||
|
loadKeyDefaults();
|
||||||
|
loadControllerDefaults();
|
||||||
|
|
||||||
|
for (int i = 0; i < A_Last; ++i)
|
||||||
|
{
|
||||||
|
mInputBinder->getChannel(i)->addListener(mListener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::setDragDrop(bool dragDrop)
|
||||||
|
{
|
||||||
|
mDragDrop = dragDrop;
|
||||||
|
}
|
||||||
|
|
||||||
|
BindingsManager::~BindingsManager()
|
||||||
|
{
|
||||||
|
mInputBinder->save(mUserFile);
|
||||||
|
delete mInputBinder;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::update(float dt)
|
||||||
|
{
|
||||||
|
// update values of channels (as a result of pressed keys)
|
||||||
|
mInputBinder->update(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BindingsManager::isLeftOrRightButton(int action, bool joystick) const
|
||||||
|
{
|
||||||
|
int mouseBinding = mInputBinder->getMouseButtonBinding(mInputBinder->getControl(action), ICS::Control::INCREASE);
|
||||||
|
if (mouseBinding != ICS_MAX_DEVICE_BUTTONS)
|
||||||
|
return true;
|
||||||
|
int buttonBinding = mInputBinder->getJoystickButtonBinding(mInputBinder->getControl(action), sFakeDeviceId, ICS::Control::INCREASE);
|
||||||
|
if (joystick && (buttonBinding == 0 || buttonBinding == 1))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::setPlayerControlsEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
int playerChannels[] = {A_AutoMove, A_AlwaysRun, A_ToggleWeapon,
|
||||||
|
A_ToggleSpell, A_Rest, A_QuickKey1, A_QuickKey2,
|
||||||
|
A_QuickKey3, A_QuickKey4, A_QuickKey5, A_QuickKey6,
|
||||||
|
A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10,
|
||||||
|
A_Use, A_Journal};
|
||||||
|
|
||||||
|
for(int pc : playerChannels)
|
||||||
|
{
|
||||||
|
mInputBinder->getChannel(pc)->setEnabled(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float BindingsManager::getActionValue (int id) const
|
||||||
|
{
|
||||||
|
return mInputBinder->getChannel(id)->getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BindingsManager::actionIsActive (int id) const
|
||||||
|
{
|
||||||
|
return getActionValue(id) == 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::loadKeyDefaults (bool force)
|
||||||
|
{
|
||||||
|
// using hardcoded key defaults is inevitable, if we want the configuration files to stay valid
|
||||||
|
// across different versions of OpenMW (in the case where another input action is added)
|
||||||
|
std::map<int, SDL_Scancode> defaultKeyBindings;
|
||||||
|
|
||||||
|
//Gets the Keyvalue from the Scancode; gives the button in the same place reguardless of keyboard format
|
||||||
|
defaultKeyBindings[A_Activate] = SDL_SCANCODE_SPACE;
|
||||||
|
defaultKeyBindings[A_MoveBackward] = SDL_SCANCODE_S;
|
||||||
|
defaultKeyBindings[A_MoveForward] = SDL_SCANCODE_W;
|
||||||
|
defaultKeyBindings[A_MoveLeft] = SDL_SCANCODE_A;
|
||||||
|
defaultKeyBindings[A_MoveRight] = SDL_SCANCODE_D;
|
||||||
|
defaultKeyBindings[A_ToggleWeapon] = SDL_SCANCODE_F;
|
||||||
|
defaultKeyBindings[A_ToggleSpell] = SDL_SCANCODE_R;
|
||||||
|
defaultKeyBindings[A_CycleSpellLeft] = SDL_SCANCODE_MINUS;
|
||||||
|
defaultKeyBindings[A_CycleSpellRight] = SDL_SCANCODE_EQUALS;
|
||||||
|
defaultKeyBindings[A_CycleWeaponLeft] = SDL_SCANCODE_LEFTBRACKET;
|
||||||
|
defaultKeyBindings[A_CycleWeaponRight] = SDL_SCANCODE_RIGHTBRACKET;
|
||||||
|
|
||||||
|
defaultKeyBindings[A_QuickKeysMenu] = SDL_SCANCODE_F1;
|
||||||
|
defaultKeyBindings[A_Console] = SDL_SCANCODE_GRAVE;
|
||||||
|
defaultKeyBindings[A_Run] = SDL_SCANCODE_LSHIFT;
|
||||||
|
defaultKeyBindings[A_Sneak] = SDL_SCANCODE_LCTRL;
|
||||||
|
defaultKeyBindings[A_AutoMove] = SDL_SCANCODE_Q;
|
||||||
|
defaultKeyBindings[A_Jump] = SDL_SCANCODE_E;
|
||||||
|
defaultKeyBindings[A_Journal] = SDL_SCANCODE_J;
|
||||||
|
defaultKeyBindings[A_Rest] = SDL_SCANCODE_T;
|
||||||
|
defaultKeyBindings[A_GameMenu] = SDL_SCANCODE_ESCAPE;
|
||||||
|
defaultKeyBindings[A_TogglePOV] = SDL_SCANCODE_TAB;
|
||||||
|
defaultKeyBindings[A_QuickKey1] = SDL_SCANCODE_1;
|
||||||
|
defaultKeyBindings[A_QuickKey2] = SDL_SCANCODE_2;
|
||||||
|
defaultKeyBindings[A_QuickKey3] = SDL_SCANCODE_3;
|
||||||
|
defaultKeyBindings[A_QuickKey4] = SDL_SCANCODE_4;
|
||||||
|
defaultKeyBindings[A_QuickKey5] = SDL_SCANCODE_5;
|
||||||
|
defaultKeyBindings[A_QuickKey6] = SDL_SCANCODE_6;
|
||||||
|
defaultKeyBindings[A_QuickKey7] = SDL_SCANCODE_7;
|
||||||
|
defaultKeyBindings[A_QuickKey8] = SDL_SCANCODE_8;
|
||||||
|
defaultKeyBindings[A_QuickKey9] = SDL_SCANCODE_9;
|
||||||
|
defaultKeyBindings[A_QuickKey10] = SDL_SCANCODE_0;
|
||||||
|
defaultKeyBindings[A_Screenshot] = SDL_SCANCODE_F12;
|
||||||
|
defaultKeyBindings[A_ToggleHUD] = SDL_SCANCODE_F11;
|
||||||
|
defaultKeyBindings[A_ToggleDebug] = SDL_SCANCODE_F10;
|
||||||
|
defaultKeyBindings[A_AlwaysRun] = SDL_SCANCODE_CAPSLOCK;
|
||||||
|
defaultKeyBindings[A_QuickSave] = SDL_SCANCODE_F5;
|
||||||
|
defaultKeyBindings[A_QuickLoad] = SDL_SCANCODE_F9;
|
||||||
|
|
||||||
|
std::map<int, int> defaultMouseButtonBindings;
|
||||||
|
defaultMouseButtonBindings[A_Inventory] = SDL_BUTTON_RIGHT;
|
||||||
|
defaultMouseButtonBindings[A_Use] = SDL_BUTTON_LEFT;
|
||||||
|
|
||||||
|
std::map<int, ICS::InputControlSystem::MouseWheelClick> defaultMouseWheelBindings;
|
||||||
|
defaultMouseWheelBindings[A_ZoomIn] = ICS::InputControlSystem::MouseWheelClick::UP;
|
||||||
|
defaultMouseWheelBindings[A_ZoomOut] = ICS::InputControlSystem::MouseWheelClick::DOWN;
|
||||||
|
|
||||||
|
for (int i = 0; i < A_Last; ++i)
|
||||||
|
{
|
||||||
|
ICS::Control* control;
|
||||||
|
bool controlExists = mInputBinder->getChannel(i)->getControlsCount() != 0;
|
||||||
|
if (!controlExists)
|
||||||
|
{
|
||||||
|
control = new ICS::Control(std::to_string(i), false, true, 0, ICS::ICS_MAX, ICS::ICS_MAX);
|
||||||
|
mInputBinder->addControl(control);
|
||||||
|
control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
control = mInputBinder->getChannel(i)->getAttachedControls().front().control;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!controlExists || force ||
|
||||||
|
(mInputBinder->getKeyBinding(control, ICS::Control::INCREASE) == SDL_SCANCODE_UNKNOWN
|
||||||
|
&& mInputBinder->getMouseButtonBinding(control, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS
|
||||||
|
&& mInputBinder->getMouseWheelBinding(control, ICS::Control::INCREASE) == ICS::InputControlSystem::MouseWheelClick::UNASSIGNED))
|
||||||
|
{
|
||||||
|
clearAllKeyBindings(mInputBinder, control);
|
||||||
|
|
||||||
|
if (defaultKeyBindings.find(i) != defaultKeyBindings.end()
|
||||||
|
&& (force || !mInputBinder->isKeyBound(defaultKeyBindings[i])))
|
||||||
|
{
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
mInputBinder->addKeyBinding(control, defaultKeyBindings[i], ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
else if (defaultMouseButtonBindings.find(i) != defaultMouseButtonBindings.end()
|
||||||
|
&& (force || !mInputBinder->isMouseButtonBound(defaultMouseButtonBindings[i])))
|
||||||
|
{
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
mInputBinder->addMouseButtonBinding(control, defaultMouseButtonBindings[i], ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
else if (defaultMouseWheelBindings.find(i) != defaultMouseWheelBindings.end()
|
||||||
|
&& (force || !mInputBinder->isMouseWheelBound(defaultMouseWheelBindings[i])))
|
||||||
|
{
|
||||||
|
control->setInitialValue(0.f);
|
||||||
|
mInputBinder->addMouseWheelBinding(control, defaultMouseWheelBindings[i], ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == A_LookLeftRight && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_4) && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_6))
|
||||||
|
{
|
||||||
|
mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_6, ICS::Control::INCREASE);
|
||||||
|
mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_4, ICS::Control::DECREASE);
|
||||||
|
}
|
||||||
|
if (i == A_LookUpDown && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_8) && !mInputBinder->isKeyBound(SDL_SCANCODE_KP_2))
|
||||||
|
{
|
||||||
|
mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_2, ICS::Control::INCREASE);
|
||||||
|
mInputBinder->addKeyBinding(control, SDL_SCANCODE_KP_8, ICS::Control::DECREASE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::loadControllerDefaults(bool force)
|
||||||
|
{
|
||||||
|
// using hardcoded key defaults is inevitable, if we want the configuration files to stay valid
|
||||||
|
// across different versions of OpenMW (in the case where another input action is added)
|
||||||
|
std::map<int, int> defaultButtonBindings;
|
||||||
|
|
||||||
|
defaultButtonBindings[A_Activate] = SDL_CONTROLLER_BUTTON_A;
|
||||||
|
defaultButtonBindings[A_ToggleWeapon] = SDL_CONTROLLER_BUTTON_X;
|
||||||
|
defaultButtonBindings[A_ToggleSpell] = SDL_CONTROLLER_BUTTON_Y;
|
||||||
|
//defaultButtonBindings[A_QuickButtonsMenu] = SDL_GetButtonFromScancode(SDL_SCANCODE_F1); // Need to implement, should be ToggleSpell(5) AND Wait(9)
|
||||||
|
defaultButtonBindings[A_Sneak] = SDL_CONTROLLER_BUTTON_LEFTSTICK;
|
||||||
|
defaultButtonBindings[A_Journal] = SDL_CONTROLLER_BUTTON_LEFTSHOULDER;
|
||||||
|
defaultButtonBindings[A_Rest] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
||||||
|
defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
|
||||||
|
defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B;
|
||||||
|
defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START;
|
||||||
|
defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE;
|
||||||
|
defaultButtonBindings[A_MoveForward] = SDL_CONTROLLER_BUTTON_DPAD_UP;
|
||||||
|
defaultButtonBindings[A_MoveLeft] = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
|
||||||
|
defaultButtonBindings[A_MoveBackward] = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
|
||||||
|
defaultButtonBindings[A_MoveRight] = SDL_CONTROLLER_BUTTON_DPAD_RIGHT;
|
||||||
|
|
||||||
|
std::map<int, int> defaultAxisBindings;
|
||||||
|
defaultAxisBindings[A_MoveForwardBackward] = SDL_CONTROLLER_AXIS_LEFTY;
|
||||||
|
defaultAxisBindings[A_MoveLeftRight] = SDL_CONTROLLER_AXIS_LEFTX;
|
||||||
|
defaultAxisBindings[A_LookUpDown] = SDL_CONTROLLER_AXIS_RIGHTY;
|
||||||
|
defaultAxisBindings[A_LookLeftRight] = SDL_CONTROLLER_AXIS_RIGHTX;
|
||||||
|
defaultAxisBindings[A_Use] = SDL_CONTROLLER_AXIS_TRIGGERRIGHT;
|
||||||
|
defaultAxisBindings[A_Jump] = SDL_CONTROLLER_AXIS_TRIGGERLEFT;
|
||||||
|
|
||||||
|
for (int i = 0; i < A_Last; i++)
|
||||||
|
{
|
||||||
|
ICS::Control* control;
|
||||||
|
bool controlExists = mInputBinder->getChannel(i)->getControlsCount() != 0;
|
||||||
|
if (!controlExists)
|
||||||
|
{
|
||||||
|
float initial;
|
||||||
|
if (defaultAxisBindings.find(i) == defaultAxisBindings.end())
|
||||||
|
initial = 0.0f;
|
||||||
|
else initial = 0.5f;
|
||||||
|
control = new ICS::Control(std::to_string(i), false, true, initial, ICS::ICS_MAX, ICS::ICS_MAX);
|
||||||
|
mInputBinder->addControl(control);
|
||||||
|
control->attachChannel(mInputBinder->getChannel(i), ICS::Channel::DIRECT);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
control = mInputBinder->getChannel(i)->getAttachedControls().front().control;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!controlExists || force || (mInputBinder->getJoystickAxisBinding(control, sFakeDeviceId, ICS::Control::INCREASE) == ICS::InputControlSystem::UNASSIGNED &&
|
||||||
|
mInputBinder->getJoystickButtonBinding(control, sFakeDeviceId, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS))
|
||||||
|
{
|
||||||
|
clearAllControllerBindings(mInputBinder, control);
|
||||||
|
|
||||||
|
if (defaultButtonBindings.find(i) != defaultButtonBindings.end()
|
||||||
|
&& (force || !mInputBinder->isJoystickButtonBound(sFakeDeviceId, defaultButtonBindings[i])))
|
||||||
|
{
|
||||||
|
control->setInitialValue(0.0f);
|
||||||
|
mInputBinder->addJoystickButtonBinding(control, sFakeDeviceId, defaultButtonBindings[i], ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
else if (defaultAxisBindings.find(i) != defaultAxisBindings.end() && (force || !mInputBinder->isJoystickAxisBound(sFakeDeviceId, defaultAxisBindings[i])))
|
||||||
|
{
|
||||||
|
control->setValue(0.5f);
|
||||||
|
control->setInitialValue(0.5f);
|
||||||
|
mInputBinder->addJoystickAxisBinding(control, sFakeDeviceId, defaultAxisBindings[i], ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BindingsManager::getActionDescription(int action)
|
||||||
|
{
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case A_Screenshot:
|
||||||
|
return "Screenshot";
|
||||||
|
case A_ZoomIn:
|
||||||
|
return "Zoom In";
|
||||||
|
case A_ZoomOut:
|
||||||
|
return "Zoom Out";
|
||||||
|
case A_ToggleHUD:
|
||||||
|
return "Toggle HUD";
|
||||||
|
case A_Use:
|
||||||
|
return "#{sUse}";
|
||||||
|
case A_Activate:
|
||||||
|
return "#{sActivate}";
|
||||||
|
case A_MoveBackward:
|
||||||
|
return "#{sBack}";
|
||||||
|
case A_MoveForward:
|
||||||
|
return "#{sForward}";
|
||||||
|
case A_MoveLeft:
|
||||||
|
return "#{sLeft}";
|
||||||
|
case A_MoveRight:
|
||||||
|
return "#{sRight}";
|
||||||
|
case A_ToggleWeapon:
|
||||||
|
return "#{sReady_Weapon}";
|
||||||
|
case A_ToggleSpell:
|
||||||
|
return "#{sReady_Magic}";
|
||||||
|
case A_CycleSpellLeft:
|
||||||
|
return "#{sPrevSpell}";
|
||||||
|
case A_CycleSpellRight:
|
||||||
|
return "#{sNextSpell}";
|
||||||
|
case A_CycleWeaponLeft:
|
||||||
|
return "#{sPrevWeapon}";
|
||||||
|
case A_CycleWeaponRight:
|
||||||
|
return "#{sNextWeapon}";
|
||||||
|
case A_Console:
|
||||||
|
return "#{sConsoleTitle}";
|
||||||
|
case A_Run:
|
||||||
|
return "#{sRun}";
|
||||||
|
case A_Sneak:
|
||||||
|
return "#{sCrouch_Sneak}";
|
||||||
|
case A_AutoMove:
|
||||||
|
return "#{sAuto_Run}";
|
||||||
|
case A_Jump:
|
||||||
|
return "#{sJump}";
|
||||||
|
case A_Journal:
|
||||||
|
return "#{sJournal}";
|
||||||
|
case A_Rest:
|
||||||
|
return "#{sRestKey}";
|
||||||
|
case A_Inventory:
|
||||||
|
return "#{sInventory}";
|
||||||
|
case A_TogglePOV:
|
||||||
|
return "#{sTogglePOVCmd}";
|
||||||
|
case A_QuickKeysMenu:
|
||||||
|
return "#{sQuickMenu}";
|
||||||
|
case A_QuickKey1:
|
||||||
|
return "#{sQuick1Cmd}";
|
||||||
|
case A_QuickKey2:
|
||||||
|
return "#{sQuick2Cmd}";
|
||||||
|
case A_QuickKey3:
|
||||||
|
return "#{sQuick3Cmd}";
|
||||||
|
case A_QuickKey4:
|
||||||
|
return "#{sQuick4Cmd}";
|
||||||
|
case A_QuickKey5:
|
||||||
|
return "#{sQuick5Cmd}";
|
||||||
|
case A_QuickKey6:
|
||||||
|
return "#{sQuick6Cmd}";
|
||||||
|
case A_QuickKey7:
|
||||||
|
return "#{sQuick7Cmd}";
|
||||||
|
case A_QuickKey8:
|
||||||
|
return "#{sQuick8Cmd}";
|
||||||
|
case A_QuickKey9:
|
||||||
|
return "#{sQuick9Cmd}";
|
||||||
|
case A_QuickKey10:
|
||||||
|
return "#{sQuick10Cmd}";
|
||||||
|
case A_AlwaysRun:
|
||||||
|
return "#{sAlways_Run}";
|
||||||
|
case A_QuickSave:
|
||||||
|
return "#{sQuickSaveCmd}";
|
||||||
|
case A_QuickLoad:
|
||||||
|
return "#{sQuickLoadCmd}";
|
||||||
|
default:
|
||||||
|
return std::string(); // not configurable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BindingsManager::getActionKeyBindingName(int action)
|
||||||
|
{
|
||||||
|
if (mInputBinder->getChannel(action)->getControlsCount() == 0)
|
||||||
|
return "#{sNone}";
|
||||||
|
|
||||||
|
ICS::Control* c = mInputBinder->getChannel(action)->getAttachedControls().front().control;
|
||||||
|
|
||||||
|
SDL_Scancode key = mInputBinder->getKeyBinding(c, ICS::Control::INCREASE);
|
||||||
|
unsigned int mouse = mInputBinder->getMouseButtonBinding(c, ICS::Control::INCREASE);
|
||||||
|
ICS::InputControlSystem::MouseWheelClick wheel = mInputBinder->getMouseWheelBinding(c, ICS::Control::INCREASE);
|
||||||
|
if (key != SDL_SCANCODE_UNKNOWN)
|
||||||
|
return MyGUI::TextIterator::toTagsString(mInputBinder->scancodeToString(key));
|
||||||
|
else if (mouse != ICS_MAX_DEVICE_BUTTONS)
|
||||||
|
return "#{sMouse} " + std::to_string(mouse);
|
||||||
|
else if (wheel != ICS::InputControlSystem::MouseWheelClick::UNASSIGNED)
|
||||||
|
switch (wheel)
|
||||||
|
{
|
||||||
|
case ICS::InputControlSystem::MouseWheelClick::UP:
|
||||||
|
return "Mouse Wheel Up";
|
||||||
|
case ICS::InputControlSystem::MouseWheelClick::DOWN:
|
||||||
|
return "Mouse Wheel Down";
|
||||||
|
case ICS::InputControlSystem::MouseWheelClick::RIGHT:
|
||||||
|
return "Mouse Wheel Right";
|
||||||
|
case ICS::InputControlSystem::MouseWheelClick::LEFT:
|
||||||
|
return "Mouse Wheel Left";
|
||||||
|
default:
|
||||||
|
return "#{sNone}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "#{sNone}";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BindingsManager::getActionControllerBindingName(int action)
|
||||||
|
{
|
||||||
|
if (mInputBinder->getChannel(action)->getControlsCount() == 0)
|
||||||
|
return "#{sNone}";
|
||||||
|
|
||||||
|
ICS::Control* c = mInputBinder->getChannel(action)->getAttachedControls().front().control;
|
||||||
|
|
||||||
|
if (mInputBinder->getJoystickAxisBinding(c, sFakeDeviceId, ICS::Control::INCREASE) != ICS::InputControlSystem::UNASSIGNED)
|
||||||
|
return sdlControllerAxisToString(mInputBinder->getJoystickAxisBinding(c, sFakeDeviceId, ICS::Control::INCREASE));
|
||||||
|
else if (mInputBinder->getJoystickButtonBinding(c, sFakeDeviceId, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS)
|
||||||
|
return sdlControllerButtonToString(mInputBinder->getJoystickButtonBinding(c, sFakeDeviceId, ICS::Control::INCREASE));
|
||||||
|
else
|
||||||
|
return "#{sNone}";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<int> BindingsManager::getActionKeySorting()
|
||||||
|
{
|
||||||
|
static const std::vector<int> actions
|
||||||
|
{
|
||||||
|
A_MoveForward, A_MoveBackward, A_MoveLeft, A_MoveRight, A_TogglePOV, A_ZoomIn, A_ZoomOut,
|
||||||
|
A_Run, A_AlwaysRun, A_Sneak, A_Activate, A_Use, A_ToggleWeapon, A_ToggleSpell,
|
||||||
|
A_CycleSpellLeft, A_CycleSpellRight, A_CycleWeaponLeft, A_CycleWeaponRight, A_AutoMove,
|
||||||
|
A_Jump, A_Inventory, A_Journal, A_Rest, A_Console, A_QuickSave, A_QuickLoad,
|
||||||
|
A_ToggleHUD, A_Screenshot, A_QuickKeysMenu, A_QuickKey1, A_QuickKey2, A_QuickKey3,
|
||||||
|
A_QuickKey4, A_QuickKey5, A_QuickKey6, A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10
|
||||||
|
};
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
std::vector<int> BindingsManager::getActionControllerSorting()
|
||||||
|
{
|
||||||
|
static const std::vector<int> actions
|
||||||
|
{
|
||||||
|
A_TogglePOV, A_ZoomIn, A_ZoomOut, A_Sneak, A_Activate, A_Use, A_ToggleWeapon, A_ToggleSpell,
|
||||||
|
A_AutoMove, A_Jump, A_Inventory, A_Journal, A_Rest, A_QuickSave, A_QuickLoad, A_ToggleHUD,
|
||||||
|
A_Screenshot, A_QuickKeysMenu, A_QuickKey1, A_QuickKey2, A_QuickKey3, A_QuickKey4,
|
||||||
|
A_QuickKey5, A_QuickKey6, A_QuickKey7, A_QuickKey8, A_QuickKey9, A_QuickKey10,
|
||||||
|
A_CycleSpellLeft, A_CycleSpellRight, A_CycleWeaponLeft, A_CycleWeaponRight
|
||||||
|
};
|
||||||
|
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::enableDetectingBindingMode(int action, bool keyboard)
|
||||||
|
{
|
||||||
|
mListener->setDetectingKeyboard(keyboard);
|
||||||
|
ICS::Control* c = mInputBinder->getChannel(action)->getAttachedControls().front().control;
|
||||||
|
mInputBinder->enableDetectingBindingState(c, ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BindingsManager::isDetectingBindingState() const
|
||||||
|
{
|
||||||
|
return mInputBinder->detectingBindingState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::mousePressed(const SDL_MouseButtonEvent &arg, int deviceID)
|
||||||
|
{
|
||||||
|
mInputBinder->mousePressed(arg, deviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::mouseReleased(const SDL_MouseButtonEvent &arg, int deviceID)
|
||||||
|
{
|
||||||
|
mInputBinder->mouseReleased(arg, deviceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::mouseMoved(const SDLUtil::MouseMotionEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->mouseMoved(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::mouseWheelMoved(const SDL_MouseWheelEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->mouseWheelMoved(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::keyPressed(const SDL_KeyboardEvent &arg)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Pass the pressed key to the multiplayer-specific GUI controller
|
||||||
|
*/
|
||||||
|
mwmp::Main::get().getGUIController()->pressedKey(arg.keysym.scancode);
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
mInputBinder->keyPressed(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::keyReleased(const SDL_KeyboardEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->keyReleased(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->controllerAdded(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->controllerRemoved(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::controllerButtonPressed(int deviceID, const SDL_ControllerButtonEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->buttonPressed(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::controllerButtonReleased(int deviceID, const SDL_ControllerButtonEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->buttonReleased(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::controllerAxisMoved(int deviceID, const SDL_ControllerAxisEvent &arg)
|
||||||
|
{
|
||||||
|
mInputBinder->axisMoved(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Scancode BindingsManager::getKeyBinding(int actionId)
|
||||||
|
{
|
||||||
|
return mInputBinder->getKeyBinding(mInputBinder->getControl(actionId), ICS::Control::INCREASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindingsManager::actionValueChanged(int action, float currentValue, float previousValue)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
|
||||||
|
if (mDragDrop && action != A_GameMenu && action != A_Inventory)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((previousValue == 1 || previousValue == 0) && (currentValue==1 || currentValue==0))
|
||||||
|
{
|
||||||
|
//Is a normal button press, so don't change it at all
|
||||||
|
}
|
||||||
|
//Otherwise only trigger button presses as they go through specific points
|
||||||
|
else if (previousValue >= 0.8 && currentValue < 0.8)
|
||||||
|
{
|
||||||
|
currentValue = 0.0;
|
||||||
|
previousValue = 1.0;
|
||||||
|
}
|
||||||
|
else if (previousValue <= 0.6 && currentValue > 0.6)
|
||||||
|
{
|
||||||
|
currentValue = 1.0;
|
||||||
|
previousValue = 0.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//If it's not switching between those values, ignore the channel change.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
{
|
||||||
|
bool joystickUsed = MWBase::Environment::get().getInputManager()->joystickLastUsed();
|
||||||
|
if (action == A_Use)
|
||||||
|
{
|
||||||
|
if (joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon))
|
||||||
|
action = A_CycleWeaponRight;
|
||||||
|
|
||||||
|
else if (joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell))
|
||||||
|
action = A_CycleSpellRight;
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Start of tes3mp addition
|
||||||
|
|
||||||
|
Prevent players from starting attacks while in the persuasion submenu in dialogue
|
||||||
|
*/
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_Dialogue))
|
||||||
|
return;
|
||||||
|
/*
|
||||||
|
End of tes3mp addition
|
||||||
|
*/
|
||||||
|
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
MWMechanics::DrawState_ state = player.getDrawState();
|
||||||
|
player.setAttackingOrSpell(currentValue != 0 && state != MWMechanics::DrawState_Nothing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (action == A_Jump)
|
||||||
|
{
|
||||||
|
if (joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleWeapon))
|
||||||
|
action = A_CycleWeaponLeft;
|
||||||
|
|
||||||
|
else if (joystickUsed && currentValue == 1.0 && actionIsActive(A_ToggleSpell))
|
||||||
|
action = A_CycleSpellLeft;
|
||||||
|
|
||||||
|
else
|
||||||
|
MWBase::Environment::get().getInputManager()->setAttemptJump(currentValue == 1.0 && previousValue == 0.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentValue == 1)
|
||||||
|
MWBase::Environment::get().getInputManager()->executeAction(action);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
#ifndef MWINPUT_MWBINDINGSMANAGER_H
|
||||||
|
#define MWINPUT_MWBINDINGSMANAGER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class BindingsListener;
|
||||||
|
class InputControlSystem;
|
||||||
|
|
||||||
|
class BindingsManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BindingsManager(const std::string& userFile, bool userFileExists);
|
||||||
|
|
||||||
|
virtual ~BindingsManager();
|
||||||
|
|
||||||
|
std::string getActionDescription (int action);
|
||||||
|
std::string getActionKeyBindingName (int action);
|
||||||
|
std::string getActionControllerBindingName (int action);
|
||||||
|
std::vector<int> getActionKeySorting();
|
||||||
|
std::vector<int> getActionControllerSorting();
|
||||||
|
|
||||||
|
void enableDetectingBindingMode (int action, bool keyboard);
|
||||||
|
bool isDetectingBindingState() const;
|
||||||
|
|
||||||
|
void loadKeyDefaults(bool force = false);
|
||||||
|
void loadControllerDefaults(bool force = false);
|
||||||
|
|
||||||
|
void setDragDrop(bool dragDrop);
|
||||||
|
|
||||||
|
void update(float dt);
|
||||||
|
|
||||||
|
void setPlayerControlsEnabled(bool enabled);
|
||||||
|
|
||||||
|
bool isLeftOrRightButton(int action, bool joystick) const;
|
||||||
|
|
||||||
|
bool actionIsActive(int id) const;
|
||||||
|
float getActionValue(int id) const;
|
||||||
|
|
||||||
|
void mousePressed(const SDL_MouseButtonEvent &evt, int deviceID);
|
||||||
|
void mouseReleased(const SDL_MouseButtonEvent &arg, int deviceID);
|
||||||
|
void mouseMoved(const SDLUtil::MouseMotionEvent &arg);
|
||||||
|
void mouseWheelMoved(const SDL_MouseWheelEvent &arg);
|
||||||
|
|
||||||
|
void keyPressed(const SDL_KeyboardEvent &arg);
|
||||||
|
void keyReleased(const SDL_KeyboardEvent &arg);
|
||||||
|
|
||||||
|
void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg);
|
||||||
|
void controllerRemoved(const SDL_ControllerDeviceEvent &arg);
|
||||||
|
void controllerButtonPressed(int deviceID, const SDL_ControllerButtonEvent &arg);
|
||||||
|
void controllerButtonReleased(int deviceID, const SDL_ControllerButtonEvent &arg);
|
||||||
|
void controllerAxisMoved(int deviceID, const SDL_ControllerAxisEvent &arg);
|
||||||
|
|
||||||
|
SDL_Scancode getKeyBinding(int actionId);
|
||||||
|
|
||||||
|
void actionValueChanged(int action, float currentValue, float previousValue);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupSDLKeyMappings();
|
||||||
|
|
||||||
|
InputControlSystem* mInputBinder;
|
||||||
|
BindingsListener* mListener;
|
||||||
|
|
||||||
|
std::string mUserFile;
|
||||||
|
|
||||||
|
bool mDragDrop;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,400 @@
|
|||||||
|
#include "controllermanager.hpp"
|
||||||
|
|
||||||
|
#include <MyGUI_Button.h>
|
||||||
|
#include <MyGUI_InputManager.h>
|
||||||
|
#include <MyGUI_Widget.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
|
#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 "bindingsmanager.hpp"
|
||||||
|
#include "mousemanager.hpp"
|
||||||
|
#include "sdlmappings.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
ControllerManager::ControllerManager(BindingsManager* bindingsManager,
|
||||||
|
ActionManager* actionManager,
|
||||||
|
MouseManager* mouseManager,
|
||||||
|
const std::string& userControllerBindingsFile,
|
||||||
|
const std::string& controllerBindingsFile)
|
||||||
|
: mBindingsManager(bindingsManager)
|
||||||
|
, 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;
|
||||||
|
static const int fakeDeviceID = 1;
|
||||||
|
controllerAdded(fakeDeviceID, 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::processChangedSettings(const Settings::CategorySettingVector& changed)
|
||||||
|
{
|
||||||
|
for (const auto& setting : changed)
|
||||||
|
{
|
||||||
|
if (setting.first == "Input" && setting.second == "enable controller")
|
||||||
|
mJoystickEnabled = Settings::Manager::getBool("enable controller", "Input");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControllerManager::update(float dt, bool disableControls)
|
||||||
|
{
|
||||||
|
mControlsDisabled = disableControls;
|
||||||
|
mGamepadPreviewMode = mActionManager->getPreviewDelay() == 1.f;
|
||||||
|
|
||||||
|
if (mGuiCursorEnabled && !(mJoystickLastUsed && !mGamepadGuiCursorEnabled))
|
||||||
|
{
|
||||||
|
float xAxis = mBindingsManager->getActionValue(A_MoveLeftRight) * 2.0f - 1.0f;
|
||||||
|
float yAxis = mBindingsManager->getActionValue(A_MoveForwardBackward) * 2.0f - 1.0f;
|
||||||
|
float zAxis = mBindingsManager->getActionValue(A_LookUpDown) * 2.0f - 1.0f;
|
||||||
|
|
||||||
|
xAxis *= (1.5f - mBindingsManager->getActionValue(A_Use));
|
||||||
|
yAxis *= (1.5f - mBindingsManager->getActionValue(A_Use));
|
||||||
|
|
||||||
|
// 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<int>(-zAxis * dt * 1500.0f);
|
||||||
|
|
||||||
|
mMouseManager->injectMouseMove(xMove, yMove, mouseWheelMove);
|
||||||
|
mMouseManager->warpMouse();
|
||||||
|
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable movement in Gui mode
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()
|
||||||
|
|| MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running)
|
||||||
|
{
|
||||||
|
mGamepadZoom = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
|
{
|
||||||
|
float xAxis = mBindingsManager->getActionValue(A_MoveLeftRight);
|
||||||
|
float yAxis = mBindingsManager->getActionValue(A_MoveForwardBackward);
|
||||||
|
if (xAxis != 0.5)
|
||||||
|
{
|
||||||
|
triedToMove = true;
|
||||||
|
player.setLeftRight((xAxis - 0.5f) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (yAxis != 0.5)
|
||||||
|
{
|
||||||
|
triedToMove = true;
|
||||||
|
player.setAutoMove (false);
|
||||||
|
player.setForwardBackward((0.5f - yAxis) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (triedToMove)
|
||||||
|
{
|
||||||
|
mJoystickLastUsed = true;
|
||||||
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const bool isToggleSneak = Settings::Manager::getBool("toggle sneak", "Input");
|
||||||
|
if (!isToggleSneak)
|
||||||
|
{
|
||||||
|
if (mJoystickLastUsed)
|
||||||
|
{
|
||||||
|
if (mBindingsManager->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(mBindingsManager->actionIsActive(A_Sneak));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch"))
|
||||||
|
{
|
||||||
|
if (!mBindingsManager->actionIsActive(A_TogglePOV))
|
||||||
|
mGamepadZoom = 0;
|
||||||
|
|
||||||
|
if (mGamepadZoom)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->changeVanityModeScale(mGamepadZoom);
|
||||||
|
MWBase::Environment::get().getWorld()->setCameraDistance(mGamepadZoom, true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return triedToMove;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg)
|
||||||
|
{
|
||||||
|
if (!mJoystickEnabled || mBindingsManager->isDetectingBindingState())
|
||||||
|
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<MyGUI::Button>(false);
|
||||||
|
if (b && b->getEnabled())
|
||||||
|
MWBase::Environment::get().getWindowManager()->playSound("Menu Click");
|
||||||
|
}
|
||||||
|
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!mousePressSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(true);
|
||||||
|
|
||||||
|
//esc, to leave initial movie screen
|
||||||
|
auto kc = sdlKeyToMyGUI(SDLK_ESCAPE);
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyPress(kc, 0));
|
||||||
|
|
||||||
|
if (!mControlsDisabled)
|
||||||
|
mBindingsManager->controllerButtonPressed(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg)
|
||||||
|
{
|
||||||
|
if (mBindingsManager->isDetectingBindingState())
|
||||||
|
{
|
||||||
|
mBindingsManager->controllerButtonReleased(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 (mBindingsManager->isDetectingBindingState()) // If the player just triggered binding, don't let button release bind.
|
||||||
|
return;
|
||||||
|
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!mousePressSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(true);
|
||||||
|
|
||||||
|
//esc, to leave initial movie screen
|
||||||
|
auto kc = sdlKeyToMyGUI(SDLK_ESCAPE);
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(kc));
|
||||||
|
|
||||||
|
mBindingsManager->controllerButtonReleased(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.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mBindingsManager->controllerAxisMoved(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg)
|
||||||
|
{
|
||||||
|
mBindingsManager->controllerAdded(deviceID, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControllerManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg)
|
||||||
|
{
|
||||||
|
mBindingsManager->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;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,66 @@
|
|||||||
|
#ifndef MWINPUT_MWCONTROLLERMANAGER_H
|
||||||
|
#define MWINPUT_MWCONTROLLERMANAGER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class ActionManager;
|
||||||
|
class BindingsManager;
|
||||||
|
class MouseManager;
|
||||||
|
|
||||||
|
class ControllerManager : public SDLUtil::ControllerListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ControllerManager(BindingsManager* bindingsManager,
|
||||||
|
ActionManager* actionManager,
|
||||||
|
MouseManager* mouseManager,
|
||||||
|
const std::string& userControllerBindingsFile,
|
||||||
|
const std::string& controllerBindingsFile);
|
||||||
|
|
||||||
|
virtual ~ControllerManager() = default;
|
||||||
|
|
||||||
|
bool update(float dt, bool disableControls);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
BindingsManager* mBindingsManager;
|
||||||
|
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
|
@ -0,0 +1,99 @@
|
|||||||
|
#include "controlswitch.hpp"
|
||||||
|
|
||||||
|
#include <components/esm/esmwriter.hpp>
|
||||||
|
#include <components/esm/esmreader.hpp>
|
||||||
|
#include <components/esm/controlsstate.hpp>
|
||||||
|
|
||||||
|
#include <components/loadinglistener/loadinglistener.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
ControlSwitch::ControlSwitch()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlSwitch::clear()
|
||||||
|
{
|
||||||
|
mSwitches["playercontrols"] = true;
|
||||||
|
mSwitches["playerfighting"] = true;
|
||||||
|
mSwitches["playerjumping"] = true;
|
||||||
|
mSwitches["playerlooking"] = true;
|
||||||
|
mSwitches["playermagic"] = true;
|
||||||
|
mSwitches["playerviewswitch"] = true;
|
||||||
|
mSwitches["vanitymode"] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ControlSwitch::get(const std::string& key)
|
||||||
|
{
|
||||||
|
return mSwitches[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlSwitch::set(const std::string& key, bool value)
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
|
||||||
|
/// \note 7 switches at all, if-else is relevant
|
||||||
|
if (key == "playercontrols" && !value)
|
||||||
|
{
|
||||||
|
player.setLeftRight(0);
|
||||||
|
player.setForwardBackward(0);
|
||||||
|
player.setAutoMove(false);
|
||||||
|
player.setUpDown(0);
|
||||||
|
}
|
||||||
|
else if (key == "playerjumping" && !value)
|
||||||
|
{
|
||||||
|
/// \fixme maybe crouching at this time
|
||||||
|
player.setUpDown(0);
|
||||||
|
}
|
||||||
|
else if (key == "vanitymode")
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->allowVanityMode(value);
|
||||||
|
}
|
||||||
|
else if (key == "playerlooking" && !value)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->rotateObject(player.getPlayer(), 0.f, 0.f, 0.f);
|
||||||
|
}
|
||||||
|
mSwitches[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlSwitch::write(ESM::ESMWriter& writer, Loading::Listener& /*progress*/)
|
||||||
|
{
|
||||||
|
ESM::ControlsState controls;
|
||||||
|
controls.mViewSwitchDisabled = !mSwitches["playerviewswitch"];
|
||||||
|
controls.mControlsDisabled = !mSwitches["playercontrols"];
|
||||||
|
controls.mJumpingDisabled = !mSwitches["playerjumping"];
|
||||||
|
controls.mLookingDisabled = !mSwitches["playerlooking"];
|
||||||
|
controls.mVanityModeDisabled = !mSwitches["vanitymode"];
|
||||||
|
controls.mWeaponDrawingDisabled = !mSwitches["playerfighting"];
|
||||||
|
controls.mSpellDrawingDisabled = !mSwitches["playermagic"];
|
||||||
|
|
||||||
|
writer.startRecord (ESM::REC_INPU);
|
||||||
|
controls.save(writer);
|
||||||
|
writer.endRecord (ESM::REC_INPU);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ControlSwitch::readRecord(ESM::ESMReader& reader, uint32_t type)
|
||||||
|
{
|
||||||
|
ESM::ControlsState controls;
|
||||||
|
controls.load(reader);
|
||||||
|
|
||||||
|
set("playerviewswitch", !controls.mViewSwitchDisabled);
|
||||||
|
set("playercontrols", !controls.mControlsDisabled);
|
||||||
|
set("playerjumping", !controls.mJumpingDisabled);
|
||||||
|
set("playerlooking", !controls.mLookingDisabled);
|
||||||
|
set("vanitymode", !controls.mVanityModeDisabled);
|
||||||
|
set("playerfighting", !controls.mWeaponDrawingDisabled);
|
||||||
|
set("playermagic", !controls.mSpellDrawingDisabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ControlSwitch::countSavedGameRecords() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef MWINPUT_CONTROLSWITCH_H
|
||||||
|
#define MWINPUT_CONTROLSWITCH_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace ESM
|
||||||
|
{
|
||||||
|
struct ControlsState;
|
||||||
|
class ESMReader;
|
||||||
|
class ESMWriter;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Loading
|
||||||
|
{
|
||||||
|
class Listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class ControlSwitch
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ControlSwitch();
|
||||||
|
|
||||||
|
bool get(const std::string& key);
|
||||||
|
void set(const std::string& key, bool value);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
void write(ESM::ESMWriter& writer, Loading::Listener& progress);
|
||||||
|
void readRecord(ESM::ESMReader& reader, uint32_t type);
|
||||||
|
int countSavedGameRecords() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::string, bool> mSwitches;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,71 @@
|
|||||||
|
#include "keyboardmanager.hpp"
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
#include <MyGUI_InputManager.h>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
#include "actions.hpp"
|
||||||
|
#include "bindingsmanager.hpp"
|
||||||
|
#include "sdlmappings.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
KeyboardManager::KeyboardManager(BindingsManager* bindingsManager)
|
||||||
|
: mBindingsManager(bindingsManager)
|
||||||
|
, mControlsDisabled(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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)
|
||||||
|
auto kc = sdlKeyToMyGUI(arg.keysym.sym);
|
||||||
|
if (mBindingsManager->getKeyBinding(A_Console) == arg.keysym.scancode
|
||||||
|
&& MWBase::Environment::get().getWindowManager()->isConsoleMode())
|
||||||
|
SDL_StopTextInput();
|
||||||
|
|
||||||
|
bool consumed = false;
|
||||||
|
if (kc != MyGUI::KeyCode::None && !mBindingsManager->isDetectingBindingState())
|
||||||
|
{
|
||||||
|
consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(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;
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!consumed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg.repeat)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mControlsDisabled && !consumed)
|
||||||
|
mBindingsManager->keyPressed(arg);
|
||||||
|
|
||||||
|
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KeyboardManager::keyReleased(const SDL_KeyboardEvent &arg)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||||
|
auto kc = sdlKeyToMyGUI(arg.keysym.sym);
|
||||||
|
|
||||||
|
if (!mBindingsManager->isDetectingBindingState())
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(kc));
|
||||||
|
mBindingsManager->keyReleased(arg);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef MWINPUT_MWKEYBOARDMANAGER_H
|
||||||
|
#define MWINPUT_MWKEYBOARDMANAGER_H
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class BindingsManager;
|
||||||
|
|
||||||
|
class KeyboardManager : public SDLUtil::KeyListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
KeyboardManager(BindingsManager* bindingsManager);
|
||||||
|
|
||||||
|
virtual ~KeyboardManager() = default;
|
||||||
|
|
||||||
|
virtual void textInput(const SDL_TextInputEvent &arg);
|
||||||
|
virtual void keyPressed(const SDL_KeyboardEvent &arg);
|
||||||
|
virtual void keyReleased(const SDL_KeyboardEvent &arg);
|
||||||
|
|
||||||
|
void setControlsDisabled(bool disabled) { mControlsDisabled = disabled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
BindingsManager* mBindingsManager;
|
||||||
|
|
||||||
|
bool mControlsDisabled;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,227 @@
|
|||||||
|
#include "mousemanager.hpp"
|
||||||
|
|
||||||
|
#include <MyGUI_Button.h>
|
||||||
|
#include <MyGUI_InputManager.h>
|
||||||
|
#include <MyGUI_RenderManager.h>
|
||||||
|
#include <MyGUI_Widget.h>
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
#include <components/sdlutil/sdlinputwrapper.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/windowmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
#include "actions.hpp"
|
||||||
|
#include "bindingsmanager.hpp"
|
||||||
|
#include "sdlmappings.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
MouseManager::MouseManager(BindingsManager* bindingsManager, SDLUtil::InputWrapper* inputWrapper, SDL_Window* window)
|
||||||
|
: mInvertX(Settings::Manager::getBool("invert x axis", "Input"))
|
||||||
|
, mInvertY(Settings::Manager::getBool("invert y axis", "Input"))
|
||||||
|
, mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input"))
|
||||||
|
, mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input"))
|
||||||
|
, mBindingsManager(bindingsManager)
|
||||||
|
, mInputWrapper(inputWrapper)
|
||||||
|
, mInvUiScalingFactor(1.f)
|
||||||
|
, mGuiCursorX(0)
|
||||||
|
, mGuiCursorY(0)
|
||||||
|
, mMouseWheel(0)
|
||||||
|
, mMouseLookEnabled(false)
|
||||||
|
, mControlsDisabled(false)
|
||||||
|
, mGuiCursorEnabled(true)
|
||||||
|
{
|
||||||
|
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
|
||||||
|
if (uiScale != 0.f)
|
||||||
|
mInvUiScalingFactor = 1.f / uiScale;
|
||||||
|
|
||||||
|
int w,h;
|
||||||
|
SDL_GetWindowSize(window, &w, &h);
|
||||||
|
|
||||||
|
mGuiCursorX = mInvUiScalingFactor * w / 2.f;
|
||||||
|
mGuiCursorY = mInvUiScalingFactor * h / 2.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
||||||
|
{
|
||||||
|
for (const auto& setting : changed)
|
||||||
|
{
|
||||||
|
if (setting.first == "Input" && setting.second == "invert x axis")
|
||||||
|
mInvertX = Settings::Manager::getBool("invert x axis", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "invert y axis")
|
||||||
|
mInvertY = Settings::Manager::getBool("invert y axis", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "camera sensitivity")
|
||||||
|
mCameraSensitivity = Settings::Manager::getFloat("camera sensitivity", "Input");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::mouseMoved(const SDLUtil::MouseMotionEvent &arg)
|
||||||
|
{
|
||||||
|
mBindingsManager->mouseMoved(arg);
|
||||||
|
|
||||||
|
MWBase::InputManager* input = MWBase::Environment::get().getInputManager();
|
||||||
|
input->setJoystickLastUsed(false);
|
||||||
|
input->resetIdleTime();
|
||||||
|
|
||||||
|
if (mGuiCursorEnabled)
|
||||||
|
{
|
||||||
|
input->setGamepadGuiCursorEnabled(true);
|
||||||
|
|
||||||
|
// 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
|
||||||
|
mGuiCursorX = static_cast<float>(arg.x) * mInvUiScalingFactor;
|
||||||
|
mGuiCursorY = static_cast<float>(arg.y) * mInvUiScalingFactor;
|
||||||
|
|
||||||
|
mMouseWheel = static_cast<int>(arg.z);
|
||||||
|
|
||||||
|
MyGUI::InputManager::getInstance().injectMouseMove(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), mMouseWheel);
|
||||||
|
// FIXME: inject twice to force updating focused widget states (tooltips) resulting from changing the viewport by scroll wheel
|
||||||
|
MyGUI::InputManager::getInstance().injectMouseMove(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), mMouseWheel);
|
||||||
|
|
||||||
|
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mMouseLookEnabled && !mControlsDisabled)
|
||||||
|
{
|
||||||
|
float x = arg.xrel * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f;
|
||||||
|
float y = arg.yrel * mCameraSensitivity * (mInvertY ? -1 : 1) * mCameraYMultiplier / 256.f;
|
||||||
|
|
||||||
|
float rot[3];
|
||||||
|
rot[0] = -y;
|
||||||
|
rot[1] = 0.0f;
|
||||||
|
rot[2] = -x;
|
||||||
|
|
||||||
|
// Only actually turn player when we're not in vanity mode
|
||||||
|
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && input->getControlSwitch("playerlooking"))
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.yaw(x);
|
||||||
|
player.pitch(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg.zrel && input->getControlSwitch("playerviewswitch") && input->getControlSwitch("playercontrols")) //Check to make sure you are allowed to zoomout and there is a change
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWorld()->changeVanityModeScale(static_cast<float>(arg.zrel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::mouseReleased(const SDL_MouseButtonEvent &arg, Uint8 id)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||||
|
|
||||||
|
if (mBindingsManager->isDetectingBindingState())
|
||||||
|
{
|
||||||
|
mBindingsManager->mouseReleased(arg, id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||||
|
guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), sdlButtonToMyGUI(id)) && guiMode;
|
||||||
|
|
||||||
|
if (mBindingsManager->isDetectingBindingState())
|
||||||
|
return; // don't allow same mouseup to bind as initiated bind
|
||||||
|
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!guiMode);
|
||||||
|
mBindingsManager->mouseReleased(arg, id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::mouseWheelMoved(const SDL_MouseWheelEvent &arg)
|
||||||
|
{
|
||||||
|
if (mBindingsManager->isDetectingBindingState() || !mControlsDisabled)
|
||||||
|
mBindingsManager->mouseWheelMoved(arg);
|
||||||
|
|
||||||
|
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::mousePressed(const SDL_MouseButtonEvent &arg, Uint8 id)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getInputManager()->setJoystickLastUsed(false);
|
||||||
|
bool guiMode = false;
|
||||||
|
|
||||||
|
if (id == SDL_BUTTON_LEFT || id == SDL_BUTTON_RIGHT) // MyGUI only uses these mouse events
|
||||||
|
{
|
||||||
|
guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
||||||
|
guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), sdlButtonToMyGUI(id)) && guiMode;
|
||||||
|
if (MyGUI::InputManager::getInstance().getMouseFocusWidget () != 0)
|
||||||
|
{
|
||||||
|
MyGUI::Button* b = MyGUI::InputManager::getInstance().getMouseFocusWidget()->castType<MyGUI::Button>(false);
|
||||||
|
if (b && b->getEnabled() && id == SDL_BUTTON_LEFT)
|
||||||
|
{
|
||||||
|
MWBase::Environment::get().getWindowManager()->playSound("Menu Click");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
mBindingsManager->setPlayerControlsEnabled(!guiMode);
|
||||||
|
|
||||||
|
// Don't trigger any mouse bindings while in settings menu, otherwise rebinding controls becomes impossible
|
||||||
|
if (MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Settings)
|
||||||
|
mBindingsManager->mousePressed(arg, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::update(float dt, bool disableControls)
|
||||||
|
{
|
||||||
|
mControlsDisabled = disableControls;
|
||||||
|
|
||||||
|
if (!mMouseLookEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float xAxis = mBindingsManager->getActionValue(A_LookLeftRight) * 2.0f - 1.0f;
|
||||||
|
float yAxis = mBindingsManager->getActionValue(A_LookUpDown) * 2.0f - 1.0f;
|
||||||
|
if (xAxis == 0 && yAxis == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float rot[3];
|
||||||
|
rot[0] = yAxis * dt * 1000.0f * mCameraSensitivity * (mInvertY ? -1 : 1) * mCameraYMultiplier / 256.f;
|
||||||
|
rot[1] = 0.0f;
|
||||||
|
rot[2] = xAxis * dt * 1000.0f * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f;
|
||||||
|
|
||||||
|
// Only actually turn player when we're not in vanity mode
|
||||||
|
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"))
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.yaw(rot[2]);
|
||||||
|
player.pitch(rot[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MouseManager::injectMouseButtonPress(Uint8 button)
|
||||||
|
{
|
||||||
|
return MyGUI::InputManager::getInstance().injectMousePress(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), sdlButtonToMyGUI(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MouseManager::injectMouseButtonRelease(Uint8 button)
|
||||||
|
{
|
||||||
|
return MyGUI::InputManager::getInstance().injectMousePress(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), sdlButtonToMyGUI(button));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::injectMouseMove(int xMove, int yMove, int mouseWheelMove)
|
||||||
|
{
|
||||||
|
mGuiCursorX += xMove;
|
||||||
|
mGuiCursorY += yMove;
|
||||||
|
mMouseWheel += mouseWheelMove;
|
||||||
|
|
||||||
|
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
||||||
|
mGuiCursorX = std::max(0.f, std::min(mGuiCursorX, float(viewSize.width - 1)));
|
||||||
|
mGuiCursorY = std::max(0.f, std::min(mGuiCursorY, float(viewSize.height - 1)));
|
||||||
|
|
||||||
|
MyGUI::InputManager::getInstance().injectMouseMove(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), mMouseWheel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MouseManager::warpMouse()
|
||||||
|
{
|
||||||
|
mInputWrapper->warpMouse(static_cast<int>(mGuiCursorX / mInvUiScalingFactor), static_cast<int>(mGuiCursorY / mInvUiScalingFactor));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
#ifndef MWINPUT_MWMOUSEMANAGER_H
|
||||||
|
#define MWINPUT_MWMOUSEMANAGER_H
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
|
namespace SDLUtil
|
||||||
|
{
|
||||||
|
class InputWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class BindingsManager;
|
||||||
|
|
||||||
|
class MouseManager : public SDLUtil::MouseListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MouseManager(BindingsManager* bindingsManager, SDLUtil::InputWrapper* inputWrapper, SDL_Window* window);
|
||||||
|
|
||||||
|
virtual ~MouseManager() = default;
|
||||||
|
|
||||||
|
void update(float dt, bool disableControls);
|
||||||
|
|
||||||
|
virtual void mouseMoved(const SDLUtil::MouseMotionEvent &arg);
|
||||||
|
virtual void mousePressed(const SDL_MouseButtonEvent &arg, Uint8 id);
|
||||||
|
virtual void mouseReleased(const SDL_MouseButtonEvent &arg, Uint8 id);
|
||||||
|
virtual void mouseWheelMoved(const SDL_MouseWheelEvent &arg);
|
||||||
|
|
||||||
|
void processChangedSettings(const Settings::CategorySettingVector& changed);
|
||||||
|
|
||||||
|
bool injectMouseButtonPress(Uint8 button);
|
||||||
|
bool injectMouseButtonRelease(Uint8 button);
|
||||||
|
void injectMouseMove(int xMove, int yMove, int mouseWheelMove);
|
||||||
|
void warpMouse();
|
||||||
|
|
||||||
|
void setMouseLookEnabled(bool enabled) { mMouseLookEnabled = enabled; }
|
||||||
|
void setGuiCursorEnabled(bool enabled) { mGuiCursorEnabled = enabled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mInvertX;
|
||||||
|
bool mInvertY;
|
||||||
|
float mCameraSensitivity;
|
||||||
|
float mCameraYMultiplier;
|
||||||
|
|
||||||
|
BindingsManager* mBindingsManager;
|
||||||
|
SDLUtil::InputWrapper* mInputWrapper;
|
||||||
|
float mInvUiScalingFactor;
|
||||||
|
|
||||||
|
float mGuiCursorX;
|
||||||
|
float mGuiCursorY;
|
||||||
|
int mMouseWheel;
|
||||||
|
bool mMouseLookEnabled;
|
||||||
|
bool mControlsDisabled;
|
||||||
|
bool mGuiCursorEnabled;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,218 @@
|
|||||||
|
#include "sdlmappings.hpp"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <MyGUI_MouseButton.h>
|
||||||
|
|
||||||
|
#include <SDL_gamecontroller.h>
|
||||||
|
#include <SDL_mouse.h>
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
std::string sdlControllerButtonToString(int button)
|
||||||
|
{
|
||||||
|
switch(button)
|
||||||
|
{
|
||||||
|
case SDL_CONTROLLER_BUTTON_A:
|
||||||
|
return "A Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_B:
|
||||||
|
return "B Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_BACK:
|
||||||
|
return "Back Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_DOWN:
|
||||||
|
return "DPad Down";
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_LEFT:
|
||||||
|
return "DPad Left";
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_RIGHT:
|
||||||
|
return "DPad Right";
|
||||||
|
case SDL_CONTROLLER_BUTTON_DPAD_UP:
|
||||||
|
return "DPad Up";
|
||||||
|
case SDL_CONTROLLER_BUTTON_GUIDE:
|
||||||
|
return "Guide Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_LEFTSHOULDER:
|
||||||
|
return "Left Shoulder";
|
||||||
|
case SDL_CONTROLLER_BUTTON_LEFTSTICK:
|
||||||
|
return "Left Stick Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_RIGHTSHOULDER:
|
||||||
|
return "Right Shoulder";
|
||||||
|
case SDL_CONTROLLER_BUTTON_RIGHTSTICK:
|
||||||
|
return "Right Stick Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_START:
|
||||||
|
return "Start Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_X:
|
||||||
|
return "X Button";
|
||||||
|
case SDL_CONTROLLER_BUTTON_Y:
|
||||||
|
return "Y Button";
|
||||||
|
default:
|
||||||
|
return "Button " + std::to_string(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string sdlControllerAxisToString(int axis)
|
||||||
|
{
|
||||||
|
switch(axis)
|
||||||
|
{
|
||||||
|
case SDL_CONTROLLER_AXIS_LEFTX:
|
||||||
|
return "Left Stick X";
|
||||||
|
case SDL_CONTROLLER_AXIS_LEFTY:
|
||||||
|
return "Left Stick Y";
|
||||||
|
case SDL_CONTROLLER_AXIS_RIGHTX:
|
||||||
|
return "Right Stick X";
|
||||||
|
case SDL_CONTROLLER_AXIS_RIGHTY:
|
||||||
|
return "Right Stick Y";
|
||||||
|
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
|
||||||
|
return "Left Trigger";
|
||||||
|
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
|
||||||
|
return "Right Trigger";
|
||||||
|
default:
|
||||||
|
return "Axis " + std::to_string(axis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button)
|
||||||
|
{
|
||||||
|
//The right button is the second button, according to MyGUI
|
||||||
|
if(button == SDL_BUTTON_RIGHT)
|
||||||
|
button = SDL_BUTTON_MIDDLE;
|
||||||
|
else if(button == SDL_BUTTON_MIDDLE)
|
||||||
|
button = SDL_BUTTON_RIGHT;
|
||||||
|
|
||||||
|
//MyGUI's buttons are 0 indexed
|
||||||
|
return MyGUI::MouseButton::Enum(button - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initKeyMap(std::map<SDL_Keycode, MyGUI::KeyCode>& keyMap)
|
||||||
|
{
|
||||||
|
keyMap[SDLK_UNKNOWN] = MyGUI::KeyCode::None;
|
||||||
|
keyMap[SDLK_ESCAPE] = MyGUI::KeyCode::Escape;
|
||||||
|
keyMap[SDLK_1] = MyGUI::KeyCode::One;
|
||||||
|
keyMap[SDLK_2] = MyGUI::KeyCode::Two;
|
||||||
|
keyMap[SDLK_3] = MyGUI::KeyCode::Three;
|
||||||
|
keyMap[SDLK_4] = MyGUI::KeyCode::Four;
|
||||||
|
keyMap[SDLK_5] = MyGUI::KeyCode::Five;
|
||||||
|
keyMap[SDLK_6] = MyGUI::KeyCode::Six;
|
||||||
|
keyMap[SDLK_7] = MyGUI::KeyCode::Seven;
|
||||||
|
keyMap[SDLK_8] = MyGUI::KeyCode::Eight;
|
||||||
|
keyMap[SDLK_9] = MyGUI::KeyCode::Nine;
|
||||||
|
keyMap[SDLK_0] = MyGUI::KeyCode::Zero;
|
||||||
|
keyMap[SDLK_MINUS] = MyGUI::KeyCode::Minus;
|
||||||
|
keyMap[SDLK_EQUALS] = MyGUI::KeyCode::Equals;
|
||||||
|
keyMap[SDLK_BACKSPACE] = MyGUI::KeyCode::Backspace;
|
||||||
|
keyMap[SDLK_TAB] = MyGUI::KeyCode::Tab;
|
||||||
|
keyMap[SDLK_q] = MyGUI::KeyCode::Q;
|
||||||
|
keyMap[SDLK_w] = MyGUI::KeyCode::W;
|
||||||
|
keyMap[SDLK_e] = MyGUI::KeyCode::E;
|
||||||
|
keyMap[SDLK_r] = MyGUI::KeyCode::R;
|
||||||
|
keyMap[SDLK_t] = MyGUI::KeyCode::T;
|
||||||
|
keyMap[SDLK_y] = MyGUI::KeyCode::Y;
|
||||||
|
keyMap[SDLK_u] = MyGUI::KeyCode::U;
|
||||||
|
keyMap[SDLK_i] = MyGUI::KeyCode::I;
|
||||||
|
keyMap[SDLK_o] = MyGUI::KeyCode::O;
|
||||||
|
keyMap[SDLK_p] = MyGUI::KeyCode::P;
|
||||||
|
keyMap[SDLK_RETURN] = MyGUI::KeyCode::Return;
|
||||||
|
keyMap[SDLK_a] = MyGUI::KeyCode::A;
|
||||||
|
keyMap[SDLK_s] = MyGUI::KeyCode::S;
|
||||||
|
keyMap[SDLK_d] = MyGUI::KeyCode::D;
|
||||||
|
keyMap[SDLK_f] = MyGUI::KeyCode::F;
|
||||||
|
keyMap[SDLK_g] = MyGUI::KeyCode::G;
|
||||||
|
keyMap[SDLK_h] = MyGUI::KeyCode::H;
|
||||||
|
keyMap[SDLK_j] = MyGUI::KeyCode::J;
|
||||||
|
keyMap[SDLK_k] = MyGUI::KeyCode::K;
|
||||||
|
keyMap[SDLK_l] = MyGUI::KeyCode::L;
|
||||||
|
keyMap[SDLK_SEMICOLON] = MyGUI::KeyCode::Semicolon;
|
||||||
|
keyMap[SDLK_QUOTE] = MyGUI::KeyCode::Apostrophe;
|
||||||
|
keyMap[SDLK_BACKQUOTE] = MyGUI::KeyCode::Grave;
|
||||||
|
keyMap[SDLK_LSHIFT] = MyGUI::KeyCode::LeftShift;
|
||||||
|
keyMap[SDLK_BACKSLASH] = MyGUI::KeyCode::Backslash;
|
||||||
|
keyMap[SDLK_z] = MyGUI::KeyCode::Z;
|
||||||
|
keyMap[SDLK_x] = MyGUI::KeyCode::X;
|
||||||
|
keyMap[SDLK_c] = MyGUI::KeyCode::C;
|
||||||
|
keyMap[SDLK_v] = MyGUI::KeyCode::V;
|
||||||
|
keyMap[SDLK_b] = MyGUI::KeyCode::B;
|
||||||
|
keyMap[SDLK_n] = MyGUI::KeyCode::N;
|
||||||
|
keyMap[SDLK_m] = MyGUI::KeyCode::M;
|
||||||
|
keyMap[SDLK_COMMA] = MyGUI::KeyCode::Comma;
|
||||||
|
keyMap[SDLK_PERIOD] = MyGUI::KeyCode::Period;
|
||||||
|
keyMap[SDLK_SLASH] = MyGUI::KeyCode::Slash;
|
||||||
|
keyMap[SDLK_RSHIFT] = MyGUI::KeyCode::RightShift;
|
||||||
|
keyMap[SDLK_KP_MULTIPLY] = MyGUI::KeyCode::Multiply;
|
||||||
|
keyMap[SDLK_LALT] = MyGUI::KeyCode::LeftAlt;
|
||||||
|
keyMap[SDLK_SPACE] = MyGUI::KeyCode::Space;
|
||||||
|
keyMap[SDLK_CAPSLOCK] = MyGUI::KeyCode::Capital;
|
||||||
|
keyMap[SDLK_F1] = MyGUI::KeyCode::F1;
|
||||||
|
keyMap[SDLK_F2] = MyGUI::KeyCode::F2;
|
||||||
|
keyMap[SDLK_F3] = MyGUI::KeyCode::F3;
|
||||||
|
keyMap[SDLK_F4] = MyGUI::KeyCode::F4;
|
||||||
|
keyMap[SDLK_F5] = MyGUI::KeyCode::F5;
|
||||||
|
keyMap[SDLK_F6] = MyGUI::KeyCode::F6;
|
||||||
|
keyMap[SDLK_F7] = MyGUI::KeyCode::F7;
|
||||||
|
keyMap[SDLK_F8] = MyGUI::KeyCode::F8;
|
||||||
|
keyMap[SDLK_F9] = MyGUI::KeyCode::F9;
|
||||||
|
keyMap[SDLK_F10] = MyGUI::KeyCode::F10;
|
||||||
|
keyMap[SDLK_NUMLOCKCLEAR] = MyGUI::KeyCode::NumLock;
|
||||||
|
keyMap[SDLK_SCROLLLOCK] = MyGUI::KeyCode::ScrollLock;
|
||||||
|
keyMap[SDLK_KP_7] = MyGUI::KeyCode::Numpad7;
|
||||||
|
keyMap[SDLK_KP_8] = MyGUI::KeyCode::Numpad8;
|
||||||
|
keyMap[SDLK_KP_9] = MyGUI::KeyCode::Numpad9;
|
||||||
|
keyMap[SDLK_KP_MINUS] = MyGUI::KeyCode::Subtract;
|
||||||
|
keyMap[SDLK_KP_4] = MyGUI::KeyCode::Numpad4;
|
||||||
|
keyMap[SDLK_KP_5] = MyGUI::KeyCode::Numpad5;
|
||||||
|
keyMap[SDLK_KP_6] = MyGUI::KeyCode::Numpad6;
|
||||||
|
keyMap[SDLK_KP_PLUS] = MyGUI::KeyCode::Add;
|
||||||
|
keyMap[SDLK_KP_1] = MyGUI::KeyCode::Numpad1;
|
||||||
|
keyMap[SDLK_KP_2] = MyGUI::KeyCode::Numpad2;
|
||||||
|
keyMap[SDLK_KP_3] = MyGUI::KeyCode::Numpad3;
|
||||||
|
keyMap[SDLK_KP_0] = MyGUI::KeyCode::Numpad0;
|
||||||
|
keyMap[SDLK_KP_PERIOD] = MyGUI::KeyCode::Decimal;
|
||||||
|
keyMap[SDLK_F11] = MyGUI::KeyCode::F11;
|
||||||
|
keyMap[SDLK_F12] = MyGUI::KeyCode::F12;
|
||||||
|
keyMap[SDLK_F13] = MyGUI::KeyCode::F13;
|
||||||
|
keyMap[SDLK_F14] = MyGUI::KeyCode::F14;
|
||||||
|
keyMap[SDLK_F15] = MyGUI::KeyCode::F15;
|
||||||
|
keyMap[SDLK_KP_EQUALS] = MyGUI::KeyCode::NumpadEquals;
|
||||||
|
keyMap[SDLK_COLON] = MyGUI::KeyCode::Colon;
|
||||||
|
keyMap[SDLK_KP_ENTER] = MyGUI::KeyCode::NumpadEnter;
|
||||||
|
keyMap[SDLK_KP_DIVIDE] = MyGUI::KeyCode::Divide;
|
||||||
|
keyMap[SDLK_SYSREQ] = MyGUI::KeyCode::SysRq;
|
||||||
|
keyMap[SDLK_RALT] = MyGUI::KeyCode::RightAlt;
|
||||||
|
keyMap[SDLK_HOME] = MyGUI::KeyCode::Home;
|
||||||
|
keyMap[SDLK_UP] = MyGUI::KeyCode::ArrowUp;
|
||||||
|
keyMap[SDLK_PAGEUP] = MyGUI::KeyCode::PageUp;
|
||||||
|
keyMap[SDLK_LEFT] = MyGUI::KeyCode::ArrowLeft;
|
||||||
|
keyMap[SDLK_RIGHT] = MyGUI::KeyCode::ArrowRight;
|
||||||
|
keyMap[SDLK_END] = MyGUI::KeyCode::End;
|
||||||
|
keyMap[SDLK_DOWN] = MyGUI::KeyCode::ArrowDown;
|
||||||
|
keyMap[SDLK_PAGEDOWN] = MyGUI::KeyCode::PageDown;
|
||||||
|
keyMap[SDLK_INSERT] = MyGUI::KeyCode::Insert;
|
||||||
|
keyMap[SDLK_DELETE] = MyGUI::KeyCode::Delete;
|
||||||
|
keyMap[SDLK_APPLICATION] = MyGUI::KeyCode::AppMenu;
|
||||||
|
|
||||||
|
//The function of the Ctrl and Meta keys are switched on macOS compared to other platforms.
|
||||||
|
//For instance] = Cmd+C versus Ctrl+C to copy from the system clipboard
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
keyMap[SDLK_LGUI] = MyGUI::KeyCode::LeftControl;
|
||||||
|
keyMap[SDLK_RGUI] = MyGUI::KeyCode::RightControl;
|
||||||
|
keyMap[SDLK_LCTRL] = MyGUI::KeyCode::LeftWindows;
|
||||||
|
keyMap[SDLK_RCTRL] = MyGUI::KeyCode::RightWindows;
|
||||||
|
#else
|
||||||
|
keyMap[SDLK_LGUI] = MyGUI::KeyCode::LeftWindows;
|
||||||
|
keyMap[SDLK_RGUI] = MyGUI::KeyCode::RightWindows;
|
||||||
|
keyMap[SDLK_LCTRL] = MyGUI::KeyCode::LeftControl;
|
||||||
|
keyMap[SDLK_RCTRL] = MyGUI::KeyCode::RightControl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
MyGUI::KeyCode sdlKeyToMyGUI(SDL_Keycode code)
|
||||||
|
{
|
||||||
|
static std::map<SDL_Keycode, MyGUI::KeyCode> keyMap;
|
||||||
|
if (keyMap.empty())
|
||||||
|
initKeyMap(keyMap);
|
||||||
|
|
||||||
|
MyGUI::KeyCode kc = MyGUI::KeyCode::None;
|
||||||
|
auto foundKey = keyMap.find(code);
|
||||||
|
if (foundKey != keyMap.end())
|
||||||
|
kc = foundKey->second;
|
||||||
|
|
||||||
|
return kc;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
#ifndef MWINPUT_SDLMAPPINGS_H
|
||||||
|
#define MWINPUT_SDLMAPPINGS_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <MyGUI_KeyCode.h>
|
||||||
|
|
||||||
|
#include <SDL_keycode.h>
|
||||||
|
|
||||||
|
namespace MyGUI
|
||||||
|
{
|
||||||
|
struct MouseButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
std::string sdlControllerButtonToString(int button);
|
||||||
|
|
||||||
|
std::string sdlControllerAxisToString(int axis);
|
||||||
|
|
||||||
|
MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button);
|
||||||
|
|
||||||
|
MyGUI::KeyCode sdlKeyToMyGUI(SDL_Keycode code);
|
||||||
|
}
|
||||||
|
#endif
|
@ -0,0 +1,267 @@
|
|||||||
|
#include "sensormanager.hpp"
|
||||||
|
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
|
#include "../mwbase/environment.hpp"
|
||||||
|
#include "../mwbase/inputmanager.hpp"
|
||||||
|
#include "../mwbase/world.hpp"
|
||||||
|
|
||||||
|
#include "../mwworld/player.hpp"
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
SensorManager::SensorManager()
|
||||||
|
: mInvertX(Settings::Manager::getBool("invert x axis", "Input"))
|
||||||
|
, mInvertY(Settings::Manager::getBool("invert y axis", "Input"))
|
||||||
|
, mGyroXSpeed(0.f)
|
||||||
|
, mGyroYSpeed(0.f)
|
||||||
|
, mGyroUpdateTimer(0.f)
|
||||||
|
, mGyroHSensitivity(Settings::Manager::getFloat("gyro horizontal sensitivity", "Input"))
|
||||||
|
, mGyroVSensitivity(Settings::Manager::getFloat("gyro vertical sensitivity", "Input"))
|
||||||
|
, mGyroHAxis(GyroscopeAxis::Minus_X)
|
||||||
|
, mGyroVAxis(GyroscopeAxis::Y)
|
||||||
|
, mGyroInputThreshold(Settings::Manager::getFloat("gyro input threshold", "Input"))
|
||||||
|
, mGyroscope(nullptr)
|
||||||
|
, mGuiCursorEnabled(true)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::init()
|
||||||
|
{
|
||||||
|
correctGyroscopeAxes();
|
||||||
|
updateSensors();
|
||||||
|
}
|
||||||
|
|
||||||
|
SensorManager::~SensorManager()
|
||||||
|
{
|
||||||
|
if (mGyroscope != nullptr)
|
||||||
|
{
|
||||||
|
SDL_SensorClose(mGyroscope);
|
||||||
|
mGyroscope = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SensorManager::GyroscopeAxis SensorManager::mapGyroscopeAxis(const std::string& axis)
|
||||||
|
{
|
||||||
|
if (axis == "x")
|
||||||
|
return GyroscopeAxis::X;
|
||||||
|
else if (axis == "y")
|
||||||
|
return GyroscopeAxis::Y;
|
||||||
|
else if (axis == "z")
|
||||||
|
return GyroscopeAxis::Z;
|
||||||
|
else if (axis == "-x")
|
||||||
|
return GyroscopeAxis::Minus_X;
|
||||||
|
else if (axis == "-y")
|
||||||
|
return GyroscopeAxis::Minus_Y;
|
||||||
|
else if (axis == "-z")
|
||||||
|
return GyroscopeAxis::Minus_Z;
|
||||||
|
|
||||||
|
return GyroscopeAxis::Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::correctGyroscopeAxes()
|
||||||
|
{
|
||||||
|
if (!Settings::Manager::getBool("enable gyroscope", "Input"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Treat setting from config as axes for landscape mode.
|
||||||
|
// If the device does not support orientation change, do nothing.
|
||||||
|
// Note: in is unclear how to correct axes for devices with non-standart Z axis direction.
|
||||||
|
mGyroHAxis = mapGyroscopeAxis(Settings::Manager::getString("gyro horizontal axis", "Input"));
|
||||||
|
mGyroVAxis = mapGyroscopeAxis(Settings::Manager::getString("gyro vertical axis", "Input"));
|
||||||
|
|
||||||
|
SDL_DisplayOrientation currentOrientation = SDL_GetDisplayOrientation(Settings::Manager::getInt("screen", "Video"));
|
||||||
|
switch (currentOrientation)
|
||||||
|
{
|
||||||
|
case SDL_ORIENTATION_UNKNOWN:
|
||||||
|
return;
|
||||||
|
case SDL_ORIENTATION_LANDSCAPE:
|
||||||
|
break;
|
||||||
|
case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
|
||||||
|
{
|
||||||
|
mGyroHAxis = GyroscopeAxis(-mGyroHAxis);
|
||||||
|
mGyroVAxis = GyroscopeAxis(-mGyroVAxis);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_ORIENTATION_PORTRAIT:
|
||||||
|
{
|
||||||
|
GyroscopeAxis oldVAxis = mGyroVAxis;
|
||||||
|
mGyroVAxis = mGyroHAxis;
|
||||||
|
mGyroHAxis = GyroscopeAxis(-oldVAxis);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SDL_ORIENTATION_PORTRAIT_FLIPPED:
|
||||||
|
{
|
||||||
|
GyroscopeAxis oldVAxis = mGyroVAxis;
|
||||||
|
mGyroVAxis = GyroscopeAxis(-mGyroHAxis);
|
||||||
|
mGyroHAxis = oldVAxis;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::updateSensors()
|
||||||
|
{
|
||||||
|
if (Settings::Manager::getBool("enable gyroscope", "Input"))
|
||||||
|
{
|
||||||
|
int numSensors = SDL_NumSensors();
|
||||||
|
for (int i = 0; i < numSensors; ++i)
|
||||||
|
{
|
||||||
|
if (SDL_SensorGetDeviceType(i) == SDL_SENSOR_GYRO)
|
||||||
|
{
|
||||||
|
// It is unclear how to handle several enabled gyroscopes, so use the first one.
|
||||||
|
// Note: Android registers some gyroscope as two separate sensors, for non-wake-up mode and for wake-up mode.
|
||||||
|
if (mGyroscope != nullptr)
|
||||||
|
{
|
||||||
|
SDL_SensorClose(mGyroscope);
|
||||||
|
mGyroscope = nullptr;
|
||||||
|
mGyroXSpeed = mGyroYSpeed = 0.f;
|
||||||
|
mGyroUpdateTimer = 0.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: SDL2 does not provide a way to configure a sensor update frequency so far.
|
||||||
|
SDL_Sensor *sensor = SDL_SensorOpen(i);
|
||||||
|
if (sensor == nullptr)
|
||||||
|
Log(Debug::Error) << "Couldn't open sensor " << SDL_SensorGetDeviceName(i) << ": " << SDL_GetError();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mGyroscope = sensor;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (mGyroscope != nullptr)
|
||||||
|
{
|
||||||
|
SDL_SensorClose(mGyroscope);
|
||||||
|
mGyroscope = nullptr;
|
||||||
|
mGyroXSpeed = mGyroYSpeed = 0.f;
|
||||||
|
mGyroUpdateTimer = 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
||||||
|
{
|
||||||
|
for (const auto& setting : changed)
|
||||||
|
{
|
||||||
|
if (setting.first == "Input" && setting.second == "invert x axis")
|
||||||
|
mInvertX = Settings::Manager::getBool("invert x axis", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "invert y axis")
|
||||||
|
mInvertY = Settings::Manager::getBool("invert y axis", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "gyro horizontal sensitivity")
|
||||||
|
mGyroHSensitivity = Settings::Manager::getFloat("gyro horizontal sensitivity", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "gyro vertical sensitivity")
|
||||||
|
mGyroVSensitivity = Settings::Manager::getFloat("gyro vertical sensitivity", "Input");
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "enable gyroscope")
|
||||||
|
init();
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "gyro horizontal axis")
|
||||||
|
correctGyroscopeAxes();
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "gyro vertical axis")
|
||||||
|
correctGyroscopeAxes();
|
||||||
|
|
||||||
|
if (setting.first == "Input" && setting.second == "gyro input threshold")
|
||||||
|
mGyroInputThreshold = Settings::Manager::getFloat("gyro input threshold", "Input");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float SensorManager::getGyroAxisSpeed(GyroscopeAxis axis, const SDL_SensorEvent &arg) const
|
||||||
|
{
|
||||||
|
switch (axis)
|
||||||
|
{
|
||||||
|
case GyroscopeAxis::X:
|
||||||
|
case GyroscopeAxis::Y:
|
||||||
|
case GyroscopeAxis::Z:
|
||||||
|
return std::abs(arg.data[0]) >= mGyroInputThreshold ? arg.data[axis-1] : 0.f;
|
||||||
|
case GyroscopeAxis::Minus_X:
|
||||||
|
case GyroscopeAxis::Minus_Y:
|
||||||
|
case GyroscopeAxis::Minus_Z:
|
||||||
|
return std::abs(arg.data[0]) >= mGyroInputThreshold ? -arg.data[std::abs(axis)-1] : 0.f;
|
||||||
|
default:
|
||||||
|
return 0.f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::displayOrientationChanged()
|
||||||
|
{
|
||||||
|
correctGyroscopeAxes();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::sensorUpdated(const SDL_SensorEvent &arg)
|
||||||
|
{
|
||||||
|
if (!Settings::Manager::getBool("enable gyroscope", "Input"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
SDL_Sensor *sensor = SDL_SensorFromInstanceID(arg.which);
|
||||||
|
if (!sensor)
|
||||||
|
{
|
||||||
|
Log(Debug::Info) << "Couldn't get sensor for sensor event";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (SDL_SensorGetType(sensor))
|
||||||
|
{
|
||||||
|
case SDL_SENSOR_ACCEL:
|
||||||
|
break;
|
||||||
|
case SDL_SENSOR_GYRO:
|
||||||
|
{
|
||||||
|
mGyroXSpeed = getGyroAxisSpeed(mGyroHAxis, arg);
|
||||||
|
mGyroYSpeed = getGyroAxisSpeed(mGyroVAxis, arg);
|
||||||
|
mGyroUpdateTimer = 0.f;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SensorManager::update(float dt)
|
||||||
|
{
|
||||||
|
if (mGyroXSpeed == 0.f && mGyroYSpeed == 0.f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mGyroUpdateTimer > 0.5f)
|
||||||
|
{
|
||||||
|
// More than half of second passed since the last gyroscope update.
|
||||||
|
// A device more likely was disconnected or switched to the sleep mode.
|
||||||
|
// Reset current rotation speed and wait for update.
|
||||||
|
mGyroXSpeed = 0.f;
|
||||||
|
mGyroYSpeed = 0.f;
|
||||||
|
mGyroUpdateTimer = 0.f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mGyroUpdateTimer += dt;
|
||||||
|
|
||||||
|
if (!mGuiCursorEnabled)
|
||||||
|
{
|
||||||
|
float rot[3];
|
||||||
|
rot[0] = mGyroYSpeed * dt * mGyroVSensitivity * 4 * (mInvertY ? -1 : 1);
|
||||||
|
rot[1] = 0.0f;
|
||||||
|
rot[2] = mGyroXSpeed * dt * mGyroHSensitivity * 4 * (mInvertX ? -1 : 1);
|
||||||
|
|
||||||
|
// Only actually turn player when we're not in vanity mode
|
||||||
|
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && MWBase::Environment::get().getInputManager()->getControlSwitch("playerlooking"))
|
||||||
|
{
|
||||||
|
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
|
||||||
|
player.yaw(rot[2]);
|
||||||
|
player.pitch(rot[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
MWBase::Environment::get().getInputManager()->resetIdleTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
#ifndef MWINPUT_MWSENSORMANAGER_H
|
||||||
|
#define MWINPUT_MWSENSORMANAGER_H
|
||||||
|
|
||||||
|
#include <SDL_sensor.h>
|
||||||
|
|
||||||
|
#include <components/settings/settings.hpp>
|
||||||
|
#include <components/sdlutil/events.hpp>
|
||||||
|
|
||||||
|
namespace SDLUtil
|
||||||
|
{
|
||||||
|
class InputWrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWWorld
|
||||||
|
{
|
||||||
|
class Player;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace MWInput
|
||||||
|
{
|
||||||
|
class SensorManager : public SDLUtil::SensorListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SensorManager();
|
||||||
|
|
||||||
|
virtual ~SensorManager();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
|
||||||
|
void update(float dt);
|
||||||
|
|
||||||
|
virtual void sensorUpdated(const SDL_SensorEvent &arg);
|
||||||
|
virtual void displayOrientationChanged();
|
||||||
|
void processChangedSettings(const Settings::CategorySettingVector& changed);
|
||||||
|
|
||||||
|
void setGuiCursorEnabled(bool enabled) { mGuiCursorEnabled = enabled; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum GyroscopeAxis
|
||||||
|
{
|
||||||
|
Unknown = 0,
|
||||||
|
X = 1,
|
||||||
|
Y = 2,
|
||||||
|
Z = 3,
|
||||||
|
Minus_X = -1,
|
||||||
|
Minus_Y = -2,
|
||||||
|
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;
|
||||||
|
|
||||||
|
float mGyroXSpeed;
|
||||||
|
float mGyroYSpeed;
|
||||||
|
float mGyroUpdateTimer;
|
||||||
|
|
||||||
|
float mGyroHSensitivity;
|
||||||
|
float mGyroVSensitivity;
|
||||||
|
GyroscopeAxis mGyroHAxis;
|
||||||
|
GyroscopeAxis mGyroVAxis;
|
||||||
|
float mGyroInputThreshold;
|
||||||
|
|
||||||
|
SDL_Sensor* mGyroscope;
|
||||||
|
|
||||||
|
bool mGuiCursorEnabled;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,159 +0,0 @@
|
|||||||
#ifndef OIS_SDL_COMPAT_H
|
|
||||||
#define OIS_SDL_COMPAT_H
|
|
||||||
|
|
||||||
#include <SDL_events.h>
|
|
||||||
#include <SDL_types.h>
|
|
||||||
|
|
||||||
namespace OIS
|
|
||||||
{
|
|
||||||
//! Keyboard scan codes
|
|
||||||
enum KeyCode
|
|
||||||
{
|
|
||||||
KC_UNASSIGNED = 0x00,
|
|
||||||
KC_ESCAPE = 0x01,
|
|
||||||
KC_1 = 0x02,
|
|
||||||
KC_2 = 0x03,
|
|
||||||
KC_3 = 0x04,
|
|
||||||
KC_4 = 0x05,
|
|
||||||
KC_5 = 0x06,
|
|
||||||
KC_6 = 0x07,
|
|
||||||
KC_7 = 0x08,
|
|
||||||
KC_8 = 0x09,
|
|
||||||
KC_9 = 0x0A,
|
|
||||||
KC_0 = 0x0B,
|
|
||||||
KC_MINUS = 0x0C, // - on main keyboard
|
|
||||||
KC_EQUALS = 0x0D,
|
|
||||||
KC_BACK = 0x0E, // backspace
|
|
||||||
KC_TAB = 0x0F,
|
|
||||||
KC_Q = 0x10,
|
|
||||||
KC_W = 0x11,
|
|
||||||
KC_E = 0x12,
|
|
||||||
KC_R = 0x13,
|
|
||||||
KC_T = 0x14,
|
|
||||||
KC_Y = 0x15,
|
|
||||||
KC_U = 0x16,
|
|
||||||
KC_I = 0x17,
|
|
||||||
KC_O = 0x18,
|
|
||||||
KC_P = 0x19,
|
|
||||||
KC_LBRACKET = 0x1A,
|
|
||||||
KC_RBRACKET = 0x1B,
|
|
||||||
KC_RETURN = 0x1C, // Enter on main keyboard
|
|
||||||
KC_LCONTROL = 0x1D,
|
|
||||||
KC_A = 0x1E,
|
|
||||||
KC_S = 0x1F,
|
|
||||||
KC_D = 0x20,
|
|
||||||
KC_F = 0x21,
|
|
||||||
KC_G = 0x22,
|
|
||||||
KC_H = 0x23,
|
|
||||||
KC_J = 0x24,
|
|
||||||
KC_K = 0x25,
|
|
||||||
KC_L = 0x26,
|
|
||||||
KC_SEMICOLON = 0x27,
|
|
||||||
KC_APOSTROPHE = 0x28,
|
|
||||||
KC_GRAVE = 0x29, // accent
|
|
||||||
KC_LSHIFT = 0x2A,
|
|
||||||
KC_BACKSLASH = 0x2B,
|
|
||||||
KC_Z = 0x2C,
|
|
||||||
KC_X = 0x2D,
|
|
||||||
KC_C = 0x2E,
|
|
||||||
KC_V = 0x2F,
|
|
||||||
KC_B = 0x30,
|
|
||||||
KC_N = 0x31,
|
|
||||||
KC_M = 0x32,
|
|
||||||
KC_COMMA = 0x33,
|
|
||||||
KC_PERIOD = 0x34, // . on main keyboard
|
|
||||||
KC_SLASH = 0x35, // / on main keyboard
|
|
||||||
KC_RSHIFT = 0x36,
|
|
||||||
KC_MULTIPLY = 0x37, // * on numeric keypad
|
|
||||||
KC_LMENU = 0x38, // left Alt
|
|
||||||
KC_SPACE = 0x39,
|
|
||||||
KC_CAPITAL = 0x3A,
|
|
||||||
KC_F1 = 0x3B,
|
|
||||||
KC_F2 = 0x3C,
|
|
||||||
KC_F3 = 0x3D,
|
|
||||||
KC_F4 = 0x3E,
|
|
||||||
KC_F5 = 0x3F,
|
|
||||||
KC_F6 = 0x40,
|
|
||||||
KC_F7 = 0x41,
|
|
||||||
KC_F8 = 0x42,
|
|
||||||
KC_F9 = 0x43,
|
|
||||||
KC_F10 = 0x44,
|
|
||||||
KC_NUMLOCK = 0x45,
|
|
||||||
KC_SCROLL = 0x46, // Scroll Lock
|
|
||||||
KC_NUMPAD7 = 0x47,
|
|
||||||
KC_NUMPAD8 = 0x48,
|
|
||||||
KC_NUMPAD9 = 0x49,
|
|
||||||
KC_SUBTRACT = 0x4A, // - on numeric keypad
|
|
||||||
KC_NUMPAD4 = 0x4B,
|
|
||||||
KC_NUMPAD5 = 0x4C,
|
|
||||||
KC_NUMPAD6 = 0x4D,
|
|
||||||
KC_ADD = 0x4E, // + on numeric keypad
|
|
||||||
KC_NUMPAD1 = 0x4F,
|
|
||||||
KC_NUMPAD2 = 0x50,
|
|
||||||
KC_NUMPAD3 = 0x51,
|
|
||||||
KC_NUMPAD0 = 0x52,
|
|
||||||
KC_DECIMAL = 0x53, // . on numeric keypad
|
|
||||||
KC_OEM_102 = 0x56, // < > | on UK/Germany keyboards
|
|
||||||
KC_F11 = 0x57,
|
|
||||||
KC_F12 = 0x58,
|
|
||||||
KC_F13 = 0x64, // (NEC PC98)
|
|
||||||
KC_F14 = 0x65, // (NEC PC98)
|
|
||||||
KC_F15 = 0x66, // (NEC PC98)
|
|
||||||
KC_KANA = 0x70, // (Japanese keyboard)
|
|
||||||
KC_ABNT_C1 = 0x73, // / ? on Portugese (Brazilian) keyboards
|
|
||||||
KC_CONVERT = 0x79, // (Japanese keyboard)
|
|
||||||
KC_NOCONVERT = 0x7B, // (Japanese keyboard)
|
|
||||||
KC_YEN = 0x7D, // (Japanese keyboard)
|
|
||||||
KC_ABNT_C2 = 0x7E, // Numpad . on Portugese (Brazilian) keyboards
|
|
||||||
KC_NUMPADEQUALS= 0x8D, // = on numeric keypad (NEC PC98)
|
|
||||||
KC_PREVTRACK = 0x90, // Previous Track (KC_CIRCUMFLEX on Japanese keyboard)
|
|
||||||
KC_AT = 0x91, // (NEC PC98)
|
|
||||||
KC_COLON = 0x92, // (NEC PC98)
|
|
||||||
KC_UNDERLINE = 0x93, // (NEC PC98)
|
|
||||||
KC_KANJI = 0x94, // (Japanese keyboard)
|
|
||||||
KC_STOP = 0x95, // (NEC PC98)
|
|
||||||
KC_AX = 0x96, // (Japan AX)
|
|
||||||
KC_UNLABELED = 0x97, // (J3100)
|
|
||||||
KC_NEXTTRACK = 0x99, // Next Track
|
|
||||||
KC_NUMPADENTER = 0x9C, // Enter on numeric keypad
|
|
||||||
KC_RCONTROL = 0x9D,
|
|
||||||
KC_MUTE = 0xA0, // Mute
|
|
||||||
KC_CALCULATOR = 0xA1, // Calculator
|
|
||||||
KC_PLAYPAUSE = 0xA2, // Play / Pause
|
|
||||||
KC_MEDIASTOP = 0xA4, // Media Stop
|
|
||||||
KC_VOLUMEDOWN = 0xAE, // Volume -
|
|
||||||
KC_VOLUMEUP = 0xB0, // Volume +
|
|
||||||
KC_WEBHOME = 0xB2, // Web home
|
|
||||||
KC_NUMPADCOMMA = 0xB3, // , on numeric keypad (NEC PC98)
|
|
||||||
KC_DIVIDE = 0xB5, // / on numeric keypad
|
|
||||||
KC_SYSRQ = 0xB7,
|
|
||||||
KC_RMENU = 0xB8, // right Alt
|
|
||||||
KC_PAUSE = 0xC5, // Pause
|
|
||||||
KC_HOME = 0xC7, // Home on arrow keypad
|
|
||||||
KC_UP = 0xC8, // UpArrow on arrow keypad
|
|
||||||
KC_PGUP = 0xC9, // PgUp on arrow keypad
|
|
||||||
KC_LEFT = 0xCB, // LeftArrow on arrow keypad
|
|
||||||
KC_RIGHT = 0xCD, // RightArrow on arrow keypad
|
|
||||||
KC_END = 0xCF, // End on arrow keypad
|
|
||||||
KC_DOWN = 0xD0, // DownArrow on arrow keypad
|
|
||||||
KC_PGDOWN = 0xD1, // PgDn on arrow keypad
|
|
||||||
KC_INSERT = 0xD2, // Insert on arrow keypad
|
|
||||||
KC_DELETE = 0xD3, // Delete on arrow keypad
|
|
||||||
KC_LWIN = 0xDB, // Left Windows key
|
|
||||||
KC_RWIN = 0xDC, // Right Windows key
|
|
||||||
KC_APPS = 0xDD, // AppMenu key
|
|
||||||
KC_POWER = 0xDE, // System Power
|
|
||||||
KC_SLEEP = 0xDF, // System Sleep
|
|
||||||
KC_WAKE = 0xE3, // System Wake
|
|
||||||
KC_WEBSEARCH = 0xE5, // Web Search
|
|
||||||
KC_WEBFAVORITES= 0xE6, // Web Favorites
|
|
||||||
KC_WEBREFRESH = 0xE7, // Web Refresh
|
|
||||||
KC_WEBSTOP = 0xE8, // Web Stop
|
|
||||||
KC_WEBFORWARD = 0xE9, // Web Forward
|
|
||||||
KC_WEBBACK = 0xEA, // Web Back
|
|
||||||
KC_MYCOMPUTER = 0xEB, // My Computer
|
|
||||||
KC_MAIL = 0xEC, // Mail
|
|
||||||
KC_MEDIASELECT = 0xED // Media Select
|
|
||||||
};
|
|
||||||
}
|
|
||||||
#endif
|
|
Loading…
Reference in New Issue