1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-01 04:45:34 +00:00

Merge pull request #2783 from akortunov/input

Refactor InputManager
This commit is contained in:
Bret Curtis 2020-05-12 09:34:22 +02:00 committed by GitHub
commit 507adac8cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 3351 additions and 2699 deletions

View file

@ -25,7 +25,8 @@ add_openmw_dir (mwrender
)
add_openmw_dir (mwinput
inputmanagerimp
actions actionmanager bindingsmanager controllermanager controlswitch
inputmanagerimp mousemanager keyboardmanager sdlmappings sensormanager
)
add_openmw_dir (mwgui

View file

@ -96,7 +96,7 @@ bool OMW::Engine::frame(float frametime)
// When the window is minimized, pause the game. Currently this *has* to be here to work around a MyGUI bug.
// If we are not currently rendering, then RenderItems will not be reused resulting in a memory leak upon changing widget textures (fixed in MyGUI 3.3.2),
// and destroyed widgets will not be deleted (not fixed yet, https://github.com/MyGUI/mygui/issues/21)
if (!mEnvironment.getInputManager()->isWindowVisible())
if (!mEnvironment.getWindowManager()->isWindowVisible())
{
mEnvironment.getSoundManager()->pausePlayback();
return false;
@ -532,20 +532,20 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
else
gameControllerdb = ""; //if it doesn't exist, pass in an empty string
MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, mScreenCaptureHandler, mScreenCaptureOperation, keybinderUser, keybinderUserExists, userGameControllerdb, gameControllerdb, mGrab);
mEnvironment.setInputManager (input);
std::string myguiResources = (mResDir / "mygui").string();
osg::ref_ptr<osg::Group> guiRoot = new osg::Group;
guiRoot->setName("GUI Root");
guiRoot->setNodeMask(MWRender::Mask_GUI);
rootNode->addChild(guiRoot);
MWGui::WindowManager* window = new MWGui::WindowManager(mViewer, guiRoot, mResourceSystem.get(), mWorkQueue.get(),
MWGui::WindowManager* window = new MWGui::WindowManager(mWindow, mViewer, guiRoot, mResourceSystem.get(), mWorkQueue.get(),
mCfgMgr.getLogPath().string() + std::string("/"), myguiResources,
mScriptConsoleMode, mTranslationDataStorage, mEncoding, mExportFonts,
Version::getOpenmwVersionDescription(mResDir.string()), mCfgMgr.getUserConfigPath().string());
mEnvironment.setWindowManager (window);
MWInput::InputManager* input = new MWInput::InputManager (mWindow, mViewer, mScreenCaptureHandler, mScreenCaptureOperation, keybinderUser, keybinderUserExists, userGameControllerdb, gameControllerdb, mGrab);
mEnvironment.setInputManager (input);
// Create sound system
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
@ -561,7 +561,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mFileCollections, mContentFiles, mEncoder, mActivationDistanceOverride, mCellName,
mStartupScript, mResDir.string(), mCfgMgr.getUserDataPath().string()));
mEnvironment.getWorld()->setupPlayer();
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
window->setStore(mEnvironment.getWorld()->getStore());
window->initUI();

View file

@ -38,8 +38,6 @@ namespace MWBase
virtual ~InputManager() {}
virtual bool isWindowVisible() = 0;
virtual void update(float dt, bool disableControls, bool disableEvents=false) = 0;
virtual void changeInputMode(bool guiMode) = 0;
@ -47,6 +45,8 @@ namespace MWBase
virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& changed) = 0;
virtual void setDragDrop(bool dragDrop) = 0;
virtual void setGamepadGuiCursorEnabled(bool enabled) = 0;
virtual void setAttemptJump(bool jumping) = 0;
virtual void toggleControlSwitch (const std::string& sw, bool value) = 0;
virtual bool getControlSwitch (const std::string& sw) = 0;
@ -54,8 +54,6 @@ namespace MWBase
virtual std::string getActionDescription (int action) = 0;
virtual std::string getActionKeyBindingName (int action) = 0;
virtual std::string getActionControllerBindingName (int action) = 0;
virtual std::string sdlControllerAxisToString(int axis) = 0;
virtual std::string sdlControllerButtonToString(int button) = 0;
///Actions available for binding to keyboard buttons
virtual std::vector<int> getActionKeySorting() = 0;
///Actions available for binding to controller buttons
@ -69,10 +67,15 @@ namespace MWBase
/// Returns if the last used input device was a joystick or a keyboard
/// @return true if joystick, false otherwise
virtual bool joystickLastUsed() = 0;
virtual void setJoystickLastUsed(bool enabled) = 0;
virtual int countSavedGameRecords() const = 0;
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress) = 0;
virtual void readRecord(ESM::ESMReader& reader, uint32_t type) = 0;
virtual void resetIdleTime() = 0;
virtual void executeAction(int action) = 0;
};
}

