feat: 添加独立的输入系统和平台抽象层

- 新增 Platform 模块:PlatformTypes.h, Window.h, WindowsWindow
- 新增 Input 模块:InputTypes, InputEvent, InputAxis, InputModule, InputManager
- 新增 WindowsInputModule 处理 Win32 消息转换
- 将 RHI 集成测试从 render_model 迁移到 sphere
- 更新 CMakeLists.txt 添加 Platform 和 Input 模块
This commit is contained in:
2026-03-22 15:21:52 +08:00
parent 6af872e9eb
commit 36d3decef6
29 changed files with 2896 additions and 236 deletions

View File

@@ -0,0 +1,34 @@
#pragma once
#include "InputTypes.h"
#include "Containers/String.h"
namespace XCEngine {
namespace Input {
class InputAxis {
public:
InputAxis() = default;
InputAxis(const Containers::String& name, KeyCode positive, KeyCode negative = KeyCode::None)
: m_name(name), m_positiveKey(positive), m_negativeKey(negative) {}
const Containers::String& GetName() const { return m_name; }
KeyCode GetPositiveKey() const { return m_positiveKey; }
KeyCode GetNegativeKey() const { return m_negativeKey; }
void SetKeys(KeyCode positive, KeyCode negative) {
m_positiveKey = positive;
m_negativeKey = negative;
}
float GetValue() const { return m_value; }
void SetValue(float value) { m_value = value; }
private:
Containers::String m_name;
KeyCode m_positiveKey = KeyCode::None;
KeyCode m_negativeKey = KeyCode::None;
float m_value = 0.0f;
};
} // namespace Input
} // namespace XCEngine

View File

@@ -0,0 +1,49 @@
#pragma once
#include "InputTypes.h"
#include "Math/Vector2.h"
#include "Containers/String.h"
namespace XCEngine {
namespace Input {
struct KeyEvent {
KeyCode keyCode;
bool alt;
bool ctrl;
bool shift;
bool meta;
enum Type { Down, Up, Repeat } type;
};
struct MouseButtonEvent {
MouseButton button;
Math::Vector2 position;
enum Type { Pressed, Released } type;
};
struct MouseMoveEvent {
Math::Vector2 position;
Math::Vector2 delta;
};
struct MouseWheelEvent {
Math::Vector2 position;
float delta;
};
struct TextInputEvent {
char character;
Containers::String text;
};
struct TouchState {
int touchId;
Math::Vector2 position;
Math::Vector2 deltaPosition;
float deltaTime;
int tapCount;
enum Phase { Began, Moved, Stationary, Ended, Canceled } phase;
};
} // namespace Input
} // namespace XCEngine

View File

