diff --git a/apps/openmw/mwbase/inputmanager.hpp b/apps/openmw/mwbase/inputmanager.hpp index 5ac7c218b5..d475d93cd1 100644 --- a/apps/openmw/mwbase/inputmanager.hpp +++ b/apps/openmw/mwbase/inputmanager.hpp @@ -49,8 +49,8 @@ namespace MWBase virtual void setGamepadGuiCursorEnabled(bool enabled) = 0; virtual void setAttemptJump(bool jumping) = 0; - virtual void toggleControlSwitch (const std::string& sw, bool value) = 0; - virtual bool getControlSwitch (const std::string& sw) = 0; + virtual void toggleControlSwitch(std::string_view sw, bool value) = 0; + virtual bool getControlSwitch(std::string_view sw) = 0; virtual std::string getActionDescription (int action) const = 0; virtual std::string getActionKeyBindingName (int action) const = 0; @@ -58,8 +58,8 @@ namespace MWBase virtual bool actionIsActive(int action) const = 0; virtual float getActionValue(int action) const = 0; // returns value in range [0, 1] + virtual bool isControllerButtonPressed(SDL_GameControllerButton button) const = 0; 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; diff --git a/apps/openmw/mwinput/bindingsmanager.cpp b/apps/openmw/mwinput/bindingsmanager.cpp index ca7911ecc2..f3e1ba2c8d 100644 --- a/apps/openmw/mwinput/bindingsmanager.cpp +++ b/apps/openmw/mwinput/bindingsmanager.cpp @@ -653,14 +653,13 @@ namespace MWInput return mInputBinder->getKeyBinding(mInputBinder->getControl(actionId), ICS::Control::INCREASE); } - float BindingsManager::getControllerAxisValue(SDL_GameControllerAxis axis) const + SDL_GameController* BindingsManager::getControllerOrNull() 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); + return nullptr; + else + return controllers.begin()->second; } void BindingsManager::actionValueChanged(int action, float currentValue, float previousValue) diff --git a/apps/openmw/mwinput/bindingsmanager.hpp b/apps/openmw/mwinput/bindingsmanager.hpp index 5c653f0b3e..668cccd4ca 100644 --- a/apps/openmw/mwinput/bindingsmanager.hpp +++ b/apps/openmw/mwinput/bindingsmanager.hpp @@ -43,7 +43,8 @@ namespace MWInput bool actionIsActive(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] + + SDL_GameController* getControllerOrNull() const; 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 bdb46e31a8..07aa89f554 100644 --- a/apps/openmw/mwinput/controllermanager.cpp +++ b/apps/openmw/mwinput/controllermanager.cpp @@ -403,4 +403,24 @@ namespace MWInput return true; } + + float ControllerManager::getAxisValue(SDL_GameControllerAxis axis) const + { + SDL_GameController* cntrl = mBindingsManager->getControllerOrNull(); + constexpr int AXIS_MAX_ABSOLUTE_VALUE = 32768; + if (cntrl) + return SDL_GameControllerGetAxis(cntrl, axis) / static_cast(AXIS_MAX_ABSOLUTE_VALUE); + else + return 0; + } + + bool ControllerManager::isButtonPressed(SDL_GameControllerButton button) const + { + SDL_GameController* cntrl = mBindingsManager->getControllerOrNull(); + if (cntrl) + return SDL_GameControllerGetButton(cntrl, button) > 0; + else + return false; + } + } diff --git a/apps/openmw/mwinput/controllermanager.hpp b/apps/openmw/mwinput/controllermanager.hpp index d8c62d57c4..1e8ef90d0e 100644 --- a/apps/openmw/mwinput/controllermanager.hpp +++ b/apps/openmw/mwinput/controllermanager.hpp @@ -34,12 +34,15 @@ namespace MWInput void processChangedSettings(const Settings::CategorySettingVector& changed); void setJoystickLastUsed(bool enabled) { mJoystickLastUsed = enabled; } - bool joystickLastUsed() { return mJoystickLastUsed; } + bool joystickLastUsed() const { return mJoystickLastUsed; } void setGuiCursorEnabled(bool enabled) { mGuiCursorEnabled = enabled; } void setGamepadGuiCursorEnabled(bool enabled) { mGamepadGuiCursorEnabled = enabled; } - bool gamepadGuiCursorEnabled() { return mGamepadGuiCursorEnabled; } + bool gamepadGuiCursorEnabled() const { return mGamepadGuiCursorEnabled; } + + float getAxisValue(SDL_GameControllerAxis axis) const; // returns value in range [-1, 1] + bool isButtonPressed(SDL_GameControllerButton button) const; private: // Return true if GUI consumes input. diff --git a/apps/openmw/mwinput/controlswitch.cpp b/apps/openmw/mwinput/controlswitch.cpp index f31744fca6..63d142434e 100644 --- a/apps/openmw/mwinput/controlswitch.cpp +++ b/apps/openmw/mwinput/controlswitch.cpp @@ -29,12 +29,15 @@ namespace MWInput mSwitches["vanitymode"] = true; } - bool ControlSwitch::get(const std::string& key) + bool ControlSwitch::get(std::string_view key) { - return mSwitches[key]; + auto it = mSwitches.find(key); + if (it == mSwitches.end()) + throw std::runtime_error("Incorrect ControlSwitch: " + std::string(key)); + return it->second; } - void ControlSwitch::set(const std::string& key, bool value) + void ControlSwitch::set(std::string_view key, bool value) { MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); @@ -59,7 +62,10 @@ namespace MWInput { MWBase::Environment::get().getWorld()->rotateObject(player.getPlayer(), osg::Vec3f()); } - mSwitches[key] = value; + auto it = mSwitches.find(key); + if (it == mSwitches.end()) + throw std::runtime_error("Incorrect ControlSwitch: " + std::string(key)); + it->second = value; } void ControlSwitch::write(ESM::ESMWriter& writer, Loading::Listener& /*progress*/) diff --git a/apps/openmw/mwinput/controlswitch.hpp b/apps/openmw/mwinput/controlswitch.hpp index 38d01066bd..b4353c31f5 100644 --- a/apps/openmw/mwinput/controlswitch.hpp +++ b/apps/openmw/mwinput/controlswitch.hpp @@ -3,6 +3,7 @@ #include #include +#include namespace ESM { @@ -23,8 +24,8 @@ namespace MWInput public: ControlSwitch(); - bool get(const std::string& key); - void set(const std::string& key, bool value); + bool get(std::string_view key); + void set(std::string_view key, bool value); void clear(); void write(ESM::ESMWriter& writer, Loading::Listener& progress); @@ -32,7 +33,7 @@ namespace MWInput int countSavedGameRecords() const; private: - std::map mSwitches; + std::map> mSwitches; }; } #endif diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 31f515afb0..cf1b0e936d 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -135,12 +135,12 @@ namespace MWInput mSensorManager->processChangedSettings(changed); } - bool InputManager::getControlSwitch(const std::string& sw) + bool InputManager::getControlSwitch(std::string_view sw) { return mControlSwitch->get(sw); } - void InputManager::toggleControlSwitch(const std::string& sw, bool value) + void InputManager::toggleControlSwitch(std::string_view sw, bool value) { mControlSwitch->set(sw, value); } @@ -180,14 +180,14 @@ namespace MWInput return mBindingsManager->getActionValue(action); } - float InputManager::getControllerAxisValue(SDL_GameControllerAxis axis) const + bool InputManager::isControllerButtonPressed(SDL_GameControllerButton button) const { - return mBindingsManager->getControllerAxisValue(axis); + return mControllerManager->isButtonPressed(button); } - uint32_t InputManager::getMouseButtonsState() const + float InputManager::getControllerAxisValue(SDL_GameControllerAxis axis) const { - return mMouseManager->getButtonsState(); + return mControllerManager->getAxisValue(axis); } int InputManager::getMouseMoveX() const diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index adb8319498..41478d5dcb 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -70,8 +70,8 @@ namespace MWInput void setGamepadGuiCursorEnabled(bool enabled) override; void setAttemptJump(bool jumping) override; - void toggleControlSwitch (const std::string& sw, bool value) override; - bool getControlSwitch (const std::string& sw) override; + void toggleControlSwitch(std::string_view sw, bool value) override; + bool getControlSwitch(std::string_view sw) override; std::string getActionDescription (int action) const override; std::string getActionKeyBindingName (int action) const override; @@ -79,8 +79,8 @@ namespace MWInput bool actionIsActive(int action) const override; float getActionValue(int action) const override; + bool isControllerButtonPressed(SDL_GameControllerButton button) const override; float getControllerAxisValue(SDL_GameControllerAxis axis) const override; - uint32_t getMouseButtonsState() const override; int getMouseMoveX() const override; int getMouseMoveY() const override; diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index f2bd4505d1..6fbe8cfc98 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -34,7 +34,6 @@ namespace MWInput , mMouseWheel(0) , mMouseLookEnabled(false) , mGuiCursorEnabled(true) - , mButtonsState(0) , mMouseMoveX(0) , mMouseMoveY(0) { @@ -199,7 +198,7 @@ namespace MWInput void MouseManager::update(float dt) { - mButtonsState = SDL_GetRelativeMouseState(&mMouseMoveX, &mMouseMoveY); + SDL_GetRelativeMouseState(&mMouseMoveX, &mMouseMoveY); if (!mMouseLookEnabled) return; diff --git a/apps/openmw/mwinput/mousemanager.hpp b/apps/openmw/mwinput/mousemanager.hpp index d5504c5f5a..16ea56d62b 100644 --- a/apps/openmw/mwinput/mousemanager.hpp +++ b/apps/openmw/mwinput/mousemanager.hpp @@ -38,7 +38,6 @@ 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; } @@ -58,7 +57,6 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; - uint32_t mButtonsState; int mMouseMoveX; int mMouseMoveY; }; diff --git a/apps/openmw/mwlua/inputbindings.cpp b/apps/openmw/mwlua/inputbindings.cpp index aaa00f3da9..b528d1b563 100644 --- a/apps/openmw/mwlua/inputbindings.cpp +++ b/apps/openmw/mwlua/inputbindings.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwbase/inputmanager.hpp" #include "../mwinput/actions.hpp" @@ -18,9 +19,14 @@ 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["symbol"] = sol::readonly_property([](const SDL_Keysym& e) + { + if (e.sym > 0 && e.sym <= 255) + return std::string(1, static_cast(e.sym)); + else + return std::string(); + }); + keyEvent["code"] = sol::readonly_property([](const SDL_Keysym& e) -> int { return e.scancode; }); 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; }); @@ -31,9 +37,26 @@ namespace MWLua api["isIdle"] = [input]() { return input->isIdle(); }; api["isActionPressed"] = [input](int action) { return input->actionIsActive(action); }; + api["isKeyPressed"] = [input](SDL_Scancode code) -> bool + { + int maxCode; + const auto* state = SDL_GetKeyboardState(&maxCode); + if (code >= 0 && code < maxCode) + return state[code] != 0; + else + return false; + }; + api["isShiftPressed"] = [input]() -> bool { return SDL_GetModState() & KMOD_SHIFT; }; + api["isCtrlPressed"] = [input]() -> bool { return SDL_GetModState() & KMOD_CTRL; }; + api["isAltPressed"] = [input]() -> bool { return SDL_GetModState() & KMOD_ALT; }; + api["isSuperPressed"] = [input]() -> bool { return SDL_GetModState() & KMOD_GUI; }; + api["isControllerButtonPressed"] = [input](int button) + { + return input->isControllerButtonPressed(static_cast(button)); + }; api["isMouseButtonPressed"] = [input](int button) -> bool { - return input->getMouseButtonsState() & (1 << (button - 1)); + return SDL_GetMouseState(nullptr, nullptr) & SDL_BUTTON(button); }; api["getMouseMoveX"] = [input]() { return input->getMouseMoveX(); }; api["getMouseMoveY"] = [input]() { return input->getMouseMoveY(); }; @@ -45,8 +68,8 @@ namespace MWLua 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["getControlSwitch"] = [input](std::string_view key) { return input->getControlSwitch(key); }; + api["setControlSwitch"] = [input](std::string_view key, bool v) { input->toggleControlSwitch(key, v); }; api["ACTION"] = LuaUtil::makeReadOnly(context.mLua->sol().create_table_with( "GameMenu", MWInput::A_GameMenu, @@ -144,6 +167,115 @@ namespace MWLua "MoveLeftRight", SDL_CONTROLLER_AXIS_MAX + MWInput::A_MoveLeftRight )); + api["KEY"] = LuaUtil::makeReadOnly(context.mLua->sol().create_table_with( + "_0", SDL_SCANCODE_0, + "_1", SDL_SCANCODE_1, + "_2", SDL_SCANCODE_2, + "_3", SDL_SCANCODE_3, + "_4", SDL_SCANCODE_4, + "_5", SDL_SCANCODE_5, + "_6", SDL_SCANCODE_6, + "_7", SDL_SCANCODE_7, + "_8", SDL_SCANCODE_8, + "_9", SDL_SCANCODE_9, + + "NP_0", SDL_SCANCODE_KP_0, + "NP_1", SDL_SCANCODE_KP_1, + "NP_2", SDL_SCANCODE_KP_2, + "NP_3", SDL_SCANCODE_KP_3, + "NP_4", SDL_SCANCODE_KP_4, + "NP_5", SDL_SCANCODE_KP_5, + "NP_6", SDL_SCANCODE_KP_6, + "NP_7", SDL_SCANCODE_KP_7, + "NP_8", SDL_SCANCODE_KP_8, + "NP_9", SDL_SCANCODE_KP_9, + "NP_Divide", SDL_SCANCODE_KP_DIVIDE, + "NP_Enter", SDL_SCANCODE_KP_ENTER, + "NP_Minus", SDL_SCANCODE_KP_MINUS, + "NP_Multiply", SDL_SCANCODE_KP_MULTIPLY, + "NP_Delete", SDL_SCANCODE_KP_PERIOD, + "NP_Plus", SDL_SCANCODE_KP_PLUS, + + "F1", SDL_SCANCODE_F1, + "F2", SDL_SCANCODE_F2, + "F3", SDL_SCANCODE_F3, + "F4", SDL_SCANCODE_F4, + "F5", SDL_SCANCODE_F5, + "F6", SDL_SCANCODE_F6, + "F7", SDL_SCANCODE_F7, + "F8", SDL_SCANCODE_F8, + "F9", SDL_SCANCODE_F9, + "F10", SDL_SCANCODE_F10, + "F11", SDL_SCANCODE_F11, + "F12", SDL_SCANCODE_F12, + + "A", SDL_SCANCODE_A, + "B", SDL_SCANCODE_B, + "C", SDL_SCANCODE_C, + "D", SDL_SCANCODE_D, + "E", SDL_SCANCODE_E, + "F", SDL_SCANCODE_F, + "G", SDL_SCANCODE_G, + "H", SDL_SCANCODE_H, + "I", SDL_SCANCODE_I, + "J", SDL_SCANCODE_J, + "K", SDL_SCANCODE_K, + "L", SDL_SCANCODE_L, + "M", SDL_SCANCODE_M, + "N", SDL_SCANCODE_N, + "O", SDL_SCANCODE_O, + "P", SDL_SCANCODE_P, + "Q", SDL_SCANCODE_Q, + "R", SDL_SCANCODE_R, + "S", SDL_SCANCODE_S, + "T", SDL_SCANCODE_T, + "U", SDL_SCANCODE_U, + "V", SDL_SCANCODE_V, + "W", SDL_SCANCODE_W, + "X", SDL_SCANCODE_X, + "Y", SDL_SCANCODE_Y, + "Z", SDL_SCANCODE_Z, + + "LeftArrow", SDL_SCANCODE_LEFT, + "RightArrow", SDL_SCANCODE_RIGHT, + "UpArrow", SDL_SCANCODE_UP, + "DownArrow", SDL_SCANCODE_DOWN, + + "LeftAlt", SDL_SCANCODE_LALT, + "LeftCtrl", SDL_SCANCODE_LCTRL, + "LeftBracket", SDL_SCANCODE_LEFTBRACKET, + "LeftSuper", SDL_SCANCODE_LGUI, + "LeftShift", SDL_SCANCODE_LSHIFT, + "RightAlt", SDL_SCANCODE_RALT, + "RightCtrl", SDL_SCANCODE_RCTRL, + "RightSuper", SDL_SCANCODE_RGUI, + "RightBracket", SDL_SCANCODE_RIGHTBRACKET, + "RightShift", SDL_SCANCODE_RSHIFT, + + "BackSlash", SDL_SCANCODE_BACKSLASH, + "Backspace", SDL_SCANCODE_BACKSPACE, + "CapsLock", SDL_SCANCODE_CAPSLOCK, + "Comma", SDL_SCANCODE_COMMA, + "Delete", SDL_SCANCODE_DELETE, + "End", SDL_SCANCODE_END, + "Enter", SDL_SCANCODE_RETURN, + "Equals", SDL_SCANCODE_EQUALS, + "Escape", SDL_SCANCODE_ESCAPE, + "Home", SDL_SCANCODE_HOME, + "Insert", SDL_SCANCODE_INSERT, + "Minus", SDL_SCANCODE_MINUS, + "NumLock", SDL_SCANCODE_NUMLOCKCLEAR, + "PageDown", SDL_SCANCODE_PAGEDOWN, + "PageUp", SDL_SCANCODE_PAGEUP, + "Pause", SDL_SCANCODE_PAUSE, + "PrintScreen", SDL_SCANCODE_PRINTSCREEN, + "ScrollLock", SDL_SCANCODE_SCROLLLOCK, + "Semicolon", SDL_SCANCODE_SEMICOLON, + "Slash", SDL_SCANCODE_SLASH, + "Space", SDL_SCANCODE_SPACE, + "Tab", SDL_SCANCODE_TAB + )); + return LuaUtil::makeReadOnly(api); } diff --git a/apps/openmw/mwlua/luabindings.cpp b/apps/openmw/mwlua/luabindings.cpp index 1c05debc73..f9d3911aa8 100644 --- a/apps/openmw/mwlua/luabindings.cpp +++ b/apps/openmw/mwlua/luabindings.cpp @@ -25,7 +25,7 @@ namespace MWLua { auto* lua = context.mLua; sol::table api(lua->sol(), sol::create); - api["API_REVISION"] = 8; + api["API_REVISION"] = 9; api["quit"] = [lua]() { std::string traceback = lua->sol()["debug"]["traceback"]().get(); diff --git a/files/lua_api/openmw/input.lua b/files/lua_api/openmw/input.lua index 0975ce6e6a..d4ff7f3475 100644 --- a/files/lua_api/openmw/input.lua +++ b/files/lua_api/openmw/input.lua @@ -17,6 +17,38 @@ -- @param #number actionId One of @{openmw.input#ACTION} -- @return #boolean +------------------------------------------------------------------------------- +-- Is a keyboard button currently pressed. +-- @function [parent=#input] isKeyPressed +-- @param #number keyCode Key code (the same code that is used in @{openmw.input#KeyEvent}) +-- @return #boolean + +------------------------------------------------------------------------------- +-- Is a controller button currently pressed. +-- @function [parent=#input] isControllerButtonPressed +-- @param #number buttonId Button index (see @{openmw.input#CONTROLLER_BUTTON}) +-- @return #boolean + +------------------------------------------------------------------------------- +-- Is `Shift` key pressed. +-- @function [parent=#input] isShiftPressed +-- @return #boolean + +------------------------------------------------------------------------------- +-- Is `Ctrl` key pressed. +-- @function [parent=#input] isCtrlPressed +-- @return #boolean + +------------------------------------------------------------------------------- +-- Is `Alt` key pressed. +-- @function [parent=#input] isAltPressed +-- @return #boolean + +------------------------------------------------------------------------------- +-- Is `Super`/`Win` key pressed. +-- @function [parent=#input] isSuperPressed +-- @return #boolean + ------------------------------------------------------------------------------- -- Is a mouse button currently pressed. -- @function [parent=#input] isMouseButtonPressed @@ -156,10 +188,117 @@ -- Values that can be used with getAxisValue. -- @field [parent=#input] #CONTROLLER_AXIS CONTROLLER_AXIS +------------------------------------------------------------------------------- +-- @type KEY +-- @field #number _0 +-- @field #number _1 +-- @field #number _2 +-- @field #number _3 +-- @field #number _4 +-- @field #number _5 +-- @field #number _6 +-- @field #number _7 +-- @field #number _8 +-- @field #number _9 +-- @field #number NP_0 +-- @field #number NP_1 +-- @field #number NP_2 +-- @field #number NP_3 +-- @field #number NP_4 +-- @field #number NP_5 +-- @field #number NP_6 +-- @field #number NP_7 +-- @field #number NP_8 +-- @field #number NP_9 +-- @field #number NP_Divide +-- @field #number NP_Enter +-- @field #number NP_Minus +-- @field #number NP_Multiply +-- @field #number NP_Delete +-- @field #number NP_Plus +-- @field #number F1 +-- @field #number F2 +-- @field #number F3 +-- @field #number F4 +-- @field #number F5 +-- @field #number F6 +-- @field #number F7 +-- @field #number F8 +-- @field #number F9 +-- @field #number F10 +-- @field #number F11 +-- @field #number F12 +-- @field #number A +-- @field #number B +-- @field #number C +-- @field #number D +-- @field #number E +-- @field #number F +-- @field #number G +-- @field #number H +-- @field #number I +-- @field #number J +-- @field #number K +-- @field #number L +-- @field #number M +-- @field #number N +-- @field #number O +-- @field #number P +-- @field #number Q +-- @field #number R +-- @field #number S +-- @field #number T +-- @field #number U +-- @field #number V +-- @field #number W +-- @field #number X +-- @field #number Y +-- @field #number Z +-- @field #number LeftArrow +-- @field #number RightArrow +-- @field #number UpArrow +-- @field #number DownArrow +-- @field #number LeftAlt +-- @field #number LeftCtrl +-- @field #number LeftBracket +-- @field #number LeftSuper +-- @field #number LeftShift +-- @field #number RightAlt +-- @field #number RightCtrl +-- @field #number RightBracket +-- @field #number RightSuper +-- @field #number RightShift +-- @field #number BackSlash +-- @field #number Backspace +-- @field #number CapsLock +-- @field #number Comma +-- @field #number Delete +-- @field #number End +-- @field #number Enter +-- @field #number Equals +-- @field #number Escape +-- @field #number Home +-- @field #number Insert +-- @field #number Minus +-- @field #number NumLock +-- @field #number PageDown +-- @field #number PageUp +-- @field #number Pause +-- @field #number PrintScreen +-- @field #number ScrollLock +-- @field #number Semicolon +-- @field #number Slash +-- @field #number Space +-- @field #number Tab + +------------------------------------------------------------------------------- +-- Key codes. +-- @field [parent=#input] #KEY KEY + ------------------------------------------------------------------------------- -- The argument of `onKeyPress`/`onKeyRelease` engine handlers. -- @type KeyboardEvent --- @field [parent=#KeyboardEvent] #string symbol The pressed symbol (1-symbol string). +-- @field [parent=#KeyboardEvent] #string symbol The pressed symbol (1-symbol string if can be represented or an empty string otherwise). -- @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.