View file

@ -11,6 +11,8 @@
#include "../mwgui/mode.hpp"
#include <components/sdlutil/events.hpp>
namespace Loading
{
class Listener;
@ -86,7 +88,7 @@ namespace SFO
namespace MWBase
{
/// \brief Interface for widnow manager (implemented in MWGui)
class WindowManager
class WindowManager : public SDLUtil::WindowListener
{
WindowManager (const WindowManager&);
///< not implemented
@ -268,8 +270,6 @@ namespace MWBase
virtual void processChangedSettings(const std::set< std::pair<std::string, std::string> >& changed) = 0;
virtual void windowResized(int x, int y) = 0;
virtual void executeInConsole (const std::string& path) = 0;
virtual void enableRest() = 0;
@ -360,6 +360,11 @@ namespace MWBase
virtual bool injectKeyPress(MyGUI::KeyCode key, unsigned int text, bool repeat) = 0;
virtual bool injectKeyRelease(MyGUI::KeyCode key) = 0;
virtual void windowVisibilityChange(bool visible) = 0;
virtual void windowResized(int x, int y) = 0;
virtual void windowClosed() = 0;
virtual bool isWindowVisible() = 0;
};
}

View file

@ -21,6 +21,7 @@
#include <components/debug/debuglog.hpp>
#include <components/sdlutil/sdlcursormanager.hpp>
#include <components/sdlutil/sdlvideowrapper.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
@ -127,7 +128,7 @@ namespace MWGui
{
WindowManager::WindowManager(
osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
SDL_Window* window, osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
const std::string& logpath, const std::string& resourcePath, bool consoleOnlyScripts, Translation::Storage& translationDataStorage,
ToUTF8::FromType encoding, bool exportFonts, const std::string& versionDescription, const std::string& userDataPath)
: mOldUpdateMask(0)
@ -196,6 +197,7 @@ namespace MWGui
, mEncoding(encoding)
, mFontHeight(16)
, mVersionDescription(versionDescription)
, mWindowVisible(true)
{
float uiScale = Settings::Manager::getFloat("scaling factor", "GUI");
mGuiPlatform = new osgMyGUI::Platform(viewer, guiRoot, resourceSystem->getImageManager(), uiScale);
@ -288,6 +290,10 @@ namespace MWGui
MyGUI::ClipboardManager::getInstance().eventClipboardRequested += MyGUI::newDelegate(this, &WindowManager::onClipboardRequested);
mShowOwned = Settings::Manager::getInt("show owned", "Game");
mVideoWrapper = new SDLUtil::VideoWrapper(window, viewer);
mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"),
Settings::Manager::getFloat("contrast", "Video"));
}
void WindowManager::loadFontDelegate(MyGUI::xml::ElementPtr _node, const std::string& _file, MyGUI::Version _version)
@ -653,6 +659,7 @@ namespace MWGui
mGuiPlatform->shutdown();
delete mGuiPlatform;
delete mVideoWrapper;
}
catch(const MyGUI::Exception& e)
{
@ -916,7 +923,7 @@ namespace MWGui
mMessageBoxManager->onFrame(dt);
MWBase::Environment::get().getInputManager()->update(dt, true, false);
if (!MWBase::Environment::get().getInputManager()->isWindowVisible())
if (!mWindowVisible)
OpenThreads::Thread::microSleep(5000);
else
{
@ -1241,6 +1248,7 @@ namespace MWGui
{
mToolTips->setDelay(Settings::Manager::getFloat("tooltip delay", "GUI"));
bool changeRes = false;
for (const auto& setting : changed)
{
if (setting.first == "HUD" && setting.second == "crosshair")
@ -1249,11 +1257,38 @@ namespace MWGui
mSubtitlesEnabled = Settings::Manager::getBool ("subtitles", "GUI");
else if (setting.first == "GUI" && setting.second == "menu transparency")
setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI"));
else if (setting.first == "Video" && (
setting.second == "resolution x"
|| setting.second == "resolution y"
|| setting.second == "fullscreen"
|| setting.second == "window border"))
changeRes = true;
else if (setting.first == "Video" && setting.second == "vsync")
mVideoWrapper->setSyncToVBlank(Settings::Manager::getBool("vsync", "Video"));
else if (setting.first == "Video" && (setting.second == "gamma" || setting.second == "contrast"))
mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"),
Settings::Manager::getFloat("contrast", "Video"));
}
if (changeRes)
{
mVideoWrapper->setVideoMode(Settings::Manager::getInt("resolution x", "Video"),
Settings::Manager::getInt("resolution y", "Video"),
Settings::Manager::getBool("fullscreen", "Video"),
Settings::Manager::getBool("window border", "Video"));
}
}
void WindowManager::windowResized(int x, int y)
{
// Note: this is a side effect of resolution change or window resize.
// There is no need to track these changes.
Settings::Manager::setInt("resolution x", "Video", x);
Settings::Manager::setInt("resolution y", "Video", y);
Settings::Manager::resetPendingChange("resolution x", "Video");
Settings::Manager::resetPendingChange("resolution y", "Video");
mGuiPlatform->getRenderManagerPtr()->setViewSize(x, y);
// scaled size
@ -1283,9 +1318,27 @@ namespace MWGui
for (WindowBase* window : mWindows)
window->onResChange(x, y);
// We should reload TrueType fonts to fit new resolution
loadUserFonts();
// TODO: check if any windows are now off-screen and move them back if so
}
bool WindowManager::isWindowVisible()
{
return mWindowVisible;
}
void WindowManager::windowVisibilityChange(bool visible)
{
mWindowVisible = visible;
}
void WindowManager::windowClosed()
{
MWBase::Environment::get().getStateManager()->requestQuit();
}
void WindowManager::onCursorChange(const std::string &name)
{
mCursorManager->cursorChanged(name);
@ -1925,7 +1978,7 @@ namespace MWGui
MWBase::Environment::get().getInputManager()->update(dt, true, false);
if (!MWBase::Environment::get().getInputManager()->isWindowVisible())
if (!mWindowVisible)
{
mVideoWidget->pause();
OpenThreads::Thread::microSleep(5000);

View file

@ -15,6 +15,7 @@
#include "../mwworld/ptr.hpp"
#include <components/sdlutil/events.hpp>
#include <components/settings/settings.hpp>
#include <components/to_utf8/to_utf8.hpp>
@ -70,6 +71,7 @@ namespace SceneUtil
namespace SDLUtil
{
class SDLCursorManager;
class VideoWrapper;
}
namespace osgMyGUI
@ -124,13 +126,14 @@ namespace MWGui
class JailScreen;
class KeyboardNavigation;
class WindowManager : public MWBase::WindowManager
class WindowManager :
public MWBase::WindowManager
{
public:
typedef std::pair<std::string, int> Faction;
typedef std::vector<Faction> FactionList;
WindowManager(osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
WindowManager(SDL_Window* window, osgViewer::Viewer* viewer, osg::Group* guiRoot, Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
const std::string& logpath, const std::string& cacheDir, bool consoleOnlyScripts, Translation::Storage& translationDataStorage,
ToUTF8::FromType encoding, bool exportFonts, const std::string& versionDescription, const std::string& localPath);
virtual ~WindowManager();
@ -296,7 +299,10 @@ namespace MWGui
virtual void processChangedSettings(const Settings::CategorySettingVector& changed);
virtual void windowVisibilityChange(bool visible);
virtual void windowResized(int x, int y);
virtual void windowClosed();
virtual bool isWindowVisible();
virtual void executeInConsole (const std::string& path);
@ -529,10 +535,14 @@ namespace MWGui
std::string mVersionDescription;
bool mWindowVisible;
MWGui::TextColours mTextColours;
std::unique_ptr<KeyboardNavigation> mKeyboardNavigation;
SDLUtil::VideoWrapper* mVideoWrapper;
/**
* Called when MyGUI tries to retrieve a tag's value. Tags must be denoted in #{tag} notation and will be replaced upon setting a user visible text/property.
* Supported syntax:

View file

@ -0,0 +1,616 @@
#include "actionmanager.hpp"
#include <MyGUI_InputManager.h>
#include <SDL_keyboard.h>
#include <components/settings/settings.hpp>
#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;
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;
// 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;
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);
}
}

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,714 @@
#include "bindingsmanager.hpp"
#include <MyGUI_EditBox.h>
#include <extern/oics/ICSChannelListener.h>
#include <extern/oics/ICSInputControlSystem.h>
#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)
{
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
{
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);
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -1,22 +1,18 @@
#ifndef MWINPUT_MWINPUTMANAGERIMP_H
#define MWINPUT_MWINPUTMANAGERIMP_H
#include "../mwgui/mode.hpp"
#include <SDL_sensor.h>
#include <osg/ref_ptr>
#include <osgViewer/ViewerEventHandlers>
#include <extern/oics/ICSChannelListener.h>
#include <extern/oics/ICSInputControlSystem.h>
#include <components/settings/settings.hpp>
#include <components/files/configurationmanager.hpp>
#include <components/sdlutil/events.hpp>
#include "../mwbase/inputmanager.hpp"
#include "../mwgui/mode.hpp"
#include "actions.hpp"
namespace MWWorld
{
class Player;
@ -27,51 +23,27 @@ namespace MWBase
class WindowManager;
}
namespace ICS
{
class InputControlSystem;
}
namespace MyGUI
{
struct MouseButton;
}
namespace Files
{
struct ConfigurationManager;
}
namespace SDLUtil
{
class InputWrapper;
class VideoWrapper;
}
namespace osgViewer
{
class Viewer;
class ScreenCaptureHandler;
}
struct SDL_Window;
namespace MWInput
{
const float ZOOM_SCALE = 120.f; /// Used for scrolling camera in and out
class ControlSwitch;
class ActionManager;
class BindingsManager;
class ControllerManager;
class KeyboardManager;
class MouseManager;
class SensorManager;
/**
* @brief Class that handles all input and key bindings for OpenMW.
* @brief Class that provides a high-level API for game input
*/
class InputManager :
public MWBase::InputManager,
public SDLUtil::KeyListener,
public SDLUtil::MouseListener,
public SDLUtil::SensorListener,
public SDLUtil::WindowListener,
public SDLUtil::ControllerListener,
public ICS::ChannelListener,
public ICS::DetectingBindingListener
class InputManager : public MWBase::InputManager
{
public:
InputManager(
@ -85,20 +57,18 @@ namespace MWInput
virtual ~InputManager();
virtual bool isWindowVisible();
/// Clear all savegame-specific data
virtual void clear();
virtual void update(float dt, bool disableControls=false, bool disableEvents=false);
void setPlayer (MWWorld::Player* player) { mPlayer = player; }
virtual void changeInputMode(bool guiMode);
virtual void processChangedSettings(const Settings::CategorySettingVector& changed);
virtual void setDragDrop(bool dragDrop);
virtual void setGamepadGuiCursorEnabled(bool enabled);
virtual void setAttemptJump(bool jumping);
virtual void toggleControlSwitch (const std::string& sw, bool value);
virtual bool getControlSwitch (const std::string& sw);
@ -113,264 +83,42 @@ namespace MWInput
virtual void resetToDefaultKeyBindings();
virtual void resetToDefaultControllerBindings();
virtual bool joystickLastUsed() {return mJoystickLastUsed;}
public:
virtual void keyPressed(const SDL_KeyboardEvent &arg );
virtual void keyReleased( const SDL_KeyboardEvent &arg );
virtual void textInput (const SDL_TextInputEvent &arg);
virtual void mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id );
virtual void mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id );
virtual void mouseMoved( const SDLUtil::MouseMotionEvent &arg );
virtual void mouseWheelMoved( const SDL_MouseWheelEvent &arg);
virtual void sensorUpdated(const SDL_SensorEvent &arg);
virtual void displayOrientationChanged();
virtual void buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg);
virtual void buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg);
virtual void axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg);
virtual void controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg);
virtual void controllerRemoved(const SDL_ControllerDeviceEvent &arg);
virtual void windowVisibilityChange( bool visible );
virtual void windowFocusChange( bool have_focus );
virtual void windowResized (int x, int y);
virtual void windowClosed ();
virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue);
virtual void keyBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
, SDL_Scancode key, ICS::Control::ControlChangingDirection direction);
virtual void mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
, ICS::InputControlSystem::NamedAxis axis, ICS::Control::ControlChangingDirection direction);
virtual void mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
, unsigned int button, ICS::Control::ControlChangingDirection direction);
virtual void mouseWheelBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
, ICS::InputControlSystem::MouseWheelClick click, ICS::Control::ControlChangingDirection direction);
virtual void joystickAxisBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control
, int axis, ICS::Control::ControlChangingDirection direction);
virtual void joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control
, unsigned int button, ICS::Control::ControlChangingDirection direction);
void clearAllKeyBindings (ICS::Control* control);
void clearAllControllerBindings (ICS::Control* control);
virtual void setJoystickLastUsed(bool enabled);
virtual bool joystickLastUsed();
virtual int countSavedGameRecords() const;
virtual void write(ESM::ESMWriter& writer, Loading::Listener& progress);
virtual void readRecord(ESM::ESMReader& reader, uint32_t type);
private:
enum GyroscopeAxis
{
Unknown = 0,
X = 1,
Y = 2,
Z = 3,
Minus_X = -1,
Minus_Y = -2,
Minus_Z = -3
};
virtual void resetIdleTime();
SDL_Window* mWindow;
bool mWindowVisible;
osg::ref_ptr<osgViewer::Viewer> mViewer;
osg::ref_ptr<osgViewer::ScreenCaptureHandler> mScreenCaptureHandler;
osgViewer::ScreenCaptureHandler::CaptureOperation *mScreenCaptureOperation;
bool mJoystickLastUsed;
MWWorld::Player* mPlayer;
ICS::InputControlSystem* mInputBinder;
SDLUtil::InputWrapper* mInputManager;
SDLUtil::VideoWrapper* mVideoWrapper;
std::string mUserFile;
bool mDragDrop;
bool mGrabCursor;
bool mInvertX;
bool mInvertY;
bool mControlsDisabled;
bool mJoystickEnabled;
float mCameraSensitivity;
float mCameraYMultiplier;
float mPreviewPOVDelay;
float mTimeIdle;
bool mMouseLookEnabled;
bool mGuiCursorEnabled;
bool mGamepadGuiCursorEnabled;
bool mDetectingKeyboard;
float mOverencumberedMessageDelay;
float mGuiCursorX;
float mGuiCursorY;
int mMouseWheel;
float mGamepadZoom;
bool mUserFileExists;
bool mAlwaysRunActive;
bool mSneakToggles;
float mSneakToggleShortcutTimer;
bool mSneakGamepadShortcut;
bool mSneaking;
bool mAttemptJump;
std::map<std::string, bool> mControlSwitch;
float mInvUiScalingFactor;
float mGamepadCursorSpeed;
float mGyroXSpeed;
float mGyroYSpeed;
float mGyroUpdateTimer;
float mGyroHSensitivity;
float mGyroVSensitivity;
GyroscopeAxis mGyroHAxis;
GyroscopeAxis mGyroVAxis;
float mGyroInputThreshold;
virtual void executeAction(int action);
private:
void convertMousePosForMyGUI(int& x, int& y);
MyGUI::MouseButton sdlButtonToMyGUI(Uint8 button);
virtual std::string sdlControllerAxisToString(int axis);
virtual std::string sdlControllerButtonToString(int button);
void resetIdleTime();
void updateIdleTime(float dt);
void setPlayerControlsEnabled(bool enabled);
void handleGuiArrowKey(int action);
// Return true if GUI consumes input.
bool gamepadToGuiControl(const SDL_ControllerButtonEvent &arg);
bool gamepadToGuiControl(const SDL_ControllerAxisEvent &arg);
void updateCursorMode();
void updateSensors();
void correctGyroscopeAxes();
GyroscopeAxis mapGyroscopeAxis(const std::string& axis);
bool checkAllowedToUseItems() const;
float getGyroAxisSpeed(GyroscopeAxis axis, const SDL_SensorEvent &arg) const;
private:
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 quickKey(int index);
void showQuickKeysMenu();
bool actionIsActive (int id);
void loadKeyDefaults(bool force = false);
void loadControllerDefaults(bool force = false);
int mFakeDeviceID; //As we only support one controller at a time, use a fake deviceID so we don't lose bindings when switching controllers
SDL_Sensor* mGyroscope;
SDLUtil::InputWrapper* mInputWrapper;
private:
enum Actions
{
// please add new actions at the bottom, in order to preserve the channel IDs in the key configuration files
bool mGrabCursor;
A_GameMenu,
ControlSwitch* mControlSwitch;
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
};
ActionManager* mActionManager;
BindingsManager* mBindingsManager;
ControllerManager* mControllerManager;
KeyboardManager* mKeyboardManager;
MouseManager* mMouseManager;
SensorManager* mSensorManager;
};
}
#endif

