openmw-tes3coop/apps/openmw/mwinput/inputmanagerimp.cpp
David Cernat d9dd7073cf [General] Send certain packets only when logged in
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.
2018-10-13 15:36:13 +03:00

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