370 lines
8.5 KiB
C++
370 lines
8.5 KiB
C++
#pragma once
|
|
|
|
#include <SDL.h>
|
|
#include <array>
|
|
#include <core/service.h>
|
|
#include <types/base/types.h>
|
|
#include <types/ptr/ref_counted.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 = Fn<void(Key)>;
|
|
using MouseBtnCb = Fn<void(MouseBtn, int32 x, int32 y)>;
|
|
using TouchCb = Fn<void(const TouchPoint &)>;
|
|
|
|
/**
|
|
* @brief 输入服务
|
|
*
|
|
* 管理键盘、鼠标、触摸、游戏手柄输入
|
|
*/
|
|
class InputSvc : public IService {
|
|
public:
|
|
/**
|
|
* @brief 获取单例实例
|
|
*/
|
|
static InputSvc &inst();
|
|
|
|
const char *name() const override { return "InputSvc"; }
|
|
int pri() const override { return Pri::Input; }
|
|
|
|
bool init() override;
|
|
void shutdown() override;
|
|
void update(float dt) override;
|
|
|
|
// ========== 键盘 ==========
|
|
|
|
/**
|
|
* @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:
|
|
InputSvc() = default;
|
|
|
|
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 processEvent(const SDL_Event &evt);
|
|
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);
|
|
|
|
friend class WindowSvc;
|
|
};
|
|
|
|
#define INPUT_SVC extra2d::InputSvc::inst()
|
|
|
|
} // namespace extra2d
|