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