forked from mirror/openmw-tes3mp
d9dd7073cf
Previously, client mods adding packet-sending scripts to the spawn area made clients send the associated packets as soon as they inputted their character name when joining a server using those mods. This made the clients either get disconnected for not replying to a handshake first, or it made them get kicked for sending object packets that are disallowed for players who are not logged in. To fix this, LocalPlayer's hasFinishedCharGen() has been replaced with isLoggedIn(), because the former was already returning true when players inputted their names.
1824 lines
72 KiB
C++
1824 lines
72 KiB
C++
#include "inputmanagerimp.hpp"
|
|
|
|
#include <osgViewer/ViewerEventHandlers>
|
|
|
|
#include <MyGUI_InputManager.h>
|
|
#include <MyGUI_RenderManager.h>
|
|
#include <MyGUI_Widget.h>
|
|
#include <MyGUI_Button.h>
|
|
#include <MyGUI_EditBox.h>
|
|
|
|
#include <SDL_version.h>
|
|
|
|
#include <components/sdlutil/sdlinputwrapper.hpp>
|
|
#include <components/sdlutil/sdlvideowrapper.hpp>
|
|
|
|
/*
|
|
Start of tes3mp addition
|
|
|
|
Include additional headers for multiplayer purposes
|
|
*/
|
|
#include "../mwmp/Main.hpp"
|
|
#include "../mwmp/LocalPlayer.hpp"
|
|
/*
|
|
End of tes3mp addition
|
|
*/
|
|
|
|
#include <components/esm/esmwriter.hpp>
|
|
#include <components/esm/esmreader.hpp>
|
|
#include <components/esm/controlsstate.hpp>
|
|
|
|
#include "../mwbase/world.hpp"
|
|
#include "../mwbase/windowmanager.hpp"
|
|
#include "../mwbase/statemanager.hpp"
|
|
#include "../mwbase/environment.hpp"
|
|
#include "../mwbase/mechanicsmanager.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"
|
|
|
|
namespace MWInput
|
|
{
|
|
InputManager::InputManager(
|
|
SDL_Window* window,
|
|
osg::ref_ptr<osgViewer::Viewer> viewer,
|
|
osg::ref_ptr<osgViewer::ScreenCaptureHandler> screenCaptureHandler,
|
|
osgViewer::ScreenCaptureHandler::CaptureOperation *screenCaptureOperation,
|
|
const std::string& userFile, bool userFileExists,
|
|
const std::string& controllerBindingsFile, bool grab)
|
|
: mWindow(window)
|
|
, mWindowVisible(true)
|
|
, mViewer(viewer)
|
|
, mScreenCaptureHandler(screenCaptureHandler)
|
|
, mScreenCaptureOperation(screenCaptureOperation)
|
|
, mJoystickLastUsed(false)
|
|
, mPlayer(NULL)
|
|
, mInputManager(NULL)
|
|
, mVideoWrapper(NULL)
|
|
, mUserFile(userFile)
|
|
, mDragDrop(false)
|
|
, mGrabCursor (Settings::Manager::getBool("grab cursor", "Input"))
|
|
, mInvertY (Settings::Manager::getBool("invert y axis", "Input"))
|
|
, mControlsDisabled(false)
|
|
, mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input"))
|
|
, mCameraYMultiplier (Settings::Manager::getFloat("camera y multiplier", "Input"))
|
|
, mPreviewPOVDelay(0.f)
|
|
, mTimeIdle(0.f)
|
|
, mMouseLookEnabled(false)
|
|
, mGuiCursorEnabled(true)
|
|
, mDetectingKeyboard(false)
|
|
, mOverencumberedMessageDelay(0.f)
|
|
, mGuiCursorX(0)
|
|
, mGuiCursorY(0)
|
|
, mMouseWheel(0)
|
|
, mUserFileExists(userFileExists)
|
|
, mAlwaysRunActive(Settings::Manager::getBool("always run", "Input"))
|
|
, mSneakToggles(Settings::Manager::getBool("toggle sneak", "Input"))
|
|
, mSneaking(false)
|
|
, mAttemptJump(false)
|
|
, mInvUiScalingFactor(1.f)
|
|
, mFakeDeviceID(1)
|
|
{
|
|
mInputManager = new SDLUtil::InputWrapper(window, viewer, grab);
|
|
mInputManager->setMouseEventCallback (this);
|
|
mInputManager->setKeyboardEventCallback (this);
|
|
mInputManager->setWindowEventCallback(this);
|
|
mInputManager->setControllerEventCallback(this);
|
|
|
|
mVideoWrapper = new SDLUtil::VideoWrapper(window, viewer);
|
|
mVideoWrapper->setGammaContrast(Settings::Manager::getFloat("gamma", "Video"),
|
|
Settings::Manager::getFloat("contrast", "Video"));
|
|
|
|
std::string file = userFileExists ? userFile : "";
|
|
mInputBinder = new ICS::InputControlSystem(file, true, this, NULL, A_Last);
|
|
|
|
loadKeyDefaults();
|
|
loadControllerDefaults();
|
|
|
|
for (int i = 0; i < A_Last; ++i)
|
|
{
|
|
mInputBinder->getChannel (i)->addListener (this);
|
|
}
|
|
|
|
mControlSwitch["playercontrols"] = true;
|
|
mControlSwitch["playerfighting"] = true;
|
|
mControlSwitch["playerjumping"] = true;
|
|
mControlSwitch["playerlooking"] = true;
|
|
mControlSwitch["playermagic"] = true;
|
|
mControlSwitch["playerviewswitch"] = true;
|
|
mControlSwitch["vanitymode"] = true;
|
|
|
|
/* Joystick Init */
|
|
|
|
// Load controller mappings
|
|
#if SDL_VERSION_ATLEAST(2,0,2)
|
|
if(controllerBindingsFile!="")
|
|
{
|
|
SDL_GameControllerAddMappingsFromFile(controllerBindingsFile.c_str());
|
|
}
|
|
#endif
|
|
|
|
// Open all presently connected sticks
|
|
int numSticks = SDL_NumJoysticks();
|
|
for(int i = 0; i < numSticks; i++)
|
|
{
|
|
if(SDL_IsGameController(i))
|
|
{
|
|
SDL_ControllerDeviceEvent evt;
|
|
evt.which = i;
|
|
controllerAdded(mFakeDeviceID, evt);
|
|
std::cout << "Detected game controller: " << SDL_GameControllerNameForIndex(i) << std::endl;
|
|
}
|
|
else
|
|
{
|
|
std::cout << "Detected unusable controller: " << SDL_JoystickNameForIndex(i) << std::endl;
|
|
}
|
|
}
|
|
|
|
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 InputManager::clear()
|
|
{
|
|
// Enable all controls
|
|
for (std::map<std::string, bool>::iterator it = mControlSwitch.begin(); it != mControlSwitch.end(); ++it)
|
|
it->second = true;
|
|
}
|
|
|
|
InputManager::~InputManager()
|
|
{
|
|
mInputBinder->save (mUserFile);
|
|
|
|
delete mInputBinder;
|
|
|
|
delete mInputManager;
|
|
|
|
delete mVideoWrapper;
|
|
}
|
|
|
|
bool InputManager::isWindowVisible()
|
|
{
|
|
return mWindowVisible;
|
|
}
|
|
|
|
void InputManager::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(size_t i = 0; i < sizeof(playerChannels)/sizeof(playerChannels[0]); i++) {
|
|
int pc = playerChannels[i];
|
|
mInputBinder->getChannel(pc)->setEnabled(enabled);
|
|
}
|
|
}
|
|
|
|
bool isLeftOrRightButton(int action, ICS::InputControlSystem* ics, int deviceId, bool joystick)
|
|
{
|
|
int mouseBinding = ics->getMouseButtonBinding(ics->getControl(action), ICS::Control::INCREASE);
|
|
if (mouseBinding != ICS_MAX_DEVICE_BUTTONS)
|
|
return true;
|
|
int buttonBinding = ics->getJoystickButtonBinding(ics->getControl(action), deviceId, ICS::Control::INCREASE);
|
|
if (joystick && (buttonBinding == 0 || buttonBinding == 1))
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
void InputManager::handleGuiArrowKey(int action)
|
|
{
|
|
if (SDL_IsTextInputActive())
|
|
return;
|
|
|
|
if (isLeftOrRightButton(action, mInputBinder, mFakeDeviceID, mJoystickLastUsed))
|
|
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);
|
|
}
|
|
|
|
void InputManager::channelChanged(ICS::Channel* channel, float currentValue, float previousValue)
|
|
{
|
|
resetIdleTime ();
|
|
|
|
int action = channel->getNumber();
|
|
|
|
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 >= .8 && currentValue < .8)
|
|
{
|
|
currentValue = 0.0;
|
|
previousValue = 1.0;
|
|
}
|
|
else if(previousValue <= .6 && currentValue > .6)
|
|
{
|
|
currentValue = 1.0;
|
|
previousValue = 0.0;
|
|
}
|
|
else
|
|
{
|
|
//If it's not switching between those values, ignore the channel change.
|
|
return;
|
|
}
|
|
|
|
if (mControlSwitch["playercontrols"])
|
|
{
|
|
if (action == A_Use)
|
|
{
|
|
MWMechanics::DrawState_ state = MWBase::Environment::get().getWorld()->getPlayer().getDrawState();
|
|
mPlayer->setAttackingOrSpell(currentValue != 0 && state != MWMechanics::DrawState_Nothing);
|
|
}
|
|
else if (action == A_Jump)
|
|
mAttemptJump = (currentValue == 1.0 && previousValue == 0.0);
|
|
}
|
|
|
|
if (currentValue == 1)
|
|
{
|
|
// 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:
|
|
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_QuickSave:
|
|
quickSave();
|
|
break;
|
|
case A_QuickLoad:
|
|
quickLoad();
|
|
break;
|
|
case A_CycleSpellLeft:
|
|
if (checkAllowedToUseItems())
|
|
MWBase::Environment::get().getWindowManager()->cycleSpell(false);
|
|
break;
|
|
case A_CycleSpellRight:
|
|
if (checkAllowedToUseItems())
|
|
MWBase::Environment::get().getWindowManager()->cycleSpell(true);
|
|
break;
|
|
case A_CycleWeaponLeft:
|
|
if (checkAllowedToUseItems())
|
|
MWBase::Environment::get().getWindowManager()->cycleWeapon(false);
|
|
break;
|
|
case A_CycleWeaponRight:
|
|
if (checkAllowedToUseItems())
|
|
MWBase::Environment::get().getWindowManager()->cycleWeapon(true);
|
|
break;
|
|
case A_Sneak:
|
|
if (mSneakToggles)
|
|
{
|
|
toggleSneaking();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void InputManager::updateCursorMode()
|
|
{
|
|
bool grab = !MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu)
|
|
&& MWBase::Environment::get().getWindowManager()->getMode() != MWGui::GM_Console;
|
|
|
|
bool was_relative = mInputManager->getMouseRelative();
|
|
bool is_relative = !MWBase::Environment::get().getWindowManager()->isGuiMode();
|
|
|
|
// don't keep the pointer away from the window edge in gui mode
|
|
// stop using raw mouse motions and switch to system cursor movements
|
|
mInputManager->setMouseRelative(is_relative);
|
|
|
|
//we let the mouse escape in the main menu
|
|
mInputManager->setGrabPointer(grab && (mGrabCursor || is_relative));
|
|
|
|
//we switched to non-relative mode, move our cursor to where the in-game
|
|
//cursor is
|
|
if( !is_relative && was_relative != is_relative )
|
|
{
|
|
mInputManager->warpMouse(static_cast<int>(mGuiCursorX/mInvUiScalingFactor), static_cast<int>(mGuiCursorY/mInvUiScalingFactor));
|
|
}
|
|
}
|
|
|
|
bool InputManager::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 InputManager::update(float dt, bool disableControls, bool disableEvents)
|
|
{
|
|
mControlsDisabled = disableControls;
|
|
|
|
mInputManager->setMouseVisible(MWBase::Environment::get().getWindowManager()->getCursorVisible());
|
|
|
|
mInputManager->capture(disableEvents);
|
|
|
|
if (mControlsDisabled)
|
|
{
|
|
updateCursorMode();
|
|
return;
|
|
}
|
|
|
|
// update values of channels (as a result of pressed keys)
|
|
mInputBinder->update(dt);
|
|
|
|
updateCursorMode();
|
|
|
|
if (mGuiCursorEnabled)
|
|
{
|
|
float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue()*2.0f-1.0f;
|
|
float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue()*2.0f-1.0f;
|
|
float zAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f;
|
|
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
|
|
|
|
xAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue());
|
|
yAxis *= (1.5f - mInputBinder->getChannel(A_Use)->getValue());
|
|
|
|
// We keep track of our own mouse position, so that moving the mouse while in
|
|
// game mode does not move the position of the GUI cursor
|
|
float xmove = xAxis * dt * 1500.0f * mInvUiScalingFactor;
|
|
float ymove = yAxis * dt * 1500.0f * mInvUiScalingFactor;
|
|
if (xmove != 0|| ymove != 0)
|
|
{
|
|
mGuiCursorX += xmove;
|
|
mGuiCursorY += ymove;
|
|
mMouseWheel -= static_cast<int>(zAxis * dt * 1500.0f);
|
|
|
|
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);
|
|
mInputManager->warpMouse(static_cast<int>(mGuiCursorX/mInvUiScalingFactor), static_cast<int>(mGuiCursorY/mInvUiScalingFactor));
|
|
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
|
}
|
|
}
|
|
if (mMouseLookEnabled)
|
|
{
|
|
float xAxis = mInputBinder->getChannel(A_LookLeftRight)->getValue()*2.0f-1.0f;
|
|
float yAxis = mInputBinder->getChannel(A_LookUpDown)->getValue()*2.0f-1.0f;
|
|
if (xAxis != 0 || yAxis != 0)
|
|
{
|
|
resetIdleTime();
|
|
|
|
float rot[3];
|
|
rot[0] = yAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier;
|
|
rot[1] = 0.0f;
|
|
rot[2] = xAxis * (dt * 100.0f) * 10.0f * mCameraSensitivity * (1.0f/256.f);
|
|
|
|
// Only actually turn player when we're not in vanity mode
|
|
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
|
|
{
|
|
mPlayer->yaw(rot[2]);
|
|
mPlayer->pitch(rot[0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Disable movement in Gui mode
|
|
if (!(MWBase::Environment::get().getWindowManager()->isGuiMode()
|
|
|| MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_Running))
|
|
{
|
|
// Configure player movement according to keyboard input. Actual movement will
|
|
// be done in the physics system.
|
|
if (mControlSwitch["playercontrols"])
|
|
{
|
|
bool triedToMove = false;
|
|
bool isRunning = false;
|
|
|
|
// joystick movement
|
|
float xAxis = mInputBinder->getChannel(A_MoveLeftRight)->getValue();
|
|
float yAxis = mInputBinder->getChannel(A_MoveForwardBackward)->getValue();
|
|
if (xAxis < .5)
|
|
{
|
|
triedToMove = true;
|
|
mPlayer->setLeftRight (-1);
|
|
}
|
|
else if (xAxis > .5)
|
|
{
|
|
triedToMove = true;
|
|
mPlayer->setLeftRight (1);
|
|
}
|
|
|
|
if (yAxis < .5)
|
|
{
|
|
triedToMove = true;
|
|
mPlayer->setAutoMove (false);
|
|
mPlayer->setForwardBackward (1);
|
|
}
|
|
else if (yAxis > .5)
|
|
{
|
|
triedToMove = true;
|
|
mPlayer->setAutoMove (false);
|
|
mPlayer->setForwardBackward (-1);
|
|
}
|
|
else if(mPlayer->getAutoMove())
|
|
{
|
|
triedToMove = true;
|
|
mPlayer->setForwardBackward (1);
|
|
}
|
|
if (triedToMove)
|
|
mJoystickLastUsed = true;
|
|
|
|
// keyboard movement
|
|
isRunning = xAxis > .75 || xAxis < .25 || yAxis > .75 || yAxis < .25;
|
|
if(triedToMove) resetIdleTime();
|
|
|
|
if (actionIsActive(A_MoveLeft) && !actionIsActive(A_MoveRight))
|
|
{
|
|
triedToMove = true;
|
|
mPlayer->setLeftRight (-1);
|
|
}
|
|
else if (actionIsActive(A_MoveRight) && !actionIsActive(A_MoveLeft))
|
|
{
|
|
triedToMove = true;
|
|
mPlayer->setLeftRight (1);
|
|
}
|
|
|
|
if (actionIsActive(A_MoveForward) && !actionIsActive(A_MoveBackward))
|
|
{
|
|
triedToMove = true;
|
|
mPlayer->setAutoMove (false);
|
|
mPlayer->setForwardBackward (1);
|
|
}
|
|
else if (actionIsActive(A_MoveBackward) && !actionIsActive(A_MoveForward))
|
|
{
|
|
triedToMove = true;
|
|
mPlayer->setAutoMove (false);
|
|
mPlayer->setForwardBackward (-1);
|
|
}
|
|
else if(mPlayer->getAutoMove())
|
|
{
|
|
triedToMove = true;
|
|
mPlayer->setForwardBackward (1);
|
|
}
|
|
|
|
if (!mSneakToggles)
|
|
{
|
|
mPlayer->setSneak(actionIsActive(A_Sneak));
|
|
}
|
|
|
|
if (mAttemptJump && mControlSwitch["playerjumping"])
|
|
{
|
|
mPlayer->setUpDown (1);
|
|
triedToMove = true;
|
|
mOverencumberedMessageDelay = 0.f;
|
|
}
|
|
|
|
if (mAlwaysRunActive || isRunning)
|
|
mPlayer->setRunState(!actionIsActive(A_Run));
|
|
else
|
|
mPlayer->setRunState(actionIsActive(A_Run));
|
|
|
|
// if player tried to start moving, but can't (due to being overencumbered), display a notification.
|
|
if (triedToMove)
|
|
{
|
|
MWWorld::Ptr player = MWBase::Environment::get().getWorld ()->getPlayerPtr();
|
|
mOverencumberedMessageDelay -= dt;
|
|
if (player.getClass().getEncumbrance(player) > player.getClass().getCapacity(player))
|
|
{
|
|
mPlayer->setAutoMove (false);
|
|
if (mOverencumberedMessageDelay <= 0)
|
|
{
|
|
MWBase::Environment::get().getWindowManager ()->messageBox("#{sNotifyMessage59}");
|
|
mOverencumberedMessageDelay = 1.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mControlSwitch["playerviewswitch"]) {
|
|
|
|
if (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 (actionIsActive(A_MoveForward) ||
|
|
actionIsActive(A_MoveBackward) ||
|
|
actionIsActive(A_MoveLeft) ||
|
|
actionIsActive(A_MoveRight) ||
|
|
actionIsActive(A_Jump) ||
|
|
actionIsActive(A_Sneak) ||
|
|
actionIsActive(A_TogglePOV))
|
|
{
|
|
resetIdleTime();
|
|
} else {
|
|
updateIdleTime(dt);
|
|
}
|
|
}
|
|
mAttemptJump = false; // Can only jump on first frame input is on
|
|
}
|
|
|
|
void InputManager::setDragDrop(bool dragDrop)
|
|
{
|
|
mDragDrop = dragDrop;
|
|
}
|
|
|
|
void InputManager::changeInputMode(bool guiMode)
|
|
{
|
|
mGuiCursorEnabled = guiMode;
|
|
mMouseLookEnabled = !guiMode;
|
|
if (guiMode)
|
|
MWBase::Environment::get().getWindowManager()->showCrosshair(false);
|
|
MWBase::Environment::get().getWindowManager()->setCursorVisible(guiMode);
|
|
// if not in gui mode, the camera decides whether to show crosshair or not.
|
|
}
|
|
|
|
void InputManager::processChangedSettings(const Settings::CategorySettingVector& changed)
|
|
{
|
|
bool changeRes = false;
|
|
|
|
for (Settings::CategorySettingVector::const_iterator it = changed.begin();
|
|
it != changed.end(); ++it)
|
|
{
|
|
if (it->first == "Input" && it->second == "invert y axis")
|
|
mInvertY = Settings::Manager::getBool("invert y axis", "Input");
|
|
|
|
if (it->first == "Input" && it->second == "camera sensitivity")
|
|
mCameraSensitivity = Settings::Manager::getFloat("camera sensitivity", "Input");
|
|
|
|
if (it->first == "Input" && it->second == "grab cursor")
|
|
mGrabCursor = Settings::Manager::getBool("grab cursor", "Input");
|
|
|
|
if (it->first == "Video" && (
|
|
it->second == "resolution x"
|
|
|| it->second == "resolution y"
|
|
|| it->second == "fullscreen"
|
|
|| it->second == "window border"))
|
|
changeRes = true;
|
|
|
|
if (it->first == "Video" && it->second == "vsync")
|
|
mVideoWrapper->setSyncToVBlank(Settings::Manager::getBool("vsync", "Video"));
|
|
|
|
if (it->first == "Video" && (it->second == "gamma" || it->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"));
|
|
}
|
|
}
|
|
|
|
bool InputManager::getControlSwitch (const std::string& sw)
|
|
{
|
|
return mControlSwitch[sw];
|
|
}
|
|
|
|
void InputManager::toggleControlSwitch (const std::string& sw, bool value)
|
|
{
|
|
if (mControlSwitch[sw] == value) {
|
|
return;
|
|
}
|
|
/// \note 7 switches at all, if-else is relevant
|
|
if (sw == "playercontrols" && !value) {
|
|
mPlayer->setLeftRight(0);
|
|
mPlayer->setForwardBackward(0);
|
|
mPlayer->setAutoMove(false);
|
|
mPlayer->setUpDown(0);
|
|
} else if (sw == "playerjumping" && !value) {
|
|
/// \fixme maybe crouching at this time
|
|
mPlayer->setUpDown(0);
|
|
} else if (sw == "vanitymode") {
|
|
MWBase::Environment::get().getWorld()->allowVanityMode(value);
|
|
} else if (sw == "playerlooking") {
|
|
MWBase::Environment::get().getWorld()->togglePlayerLooking(value);
|
|
}
|
|
mControlSwitch[sw] = value;
|
|
}
|
|
|
|
void InputManager::keyPressed( const SDL_KeyboardEvent &arg )
|
|
{
|
|
mwmp::Main::pressedKey(arg.keysym.scancode);
|
|
// HACK: to make Morrowind's default keybinding for the console work without printing an extra "^" upon closing
|
|
// This assumes that SDL_TextInput events always come *after* the key event
|
|
// (which is somewhat reasonable, and hopefully true for all SDL platforms)
|
|
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
|
|
if (mInputBinder->getKeyBinding(mInputBinder->getControl(A_Console), ICS::Control::INCREASE)
|
|
== arg.keysym.scancode
|
|
&& MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Console)
|
|
SDL_StopTextInput();
|
|
|
|
bool consumed = false;
|
|
if (kc != OIS::KC_UNASSIGNED && !mInputBinder->detectingBindingState())
|
|
{
|
|
consumed = MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Enum(kc), 0);
|
|
if (SDL_IsTextInputActive() && // Little trick to check if key is printable
|
|
( !(SDLK_SCANCODE_MASK & arg.keysym.sym) && std::isprint(arg.keysym.sym)))
|
|
consumed = true;
|
|
setPlayerControlsEnabled(!consumed);
|
|
}
|
|
if (arg.repeat)
|
|
return;
|
|
|
|
if (!mControlsDisabled && !consumed)
|
|
mInputBinder->keyPressed (arg);
|
|
mJoystickLastUsed = false;
|
|
}
|
|
|
|
void InputManager::textInput(const SDL_TextInputEvent &arg)
|
|
{
|
|
MyGUI::UString ustring(&arg.text[0]);
|
|
MyGUI::UString::utf32string utf32string = ustring.asUTF32();
|
|
for (MyGUI::UString::utf32string::const_iterator it = utf32string.begin(); it != utf32string.end(); ++it)
|
|
MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it);
|
|
}
|
|
|
|
void InputManager::keyReleased(const SDL_KeyboardEvent &arg )
|
|
{
|
|
mJoystickLastUsed = false;
|
|
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym);
|
|
|
|
if (!mInputBinder->detectingBindingState())
|
|
setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc)));
|
|
mInputBinder->keyReleased (arg);
|
|
}
|
|
|
|
void InputManager::mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id )
|
|
{
|
|
mJoystickLastUsed = 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);
|
|
}
|
|
|
|
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)
|
|
mInputBinder->mousePressed (arg, id);
|
|
}
|
|
|
|
void InputManager::mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id )
|
|
{
|
|
mJoystickLastUsed = false;
|
|
|
|
if(mInputBinder->detectingBindingState())
|
|
{
|
|
mInputBinder->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(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind
|
|
|
|
setPlayerControlsEnabled(!guiMode);
|
|
mInputBinder->mouseReleased (arg, id);
|
|
}
|
|
}
|
|
|
|
void InputManager::mouseMoved(const SDLUtil::MouseMotionEvent &arg )
|
|
{
|
|
mInputBinder->mouseMoved (arg);
|
|
|
|
mJoystickLastUsed = false;
|
|
resetIdleTime ();
|
|
|
|
if (mGuiCursorEnabled)
|
|
{
|
|
// 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 = int(arg.z);
|
|
|
|
MyGUI::InputManager::getInstance().injectMouseMove( int(mGuiCursorX), 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( int(mGuiCursorX), int(mGuiCursorY), mMouseWheel);
|
|
|
|
MWBase::Environment::get().getWindowManager()->setCursorActive(true);
|
|
}
|
|
|
|
if (mMouseLookEnabled && !mControlsDisabled)
|
|
{
|
|
resetIdleTime();
|
|
|
|
float x = arg.xrel * mCameraSensitivity * (1.0f/256.f);
|
|
float y = arg.yrel * mCameraSensitivity * (1.0f/256.f) * (mInvertY ? -1 : 1) * mCameraYMultiplier;
|
|
|
|
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))
|
|
{
|
|
mPlayer->yaw(x);
|
|
mPlayer->pitch(y);
|
|
}
|
|
|
|
if (arg.zrel && mControlSwitch["playerviewswitch"] && mControlSwitch["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));
|
|
|
|
if (Settings::Manager::getBool("allow third person zoom", "Input"))
|
|
MWBase::Environment::get().getWorld()->setCameraDistance(static_cast<float>(arg.zrel), true, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void InputManager::buttonPressed(int deviceID, const SDL_ControllerButtonEvent &arg )
|
|
{
|
|
mJoystickLastUsed = true;
|
|
bool guiMode = false;
|
|
|
|
if (arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B) // We'll pretend that A is left click and B is right click
|
|
{
|
|
guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
|
if(!mInputBinder->detectingBindingState())
|
|
{
|
|
guiMode = MyGUI::InputManager::getInstance().injectMousePress(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY),
|
|
sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode;
|
|
if (MyGUI::InputManager::getInstance ().getMouseFocusWidget () != 0)
|
|
{
|
|
MyGUI::Button* b = MyGUI::InputManager::getInstance ().getMouseFocusWidget ()->castType<MyGUI::Button>(false);
|
|
if (b && b->getEnabled())
|
|
{
|
|
MWBase::Environment::get().getWindowManager()->playSound("Menu Click");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
setPlayerControlsEnabled(!guiMode);
|
|
|
|
//esc, to leave initial movie screen
|
|
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE);
|
|
bool guiFocus = MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0);
|
|
setPlayerControlsEnabled(!guiFocus);
|
|
|
|
if (!mControlsDisabled)
|
|
mInputBinder->buttonPressed(deviceID, arg);
|
|
}
|
|
|
|
void InputManager::buttonReleased(int deviceID, const SDL_ControllerButtonEvent &arg )
|
|
{
|
|
mJoystickLastUsed = true;
|
|
if(mInputBinder->detectingBindingState())
|
|
mInputBinder->buttonReleased(deviceID, arg);
|
|
else if(arg.button == SDL_CONTROLLER_BUTTON_A || arg.button == SDL_CONTROLLER_BUTTON_B)
|
|
{
|
|
bool guiMode = MWBase::Environment::get().getWindowManager()->isGuiMode();
|
|
guiMode = MyGUI::InputManager::getInstance().injectMouseRelease(static_cast<int>(mGuiCursorX), static_cast<int>(mGuiCursorY), sdlButtonToMyGUI((arg.button == SDL_CONTROLLER_BUTTON_B) ? SDL_BUTTON_RIGHT : SDL_BUTTON_LEFT)) && guiMode;
|
|
|
|
if(mInputBinder->detectingBindingState()) return; // don't allow same mouseup to bind as initiated bind
|
|
|
|
setPlayerControlsEnabled(!guiMode);
|
|
mInputBinder->buttonReleased(deviceID, arg);
|
|
}
|
|
else
|
|
mInputBinder->buttonReleased(deviceID, arg);
|
|
|
|
///to escape initial movie
|
|
OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(SDLK_ESCAPE);
|
|
setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(MyGUI::KeyCode::Enum(kc)));
|
|
}
|
|
|
|
void InputManager::axisMoved(int deviceID, const SDL_ControllerAxisEvent &arg )
|
|
{
|
|
if (!mControlsDisabled)
|
|
mInputBinder->axisMoved(deviceID, arg);
|
|
}
|
|
|
|
void InputManager::controllerAdded(int deviceID, const SDL_ControllerDeviceEvent &arg)
|
|
{
|
|
mInputBinder->controllerAdded(deviceID, arg);
|
|
}
|
|
void InputManager::controllerRemoved(const SDL_ControllerDeviceEvent &arg)
|
|
{
|
|
mInputBinder->controllerRemoved(arg);
|
|
}
|
|
|
|
void InputManager::windowFocusChange(bool have_focus)
|
|
{
|
|
}
|
|
|
|
void InputManager::windowVisibilityChange(bool visible)
|
|
{
|
|
mWindowVisible = visible;
|
|
}
|
|
|
|
void InputManager::windowResized(int x, int y)
|
|
{
|
|
Settings::Manager::setInt("resolution x", "Video", x);
|
|
Settings::Manager::setInt("resolution y", "Video", y);
|
|
|
|
MWBase::Environment::get().getWindowManager()->windowResized(x, y);
|
|
}
|
|
|
|
void InputManager::windowClosed()
|
|
{
|
|
MWBase::Environment::get().getStateManager()->requestQuit();
|
|
}
|
|
|
|
void InputManager::toggleMainMenu()
|
|
{
|
|
if (MyGUI::InputManager::getInstance().isModalAny()) {
|
|
MWBase::Environment::get().getWindowManager()->exitCurrentModal();
|
|
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 InputManager::quickLoad() {
|
|
/*
|
|
Start of tes3mp change (major)
|
|
|
|
It should not be possible to quickload the game in multiplayer, so it has been disabled
|
|
*/
|
|
|
|
/*
|
|
if (!MyGUI::InputManager::getInstance().isModalAny())
|
|
MWBase::Environment::get().getStateManager()->quickLoad();
|
|
*/
|
|
|
|
/*
|
|
End of tes3mp change (major)
|
|
*/
|
|
}
|
|
|
|
void InputManager::quickSave() {
|
|
/*
|
|
Start of tes3mp change (major)
|
|
|
|
It should not be possible to quicksave the game in multiplayer, so it has been disabled
|
|
*/
|
|
|
|
/*
|
|
if (!MyGUI::InputManager::getInstance().isModalAny())
|
|
MWBase::Environment::get().getStateManager()->quickSave();
|
|
*/
|
|
|
|
/*
|
|
End of tes3mp change (major)
|
|
*/
|
|
}
|
|
void InputManager::toggleSpell()
|
|
{
|
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
|
|
|
// Not allowed before the magic window is accessible
|
|
if (!mControlSwitch["playermagic"] || !mControlSwitch["playercontrols"])
|
|
return;
|
|
|
|
if (!checkAllowedToUseItems())
|
|
return;
|
|
|
|
// Not allowed if no spell selected
|
|
MWWorld::InventoryStore& inventory = mPlayer->getPlayer().getClass().getInventoryStore(mPlayer->getPlayer());
|
|
if (MWBase::Environment::get().getWindowManager()->getSelectedSpell().empty() &&
|
|
inventory.getSelectedEnchantItem() == inventory.end())
|
|
return;
|
|
|
|
if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer()))
|
|
return;
|
|
|
|
MWMechanics::DrawState_ state = mPlayer->getDrawState();
|
|
if (state == MWMechanics::DrawState_Weapon || state == MWMechanics::DrawState_Nothing)
|
|
mPlayer->setDrawState(MWMechanics::DrawState_Spell);
|
|
else
|
|
mPlayer->setDrawState(MWMechanics::DrawState_Nothing);
|
|
}
|
|
|
|
void InputManager::toggleWeapon()
|
|
{
|
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
|
|
|
// Not allowed before the inventory window is accessible
|
|
if (!mControlSwitch["playerfighting"] || !mControlSwitch["playercontrols"])
|
|
return;
|
|
|
|
// We want to interrupt animation only if attack is prepairing, 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()->isAttackPrepairing(mPlayer->getPlayer()))
|
|
mPlayer->setAttackingOrSpell(false);
|
|
else if (MWBase::Environment::get().getMechanicsManager()->isAttackingOrSpell(mPlayer->getPlayer()))
|
|
return;
|
|
|
|
MWMechanics::DrawState_ state = mPlayer->getDrawState();
|
|
if (state == MWMechanics::DrawState_Spell || state == MWMechanics::DrawState_Nothing)
|
|
mPlayer->setDrawState(MWMechanics::DrawState_Weapon);
|
|
else
|
|
mPlayer->setDrawState(MWMechanics::DrawState_Nothing);
|
|
}
|
|
|
|
void InputManager::rest()
|
|
{
|
|
if (!mControlSwitch["playercontrols"])
|
|
return;
|
|
|
|
if (!MWBase::Environment::get().getWindowManager()->getRestEnabled () || MWBase::Environment::get().getWindowManager()->isGuiMode ())
|
|
return;
|
|
|
|
if(mPlayer->enemiesNearby()) {//Check if in combat
|
|
MWBase::Environment::get().getWindowManager()->messageBox("#{sNotifyMessage2}"); //Nope,
|
|
return;
|
|
}
|
|
|
|
/*
|
|
Start of tes3mp addition
|
|
|
|
Ignore attempts to rest if the player has not logged in on the server yet
|
|
*/
|
|
if (!mwmp::Main::get().getLocalPlayer()->isLoggedIn())
|
|
return;
|
|
/*
|
|
End of tes3mp addition
|
|
*/
|
|
|
|
/*
|
|
Start of tes3mp addition
|
|
|
|
Prevent resting and waiting if they have been disabled by the server for the local player
|
|
*/
|
|
int canRest = MWBase::Environment::get().getWorld()->canRest();
|
|
|
|
if (canRest == 0 && !mwmp::Main::get().getLocalPlayer()->wildernessRestAllowed)
|
|
{
|
|
MWBase::Environment::get().getWindowManager()->messageBox("You are not allowed to rest in the wilderness.");
|
|
return;
|
|
}
|
|
else if (canRest == 1 && !mwmp::Main::get().getLocalPlayer()->waitAllowed)
|
|
{
|
|
MWBase::Environment::get().getWindowManager()->messageBox("You are not allowed to wait.");
|
|
return;
|
|
}
|
|
/*
|
|
End of tes3mp addition
|
|
*/
|
|
|
|
MWBase::Environment::get().getWindowManager()->pushGuiMode (MWGui::GM_Rest); //Open rest GUI
|
|
|
|
}
|
|
|
|
void InputManager::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 InputManager::toggleInventory()
|
|
{
|
|
if (!mControlSwitch["playercontrols"])
|
|
return;
|
|
|
|
if (MyGUI::InputManager::getInstance ().isModalAny())
|
|
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 InputManager::toggleConsole()
|
|
{
|
|
/*
|
|
Start of tes3mp addition
|
|
|
|
If a player's console is disabled by the server, go no further
|
|
*/
|
|
if (!mwmp::Main::get().getLocalPlayer()->consoleAllowed)
|
|
return;
|
|
/*
|
|
End of tes3mp addition
|
|
*/
|
|
|
|
if (MyGUI::InputManager::getInstance ().isModalAny())
|
|
return;
|
|
|
|
// Switch to console mode no matter what mode we are currently
|
|
// in, except of course if we are already in console mode
|
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
|
{
|
|
if (MWBase::Environment::get().getWindowManager()->getMode() == MWGui::GM_Console)
|
|
MWBase::Environment::get().getWindowManager()->popGuiMode();
|
|
else
|
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Console);
|
|
}
|
|
else
|
|
MWBase::Environment::get().getWindowManager()->pushGuiMode(MWGui::GM_Console);
|
|
}
|
|
|
|
void InputManager::toggleJournal()
|
|
{
|
|
if (!mControlSwitch["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 ()->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 InputManager::quickKey (int index)
|
|
{
|
|
if (!mControlSwitch["playercontrols"])
|
|
return;
|
|
if (!checkAllowedToUseItems())
|
|
return;
|
|
|
|
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
|
|
MWBase::Environment::get().getWindowManager()->activateQuickKey (index);
|
|
}
|
|
|
|
void InputManager::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 InputManager::activate()
|
|
{
|
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode())
|
|
{
|
|
if (!SDL_IsTextInputActive() && !isLeftOrRightButton(A_Activate, mInputBinder, mFakeDeviceID, mJoystickLastUsed))
|
|
MWBase::Environment::get().getWindowManager()->injectKeyPress(MyGUI::KeyCode::Return, 0);
|
|
}
|
|
else if (mControlSwitch["playercontrols"])
|
|
mPlayer->activate();
|
|
}
|
|
|
|
void InputManager::toggleAutoMove()
|
|
{
|
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
|
|
|
if (mControlSwitch["playercontrols"])
|
|
mPlayer->setAutoMove (!mPlayer->getAutoMove());
|
|
}
|
|
|
|
void InputManager::toggleWalking()
|
|
{
|
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
|
mAlwaysRunActive = !mAlwaysRunActive;
|
|
|
|
Settings::Manager::setBool("always run", "Input", mAlwaysRunActive);
|
|
}
|
|
|
|
void InputManager::toggleSneaking()
|
|
{
|
|
if (MWBase::Environment::get().getWindowManager()->isGuiMode()) return;
|
|
mSneaking = !mSneaking;
|
|
mPlayer->setSneak(mSneaking);
|
|
}
|
|
|
|
void InputManager::resetIdleTime()
|
|
{
|
|
if (mTimeIdle < 0)
|
|
MWBase::Environment::get().getWorld()->toggleVanityMode(false);
|
|
mTimeIdle = 0.f;
|
|
}
|
|
|
|
void InputManager::updateIdleTime(float dt)
|
|
{
|
|
static const float vanityDelay = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
|
|
.find("fVanityDelay")->getFloat();
|
|
if (mTimeIdle >= 0.f)
|
|
mTimeIdle += dt;
|
|
if (mTimeIdle > vanityDelay) {
|
|
MWBase::Environment::get().getWorld()->toggleVanityMode(true);
|
|
mTimeIdle = -1.f;
|
|
}
|
|
}
|
|
|
|
bool InputManager::actionIsActive (int id)
|
|
{
|
|
return (mInputBinder->getChannel (id)->getValue ()==1.0);
|
|
}
|
|
|
|
void InputManager::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;
|
|
|
|
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
|
|
))
|
|
{
|
|
clearAllKeyBindings(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);
|
|
}
|
|
|
|
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 InputManager::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_LEFTSHOULDER;
|
|
//defaultButtonBindings[A_QuickButtonsMenu] = SDL_GetButtonFromScancode(SDL_SCANCODE_F1); // Need to implement, should be ToggleSpell(5) AND Wait(9)
|
|
defaultButtonBindings[A_Sneak] = SDL_CONTROLLER_BUTTON_RIGHTSTICK;
|
|
defaultButtonBindings[A_Jump] = SDL_CONTROLLER_BUTTON_Y;
|
|
defaultButtonBindings[A_Journal] = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER;
|
|
defaultButtonBindings[A_Rest] = SDL_CONTROLLER_BUTTON_BACK;
|
|
defaultButtonBindings[A_TogglePOV] = SDL_CONTROLLER_BUTTON_LEFTSTICK;
|
|
defaultButtonBindings[A_Inventory] = SDL_CONTROLLER_BUTTON_B;
|
|
defaultButtonBindings[A_GameMenu] = SDL_CONTROLLER_BUTTON_START;
|
|
defaultButtonBindings[A_QuickSave] = SDL_CONTROLLER_BUTTON_GUIDE;
|
|
defaultButtonBindings[A_QuickKey1] = SDL_CONTROLLER_BUTTON_DPAD_UP;
|
|
defaultButtonBindings[A_QuickKey2] = SDL_CONTROLLER_BUTTON_DPAD_LEFT;
|
|
defaultButtonBindings[A_QuickKey3] = SDL_CONTROLLER_BUTTON_DPAD_DOWN;
|
|
defaultButtonBindings[A_QuickKey4] = 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;
|
|
|
|
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, mFakeDeviceID, ICS::Control::INCREASE) == ICS::InputControlSystem::UNASSIGNED && mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE) == ICS_MAX_DEVICE_BUTTONS ))
|
|
{
|
|
clearAllControllerBindings(control);
|
|
|
|
if (defaultButtonBindings.find(i) != defaultButtonBindings.end()
|
|
&& (force || !mInputBinder->isJoystickButtonBound(mFakeDeviceID, defaultButtonBindings[i])))
|
|
{
|
|
control->setInitialValue(0.0f);
|
|
mInputBinder->addJoystickButtonBinding(control, mFakeDeviceID, defaultButtonBindings[i], ICS::Control::INCREASE);
|
|
}
|
|
else if (defaultAxisBindings.find(i) != defaultAxisBindings.end() && (force || !mInputBinder->isJoystickAxisBound(mFakeDeviceID, defaultAxisBindings[i])))
|
|
{
|
|
control->setValue(0.5f);
|
|
control->setInitialValue(0.5f);
|
|
mInputBinder->addJoystickAxisBinding(control, mFakeDeviceID, defaultAxisBindings[i], ICS::Control::INCREASE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
std::string InputManager::getActionDescription (int action)
|
|
{
|
|
std::map<int, std::string> descriptions;
|
|
|
|
if (action == A_Screenshot)
|
|
return "Screenshot";
|
|
|
|
descriptions[A_Use] = "sUse";
|
|
descriptions[A_Activate] = "sActivate";
|
|
descriptions[A_MoveBackward] = "sBack";
|
|
descriptions[A_MoveForward] = "sForward";
|
|
descriptions[A_MoveLeft] = "sLeft";
|
|
descriptions[A_MoveRight] = "sRight";
|
|
descriptions[A_ToggleWeapon] = "sReady_Weapon";
|
|
descriptions[A_ToggleSpell] = "sReady_Magic";
|
|
descriptions[A_CycleSpellLeft] = "sPrevSpell";
|
|
descriptions[A_CycleSpellRight] = "sNextSpell";
|
|
descriptions[A_CycleWeaponLeft] = "sPrevWeapon";
|
|
descriptions[A_CycleWeaponRight] = "sNextWeapon";
|
|
descriptions[A_Console] = "sConsoleTitle";
|
|
descriptions[A_Run] = "sRun";
|
|
descriptions[A_Sneak] = "sCrouch_Sneak";
|
|
descriptions[A_AutoMove] = "sAuto_Run";
|
|
descriptions[A_Jump] = "sJump";
|
|
descriptions[A_Journal] = "sJournal";
|
|
descriptions[A_Rest] = "sRestKey";
|
|
descriptions[A_Inventory] = "sInventory";
|
|
descriptions[A_TogglePOV] = "sTogglePOVCmd";
|
|
descriptions[A_QuickKeysMenu] = "sQuickMenu";
|
|
descriptions[A_QuickKey1] = "sQuick1Cmd";
|
|
descriptions[A_QuickKey2] = "sQuick2Cmd";
|
|
descriptions[A_QuickKey3] = "sQuick3Cmd";
|
|
descriptions[A_QuickKey4] = "sQuick4Cmd";
|
|
descriptions[A_QuickKey5] = "sQuick5Cmd";
|
|
descriptions[A_QuickKey6] = "sQuick6Cmd";
|
|
descriptions[A_QuickKey7] = "sQuick7Cmd";
|
|
descriptions[A_QuickKey8] = "sQuick8Cmd";
|
|
descriptions[A_QuickKey9] = "sQuick9Cmd";
|
|
descriptions[A_QuickKey10] = "sQuick10Cmd";
|
|
descriptions[A_AlwaysRun] = "sAlways_Run";
|
|
descriptions[A_QuickSave] = "sQuickSaveCmd";
|
|
descriptions[A_QuickLoad] = "sQuickLoadCmd";
|
|
|
|
if (descriptions[action] == "")
|
|
return ""; // not configurable
|
|
|
|
return "#{" + descriptions[action] + "}";
|
|
}
|
|
|
|
std::string InputManager::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);
|
|
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
|
|
return "#{sNone}";
|
|
}
|
|
|
|
std::string InputManager::getActionControllerBindingName (int action)
|
|
{
|
|
if (mInputBinder->getChannel (action)->getControlsCount () == 0)
|
|
return "#{sNone}";
|
|
|
|
ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control;
|
|
|
|
if (mInputBinder->getJoystickAxisBinding (c, mFakeDeviceID, ICS::Control::INCREASE) != ICS::InputControlSystem::UNASSIGNED)
|
|
return sdlControllerAxisToString(mInputBinder->getJoystickAxisBinding (c, mFakeDeviceID, ICS::Control::INCREASE));
|
|
else if (mInputBinder->getJoystickButtonBinding (c, mFakeDeviceID, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS )
|
|
return sdlControllerButtonToString(mInputBinder->getJoystickButtonBinding (c, mFakeDeviceID, ICS::Control::INCREASE));
|
|
else
|
|
return "#{sNone}";
|
|
}
|
|
|
|
std::string InputManager::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 InputManager::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);
|
|
}
|
|
}
|
|
|
|
std::vector<int> InputManager::getActionKeySorting()
|
|
{
|
|
std::vector<int> ret;
|
|
ret.push_back(A_MoveForward);
|
|
ret.push_back(A_MoveBackward);
|
|
ret.push_back(A_MoveLeft);
|
|
ret.push_back(A_MoveRight);
|
|
ret.push_back(A_TogglePOV);
|
|
ret.push_back(A_Run);
|
|
ret.push_back(A_AlwaysRun);
|
|
ret.push_back(A_Sneak);
|
|
ret.push_back(A_Activate);
|
|
ret.push_back(A_Use);
|
|
ret.push_back(A_ToggleWeapon);
|
|
ret.push_back(A_ToggleSpell);
|
|
ret.push_back(A_CycleSpellLeft);
|
|
ret.push_back(A_CycleSpellRight);
|
|
ret.push_back(A_CycleWeaponLeft);
|
|
ret.push_back(A_CycleWeaponRight);
|
|
ret.push_back(A_AutoMove);
|
|
ret.push_back(A_Jump);
|
|
ret.push_back(A_Inventory);
|
|
ret.push_back(A_Journal);
|
|
ret.push_back(A_Rest);
|
|
ret.push_back(A_Console);
|
|
ret.push_back(A_QuickSave);
|
|
ret.push_back(A_QuickLoad);
|
|
ret.push_back(A_Screenshot);
|
|
ret.push_back(A_QuickKeysMenu);
|
|
ret.push_back(A_QuickKey1);
|
|
ret.push_back(A_QuickKey2);
|
|
ret.push_back(A_QuickKey3);
|
|
ret.push_back(A_QuickKey4);
|
|
ret.push_back(A_QuickKey5);
|
|
ret.push_back(A_QuickKey6);
|
|
ret.push_back(A_QuickKey7);
|
|
ret.push_back(A_QuickKey8);
|
|
ret.push_back(A_QuickKey9);
|
|
ret.push_back(A_QuickKey10);
|
|
|
|
return ret;
|
|
}
|
|
std::vector<int> InputManager::getActionControllerSorting()
|
|
{
|
|
std::vector<int> ret;
|
|
ret.push_back(A_TogglePOV);
|
|
ret.push_back(A_Sneak);
|
|
ret.push_back(A_Activate);
|
|
ret.push_back(A_Use);
|
|
ret.push_back(A_ToggleWeapon);
|
|
ret.push_back(A_ToggleSpell);
|
|
ret.push_back(A_AutoMove);
|
|
ret.push_back(A_Jump);
|
|
ret.push_back(A_Inventory);
|
|
ret.push_back(A_Journal);
|
|
ret.push_back(A_Rest);
|
|
ret.push_back(A_QuickSave);
|
|
ret.push_back(A_QuickLoad);
|
|
ret.push_back(A_Screenshot);
|
|
ret.push_back(A_QuickKeysMenu);
|
|
ret.push_back(A_QuickKey1);
|
|
ret.push_back(A_QuickKey2);
|
|
ret.push_back(A_QuickKey3);
|
|
ret.push_back(A_QuickKey4);
|
|
ret.push_back(A_QuickKey5);
|
|
ret.push_back(A_QuickKey6);
|
|
ret.push_back(A_QuickKey7);
|
|
ret.push_back(A_QuickKey8);
|
|
ret.push_back(A_QuickKey9);
|
|
ret.push_back(A_QuickKey10);
|
|
ret.push_back(A_CycleSpellLeft);
|
|
ret.push_back(A_CycleSpellRight);
|
|
ret.push_back(A_CycleWeaponLeft);
|
|
ret.push_back(A_CycleWeaponRight);
|
|
|
|
return ret;
|
|
}
|
|
|
|
void InputManager::enableDetectingBindingMode (int action, bool keyboard)
|
|
{
|
|
mDetectingKeyboard = keyboard;
|
|
ICS::Control* c = mInputBinder->getChannel (action)->getAttachedControls ().front().control;
|
|
mInputBinder->enableDetectingBindingState (c, ICS::Control::INCREASE);
|
|
}
|
|
|
|
void InputManager::mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
|
, ICS::InputControlSystem::NamedAxis axis, ICS::Control::ControlChangingDirection direction)
|
|
{
|
|
// we don't want mouse movement bindings
|
|
return;
|
|
}
|
|
|
|
void InputManager::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;
|
|
}
|
|
if(!mDetectingKeyboard)
|
|
return;
|
|
|
|
clearAllKeyBindings(control);
|
|
control->setInitialValue(0.0f);
|
|
ICS::DetectingBindingListener::keyBindingDetected (ICS, control, key, direction);
|
|
MWBase::Environment::get().getWindowManager ()->notifyInputActionBound ();
|
|
}
|
|
|
|
void InputManager::mouseButtonBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
|
|
, unsigned int button, ICS::Control::ControlChangingDirection direction)
|
|
{
|
|
if(!mDetectingKeyboard)
|
|
return;
|
|
clearAllKeyBindings(control);
|
|
control->setInitialValue(0.0f);
|
|
ICS::DetectingBindingListener::mouseButtonBindingDetected (ICS, control, button, direction);
|
|
MWBase::Environment::get().getWindowManager ()->notifyInputActionBound ();
|
|
}
|
|
|
|
void InputManager::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(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 ();
|
|
}
|
|
|
|
void InputManager::joystickButtonBindingDetected(ICS::InputControlSystem* ICS, int deviceID, ICS::Control* control
|
|
, unsigned int button, ICS::Control::ControlChangingDirection direction)
|
|
{
|
|
if(mDetectingKeyboard)
|
|
return;
|
|
clearAllControllerBindings(control);
|
|
control->setInitialValue(0.0f);
|
|
ICS::DetectingBindingListener::joystickButtonBindingDetected (ICS, deviceID, control, button, direction);
|
|
MWBase::Environment::get().getWindowManager ()->notifyInputActionBound ();
|
|
}
|
|
|
|
void InputManager::clearAllKeyBindings (ICS::Control* control)
|
|
{
|
|
// right now we don't really need multiple bindings for the same action, so remove all others first
|
|
if (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN)
|
|
mInputBinder->removeKeyBinding (mInputBinder->getKeyBinding (control, ICS::Control::INCREASE));
|
|
if (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS)
|
|
mInputBinder->removeMouseButtonBinding (mInputBinder->getMouseButtonBinding (control, ICS::Control::INCREASE));
|
|
}
|
|
|
|
void InputManager::clearAllControllerBindings (ICS::Control* control)
|
|
{
|
|
// right now we don't really need multiple bindings for the same action, so remove all others first
|
|
if (mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE) != SDL_SCANCODE_UNKNOWN)
|
|
mInputBinder->removeJoystickAxisBinding (mFakeDeviceID, mInputBinder->getJoystickAxisBinding (control, mFakeDeviceID, ICS::Control::INCREASE));
|
|
if (mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE) != ICS_MAX_DEVICE_BUTTONS)
|
|
mInputBinder->removeJoystickButtonBinding (mFakeDeviceID, mInputBinder->getJoystickButtonBinding (control, mFakeDeviceID, ICS::Control::INCREASE));
|
|
}
|
|
|
|
int InputManager::countSavedGameRecords() const
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
void InputManager::write(ESM::ESMWriter& writer, Loading::Listener& /*progress*/)
|
|
{
|
|
ESM::ControlsState controls;
|
|
controls.mViewSwitchDisabled = !getControlSwitch("playerviewswitch");
|
|
controls.mControlsDisabled = !getControlSwitch("playercontrols");
|
|
controls.mJumpingDisabled = !getControlSwitch("playerjumping");
|
|
controls.mLookingDisabled = !getControlSwitch("playerlooking");
|
|
controls.mVanityModeDisabled = !getControlSwitch("vanitymode");
|
|
controls.mWeaponDrawingDisabled = !getControlSwitch("playerfighting");
|
|
controls.mSpellDrawingDisabled = !getControlSwitch("playermagic");
|
|
|
|
writer.startRecord (ESM::REC_INPU);
|
|
controls.save(writer);
|
|
writer.endRecord (ESM::REC_INPU);
|
|
}
|
|
|
|
void InputManager::readRecord(ESM::ESMReader& reader, uint32_t type)
|
|
{
|
|
if (type == ESM::REC_INPU)
|
|
{
|
|
ESM::ControlsState controls;
|
|
controls.load(reader);
|
|
|
|
toggleControlSwitch("playerviewswitch", !controls.mViewSwitchDisabled);
|
|
toggleControlSwitch("playercontrols", !controls.mControlsDisabled);
|
|
toggleControlSwitch("playerjumping", !controls.mJumpingDisabled);
|
|
toggleControlSwitch("playerlooking", !controls.mLookingDisabled);
|
|
toggleControlSwitch("vanitymode", !controls.mVanityModeDisabled);
|
|
toggleControlSwitch("playerfighting", !controls.mWeaponDrawingDisabled);
|
|
toggleControlSwitch("playermagic", !controls.mSpellDrawingDisabled);
|
|
}
|
|
}
|
|
|
|
void InputManager::resetToDefaultKeyBindings()
|
|
{
|
|
loadKeyDefaults(true);
|
|
}
|
|
|
|
void InputManager::resetToDefaultControllerBindings()
|
|
{
|
|
loadControllerDefaults(true);
|
|
}
|
|
|
|
MyGUI::MouseButton InputManager::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);
|
|
}
|
|
}
|