@@ -0,0 +1,101 @@
#pragma once
#include "Core/Event.h"
#include "InputTypes.h"
#include "InputEvent.h"
#include "InputAxis.h"
#include "Math/Vector2.h"
namespace XCEngine {
namespace Input {
class InputManager {
public:
static InputManager& Get();
void Initialize(void* platformWindowHandle);
void Shutdown();
void Update(float deltaTime);
// ============ 轮询接口 ============
bool IsKeyDown(KeyCode key) const;
bool IsKeyUp(KeyCode key) const;
bool IsKeyPressed(KeyCode key) const;
Math::Vector2 GetMousePosition() const;
Math::Vector2 GetMouseDelta() const;
float GetMouseScrollDelta() const;
bool IsMouseButtonDown(MouseButton button) const;
bool IsMouseButtonUp(MouseButton button) const;
bool IsMouseButtonClicked(MouseButton button) const;
int GetTouchCount() const;
TouchState GetTouch(int index) const;
// ============ 轴接口 (参考 Unity) ============
float GetAxis(const Containers::String& axisName) const;
float GetAxisRaw(const Containers::String& axisName) const;
bool GetButton(const Containers::String& buttonName) const;
bool GetButtonDown(const Containers::String& buttonName) const;
bool GetButtonUp(const Containers::String& buttonName) const;
void RegisterAxis(const InputAxis& axis);
void RegisterButton(const Containers::String& name, KeyCode key);
void ClearAxes();
// ============ 事件接口 ============
Core::Event<const KeyEvent&>& OnKeyEvent() { return m_onKeyEvent; }
Core::Event<const MouseButtonEvent&>& OnMouseButton() { return m_onMouseButton; }
Core::Event<const MouseMoveEvent&>& OnMouseMove() { return m_onMouseMove; }
Core::Event<const MouseWheelEvent&>& OnMouseWheel() { return m_onMouseWheel; }
Core::Event<const TextInputEvent&>& OnTextInput() { return m_onTextInput; }
// ============ 内部方法(供 PlatformInputModule 调用) ============
void ProcessKeyDown(KeyCode key, bool repeat);
void ProcessKeyUp(KeyCode key);
void ProcessMouseMove(int x, int y, int deltaX, int deltaY);
void ProcessMouseButton(MouseButton button, bool pressed, int x, int y);
void ProcessMouseWheel(float delta, int x, int y);
void ProcessTextInput(char c);
private:
InputManager() = default;
~InputManager() = default;
size_t GetKeyIndex(KeyCode key) const;
size_t GetMouseButtonIndex(MouseButton button) const;
void* m_platformWindowHandle = nullptr;
bool m_initialized = false;
std::vector<bool> m_keyDownThisFrame;
std::vector<bool> m_keyDownLastFrame;
std::vector<bool> m_keyDown;
Math::Vector2 m_mousePosition;
Math::Vector2 m_mouseDelta;
float m_mouseScrollDelta = 0.0f;
std::vector<bool> m_mouseButtonDownThisFrame;
std::vector<bool> m_mouseButtonDownLastFrame;
std::vector<bool> m_mouseButtonDown;
std::vector<TouchState> m_touches;
std::unordered_map<Containers::String, InputAxis> m_axes;
std::unordered_map<Containers::String, KeyCode> m_buttons;
std::vector<bool> m_buttonDownThisFrame;
std::vector<bool> m_buttonDownLastFrame;
Core::Event<const KeyEvent&> m_onKeyEvent;
Core::Event<const MouseButtonEvent&> m_onMouseButton;
Core::Event<const MouseMoveEvent&> m_onMouseMove;
Core::Event<const MouseWheelEvent&> m_onMouseWheel;
Core::Event<const TextInputEvent&> m_onTextInput;
};
} // namespace Input
} // namespace XCEngine

View File

@@ -0,0 +1,19 @@
#pragma once
namespace XCEngine {
namespace Input {
class InputModule {
public:
virtual ~InputModule() = default;
virtual void Initialize(void* windowHandle) = 0;
virtual void Shutdown() = 0;
virtual void PumpEvents() = 0;
protected:
InputModule() = default;
};
} // namespace Input
} // namespace XCEngine

View File

@@ -0,0 +1,54 @@
#pragma once
#include "Core/Types.h"
namespace XCEngine {
namespace Input {
enum class KeyCode : Core::uint8 {
None = 0,
A = 4, B = 5, C = 6, D = 7, E = 8, F = 9, G = 10,
H = 11, I = 12, J = 13, K = 14, L = 15, M = 16, N = 17,
O = 18, P = 19, Q = 20, R = 21, S = 22, T = 23, U = 24,
V = 25, W = 26, X = 27, Y = 28, Z = 29,
F1 = 58, F2 = 59, F3 = 60, F4 = 61, F5 = 62, F6 = 63,
F7 = 64, F8 = 65, F9 = 66, F10 = 67, F11 = 68, F12 = 69,
Space = 49, Tab = 48, Enter = 36, Escape = 53,
LeftShift = 56, RightShift = 60, LeftCtrl = 59, RightCtrl = 62,
LeftAlt = 58, RightAlt = 61,
Up = 126, Down = 125, Left = 123, Right = 124,
Home = 115, End = 119, PageUp = 116, PageDown = 121,
Delete = 51, Backspace = 51,
Zero = 39, One = 30, Two = 31, Three = 32,
Four = 33, Five = 34, Six = 35, Seven = 37,
Eight = 38, Nine = 40,
Minus = 43, Equals = 46, BracketLeft = 47, BracketRight = 54,
Semicolon = 42, Quote = 40, Comma = 54, Period = 55,
Slash = 44, Backslash = 45, Backtick = 41
};
enum class MouseButton : Core::uint8 {
Left = 0,
Right = 1,
Middle = 2,
Button4 = 3,
Button5 = 4
};
enum class JoystickAxis : Core::uint8 {
LeftX = 0,
LeftY = 1,
RightX = 2,
RightY = 3,
LeftTrigger = 4,
RightTrigger = 5
};
} // namespace Input
} // namespace XCEngine

