#pragma once #include #include #include #include #include #include #include namespace extra2d { /** * @brief 键键码别名 */ using Key = SDL_Scancode; /** * @brief 按键常量 */ namespace Keys { constexpr Key Unknown = SDL_SCANCODE_UNKNOWN; constexpr Key A = SDL_SCANCODE_A; constexpr Key B = SDL_SCANCODE_B; constexpr Key C = SDL_SCANCODE_C; constexpr Key D = SDL_SCANCODE_D; constexpr Key E = SDL_SCANCODE_E; constexpr Key F = SDL_SCANCODE_F; constexpr Key G = SDL_SCANCODE_G; constexpr Key H = SDL_SCANCODE_H; constexpr Key I = SDL_SCANCODE_I; constexpr Key J = SDL_SCANCODE_J; constexpr Key K = SDL_SCANCODE_K; constexpr Key L = SDL_SCANCODE_L; constexpr Key M = SDL_SCANCODE_M; constexpr Key N = SDL_SCANCODE_N; constexpr Key O = SDL_SCANCODE_O; constexpr Key P = SDL_SCANCODE_P; constexpr Key Q = SDL_SCANCODE_Q; constexpr Key R = SDL_SCANCODE_R; constexpr Key S = SDL_SCANCODE_S; constexpr Key T = SDL_SCANCODE_T; constexpr Key U = SDL_SCANCODE_U; constexpr Key V = SDL_SCANCODE_V; constexpr Key W = SDL_SCANCODE_W; constexpr Key X = SDL_SCANCODE_X; constexpr Key Y = SDL_SCANCODE_Y; constexpr Key Z = SDL_SCANCODE_Z; constexpr Key Num0 = SDL_SCANCODE_0; constexpr Key Num1 = SDL_SCANCODE_1; constexpr Key Num2 = SDL_SCANCODE_2; constexpr Key Num3 = SDL_SCANCODE_3; constexpr Key Num4 = SDL_SCANCODE_4; constexpr Key Num5 = SDL_SCANCODE_5; constexpr Key Num6 = SDL_SCANCODE_6; constexpr Key Num7 = SDL_SCANCODE_7; constexpr Key Num8 = SDL_SCANCODE_8; constexpr Key Num9 = SDL_SCANCODE_9; constexpr Key F1 = SDL_SCANCODE_F1; constexpr Key F2 = SDL_SCANCODE_F2; constexpr Key F3 = SDL_SCANCODE_F3; constexpr Key F4 = SDL_SCANCODE_F4; constexpr Key F5 = SDL_SCANCODE_F5; constexpr Key F6 = SDL_SCANCODE_F6; constexpr Key F7 = SDL_SCANCODE_F7; constexpr Key F8 = SDL_SCANCODE_F8; constexpr Key F9 = SDL_SCANCODE_F9; constexpr Key F10 = SDL_SCANCODE_F10; constexpr Key F11 = SDL_SCANCODE_F11; constexpr Key F12 = SDL_SCANCODE_F12; constexpr Key Space = SDL_SCANCODE_SPACE; constexpr Key Enter = SDL_SCANCODE_RETURN; constexpr Key Escape = SDL_SCANCODE_ESCAPE; constexpr Key Tab = SDL_SCANCODE_TAB; constexpr Key Backspace = SDL_SCANCODE_BACKSPACE; constexpr Key Insert = SDL_SCANCODE_INSERT; constexpr Key Delete = SDL_SCANCODE_DELETE; constexpr Key Home = SDL_SCANCODE_HOME; constexpr Key End = SDL_SCANCODE_END; constexpr Key PageUp = SDL_SCANCODE_PAGEUP; constexpr Key PageDown = SDL_SCANCODE_PAGEDOWN; constexpr Key Left = SDL_SCANCODE_LEFT; constexpr Key Right = SDL_SCANCODE_RIGHT; constexpr Key Up = SDL_SCANCODE_UP; constexpr Key Down = SDL_SCANCODE_DOWN; constexpr Key LeftShift = SDL_SCANCODE_LSHIFT; constexpr Key RightShift = SDL_SCANCODE_RSHIFT; constexpr Key LeftCtrl = SDL_SCANCODE_LCTRL; constexpr Key RightCtrl = SDL_SCANCODE_RCTRL; constexpr Key LeftAlt = SDL_SCANCODE_LALT; constexpr Key RightAlt = SDL_SCANCODE_RALT; } // namespace Keys /** * @brief 鼠标按键 */ enum class MouseBtn : uint8 { Left = 0, Middle = 1, Right = 2, X1 = 3, X2 = 4, Count = 5 }; /** * @brief 游戏手柄按键 */ enum class GamepadBtn : uint8 { A = 0, B = 1, X = 2, Y = 3, Back = 4, Guide = 5, Start = 6, LeftStick = 7, RightStick = 8, LeftShoulder = 9, RightShoulder = 10, DPadUp = 11, DPadDown = 12, DPadLeft = 13, DPadRight = 14, Count = 15 }; /** * @brief 游戏手柄轴 */ enum class GamepadAxis : uint8 { LeftX = 0, LeftY = 1, RightX = 2, RightY = 3, TriggerLeft = 4, TriggerRight = 5, Count = 6 }; /** * @brief 触摸状态 */ enum class TouchState : uint8 { None = 0, Began, Moved, Ended, Cancelled }; /** * @brief 触摸点信息 */ struct TouchPoint { int64 id = 0; float x = 0.0f; float y = 0.0f; float prevX = 0.0f; float prevY = 0.0f; float deltaX = 0.0f; float deltaY = 0.0f; TouchState state = TouchState::None; float pressure = 1.0f; }; /** * @brief 按键回调类型 */ using KeyCb = std::function; using MouseBtnCb = std::function; using TouchCb = std::function; /** * @brief 输入模块 * * 管理键盘、鼠标、触摸、游戏手柄输入 * 非单例设计,通过 Context 管理生命周期 */ class InputModule : public IModule { public: InputModule(); ~InputModule() override; // 禁止拷贝 InputModule(const InputModule&) = delete; InputModule& operator=(const InputModule&) = delete; // 允许移动 InputModule(InputModule&&) noexcept; InputModule& operator=(InputModule&&) noexcept; // IModule 接口实现 const char* name() const override { return "Input"; } ModuleType type() const override { return ModuleType::System; } int priority() const override { return Pri::Input; } bool init() override; void shutdown() override; /** * @brief 处理输入事件 */ void processEvent(const SDL_Event& evt); /** * @brief 更新输入状态(每帧调用) */ void update(); // ========== 键盘 ========== /** * @brief 检查按键是否按下 */ bool isKeyDown(Key key) const; /** * @brief 检查按键是否刚按下 */ bool isKeyPressed(Key key) const; /** * @brief 检查按键是否刚释放 */ bool isKeyReleased(Key key) const; // ========== 鼠标 ========== /** * @brief 获取鼠标位置 */ void getMousePos(int32& x, int32& y) const; /** * @brief 获取鼠标位置(浮点) */ void getMousePos(float& x, float& y) const; /** * @brief 检查鼠标按键是否按下 */ bool isMouseBtnDown(MouseBtn btn) const; /** * @brief 检查鼠标按键是否刚按下 */ bool isMouseBtnPressed(MouseBtn btn) const; /** * @brief 检查鼠标按键是否刚释放 */ bool isMouseBtnReleased(MouseBtn btn) const; /** * @brief 获取鼠标滚轮 */ int32 getMouseWheel() const; // ========== 触摸 ========== /** * @brief 获取触摸点数量 */ int32 touchCount() const; /** * @brief 获取触摸点 * @param idx 触摸点索引 * @return 触摸点信息,无效索引返回 nullptr */ const TouchPoint* getTouch(int32 idx) const; /** * @brief 根据 ID 获取触摸点 */ const TouchPoint* getTouchById(int64 id) const; /** * @brief 检查是否有触摸 */ bool hasTouch() const { return touchCount() > 0; } /** * @brief 获取所有活跃触摸点 */ const std::vector& getTouches() const { return activeTouches_; } // ========== 游戏手柄 ========== /** * @brief 连接的游戏手柄数量 */ int32 gamepadCount() const; /** * @brief 检查手柄按键是否按下 */ bool isGamepadBtnDown(int32 idx, GamepadBtn btn) const; /** * @brief 检查手柄按键是否刚按下 */ bool isGamepadBtnPressed(int32 idx, GamepadBtn btn) const; /** * @brief 获取手柄轴值 (-1.0 到 1.0) */ float getGamepadAxis(int32 idx, GamepadAxis axis) const; // ========== 回调设置 ========== /** * @brief 设置按键按下回调 */ void setOnKeyDown(KeyCb cb) { onKeyDown_ = std::move(cb); } /** * @brief 设置按键释放回调 */ void setOnKeyUp(KeyCb cb) { onKeyUp_ = std::move(cb); } /** * @brief 设置鼠标按下回调 */ void setOnMouseDown(MouseBtnCb cb) { onMouseDown_ = std::move(cb); } /** * @brief 设置鼠标释放回调 */ void setOnMouseUp(MouseBtnCb cb) { onMouseUp_ = std::move(cb); } /** * @brief 设置触摸开始回调 */ void setOnTouchBegan(TouchCb cb) { onTouchBegan_ = std::move(cb); } /** * @brief 设置触摸移动回调 */ void setOnTouchMoved(TouchCb cb) { onTouchMoved_ = std::move(cb); } /** * @brief 设置触摸结束回调 */ void setOnTouchEnded(TouchCb cb) { onTouchEnded_ = std::move(cb); } private: static constexpr int32 KEY_COUNT = SDL_NUM_SCANCODES; static constexpr int32 MAX_GAMEPADS = 4; static constexpr int32 MAX_TOUCHES = 10; std::array keyState_{}; std::array keyPrev_{}; int32 mouseX_ = 0; int32 mouseY_ = 0; int32 mouseWheel_ = 0; std::array(MouseBtn::Count)> mouseState_{}; std::array(MouseBtn::Count)> mousePrev_{}; std::vector activeTouches_; std::vector endedTouches_; SDL_GameController* gamepads_[MAX_GAMEPADS] = {}; std::array(GamepadBtn::Count)> padState_[MAX_GAMEPADS]; std::array(GamepadBtn::Count)> padPrev_[MAX_GAMEPADS]; KeyCb onKeyDown_; KeyCb onKeyUp_; MouseBtnCb onMouseDown_; MouseBtnCb onMouseUp_; TouchCb onTouchBegan_; TouchCb onTouchMoved_; TouchCb onTouchEnded_; void openGamepad(int32 idx); void closeGamepad(int32 idx); void processTouchDown(const SDL_TouchFingerEvent& evt); void processTouchUp(const SDL_TouchFingerEvent& evt); void processTouchMotion(const SDL_TouchFingerEvent& evt); }; } // namespace extra2d