View file

@ -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);
}
}

View file

@ -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

View file

@ -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));
}
}

View file

@ -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

View file

@ -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;
}
}

View file

@ -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

View file

@ -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();
}
}
}

View file

@ -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

View file

@ -139,7 +139,7 @@ add_component_dir (fontloader
)
add_component_dir (sdlutil
sdlgraphicswindow imagetosurface sdlinputwrapper sdlvideowrapper OISCompat events sdlcursormanager
sdlgraphicswindow imagetosurface sdlinputwrapper sdlvideowrapper events sdlcursormanager
)
add_component_dir (version

View file

@ -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

View file

@ -79,9 +79,6 @@ public:
/** @remarks The window's visibility changed */
virtual void windowVisibilityChange( bool visible ) {}
/** @remarks The window got / lost input focus */
virtual void windowFocusChange( bool have_focus ) {}
virtual void windowClosed () {}
virtual void windowResized (int x, int y) {}

View file

@ -33,8 +33,6 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> v
mWindowHasFocus(true),
mMouseInWindow(true)
{
_setupOISKeys();
Uint32 flags = SDL_GetWindowFlags(mSDLWindow);
mWindowHasFocus = (flags & SDL_WINDOW_INPUT_FOCUS);
mMouseInWindow = (flags & SDL_WINDOW_MOUSE_FOCUS);
@ -231,15 +229,10 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> v
case SDL_WINDOWEVENT_FOCUS_GAINED:
mWindowHasFocus = true;
updateMouseSettings();
if (mWindowListener)
mWindowListener->windowFocusChange(true);
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
mWindowHasFocus = false;
updateMouseSettings();
if (mWindowListener)
mWindowListener->windowFocusChange(false);
break;
case SDL_WINDOWEVENT_CLOSE:
break;
@ -402,139 +395,4 @@ InputWrapper::InputWrapper(SDL_Window* window, osg::ref_ptr<osgViewer::Viewer> v
return pack_evt;
}
OIS::KeyCode InputWrapper::sdl2OISKeyCode(SDL_Keycode code)
{
OIS::KeyCode kc = OIS::KC_UNASSIGNED;
KeyMap::const_iterator ois_equiv = mKeyMap.find(code);
if(ois_equiv != mKeyMap.end())
kc = ois_equiv->second;
return kc;
}
void InputWrapper::_setupOISKeys()
{
//lifted from OIS's SDLKeyboard.cpp
mKeyMap.insert( KeyMap::value_type(SDLK_UNKNOWN, OIS::KC_UNASSIGNED));
mKeyMap.insert( KeyMap::value_type(SDLK_ESCAPE, OIS::KC_ESCAPE) );
mKeyMap.insert( KeyMap::value_type(SDLK_1, OIS::KC_1) );
mKeyMap.insert( KeyMap::value_type(SDLK_2, OIS::KC_2) );
mKeyMap.insert( KeyMap::value_type(SDLK_3, OIS::KC_3) );
mKeyMap.insert( KeyMap::value_type(SDLK_4, OIS::KC_4) );
mKeyMap.insert( KeyMap::value_type(SDLK_5, OIS::KC_5) );
mKeyMap.insert( KeyMap::value_type(SDLK_6, OIS::KC_6) );
mKeyMap.insert( KeyMap::value_type(SDLK_7, OIS::KC_7) );
mKeyMap.insert( KeyMap::value_type(SDLK_8, OIS::KC_8) );
mKeyMap.insert( KeyMap::value_type(SDLK_9, OIS::KC_9) );
mKeyMap.insert( KeyMap::value_type(SDLK_0, OIS::KC_0) );
mKeyMap.insert( KeyMap::value_type(SDLK_MINUS, OIS::KC_MINUS) );
mKeyMap.insert( KeyMap::value_type(SDLK_EQUALS, OIS::KC_EQUALS) );
mKeyMap.insert( KeyMap::value_type(SDLK_BACKSPACE, OIS::KC_BACK) );
mKeyMap.insert( KeyMap::value_type(SDLK_TAB, OIS::KC_TAB) );
mKeyMap.insert( KeyMap::value_type(SDLK_q, OIS::KC_Q) );
mKeyMap.insert( KeyMap::value_type(SDLK_w, OIS::KC_W) );
mKeyMap.insert( KeyMap::value_type(SDLK_e, OIS::KC_E) );
mKeyMap.insert( KeyMap::value_type(SDLK_r, OIS::KC_R) );
mKeyMap.insert( KeyMap::value_type(SDLK_t, OIS::KC_T) );
mKeyMap.insert( KeyMap::value_type(SDLK_y, OIS::KC_Y) );
mKeyMap.insert( KeyMap::value_type(SDLK_u, OIS::KC_U) );
mKeyMap.insert( KeyMap::value_type(SDLK_i, OIS::KC_I) );
mKeyMap.insert( KeyMap::value_type(SDLK_o, OIS::KC_O) );
mKeyMap.insert( KeyMap::value_type(SDLK_p, OIS::KC_P) );
mKeyMap.insert( KeyMap::value_type(SDLK_RETURN, OIS::KC_RETURN) );
mKeyMap.insert( KeyMap::value_type(SDLK_a, OIS::KC_A) );
mKeyMap.insert( KeyMap::value_type(SDLK_s, OIS::KC_S) );
mKeyMap.insert( KeyMap::value_type(SDLK_d, OIS::KC_D) );
mKeyMap.insert( KeyMap::value_type(SDLK_f, OIS::KC_F) );
mKeyMap.insert( KeyMap::value_type(SDLK_g, OIS::KC_G) );
mKeyMap.insert( KeyMap::value_type(SDLK_h, OIS::KC_H) );
mKeyMap.insert( KeyMap::value_type(SDLK_j, OIS::KC_J) );
mKeyMap.insert( KeyMap::value_type(SDLK_k, OIS::KC_K) );
mKeyMap.insert( KeyMap::value_type(SDLK_l, OIS::KC_L) );
mKeyMap.insert( KeyMap::value_type(SDLK_SEMICOLON, OIS::KC_SEMICOLON) );
mKeyMap.insert( KeyMap::value_type(SDLK_COLON, OIS::KC_COLON) );
mKeyMap.insert( KeyMap::value_type(SDLK_QUOTE, OIS::KC_APOSTROPHE) );
mKeyMap.insert( KeyMap::value_type(SDLK_BACKQUOTE, OIS::KC_GRAVE) );
mKeyMap.insert( KeyMap::value_type(SDLK_LSHIFT, OIS::KC_LSHIFT) );
mKeyMap.insert( KeyMap::value_type(SDLK_BACKSLASH, OIS::KC_BACKSLASH) );
mKeyMap.insert( KeyMap::value_type(SDLK_SLASH, OIS::KC_SLASH) );
mKeyMap.insert( KeyMap::value_type(SDLK_z, OIS::KC_Z) );
mKeyMap.insert( KeyMap::value_type(SDLK_x, OIS::KC_X) );
mKeyMap.insert( KeyMap::value_type(SDLK_c, OIS::KC_C) );
mKeyMap.insert( KeyMap::value_type(SDLK_v, OIS::KC_V) );
mKeyMap.insert( KeyMap::value_type(SDLK_b, OIS::KC_B) );
mKeyMap.insert( KeyMap::value_type(SDLK_n, OIS::KC_N) );
mKeyMap.insert( KeyMap::value_type(SDLK_m, OIS::KC_M) );
mKeyMap.insert( KeyMap::value_type(SDLK_COMMA, OIS::KC_COMMA) );
mKeyMap.insert( KeyMap::value_type(SDLK_PERIOD, OIS::KC_PERIOD));
mKeyMap.insert( KeyMap::value_type(SDLK_RSHIFT, OIS::KC_RSHIFT));
mKeyMap.insert( KeyMap::value_type(SDLK_KP_MULTIPLY, OIS::KC_MULTIPLY) );
mKeyMap.insert( KeyMap::value_type(SDLK_LALT, OIS::KC_LMENU) );
mKeyMap.insert( KeyMap::value_type(SDLK_SPACE, OIS::KC_SPACE));
mKeyMap.insert( KeyMap::value_type(SDLK_CAPSLOCK, OIS::KC_CAPITAL) );
mKeyMap.insert( KeyMap::value_type(SDLK_F1, OIS::KC_F1) );
mKeyMap.insert( KeyMap::value_type(SDLK_F2, OIS::KC_F2) );
mKeyMap.insert( KeyMap::value_type(SDLK_F3, OIS::KC_F3) );
mKeyMap.insert( KeyMap::value_type(SDLK_F4, OIS::KC_F4) );
mKeyMap.insert( KeyMap::value_type(SDLK_F5, OIS::KC_F5) );
mKeyMap.insert( KeyMap::value_type(SDLK_F6, OIS::KC_F6) );
mKeyMap.insert( KeyMap::value_type(SDLK_F7, OIS::KC_F7) );
mKeyMap.insert( KeyMap::value_type(SDLK_F8, OIS::KC_F8) );
mKeyMap.insert( KeyMap::value_type(SDLK_F9, OIS::KC_F9) );
mKeyMap.insert( KeyMap::value_type(SDLK_F10, OIS::KC_F10) );
mKeyMap.insert( KeyMap::value_type(SDLK_NUMLOCKCLEAR, OIS::KC_NUMLOCK) );
mKeyMap.insert( KeyMap::value_type(SDLK_SCROLLLOCK, OIS::KC_SCROLL));
mKeyMap.insert( KeyMap::value_type(SDLK_KP_7, OIS::KC_NUMPAD7) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_8, OIS::KC_NUMPAD8) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_9, OIS::KC_NUMPAD9) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_MINUS, OIS::KC_SUBTRACT) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_4, OIS::KC_NUMPAD4) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_5, OIS::KC_NUMPAD5) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_6, OIS::KC_NUMPAD6) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_PLUS, OIS::KC_ADD) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_1, OIS::KC_NUMPAD1) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_2, OIS::KC_NUMPAD2) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_3, OIS::KC_NUMPAD3) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_0, OIS::KC_NUMPAD0) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_PERIOD, OIS::KC_DECIMAL) );
mKeyMap.insert( KeyMap::value_type(SDLK_F11, OIS::KC_F11) );
mKeyMap.insert( KeyMap::value_type(SDLK_F12, OIS::KC_F12) );
mKeyMap.insert( KeyMap::value_type(SDLK_F13, OIS::KC_F13) );
mKeyMap.insert( KeyMap::value_type(SDLK_F14, OIS::KC_F14) );
mKeyMap.insert( KeyMap::value_type(SDLK_F15, OIS::KC_F15) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_EQUALS, OIS::KC_NUMPADEQUALS) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_DIVIDE, OIS::KC_DIVIDE) );
mKeyMap.insert( KeyMap::value_type(SDLK_SYSREQ, OIS::KC_SYSRQ) );
mKeyMap.insert( KeyMap::value_type(SDLK_RALT, OIS::KC_RMENU) );
mKeyMap.insert( KeyMap::value_type(SDLK_HOME, OIS::KC_HOME) );
mKeyMap.insert( KeyMap::value_type(SDLK_UP, OIS::KC_UP) );
mKeyMap.insert( KeyMap::value_type(SDLK_PAGEUP, OIS::KC_PGUP) );
mKeyMap.insert( KeyMap::value_type(SDLK_LEFT, OIS::KC_LEFT) );
mKeyMap.insert( KeyMap::value_type(SDLK_RIGHT, OIS::KC_RIGHT) );
mKeyMap.insert( KeyMap::value_type(SDLK_END, OIS::KC_END) );
mKeyMap.insert( KeyMap::value_type(SDLK_DOWN, OIS::KC_DOWN) );
mKeyMap.insert( KeyMap::value_type(SDLK_PAGEDOWN, OIS::KC_PGDOWN) );
mKeyMap.insert( KeyMap::value_type(SDLK_INSERT, OIS::KC_INSERT) );
mKeyMap.insert( KeyMap::value_type(SDLK_DELETE, OIS::KC_DELETE) );
mKeyMap.insert( KeyMap::value_type(SDLK_KP_ENTER, OIS::KC_NUMPADENTER) );
mKeyMap.insert( KeyMap::value_type(SDLK_APPLICATION, OIS::KC_APPS) );
//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__)
mKeyMap.insert( KeyMap::value_type(SDLK_LGUI, OIS::KC_LCONTROL) );
mKeyMap.insert( KeyMap::value_type(SDLK_RGUI, OIS::KC_RCONTROL) );
mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LWIN));
mKeyMap.insert( KeyMap::value_type(SDLK_RCTRL, OIS::KC_RWIN) );
#else
mKeyMap.insert( KeyMap::value_type(SDLK_LGUI, OIS::KC_LWIN) );
mKeyMap.insert( KeyMap::value_type(SDLK_RGUI, OIS::KC_RWIN) );
mKeyMap.insert( KeyMap::value_type(SDLK_LCTRL, OIS::KC_LCONTROL));
mKeyMap.insert( KeyMap::value_type(SDLK_RCTRL, OIS::KC_RCONTROL) );
#endif
}
}

View file

@ -8,7 +8,6 @@
#include <SDL_events.h>
#include <SDL_version.h>
#include "OISCompat.hpp"
#include "events.hpp"
namespace osgViewer
@ -40,8 +39,6 @@ namespace SDLUtil
bool getMouseRelative() { return mMouseRelative; }
void setGrabPointer(bool grab);
OIS::KeyCode sdl2OISKeyCode(SDL_Keycode code);
void warpMouse(int x, int y);
void updateMouseSettings();
@ -53,8 +50,6 @@ namespace SDLUtil
void _wrapMousePointer(const SDL_MouseMotionEvent &evt);
MouseMotionEvent _packageMouseMotion(const SDL_Event& evt);
void _setupOISKeys();
SDL_Window* mSDLWindow;
osg::ref_ptr<osgViewer::Viewer> mViewer;
@ -64,9 +59,6 @@ namespace SDLUtil
WindowListener* mWindowListener;
ControllerListener* mConListener;
typedef std::map<SDL_Keycode, OIS::KeyCode> KeyMap;
KeyMap mKeyMap;
Uint16 mWarpX;
Uint16 mWarpY;
bool mWarpCompensate;