View File

@@ -0,0 +1,40 @@
#pragma once
#include "Input/InputModule.h"
#include "Input/InputTypes.h"
#include "Math/Vector2.h"
#include <Windows.h>
namespace XCEngine {
namespace Input {
namespace Platform {
class WindowsInputModule : public InputModule {
public:
WindowsInputModule();
virtual ~WindowsInputModule();
void Initialize(void* windowHandle) override;
void Shutdown() override;
void PumpEvents() override;
void HandleMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
private:
void ProcessKeyDown(WPARAM wParam, LPARAM lParam);
void ProcessKeyUp(WPARAM wParam);
void ProcessMouseMove(WPARAM wParam, LPARAM lParam);
void ProcessMouseButton(WPARAM wParam, LPARAM lParam, bool pressed, MouseButton button);
void ProcessMouseWheel(WPARAM wParam, LPARAM lParam);
void ProcessCharInput(WPARAM wParam);
KeyCode VKCodeToKeyCode(int vkCode);
HWND m_hwnd = nullptr;
Math::Vector2 m_lastMousePosition;
bool m_captureMouse = false;
bool m_isInitialized = false;
};
} // namespace Platform
} // namespace Input
} // namespace XCEngine

View File

@@ -0,0 +1,36 @@
#pragma once
#include "Core/Types.h"
#include "Containers/String.h"
namespace XCEngine {
namespace Platform {
using WindowHandle = void*;
struct WindowDesc {
Containers::String title;
Core::uint32 width;
Core::uint32 height;
bool fullscreen;
WindowDesc()
: title("XCEngine")
, width(1280)
, height(720)
, fullscreen(false) {}
};
struct Point {
Core::int32 x;
Core::int32 y;
};
struct Rect {
Core::int32 x;
Core::int32 y;
Core::int32 width;
Core::int32 height;
};
} // namespace Platform
} // namespace XCEngine

View File

@@ -0,0 +1,29 @@
#pragma once
#include "PlatformTypes.h"
namespace XCEngine {
namespace Platform {
class Window {
public:
virtual ~Window() = default;
virtual bool Create(const WindowDesc& desc) = 0;
virtual void Destroy() = 0;
virtual WindowHandle GetHandle() const = 0;
virtual void PumpEvents() = 0;
virtual void SetTitle(const Containers::String& title) = 0;
virtual void SetFullscreen(bool fullscreen) = 0;
virtual bool IsFullscreen() const = 0;
virtual void Minimize() = 0;
virtual void Maximize() = 0;
virtual void Restore() = 0;
virtual bool ShouldClose() const = 0;
virtual void* GetNativeHandle() = 0;
};
} // namespace Platform
} // namespace XCEngine

View File

@@ -0,0 +1,48 @@
#pragma once
#include "Platform/Window.h"
#include <Windows.h>
#include <functional>
namespace XCEngine {
namespace Platform {
class WindowsWindow : public Window {
public:
WindowsWindow();
virtual ~WindowsWindow();
bool Create(const WindowDesc& desc) override;
void Destroy() override;
WindowHandle GetHandle() const override { return m_hwnd; }
void PumpEvents() override;
void SetTitle(const Containers::String& title) override;
void SetFullscreen(bool fullscreen) override;
bool IsFullscreen() const override { return m_fullscreen; }
void Minimize() override;
void Maximize() override;
void Restore() override;
bool ShouldClose() const override { return m_shouldClose; }
void* GetNativeHandle() override { return m_hwnd; }
void SetMessageCallback(std::function<void(HWND, UINT, WPARAM, LPARAM)> callback);
private:
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void RegisterWindowClass();
bool CreateMainWindow(const WindowDesc& desc);
HWND m_hwnd = nullptr;
HINSTANCE m_hInstance = nullptr;
bool m_fullscreen = false;
bool m_shouldClose = false;
bool m_minimized = false;
RECT m_oldWindowRect = {};
std::function<void(HWND, UINT, WPARAM, LPARAM)> m_messageCallback;
};
} // namespace Platform
} // namespace XCEngine