diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index a6d9402c4f..53e35f3310 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -57,7 +57,8 @@ add_openmw_dir (mwscript add_openmw_dir (mwlua luamanagerimp actions object worldview userdataserializer eventqueue query - luabindings localscripts objectbindings cellbindings asyncbindings camerabindings uibindings settingsbindings + luabindings localscripts objectbindings cellbindings asyncbindings settingsbindings + camerabindings uibindings inputbindings ) add_openmw_dir (mwsound diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 951b5053a2..5ac7c218b5 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -5,6 +5,7 @@ #include #include +#include #include namespace Loading @@ -51,9 +52,17 @@ namespace MWBase virtual void toggleControlSwitch (const std::string& sw, bool value) = 0; virtual bool getControlSwitch (const std::string& sw) = 0; - virtual std::string getActionDescription (int action) = 0; - virtual std::string getActionKeyBindingName (int action) = 0; - virtual std::string getActionControllerBindingName (int action) = 0; + virtual std::string getActionDescription (int action) const = 0; + virtual std::string getActionKeyBindingName (int action) const = 0; + virtual std::string getActionControllerBindingName (int action) const = 0; + virtual bool actionIsActive(int action) const = 0; + + virtual float getActionValue(int action) const = 0; // returns value in range [0, 1] + virtual float getControllerAxisValue(SDL_GameControllerAxis axis) const = 0; // returns value in range [-1, 1] + virtual uint32_t getMouseButtonsState() const = 0; + virtual int getMouseMoveX() const = 0; + virtual int getMouseMoveY() const = 0; + ///Actions available for binding to keyboard buttons virtual std::vector getActionKeySorting() = 0; ///Actions available for binding to controller buttons @@ -74,6 +83,7 @@ namespace MWBase virtual void readRecord(ESM::ESMReader& reader, uint32_t type) = 0; virtual void resetIdleTime() = 0; + virtual bool isIdle() const = 0; virtual void executeAction(int action) = 0; diff --git a/apps/openmw/mwbase/luamanager.hpp b/apps/openmw/mwbase/luamanager.hpp index cc416c9ab0..ebcd8f50b3 100644 --- a/apps/openmw/mwbase/luamanager.hpp +++ b/apps/openmw/mwbase/luamanager.hpp @@ -1,6 +1,7 @@ #ifndef GAME_MWBASE_LUAMANAGER_H #define GAME_MWBASE_LUAMANAGER_H +#include #include namespace MWWorld @@ -29,8 +30,6 @@ namespace MWBase virtual ~LuaManager() = default; virtual void newGameStarted() = 0; - virtual void keyPressed(const SDL_KeyboardEvent &arg) = 0; - virtual void registerObject(const MWWorld::Ptr& ptr) = 0; virtual void deregisterObject(const MWWorld::Ptr& ptr) = 0; virtual void objectAddedToScene(const MWWorld::Ptr& ptr) = 0; @@ -40,6 +39,13 @@ namespace MWBase // virtual void objectOnHit(const MWWorld::Ptr &ptr, float damage, bool ishealth, const MWWorld::Ptr &object, // const MWWorld::Ptr &attacker, const osg::Vec3f &hitPosition, bool successful) = 0; + struct InputEvent + { + enum {KeyPressed, KeyReleased, ControllerPressed, ControllerReleased, Action} mType; + std::variant mValue; + }; + virtual void inputEvent(const InputEvent& event) = 0; + struct ActorControls { bool mDisableAI = false; diff --git a/apps/openmw/mwinput/actionmanager.cpp b/apps/openmw/mwinput/actionmanager.cpp index c91722fbfb..e080437d92 100644 --- a/apps/openmw/mwinput/actionmanager.cpp +++ b/apps/openmw/mwinput/actionmanager.cpp @@ -9,6 +9,7 @@ #include "../mwbase/inputmanager.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/luamanager.hpp" #include "../mwbase/mechanicsmanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" @@ -195,6 +196,7 @@ namespace MWInput void ActionManager::executeAction(int action) { + MWBase::Environment::get().getLuaManager()->inputEvent({MWBase::LuaManager::InputEvent::Action, action}); auto* inputManager = MWBase::Environment::get().getInputManager(); auto* windowManager = MWBase::Environment::get().getWindowManager(); // trigger action activated diff --git a/apps/openmw/mwinput/actionmanager.hpp b/apps/openmw/mwinput/actionmanager.hpp index eceac2e94f..2180e1944e 100644 --- a/apps/openmw/mwinput/actionmanager.hpp +++ b/apps/openmw/mwinput/actionmanager.hpp @@ -48,6 +48,7 @@ namespace MWInput void showQuickKeysMenu(); void resetIdleTime(); + float getIdleTime() const { return mTimeIdle; } bool isAlwaysRunActive() const { return mAlwaysRunActive; }; bool isSneaking() const { return mSneaking; }; diff --git a/apps/openmw/mwinput/bindingsmanager.cpp b/apps/openmw/mwinput/bindingsmanager.cpp index 851e33a87c..ca7911ecc2 100644 --- a/apps/openmw/mwinput/bindingsmanager.cpp +++ b/apps/openmw/mwinput/bindingsmanager.cpp @@ -653,6 +653,16 @@ namespace MWInput return mInputBinder->getKeyBinding(mInputBinder->getControl(actionId), ICS::Control::INCREASE); } + float BindingsManager::getControllerAxisValue(SDL_GameControllerAxis axis) const + { + const auto& controllers = mInputBinder->getJoystickInstanceMap(); + if (controllers.empty()) + return 0; + SDL_GameController* cntrl = controllers.begin()->second; + constexpr int AXIS_MAX_ABSOLUTE_VALUE = 32768; + return SDL_GameControllerGetAxis(cntrl, axis) / static_cast(AXIS_MAX_ABSOLUTE_VALUE); + } + void BindingsManager::actionValueChanged(int action, float currentValue, float previousValue) { MWBase::Environment::get().getInputManager()->resetIdleTime(); diff --git a/apps/openmw/mwinput/bindingsmanager.hpp b/apps/openmw/mwinput/bindingsmanager.hpp index 74416d3c7f..5c653f0b3e 100644 --- a/apps/openmw/mwinput/bindingsmanager.hpp +++ b/apps/openmw/mwinput/bindingsmanager.hpp @@ -42,7 +42,8 @@ namespace MWInput bool isLeftOrRightButton(int action, bool joystick) const; bool actionIsActive(int id) const; - float getActionValue(int id) const; + float getActionValue(int id) const; // returns value in range [0, 1] + float getControllerAxisValue(SDL_GameControllerAxis axis) const; // returns value in range [-1, 1] void mousePressed(const SDL_MouseButtonEvent &evt, int deviceID); void mouseReleased(const SDL_MouseButtonEvent &arg, int deviceID); diff --git a/apps/openmw/mwinput/controllermanager.cpp b/apps/openmw/mwinput/controllermanager.cpp index 03d492c9cf..7a91f8643b 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -8,6 +8,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/inputmanager.hpp" +#include "../mwbase/luamanager.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" @@ -198,6 +199,9 @@ namespace MWInput if (!mJoystickEnabled || mBindingsManager->isDetectingBindingState()) return; + MWBase::Environment::get().getLuaManager()->inputEvent( + {MWBase::LuaManager::InputEvent::ControllerPressed, arg.button}); + mJoystickLastUsed = true; if (MWBase::Environment::get().getWindowManager()->isGuiMode()) { @@ -240,6 +244,12 @@ namespace MWInput return; } + if (mJoystickEnabled) + { + MWBase::Environment::get().getLuaManager()->inputEvent( + {MWBase::LuaManager::InputEvent::ControllerReleased, arg.button}); + } + if (!mJoystickEnabled || MWBase::Environment::get().getInputManager()->controlsDisabled()) return; diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 436eab7ad3..31f515afb0 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -150,21 +150,56 @@ namespace MWInput mActionManager->resetIdleTime(); } - std::string InputManager::getActionDescription(int action) + bool InputManager::isIdle() const + { + return mActionManager->getIdleTime() > 0.5; + } + + std::string InputManager::getActionDescription(int action) const { return mBindingsManager->getActionDescription(action); } - std::string InputManager::getActionKeyBindingName(int action) + std::string InputManager::getActionKeyBindingName(int action) const { return mBindingsManager->getActionKeyBindingName(action); } - std::string InputManager::getActionControllerBindingName(int action) + std::string InputManager::getActionControllerBindingName(int action) const { return mBindingsManager->getActionControllerBindingName(action); } + bool InputManager::actionIsActive(int action) const + { + return mBindingsManager->actionIsActive(action); + } + + float InputManager::getActionValue(int action) const + { + return mBindingsManager->getActionValue(action); + } + + float InputManager::getControllerAxisValue(SDL_GameControllerAxis axis) const + { + return mBindingsManager->getControllerAxisValue(axis); + } + + uint32_t InputManager::getMouseButtonsState() const + { + return mMouseManager->getButtonsState(); + } + + int InputManager::getMouseMoveX() const + { + return mMouseManager->getMouseMoveX(); + } + + int InputManager::getMouseMoveY() const + { + return mMouseManager->getMouseMoveY(); + } + std::vector InputManager::getActionKeySorting() { return mBindingsManager->getActionKeySorting(); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index f930836d1c..adb8319498 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -73,9 +73,17 @@ namespace MWInput void toggleControlSwitch (const std::string& sw, bool value) override; bool getControlSwitch (const std::string& sw) override; - std::string getActionDescription (int action) override; - std::string getActionKeyBindingName (int action) override; - std::string getActionControllerBindingName (int action) override; + std::string getActionDescription (int action) const override; + std::string getActionKeyBindingName (int action) const override; + std::string getActionControllerBindingName (int action) const override; + bool actionIsActive(int action) const override; + + float getActionValue(int action) const override; + float getControllerAxisValue(SDL_GameControllerAxis axis) const override; + uint32_t getMouseButtonsState() const override; + int getMouseMoveX() const override; + int getMouseMoveY() const override; + int getNumActions() override { return A_Last; } std::vector getActionKeySorting() override; std::vector getActionControllerSorting() override; @@ -91,6 +99,7 @@ namespace MWInput void readRecord(ESM::ESMReader& reader, uint32_t type) override; void resetIdleTime() override; + bool isIdle() const override; void executeAction(int action) override; diff --git a/apps/openmw/mwinput/keyboardmanager.cpp b/apps/openmw/mwinput/keyboardmanager.cpp index 03db584192..b8019b12ba 100644 --- a/apps/openmw/mwinput/keyboardmanager.cpp +++ b/apps/openmw/mwinput/keyboardmanager.cpp @@ -60,7 +60,10 @@ namespace MWInput mBindingsManager->keyPressed(arg); if (!consumed) - MWBase::Environment::get().getLuaManager()->keyPressed(arg); + { + MWBase::Environment::get().getLuaManager()->inputEvent( + {MWBase::LuaManager::InputEvent::KeyPressed, arg.keysym}); + } input->setJoystickLastUsed(false); } @@ -73,5 +76,6 @@ namespace MWInput if (!mBindingsManager->isDetectingBindingState()) mBindingsManager->setPlayerControlsEnabled(!MyGUI::InputManager::getInstance().injectKeyRelease(kc)); mBindingsManager->keyReleased(arg); + MWBase::Environment::get().getLuaManager()->inputEvent({MWBase::LuaManager::InputEvent::KeyReleased, arg.keysym}); } } diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index cf151dfac7..7810a40ad2 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -34,6 +34,9 @@ namespace MWInput , mMouseWheel(0) , mMouseLookEnabled(false) , mGuiCursorEnabled(true) + , mButtonsState(0) + , mMouseMoveX(0) + , mMouseMoveY(0) { int w,h; SDL_GetWindowSize(window, &w, &h); @@ -196,6 +199,8 @@ namespace MWInput void MouseManager::update(float dt) { + mButtonsState = SDL_GetRelativeMouseState(&mMouseMoveX, &mMouseMoveY); + if (!mMouseLookEnabled) return; diff --git a/apps/openmw/mwinput/mousemanager.hpp b/apps/openmw/mwinput/mousemanager.hpp index 000e7cd0b6..d5504c5f5a 100644 --- a/apps/openmw/mwinput/mousemanager.hpp +++ b/apps/openmw/mwinput/mousemanager.hpp @@ -38,6 +38,10 @@ namespace MWInput void setMouseLookEnabled(bool enabled) { mMouseLookEnabled = enabled; } void setGuiCursorEnabled(bool enabled) { mGuiCursorEnabled = enabled; } + uint32_t getButtonsState() const { return mButtonsState; } + int getMouseMoveX() const { return mMouseMoveX; } + int getMouseMoveY() const { return mMouseMoveY; } + private: bool mInvertX; bool mInvertY; @@ -53,6 +57,10 @@ namespace MWInput int mMouseWheel; bool mMouseLookEnabled; bool mGuiCursorEnabled; + + uint32_t mButtonsState; + int mMouseMoveX; + int mMouseMoveY; }; } #endif diff --git a/apps/openmw/mwlua/inputbindings.cpp b/apps/openmw/mwlua/inputbindings.cpp new file mode 100644 index 0000000000..f815d9c344 --- /dev/null +++ b/apps/openmw/mwlua/inputbindings.cpp @@ -0,0 +1,150 @@ +#include "luabindings.hpp" + +#include +#include + +#include "../mwbase/inputmanager.hpp" +#include "../mwinput/actions.hpp" + +namespace sol +{ + template <> + struct is_automagical : std::false_type {}; +} + +namespace MWLua +{ + + sol::table initInputPackage(const Context& context) + { + sol::usertype keyEvent = context.mLua->sol().new_usertype("KeyEvent"); + keyEvent["symbol"] = sol::readonly_property([](const SDL_Keysym& e) { return std::string(1, static_cast(e.sym)); }); + keyEvent["code"] = sol::readonly_property([](const SDL_Keysym& e) -> int { return e.sym; }); + keyEvent["modifiers"] = sol::readonly_property([](const SDL_Keysym& e) -> int { return e.mod; }); + keyEvent["withShift"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_SHIFT; }); + keyEvent["withCtrl"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_CTRL; }); + keyEvent["withAlt"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_ALT; }); + keyEvent["withSuper"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_GUI; }); + + MWBase::InputManager* input = MWBase::Environment::get().getInputManager(); + sol::table api(context.mLua->sol(), sol::create); + + api["isIdle"] = [input]() { return input->isIdle(); }; + api["isActionPressed"] = [input](int action) { return input->actionIsActive(action); }; + api["isMouseButtonPressed"] = [input](int button) -> bool + { + return input->getMouseButtonsState() & (1 << (button - 1)); + }; + api["getMouseMoveX"] = [input]() { return input->getMouseMoveX(); }; + api["getMouseMoveY"] = [input]() { return input->getMouseMoveY(); }; + api["getAxisValue"] = [input](int axis) + { + if (axis < SDL_CONTROLLER_AXIS_MAX) + return input->getControllerAxisValue(static_cast(axis)); + else + return input->getActionValue(axis - SDL_CONTROLLER_AXIS_MAX) * 2 - 1; + }; + + api["getControlSwitch"] = [input](const std::string& key) { return input->getControlSwitch(key); }; + api["setControlSwitch"] = [input](const std::string& key, bool v) { input->toggleControlSwitch(key, v); }; + + api["ACTION"] = context.mLua->makeReadOnly(context.mLua->sol().create_table_with( + "GameMenu", MWInput::A_GameMenu, + "Screenshot", MWInput::A_Screenshot, + "Inventory", MWInput::A_Inventory, + "Console", MWInput::A_Console, + + "MoveLeft", MWInput::A_MoveLeft, + "MoveRight", MWInput::A_MoveRight, + "MoveForward", MWInput::A_MoveForward, + "MoveBackward", MWInput::A_MoveBackward, + + "Activate", MWInput::A_Activate, + "Use", MWInput::A_Use, + "Jump", MWInput::A_Jump, + "AutoMove", MWInput::A_AutoMove, + "Rest", MWInput::A_Rest, + "Journal", MWInput::A_Journal, + "Weapon", MWInput::A_Weapon, + "Spell", MWInput::A_Spell, + "Run", MWInput::A_Run, + "CycleSpellLeft", MWInput::A_CycleSpellLeft, + "CycleSpellRight", MWInput::A_CycleSpellRight, + "CycleWeaponLeft", MWInput::A_CycleWeaponLeft, + "CycleWeaponRight", MWInput::A_CycleWeaponRight, + "ToggleSneak", MWInput::A_ToggleSneak, + "AlwaysRun", MWInput::A_AlwaysRun, + "Sneak", MWInput::A_Sneak, + + "QuickSave", MWInput::A_QuickSave, + "QuickLoad", MWInput::A_QuickLoad, + "QuickMenu", MWInput::A_QuickMenu, + "ToggleWeapon", MWInput::A_ToggleWeapon, + "ToggleSpell", MWInput::A_ToggleSpell, + "TogglePOV", MWInput::A_TogglePOV, + + "QuickKey1", MWInput::A_QuickKey1, + "QuickKey2", MWInput::A_QuickKey2, + "QuickKey3", MWInput::A_QuickKey3, + "QuickKey4", MWInput::A_QuickKey4, + "QuickKey5", MWInput::A_QuickKey5, + "QuickKey6", MWInput::A_QuickKey6, + "QuickKey7", MWInput::A_QuickKey7, + "QuickKey8", MWInput::A_QuickKey8, + "QuickKey9", MWInput::A_QuickKey9, + "QuickKey10", MWInput::A_QuickKey10, + "QuickKeysMenu", MWInput::A_QuickKeysMenu, + + "ToggleHUD", MWInput::A_ToggleHUD, + "ToggleDebug", MWInput::A_ToggleDebug, + + "ZoomIn", MWInput::A_ZoomIn, + "ZoomOut", MWInput::A_ZoomOut + )); + + api["CONTROL_SWITCH"] = context.mLua->makeReadOnly(context.mLua->sol().create_table_with( + "Controls", "playercontrols", + "Fighting", "playerfighting", + "Jumping", "playerjumping", + "Looking", "playerlooking", + "Magic", "playermagic", + "ViewMode", "playerviewswitch", + "VanityMode", "vanitymode" + )); + + api["CONTROLLER_BUTTON"] = context.mLua->makeReadOnly(context.mLua->sol().create_table_with( + "A", SDL_CONTROLLER_BUTTON_A, + "B", SDL_CONTROLLER_BUTTON_B, + "X", SDL_CONTROLLER_BUTTON_X, + "Y", SDL_CONTROLLER_BUTTON_Y, + "Back", SDL_CONTROLLER_BUTTON_BACK, + "Guide", SDL_CONTROLLER_BUTTON_GUIDE, + "Start", SDL_CONTROLLER_BUTTON_START, + "LeftStick", SDL_CONTROLLER_BUTTON_LEFTSTICK, + "RightStick", SDL_CONTROLLER_BUTTON_RIGHTSTICK, + "LeftShoulder", SDL_CONTROLLER_BUTTON_LEFTSHOULDER, + "RightShoulder", SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, + "DPadUp", SDL_CONTROLLER_BUTTON_DPAD_UP, + "DPadDown", SDL_CONTROLLER_BUTTON_DPAD_DOWN, + "DPadLeft", SDL_CONTROLLER_BUTTON_DPAD_LEFT, + "DPadRight", SDL_CONTROLLER_BUTTON_DPAD_RIGHT + )); + + api["CONTROLLER_AXIS"] = context.mLua->makeReadOnly(context.mLua->sol().create_table_with( + "LeftX", SDL_CONTROLLER_AXIS_LEFTX, + "LeftY", SDL_CONTROLLER_AXIS_LEFTY, + "RightX", SDL_CONTROLLER_AXIS_RIGHTX, + "RightY", SDL_CONTROLLER_AXIS_RIGHTY, + "TriggerLeft", SDL_CONTROLLER_AXIS_TRIGGERLEFT, + "TriggerRight", SDL_CONTROLLER_AXIS_TRIGGERRIGHT, + + "LookUpDown", SDL_CONTROLLER_AXIS_MAX + MWInput::A_LookUpDown, + "LookLeftRight", SDL_CONTROLLER_AXIS_MAX + MWInput::A_LookLeftRight, + "MoveForwardBackward", SDL_CONTROLLER_AXIS_MAX + MWInput::A_MoveForwardBackward, + "MoveLeftRight", SDL_CONTROLLER_AXIS_MAX + MWInput::A_MoveLeftRight + )); + + return context.mLua->makeReadOnly(api); + } + +} diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index 9d978ddd52..e50af836b5 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -1,7 +1,5 @@ #include "luabindings.hpp" -#include - #include #include @@ -12,12 +10,6 @@ #include "eventqueue.hpp" #include "worldview.hpp" -namespace sol -{ - template <> - struct is_automagical : std::false_type {}; -} - namespace MWLua { @@ -33,7 +25,7 @@ namespace MWLua { auto* lua = context.mLua; sol::table api(lua->sol(), sol::create); - api["API_REVISION"] = 3; + api["API_REVISION"] = 4; api["quit"] = [lua]() { std::string traceback = lua->sol()["debug"]["traceback"]().get(); @@ -179,17 +171,5 @@ namespace MWLua return context.mLua->makeReadOnly(res); } - void initInputBindings(const Context& context) - { - sol::usertype keyEvent = context.mLua->sol().new_usertype("KeyEvent"); - keyEvent["symbol"] = sol::readonly_property([](const SDL_Keysym& e) { return std::string(1, static_cast(e.sym)); }); - keyEvent["code"] = sol::readonly_property([](const SDL_Keysym& e) -> int { return e.sym; }); - keyEvent["modifiers"] = sol::readonly_property([](const SDL_Keysym& e) -> int { return e.mod; }); - keyEvent["withShift"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_SHIFT; }); - keyEvent["withCtrl"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_CTRL; }); - keyEvent["withAlt"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_ALT; }); - keyEvent["withSuper"] = sol::readonly_property([](const SDL_Keysym& e) -> bool { return e.mod & KMOD_GUI; }); - } - } diff --git a/apps/openmw/mwlua/luabindings.hpp b/apps/openmw/mwlua/luabindings.hpp index 568eb4e1ef..c58b556a3d 100644 --- a/apps/openmw/mwlua/luabindings.hpp +++ b/apps/openmw/mwlua/luabindings.hpp @@ -26,8 +26,6 @@ namespace MWLua sol::table initFieldGroup(const Context&, const QueryFieldGroup&); - void initInputBindings(const Context&); - // Implemented in objectbindings.cpp void initObjectBindingsForLocalScripts(const Context&); void initObjectBindingsForGlobalScripts(const Context&); @@ -59,6 +57,9 @@ namespace MWLua // Implemented in uibindings.cpp sol::table initUserInterfacePackage(const Context&); + // Implemented in inputbindings.cpp + sol::table initInputPackage(const Context&); + // Implemented in settingsbindings.cpp sol::table initGlobalSettingsPackage(const Context&); sol::table initLocalSettingsPackage(const Context&); diff --git a/apps/openmw/mwlua/luamanagerimp.cpp b/apps/openmw/mwlua/luamanagerimp.cpp index bbfe0b8c3a..d358979aec 100644 --- a/apps/openmw/mwlua/luamanagerimp.cpp +++ b/apps/openmw/mwlua/luamanagerimp.cpp @@ -53,7 +53,6 @@ namespace MWLua initObjectBindingsForLocalScripts(localContext); initCellBindingsForLocalScripts(localContext); LocalScripts::initializeSelfPackage(localContext); - initInputBindings(localContext); mLua.addCommonPackage("openmw.async", getAsyncPackageInitializer(context)); mLua.addCommonPackage("openmw.util", LuaUtil::initUtilPackage(mLua.sol())); @@ -63,11 +62,12 @@ namespace MWLua mGlobalScripts.addPackage("openmw.settings", initGlobalSettingsPackage(context)); mCameraPackage = initCameraPackage(localContext); mUserInterfacePackage = initUserInterfacePackage(localContext); + mInputPackage = initInputPackage(localContext); mNearbyPackage = initNearbyPackage(localContext); mLocalSettingsPackage = initLocalSettingsPackage(localContext); mPlayerSettingsPackage = initPlayerSettingsPackage(localContext); - mKeyPressEvents.clear(); + mInputEvents.clear(); for (const std::string& path : mGlobalScriptList) if (mGlobalScripts.addNewScript(path)) Log(Debug::Info) << "Global script started: " << path; @@ -93,7 +93,7 @@ namespace MWLua if (paused) { - mKeyPressEvents.clear(); + mInputEvents.clear(); return; } @@ -130,10 +130,10 @@ namespace MWLua PlayerScripts* playerScripts = dynamic_cast(mPlayer.getRefData().getLuaScripts()); if (playerScripts) { - for (const SDL_Keysym& key : mKeyPressEvents) - playerScripts->keyPress(key); + for (const auto& event : mInputEvents) + playerScripts->processInputEvent(event); } - mKeyPressEvents.clear(); + mInputEvents.clear(); for (const LocalEngineEvent& e : mLocalEngineEvents) { @@ -187,7 +187,7 @@ namespace MWLua mActiveLocalScripts.clear(); mLocalEvents.clear(); mGlobalEvents.clear(); - mKeyPressEvents.clear(); + mInputEvents.clear(); mActorAddedEvents.clear(); mLocalEngineEvents.clear(); mPlayerChanged = false; @@ -253,11 +253,6 @@ namespace MWLua mWorldView.getObjectRegistry()->deregisterPtr(ptr); } - void LuaManager::keyPressed(const SDL_KeyboardEvent& arg) - { - mKeyPressEvents.push_back(arg.keysym); - } - void LuaManager::appliedToObject(const MWWorld::Ptr& toPtr, std::string_view recordId, const MWWorld::Ptr& fromPtr) { mLocalEngineEvents.push_back({getId(toPtr), LocalScripts::OnConsume{std::string(recordId)}}); @@ -294,6 +289,7 @@ namespace MWLua scripts = std::make_shared(&mLua, LObject(getId(ptr), mWorldView.getObjectRegistry())); scripts->addPackage("openmw.ui", mUserInterfacePackage); scripts->addPackage("openmw.camera", mCameraPackage); + scripts->addPackage("openmw.input", mInputPackage); scripts->addPackage("openmw.settings", mPlayerSettingsPackage); } else diff --git a/apps/openmw/mwlua/luamanagerimp.hpp b/apps/openmw/mwlua/luamanagerimp.hpp index 48cdeba026..8fdfb02701 100644 --- a/apps/openmw/mwlua/luamanagerimp.hpp +++ b/apps/openmw/mwlua/luamanagerimp.hpp @@ -41,7 +41,7 @@ namespace MWLua void objectRemovedFromScene(const MWWorld::Ptr& ptr) override; void registerObject(const MWWorld::Ptr& ptr) override; void deregisterObject(const MWWorld::Ptr& ptr) override; - void keyPressed(const SDL_KeyboardEvent &arg) override; + void inputEvent(const InputEvent& event) override { mInputEvents.push_back(event); } void appliedToObject(const MWWorld::Ptr& toPtr, std::string_view recordId, const MWWorld::Ptr& fromPtr) override; MWBase::LuaManager::ActorControls* getActorControls(const MWWorld::Ptr&) const override; @@ -75,6 +75,7 @@ namespace MWLua sol::table mNearbyPackage; sol::table mUserInterfacePackage; sol::table mCameraPackage; + sol::table mInputPackage; sol::table mLocalSettingsPackage; sol::table mPlayerSettingsPackage; @@ -96,7 +97,7 @@ namespace MWLua std::unique_ptr mGlobalLoader; std::unique_ptr mLocalLoader; - std::vector mKeyPressEvents; + std::vector mInputEvents; std::vector mActorAddedEvents; struct LocalEngineEvent diff --git a/apps/openmw/mwlua/playerscripts.hpp b/apps/openmw/mwlua/playerscripts.hpp index 72e064bb9b..ff0349b3c6 100644 --- a/apps/openmw/mwlua/playerscripts.hpp +++ b/apps/openmw/mwlua/playerscripts.hpp @@ -3,6 +3,8 @@ #include +#include "../mwbase/luamanager.hpp" + #include "localscripts.hpp" namespace MWLua @@ -13,13 +15,40 @@ namespace MWLua public: PlayerScripts(LuaUtil::LuaState* lua, const LObject& obj) : LocalScripts(lua, obj) { - registerEngineHandlers({&mKeyPressHandlers}); + registerEngineHandlers({&mKeyPressHandlers, &mKeyReleaseHandlers, + &mControllerButtonPressHandlers, &mControllerButtonReleaseHandlers, + &mActionHandlers}); } - void keyPress(const SDL_Keysym& key) { callEngineHandlers(mKeyPressHandlers, key); } + void processInputEvent(const MWBase::LuaManager::InputEvent& event) + { + using InputEvent = MWBase::LuaManager::InputEvent; + switch (event.mType) + { + case InputEvent::KeyPressed: + callEngineHandlers(mKeyPressHandlers, std::get(event.mValue)); + break; + case InputEvent::KeyReleased: + callEngineHandlers(mKeyReleaseHandlers, std::get(event.mValue)); + break; + case InputEvent::ControllerPressed: + callEngineHandlers(mControllerButtonPressHandlers, std::get(event.mValue)); + break; + case InputEvent::ControllerReleased: + callEngineHandlers(mControllerButtonReleaseHandlers, std::get(event.mValue)); + break; + case InputEvent::Action: + callEngineHandlers(mActionHandlers, std::get(event.mValue)); + break; + } + } private: EngineHandlerList mKeyPressHandlers{"onKeyPress"}; + EngineHandlerList mKeyReleaseHandlers{"onKeyRelease"}; + EngineHandlerList mControllerButtonPressHandlers{"onControllerButtonPress"}; + EngineHandlerList mControllerButtonReleaseHandlers{"onControllerButtonRelease"}; + EngineHandlerList mActionHandlers{"onInputAction"}; }; } diff --git a/docs/source/reference/lua-scripting/api.rst b/docs/source/reference/lua-scripting/api.rst index 356fc16cbb..5075f8a5fe 100644 --- a/docs/source/reference/lua-scripting/api.rst +++ b/docs/source/reference/lua-scripting/api.rst @@ -14,6 +14,7 @@ Lua API reference openmw_world openmw_self openmw_nearby + openmw_input openmw_ui openmw_aux_util @@ -53,6 +54,8 @@ Player scripts are local scripts that are attached to a player. +---------------------------------------------------------+--------------------+---------------------------------------------------------------+ |:ref:`openmw.nearby ` | by local scripts | | Read-only access to the nearest area of the game world. | +---------------------------------------------------------+--------------------+---------------------------------------------------------------+ +|:ref:`openmw.input ` | by player scripts | | User input | ++---------------------------------------------------------+--------------------+---------------------------------------------------------------+ |:ref:`openmw.ui ` | by player scripts | | Controls user interface | +---------------------------------------------------------+--------------------+---------------------------------------------------------------+ |openmw.camera | by player scripts | | Controls camera (not implemented) | diff --git a/docs/source/reference/lua-scripting/engine_handlers.rst b/docs/source/reference/lua-scripting/engine_handlers.rst index f08892be36..bcbee4349e 100644 --- a/docs/source/reference/lua-scripting/engine_handlers.rst +++ b/docs/source/reference/lua-scripting/engine_handlers.rst @@ -36,8 +36,21 @@ Engine handler is a function defined by a script, that can be called by the engi +----------------------------------+----------------------------------------------------------------------+ | **Only for local scripts attached to a player** | +----------------------------------+----------------------------------------------------------------------+ -| onKeyPress(key) | | `Key `_ pressed. Usage example: | -| | | ``if key.symbol == 'z' and key.withShift then ...`` | +| onKeyPress(key) | | `Key `_ is pressed. | +| | | Usage example: ``if key.symbol == 'z' and key.withShift then ...`` | ++----------------------------------+----------------------------------------------------------------------+ +| onKeyRelease(key) | | `Key `_ is released. | +| | | Usage example: ``if key.symbol == 'z' and key.withShift then ...`` | ++----------------------------------+----------------------------------------------------------------------+ +| onControllerButtonPress(id) | | A `button `_ on a game | +| | controller is pressed. Usage example: | +| | | ``if id == input.CONTROLLER_BUTTON.LeftStick then ...`` | ++----------------------------------+----------------------------------------------------------------------+ +| onControllerButtonRelease(id) | | A `button `_ on a game | +| | controller is released. Usage example: | +| | | ``if id == input.CONTROLLER_BUTTON.LeftStick then ...`` | ++----------------------------------+----------------------------------------------------------------------+ +| onInputAction(id) | | `Game control `_ is pressed. | +| | | Usage example: ``if id == input.ACTION.ToggleWeapon then ...`` | +----------------------------------+----------------------------------------------------------------------+ - diff --git a/docs/source/reference/lua-scripting/openmw_input.rst b/docs/source/reference/lua-scripting/openmw_input.rst new file mode 100644 index 0000000000..39136dc4c2 --- /dev/null +++ b/docs/source/reference/lua-scripting/openmw_input.rst @@ -0,0 +1,6 @@ +Package openmw.input +==================== + +.. raw:: html + :file: generated_html/openmw_input.html + diff --git a/docs/source/reference/lua-scripting/overview.rst b/docs/source/reference/lua-scripting/overview.rst index c193886340..44c79c35d8 100644 --- a/docs/source/reference/lua-scripting/overview.rst +++ b/docs/source/reference/lua-scripting/overview.rst @@ -314,6 +314,8 @@ Player scripts are local scripts that are attached to a player. +---------------------------------------------------------+--------------------+---------------------------------------------------------------+ |:ref:`openmw.nearby ` | by local scripts | | Read-only access to the nearest area of the game world. | +---------------------------------------------------------+--------------------+---------------------------------------------------------------+ +|:ref:`openmw.input ` | by player scripts | | User input | ++---------------------------------------------------------+--------------------+---------------------------------------------------------------+ |:ref:`openmw.ui ` | by player scripts | | Controls user interface | +---------------------------------------------------------+--------------------+---------------------------------------------------------------+ |openmw.camera | by player scripts | | Controls camera (not implemented) | diff --git a/files/lua_api/openmw/core.lua b/files/lua_api/openmw/core.lua index affd052700..eed2005cfa 100644 --- a/files/lua_api/openmw/core.lua +++ b/files/lua_api/openmw/core.lua @@ -318,15 +318,5 @@ -- @return #ObjectList -------------------------------------------------------------------------------- --- Argument of `onKeyPress` engine handler --- @type KeyboardEvent --- @field [parent=#KeyboardEvent] #string symbol The pressed symbol (1-symbol string). --- @field [parent=#KeyboardEvent] #string code Key code. --- @field [parent=#KeyboardEvent] #boolean withShift Is `Shift` key pressed. --- @field [parent=#KeyboardEvent] #boolean withCtrl Is `Control` key pressed. --- @field [parent=#KeyboardEvent] #boolean withAlt Is `Alt` key pressed. --- @field [parent=#KeyboardEvent] #boolean withSuper Is `Super`/`Win` key pressed. - return nil diff --git a/files/lua_api/openmw/input.lua b/files/lua_api/openmw/input.lua new file mode 100644 index 0000000000..0975ce6e6a --- /dev/null +++ b/files/lua_api/openmw/input.lua @@ -0,0 +1,170 @@ +------------------------------------------------------------------------------- +-- `openmw.input` can be used only in scripts attached to a player. +-- @module input +-- @usage local input = require('openmw.input') + + + +------------------------------------------------------------------------------- +-- Is player idle. +-- @function [parent=#input] isIdle +-- @return #boolean + +------------------------------------------------------------------------------- +-- Is a specific control currently pressed. +-- Input bindings can be changed ingame using Options/Controls menu. +-- @function [parent=#input] isActionPressed +-- @param #number actionId One of @{openmw.input#ACTION} +-- @return #boolean + +------------------------------------------------------------------------------- +-- Is a mouse button currently pressed. +-- @function [parent=#input] isMouseButtonPressed +-- @param #number buttonId Button index (1 - left, 2 - middle, 3 - right, 4 - X1, 5 - X2) +-- @return #boolean + +------------------------------------------------------------------------------- +-- Horizontal mouse movement during the last frame. +-- @function [parent=#input] getMouseMoveX +-- @return #number + +------------------------------------------------------------------------------- +-- Vertical mouse movement during the last frame. +-- @function [parent=#input] getMouseMoveY +-- @return #number + +------------------------------------------------------------------------------- +-- Get value of an axis of a game controller. +-- @function [parent=#input] getAxisValue +-- @param #number axisId Index of a controller axis, one of @{openmw.input#CONTROLLER_AXIS}. +-- @return #number Value in range [-1, 1]. + +------------------------------------------------------------------------------- +-- Get state of a control switch. I.e. is player able to move/fight/jump/etc. +-- @function [parent=#input] getControlSwitch +-- @param #string key Control type (see @{openmw.input#CONTROL_SWITCH}) +-- @return #boolean + +------------------------------------------------------------------------------- +-- Set state of a control switch. I.e. forbid or allow player to move/fight/jump/etc. +-- @function [parent=#input] setControlSwitch +-- @param #string key Control type (see @{openmw.input#CONTROL_SWITCH}) +-- @param #boolean value + +------------------------------------------------------------------------------- +-- @type CONTROL_SWITCH +-- @field [parent=#CONTROL_SWITCH] #string Controls Ability to move +-- @field [parent=#CONTROL_SWITCH] #string Fighting Ability to attack +-- @field [parent=#CONTROL_SWITCH] #string Jumping Ability to jump +-- @field [parent=#CONTROL_SWITCH] #string Looking Ability to change view direction +-- @field [parent=#CONTROL_SWITCH] #string Magic Ability to use magic +-- @field [parent=#CONTROL_SWITCH] #string ViewMode Ability to toggle 1st/3rd person view +-- @field [parent=#CONTROL_SWITCH] #string VanityMode Vanity view if player doesn't touch controls for a long time + +------------------------------------------------------------------------------- +-- Values that can be used with getControlSwitch/setControlSwitch. +-- @field [parent=#input] #CONTROL_SWITCH CONTROL_SWITCH + +------------------------------------------------------------------------------- +-- @type ACTION +-- @field [parent=#ACTION] #number GameMenu +-- @field [parent=#ACTION] #number Screenshot +-- @field [parent=#ACTION] #number Inventory +-- @field [parent=#ACTION] #number Console +-- @field [parent=#ACTION] #number MoveLeft +-- @field [parent=#ACTION] #number MoveRight +-- @field [parent=#ACTION] #number MoveForward +-- @field [parent=#ACTION] #number MoveBackward +-- @field [parent=#ACTION] #number Activate +-- @field [parent=#ACTION] #number Use +-- @field [parent=#ACTION] #number Jump +-- @field [parent=#ACTION] #number AutoMove +-- @field [parent=#ACTION] #number Journal +-- @field [parent=#ACTION] #number Weapon +-- @field [parent=#ACTION] #number Spell +-- @field [parent=#ACTION] #number Run +-- @field [parent=#ACTION] #number CycleSpellLeft +-- @field [parent=#ACTION] #number CycleSpellRight +-- @field [parent=#ACTION] #number CycleWeaponLeft +-- @field [parent=#ACTION] #number CycleWeaponRight +-- @field [parent=#ACTION] #number ToggleSneak +-- @field [parent=#ACTION] #number AlwaysRun +-- @field [parent=#ACTION] #number Sneak +-- @field [parent=#ACTION] #number QuickSave +-- @field [parent=#ACTION] #number QuickLoad +-- @field [parent=#ACTION] #number QuickMenu +-- @field [parent=#ACTION] #number ToggleWeapon +-- @field [parent=#ACTION] #number ToggleSpell +-- @field [parent=#ACTION] #number TogglePOV +-- @field [parent=#ACTION] #number QuickKey1 +-- @field [parent=#ACTION] #number QuickKey2 +-- @field [parent=#ACTION] #number QuickKey3 +-- @field [parent=#ACTION] #number QuickKey4 +-- @field [parent=#ACTION] #number QuickKey5 +-- @field [parent=#ACTION] #number QuickKey6 +-- @field [parent=#ACTION] #number QuickKey7 +-- @field [parent=#ACTION] #number QuickKey8 +-- @field [parent=#ACTION] #number QuickKey9 +-- @field [parent=#ACTION] #number QuickKey10 +-- @field [parent=#ACTION] #number QuickKeysMenu +-- @field [parent=#ACTION] #number ToggleHUD +-- @field [parent=#ACTION] #number ToggleDebug +-- @field [parent=#ACTION] #number ZoomIn +-- @field [parent=#ACTION] #number ZoomOut + +------------------------------------------------------------------------------- +-- Values that can be used with isActionPressed. +-- @field [parent=#input] #ACTION ACTION + +------------------------------------------------------------------------------- +-- @type CONTROLLER_BUTTON +-- @field [parent=#CONTROLLER_BUTTON] #number A +-- @field [parent=#CONTROLLER_BUTTON] #number B +-- @field [parent=#CONTROLLER_BUTTON] #number X +-- @field [parent=#CONTROLLER_BUTTON] #number Y +-- @field [parent=#CONTROLLER_BUTTON] #number Back +-- @field [parent=#CONTROLLER_BUTTON] #number Guide +-- @field [parent=#CONTROLLER_BUTTON] #number Start +-- @field [parent=#CONTROLLER_BUTTON] #number LeftStick +-- @field [parent=#CONTROLLER_BUTTON] #number RightStick +-- @field [parent=#CONTROLLER_BUTTON] #number LeftShoulder +-- @field [parent=#CONTROLLER_BUTTON] #number RightShoulder +-- @field [parent=#CONTROLLER_BUTTON] #number DPadUp +-- @field [parent=#CONTROLLER_BUTTON] #number DPadDown +-- @field [parent=#CONTROLLER_BUTTON] #number DPadLeft +-- @field [parent=#CONTROLLER_BUTTON] #number DPadRight + +------------------------------------------------------------------------------- +-- Values that can be passed to onControllerButtonPress/onControllerButtonRelease engine handlers. +-- @field [parent=#input] #CONTROLLER_BUTTON CONTROLLER_BUTTON + +------------------------------------------------------------------------------- +-- Ids of game controller axises. Used as an argument in getAxisValue. +-- @type CONTROLLER_AXIS +-- @field [parent=#CONTROLLER_AXIS] #number LeftX Left stick horizontal axis (from -1 to 1) +-- @field [parent=#CONTROLLER_AXIS] #number LeftY Left stick vertical axis (from -1 to 1) +-- @field [parent=#CONTROLLER_AXIS] #number RightX Right stick horizontal axis (from -1 to 1) +-- @field [parent=#CONTROLLER_AXIS] #number RightY Right stick vertical axis (from -1 to 1) +-- @field [parent=#CONTROLLER_AXIS] #number TriggerLeft Left trigger (from 0 to 1) +-- @field [parent=#CONTROLLER_AXIS] #number TriggerRight Right trigger (from 0 to 1) +-- @field [parent=#CONTROLLER_AXIS] #number LookUpDown View direction vertical axis (RightY by default, can be mapped to another axis in Options/Controls menu) +-- @field [parent=#CONTROLLER_AXIS] #number LookLeftRight View direction horizontal axis (RightX by default, can be mapped to another axis in Options/Controls menu) +-- @field [parent=#CONTROLLER_AXIS] #number MoveForwardBackward Movement forward/backward (LeftY by default, can be mapped to another axis in Options/Controls menu) +-- @field [parent=#CONTROLLER_AXIS] #number MoveLeftRight Side movement (LeftX by default, can be mapped to another axis in Options/Controls menu) + +------------------------------------------------------------------------------- +-- Values that can be used with getAxisValue. +-- @field [parent=#input] #CONTROLLER_AXIS CONTROLLER_AXIS + +------------------------------------------------------------------------------- +-- The argument of `onKeyPress`/`onKeyRelease` engine handlers. +-- @type KeyboardEvent +-- @field [parent=#KeyboardEvent] #string symbol The pressed symbol (1-symbol string). +-- @field [parent=#KeyboardEvent] #string code Key code. +-- @field [parent=#KeyboardEvent] #boolean withShift Is `Shift` key pressed. +-- @field [parent=#KeyboardEvent] #boolean withCtrl Is `Control` key pressed. +-- @field [parent=#KeyboardEvent] #boolean withAlt Is `Alt` key pressed. +-- @field [parent=#KeyboardEvent] #boolean withSuper Is `Super`/`Win` key pressed. + +return nil +