Extra2D/include/platform/input_module.h

375 lines
8.8 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <SDL.h>
#include <array>
#include <functional>
#include <module/module.h>
#include <module/module_registry.h>
#include <types/base/types.h>
#include <vector>
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<void(Key)>;
using MouseBtnCb = std::function<void(MouseBtn, int32 x, int32 y)>;
using TouchCb = std::function<void(const TouchPoint &)>;
/**
* @brief 输入模块 - 简化版
*
* 管理键盘、鼠标、触摸、游戏手柄输入
* 使用新的 Module 基类,支持自动注册
*/
class InputModule : public Module {
// 优先级为 7在 TimerModule (优先级 6) 之后初始化
E2D_REGISTER_MODULE(InputModule, "Input", 7)
public:
InputModule();
~InputModule() override;
// 禁止拷贝和移动
InputModule(const InputModule &) = delete;
InputModule &operator=(const InputModule &) = delete;
InputModule(InputModule &&) = delete;
InputModule &operator=(InputModule &&) = delete;
// Module 接口实现
bool init() override;
void shutdown() override;
void update(float deltaTime) override;
/**
* @brief 处理输入事件
*/
void processEvent(const SDL_Event &evt);
// ========== 键盘 ==========
/**
* @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<TouchPoint> &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<uint8, KEY_COUNT> keyState_{};
std::array<uint8, KEY_COUNT> keyPrev_{};
int32 mouseX_ = 0;
int32 mouseY_ = 0;
int32 mouseWheel_ = 0;
std::array<uint8, static_cast<size_t>(MouseBtn::Count)> mouseState_{};
std::array<uint8, static_cast<size_t>(MouseBtn::Count)> mousePrev_{};
std::vector<TouchPoint> activeTouches_;
std::vector<TouchPoint> endedTouches_;
SDL_GameController *gamepads_[MAX_GAMEPADS] = {};
std::array<uint8, static_cast<size_t>(GamepadBtn::Count)>
padState_[MAX_GAMEPADS];
std::array<uint8, static_cast<size_t>(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