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:
@@ -223,6 +223,22 @@ add_library(XCEngine STATIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Scene/Scene.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Scene/SceneManager.cpp
|
||||
|
||||
# Platform
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Platform/PlatformTypes.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Platform/Window.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Platform/Windows/WindowsWindow.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Platform/Windows/WindowsWindow.cpp
|
||||
|
||||
# Input
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Input/InputTypes.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Input/InputEvent.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Input/InputAxis.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Input/InputModule.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Input/InputManager.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Input/Platform/WindowsInputModule.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Input/InputManager.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Input/Windows/WindowsInputModule.cpp
|
||||
|
||||
# Audio
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Audio/AudioTypes.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Audio/AudioConfig.h
|
||||
|
||||
34
engine/include/XCEngine/Input/InputAxis.h
Normal file
34
engine/include/XCEngine/Input/InputAxis.h
Normal 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
|
||||
49
engine/include/XCEngine/Input/InputEvent.h
Normal file
49
engine/include/XCEngine/Input/InputEvent.h
Normal 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
|
||||
101
engine/include/XCEngine/Input/InputManager.h
Normal file
101
engine/include/XCEngine/Input/InputManager.h
Normal 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
|
||||
19
engine/include/XCEngine/Input/InputModule.h
Normal file
19
engine/include/XCEngine/Input/InputModule.h
Normal 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
|
||||
54
engine/include/XCEngine/Input/InputTypes.h
Normal file
54
engine/include/XCEngine/Input/InputTypes.h
Normal 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
|
||||
40
engine/include/XCEngine/Input/Platform/WindowsInputModule.h
Normal file
40
engine/include/XCEngine/Input/Platform/WindowsInputModule.h
Normal 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
|
||||
36
engine/include/XCEngine/Platform/PlatformTypes.h
Normal file
36
engine/include/XCEngine/Platform/PlatformTypes.h
Normal 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
|
||||
29
engine/include/XCEngine/Platform/Window.h
Normal file
29
engine/include/XCEngine/Platform/Window.h
Normal 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
|
||||
48
engine/include/XCEngine/Platform/Windows/WindowsWindow.h
Normal file
48
engine/include/XCEngine/Platform/Windows/WindowsWindow.h
Normal 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
|
||||
304
engine/src/Input/InputManager.cpp
Normal file
304
engine/src/Input/InputManager.cpp
Normal file
@@ -0,0 +1,304 @@
|
||||
#include "Input/InputManager.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Input {
|
||||
|
||||
InputManager& InputManager::Get() {
|
||||
static InputManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void InputManager::Initialize(void* platformWindowHandle) {
|
||||
if (m_initialized) return;
|
||||
|
||||
m_platformWindowHandle = platformWindowHandle;
|
||||
|
||||
m_keyDownThisFrame.resize(256, false);
|
||||
m_keyDownLastFrame.resize(256, false);
|
||||
m_keyDown.resize(256, false);
|
||||
|
||||
m_mouseButtonDownThisFrame.resize(5, false);
|
||||
m_mouseButtonDownLastFrame.resize(5, false);
|
||||
m_mouseButtonDown.resize(5, false);
|
||||
|
||||
m_buttonDownThisFrame.resize(32, false);
|
||||
m_buttonDownLastFrame.resize(32, false);
|
||||
|
||||
RegisterAxis(InputAxis("Horizontal", KeyCode::D, KeyCode::A));
|
||||
RegisterAxis(InputAxis("Vertical", KeyCode::W, KeyCode::S));
|
||||
RegisterAxis(InputAxis("Mouse X", KeyCode::None, KeyCode::None));
|
||||
RegisterAxis(InputAxis("Mouse Y", KeyCode::None, KeyCode::None));
|
||||
|
||||
RegisterButton("Jump", KeyCode::Space);
|
||||
RegisterButton("Fire1", KeyCode::LeftCtrl);
|
||||
RegisterButton("Fire2", KeyCode::LeftAlt);
|
||||
RegisterButton("Fire3", KeyCode::LeftShift);
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
void InputManager::Shutdown() {
|
||||
if (!m_initialized) return;
|
||||
|
||||
m_keyDownThisFrame.clear();
|
||||
m_keyDownLastFrame.clear();
|
||||
m_keyDown.clear();
|
||||
|
||||
m_mouseButtonDownThisFrame.clear();
|
||||
m_mouseButtonDownLastFrame.clear();
|
||||
m_mouseButtonDown.clear();
|
||||
|
||||
m_axes.clear();
|
||||
m_buttons.clear();
|
||||
m_buttonDownThisFrame.clear();
|
||||
m_buttonDownLastFrame.clear();
|
||||
|
||||
m_platformWindowHandle = nullptr;
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
void InputManager::Update(float deltaTime) {
|
||||
if (!m_initialized) return;
|
||||
|
||||
m_keyDownLastFrame = m_keyDownThisFrame;
|
||||
m_mouseButtonDownLastFrame = m_mouseButtonDownThisFrame;
|
||||
m_buttonDownLastFrame = m_buttonDownThisFrame;
|
||||
|
||||
m_mouseDelta = Math::Vector2::Zero();
|
||||
m_mouseScrollDelta = 0.0f;
|
||||
}
|
||||
|
||||
size_t InputManager::GetKeyIndex(KeyCode key) const {
|
||||
return static_cast<size_t>(key);
|
||||
}
|
||||
|
||||
size_t InputManager::GetMouseButtonIndex(MouseButton button) const {
|
||||
return static_cast<size_t>(button);
|
||||
}
|
||||
|
||||
bool InputManager::IsKeyDown(KeyCode key) const {
|
||||
if (!m_initialized) return false;
|
||||
size_t index = GetKeyIndex(key);
|
||||
if (index >= m_keyDown.size()) return false;
|
||||
return m_keyDown[index];
|
||||
}
|
||||
|
||||
bool InputManager::IsKeyUp(KeyCode key) const {
|
||||
if (!m_initialized) return true;
|
||||
return !IsKeyDown(key);
|
||||
}
|
||||
|
||||
bool InputManager::IsKeyPressed(KeyCode key) const {
|
||||
if (!m_initialized) return false;
|
||||
size_t index = GetKeyIndex(key);
|
||||
if (index >= m_keyDownThisFrame.size()) return false;
|
||||
return m_keyDownThisFrame[index] && !m_keyDownLastFrame[index];
|
||||
}
|
||||
|
||||
Math::Vector2 InputManager::GetMousePosition() const {
|
||||
return m_mousePosition;
|
||||
}
|
||||
|
||||
Math::Vector2 InputManager::GetMouseDelta() const {
|
||||
return m_mouseDelta;
|
||||
}
|
||||
|
||||
float InputManager::GetMouseScrollDelta() const {
|
||||
return m_mouseScrollDelta;
|
||||
}
|
||||
|
||||
bool InputManager::IsMouseButtonDown(MouseButton button) const {
|
||||
if (!m_initialized) return false;
|
||||
size_t index = GetMouseButtonIndex(button);
|
||||
if (index >= m_mouseButtonDown.size()) return false;
|
||||
return m_mouseButtonDown[index];
|
||||
}
|
||||
|
||||
bool InputManager::IsMouseButtonUp(MouseButton button) const {
|
||||
if (!m_initialized) return true;
|
||||
return !IsMouseButtonDown(button);
|
||||
}
|
||||
|
||||
bool InputManager::IsMouseButtonClicked(MouseButton button) const {
|
||||
if (!m_initialized) return false;
|
||||
size_t index = GetMouseButtonIndex(button);
|
||||
if (index >= m_mouseButtonDownThisFrame.size()) return false;
|
||||
return m_mouseButtonDownThisFrame[index] && !m_mouseButtonDownLastFrame[index];
|
||||
}
|
||||
|
||||
int InputManager::GetTouchCount() const {
|
||||
return static_cast<int>(m_touches.size());
|
||||
}
|
||||
|
||||
TouchState InputManager::GetTouch(int index) const {
|
||||
if (index >= 0 && index < static_cast<int>(m_touches.size())) {
|
||||
return m_touches[index];
|
||||
}
|
||||
return TouchState{};
|
||||
}
|
||||
|
||||
float InputManager::GetAxis(const Containers::String& axisName) const {
|
||||
auto it = m_axes.find(axisName);
|
||||
if (it == m_axes.end()) return 0.0f;
|
||||
|
||||
const auto& axis = it->second;
|
||||
float value = 0.0f;
|
||||
|
||||
if (axis.GetPositiveKey() != KeyCode::None && IsKeyDown(axis.GetPositiveKey())) {
|
||||
value += 1.0f;
|
||||
}
|
||||
if (axis.GetNegativeKey() != KeyCode::None && IsKeyDown(axis.GetNegativeKey())) {
|
||||
value -= 1.0f;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float InputManager::GetAxisRaw(const Containers::String& axisName) const {
|
||||
auto it = m_axes.find(axisName);
|
||||
if (it == m_axes.end()) return 0.0f;
|
||||
|
||||
const auto& axis = it->second;
|
||||
float value = 0.0f;
|
||||
|
||||
if (axis.GetPositiveKey() != KeyCode::None && IsKeyPressed(axis.GetPositiveKey())) {
|
||||
value += 1.0f;
|
||||
}
|
||||
if (axis.GetNegativeKey() != KeyCode::None && IsKeyPressed(axis.GetNegativeKey())) {
|
||||
value -= 1.0f;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool InputManager::GetButton(const Containers::String& buttonName) const {
|
||||
auto it = m_buttons.find(buttonName);
|
||||
if (it == m_buttons.end()) return false;
|
||||
return IsKeyDown(it->second);
|
||||
}
|
||||
|
||||
bool InputManager::GetButtonDown(const Containers::String& buttonName) const {
|
||||
auto it = m_buttons.find(buttonName);
|
||||
if (it == m_buttons.end()) return false;
|
||||
return IsKeyPressed(it->second);
|
||||
}
|
||||
|
||||
bool InputManager::GetButtonUp(const Containers::String& buttonName) const {
|
||||
auto it = m_buttons.find(buttonName);
|
||||
if (it == m_buttons.end()) return true;
|
||||
return IsKeyUp(it->second);
|
||||
}
|
||||
|
||||
void InputManager::RegisterAxis(const InputAxis& axis) {
|
||||
m_axes[axis.GetName()] = axis;
|
||||
}
|
||||
|
||||
void InputManager::RegisterButton(const Containers::String& name, KeyCode key) {
|
||||
m_buttons[name] = key;
|
||||
}
|
||||
|
||||
void InputManager::ClearAxes() {
|
||||
m_axes.clear();
|
||||
m_buttons.clear();
|
||||
}
|
||||
|
||||
void InputManager::ProcessKeyDown(KeyCode key, bool repeat) {
|
||||
if (!m_initialized) return;
|
||||
|
||||
size_t index = GetKeyIndex(key);
|
||||
if (index >= m_keyDown.size()) return;
|
||||
|
||||
m_keyDown[index] = true;
|
||||
m_keyDownThisFrame[index] = true;
|
||||
|
||||
KeyEvent event;
|
||||
event.keyCode = key;
|
||||
event.type = repeat ? KeyEvent::Repeat : KeyEvent::Down;
|
||||
event.alt = false;
|
||||
event.ctrl = false;
|
||||
event.shift = false;
|
||||
event.meta = false;
|
||||
|
||||
m_onKeyEvent.Invoke(event);
|
||||
}
|
||||
|
||||
void InputManager::ProcessKeyUp(KeyCode key) {
|
||||
if (!m_initialized) return;
|
||||
|
||||
size_t index = GetKeyIndex(key);
|
||||
if (index >= m_keyDown.size()) return;
|
||||
|
||||
m_keyDown[index] = false;
|
||||
|
||||
KeyEvent event;
|
||||
event.keyCode = key;
|
||||
event.type = KeyEvent::Up;
|
||||
event.alt = false;
|
||||
event.ctrl = false;
|
||||
event.shift = false;
|
||||
event.meta = false;
|
||||
|
||||
m_onKeyEvent.Invoke(event);
|
||||
}
|
||||
|
||||
void InputManager::ProcessMouseMove(int x, int y, int deltaX, int deltaY) {
|
||||
if (!m_initialized) return;
|
||||
|
||||
m_mousePosition.x = static_cast<float>(x);
|
||||
m_mousePosition.y = static_cast<float>(y);
|
||||
m_mouseDelta.x = static_cast<float>(deltaX);
|
||||
m_mouseDelta.y = static_cast<float>(deltaY);
|
||||
|
||||
MouseMoveEvent event;
|
||||
event.position = m_mousePosition;
|
||||
event.delta = m_mouseDelta;
|
||||
|
||||
m_onMouseMove.Invoke(event);
|
||||
}
|
||||
|
||||
void InputManager::ProcessMouseButton(MouseButton button, bool pressed, int x, int y) {
|
||||
if (!m_initialized) return;
|
||||
|
||||
size_t index = GetMouseButtonIndex(button);
|
||||
if (index >= m_mouseButtonDown.size()) return;
|
||||
|
||||
m_mouseButtonDown[index] = pressed;
|
||||
if (pressed) {
|
||||
m_mouseButtonDownThisFrame[index] = true;
|
||||
}
|
||||
|
||||
MouseButtonEvent event;
|
||||
event.button = button;
|
||||
event.position.x = static_cast<float>(x);
|
||||
event.position.y = static_cast<float>(y);
|
||||
event.type = pressed ? MouseButtonEvent::Pressed : MouseButtonEvent::Released;
|
||||
|
||||
m_onMouseButton.Invoke(event);
|
||||
}
|
||||
|
||||
void InputManager::ProcessMouseWheel(float delta, int x, int y) {
|
||||
if (!m_initialized) return;
|
||||
|
||||
m_mouseScrollDelta = delta;
|
||||
|
||||
MouseWheelEvent event;
|
||||
event.position.x = static_cast<float>(x);
|
||||
event.position.y = static_cast<float>(y);
|
||||
event.delta = delta;
|
||||
|
||||
m_onMouseWheel.Invoke(event);
|
||||
}
|
||||
|
||||
void InputManager::ProcessTextInput(char c) {
|
||||
if (!m_initialized) return;
|
||||
|
||||
TextInputEvent event;
|
||||
event.character = c;
|
||||
event.text = Containers::String(&c, 1);
|
||||
|
||||
m_onTextInput.Invoke(event);
|
||||
}
|
||||
|
||||
} // namespace Input
|
||||
} // namespace XCEngine
|
||||
240
engine/src/Input/Windows/WindowsInputModule.cpp
Normal file
240
engine/src/Input/Windows/WindowsInputModule.cpp
Normal file
@@ -0,0 +1,240 @@
|
||||
#include "Input/Platform/WindowsInputModule.h"
|
||||
#include "Input/InputManager.h"
|
||||
#include <Windows.h>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Input {
|
||||
namespace Platform {
|
||||
|
||||
WindowsInputModule::WindowsInputModule()
|
||||
: m_hwnd(nullptr)
|
||||
, m_isInitialized(false) {
|
||||
}
|
||||
|
||||
WindowsInputModule::~WindowsInputModule() {
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void WindowsInputModule::Initialize(void* windowHandle) {
|
||||
if (m_isInitialized) return;
|
||||
|
||||
m_hwnd = reinterpret_cast<HWND>(windowHandle);
|
||||
m_isInitialized = true;
|
||||
m_lastMousePosition = Math::Vector2::Zero();
|
||||
}
|
||||
|
||||
void WindowsInputModule::Shutdown() {
|
||||
if (!m_isInitialized) return;
|
||||
|
||||
m_hwnd = nullptr;
|
||||
m_isInitialized = false;
|
||||
}
|
||||
|
||||
void WindowsInputModule::PumpEvents() {
|
||||
}
|
||||
|
||||
void WindowsInputModule::HandleMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
if (!m_isInitialized) return;
|
||||
|
||||
switch (message) {
|
||||
case WM_KEYDOWN:
|
||||
ProcessKeyDown(wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_KEYUP:
|
||||
ProcessKeyUp(wParam);
|
||||
break;
|
||||
|
||||
case WM_CHAR:
|
||||
ProcessCharInput(wParam);
|
||||
break;
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
ProcessMouseMove(wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDOWN:
|
||||
ProcessMouseButton(wParam, lParam, true, MouseButton::Left);
|
||||
break;
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
ProcessMouseButton(wParam, lParam, false, MouseButton::Left);
|
||||
break;
|
||||
|
||||
case WM_RBUTTONDOWN:
|
||||
ProcessMouseButton(wParam, lParam, true, MouseButton::Right);
|
||||
break;
|
||||
|
||||
case WM_RBUTTONUP:
|
||||
ProcessMouseButton(wParam, lParam, false, MouseButton::Right);
|
||||
break;
|
||||
|
||||
case WM_MBUTTONDOWN:
|
||||
ProcessMouseButton(wParam, lParam, true, MouseButton::Middle);
|
||||
break;
|
||||
|
||||
case WM_MBUTTONUP:
|
||||
ProcessMouseButton(wParam, lParam, false, MouseButton::Middle);
|
||||
break;
|
||||
|
||||
case WM_MOUSEWHEEL:
|
||||
ProcessMouseWheel(wParam, lParam);
|
||||
break;
|
||||
|
||||
case WM_XBUTTONDOWN:
|
||||
ProcessMouseButton(wParam, lParam, true,
|
||||
(HIWORD(wParam) == 1) ? MouseButton::Button4 : MouseButton::Button5);
|
||||
break;
|
||||
|
||||
case WM_XBUTTONUP:
|
||||
ProcessMouseButton(wParam, lParam, false,
|
||||
(HIWORD(wParam) == 1) ? MouseButton::Button4 : MouseButton::Button5);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsInputModule::ProcessKeyDown(WPARAM wParam, LPARAM lParam) {
|
||||
bool repeat = (lParam & (1 << 30)) != 0;
|
||||
KeyCode keyCode = VKCodeToKeyCode(static_cast<int>(wParam));
|
||||
|
||||
if (keyCode != KeyCode::None) {
|
||||
InputManager::Get().ProcessKeyDown(keyCode, repeat);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsInputModule::ProcessKeyUp(WPARAM wParam) {
|
||||
KeyCode keyCode = VKCodeToKeyCode(static_cast<int>(wParam));
|
||||
|
||||
if (keyCode != KeyCode::None) {
|
||||
InputManager::Get().ProcessKeyUp(keyCode);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsInputModule::ProcessMouseMove(WPARAM wParam, LPARAM lParam) {
|
||||
int x = LOWORD(lParam);
|
||||
int y = HIWORD(lParam);
|
||||
|
||||
int deltaX = x - static_cast<int>(m_lastMousePosition.x);
|
||||
int deltaY = y - static_cast<int>(m_lastMousePosition.y);
|
||||
|
||||
m_lastMousePosition.x = static_cast<float>(x);
|
||||
m_lastMousePosition.y = static_cast<float>(y);
|
||||
|
||||
InputManager::Get().ProcessMouseMove(x, y, deltaX, deltaY);
|
||||
}
|
||||
|
||||
void WindowsInputModule::ProcessMouseButton(WPARAM wParam, LPARAM lParam, bool pressed, MouseButton button) {
|
||||
int x = LOWORD(lParam);
|
||||
int y = HIWORD(lParam);
|
||||
|
||||
InputManager::Get().ProcessMouseButton(button, pressed, x, y);
|
||||
}
|
||||
|
||||
void WindowsInputModule::ProcessMouseWheel(WPARAM wParam, LPARAM lParam) {
|
||||
int x = LOWORD(lParam);
|
||||
int y = HIWORD(lParam);
|
||||
short delta = static_cast<short>(HIWORD(wParam));
|
||||
|
||||
InputManager::Get().ProcessMouseWheel(static_cast<float>(delta) / 120.0f, x, y);
|
||||
}
|
||||
|
||||
void WindowsInputModule::ProcessCharInput(WPARAM wParam) {
|
||||
char c = static_cast<char>(wParam);
|
||||
|
||||
if (c >= 32 && c < 127) {
|
||||
InputManager::Get().ProcessTextInput(c);
|
||||
}
|
||||
}
|
||||
|
||||
KeyCode WindowsInputModule::VKCodeToKeyCode(int vkCode) {
|
||||
switch (vkCode) {
|
||||
case 'A': return KeyCode::A;
|
||||
case 'B': return KeyCode::B;
|
||||
case 'C': return KeyCode::C;
|
||||
case 'D': return KeyCode::D;
|
||||
case 'E': return KeyCode::E;
|
||||
case 'F': return KeyCode::F;
|
||||
case 'G': return KeyCode::G;
|
||||
case 'H': return KeyCode::H;
|
||||
case 'I': return KeyCode::I;
|
||||
case 'J': return KeyCode::J;
|
||||
case 'K': return KeyCode::K;
|
||||
case 'L': return KeyCode::L;
|
||||
case 'M': return KeyCode::M;
|
||||
case 'N': return KeyCode::N;
|
||||
case 'O': return KeyCode::O;
|
||||
case 'P': return KeyCode::P;
|
||||
case 'Q': return KeyCode::Q;
|
||||
case 'R': return KeyCode::R;
|
||||
case 'S': return KeyCode::S;
|
||||
case 'T': return KeyCode::T;
|
||||
case 'U': return KeyCode::U;
|
||||
case 'V': return KeyCode::V;
|
||||
case 'W': return KeyCode::W;
|
||||
case 'X': return KeyCode::X;
|
||||
case 'Y': return KeyCode::Y;
|
||||
case 'Z': return KeyCode::Z;
|
||||
|
||||
case '0': return KeyCode::Zero;
|
||||
case '1': return KeyCode::One;
|
||||
case '2': return KeyCode::Two;
|
||||
case '3': return KeyCode::Three;
|
||||
case '4': return KeyCode::Four;
|
||||
case '5': return KeyCode::Five;
|
||||
case '6': return KeyCode::Six;
|
||||
case '7': return KeyCode::Seven;
|
||||
case '8': return KeyCode::Eight;
|
||||
case '9': return KeyCode::Nine;
|
||||
|
||||
case VK_SPACE: return KeyCode::Space;
|
||||
case VK_TAB: return KeyCode::Tab;
|
||||
case VK_RETURN: return KeyCode::Enter;
|
||||
case VK_ESCAPE: return KeyCode::Escape;
|
||||
case VK_SHIFT: return KeyCode::LeftShift;
|
||||
case VK_CONTROL: return KeyCode::LeftCtrl;
|
||||
case VK_MENU: return KeyCode::LeftAlt;
|
||||
|
||||
case VK_UP: return KeyCode::Up;
|
||||
case VK_DOWN: return KeyCode::Down;
|
||||
case VK_LEFT: return KeyCode::Left;
|
||||
case VK_RIGHT: return KeyCode::Right;
|
||||
|
||||
case VK_HOME: return KeyCode::Home;
|
||||
case VK_END: return KeyCode::End;
|
||||
case VK_PRIOR: return KeyCode::PageUp;
|
||||
case VK_NEXT: return KeyCode::PageDown;
|
||||
case VK_DELETE: return KeyCode::Delete;
|
||||
case VK_BACK: return KeyCode::Backspace;
|
||||
|
||||
case VK_F1: return KeyCode::F1;
|
||||
case VK_F2: return KeyCode::F2;
|
||||
case VK_F3: return KeyCode::F3;
|
||||
case VK_F4: return KeyCode::F4;
|
||||
case VK_F5: return KeyCode::F5;
|
||||
case VK_F6: return KeyCode::F6;
|
||||
case VK_F7: return KeyCode::F7;
|
||||
case VK_F8: return KeyCode::F8;
|
||||
case VK_F9: return KeyCode::F9;
|
||||
case VK_F10: return KeyCode::F10;
|
||||
case VK_F11: return KeyCode::F11;
|
||||
case VK_F12: return KeyCode::F12;
|
||||
|
||||
case VK_OEM_MINUS: return KeyCode::Minus;
|
||||
case VK_OEM_PLUS: return KeyCode::Equals;
|
||||
case VK_OEM_4: return KeyCode::BracketLeft;
|
||||
case VK_OEM_6: return KeyCode::BracketRight;
|
||||
case 0xBA: return KeyCode::Semicolon;
|
||||
case 0xDE: return KeyCode::Quote;
|
||||
case VK_OEM_COMMA: return KeyCode::Comma;
|
||||
case VK_OEM_PERIOD: return KeyCode::Period;
|
||||
case VK_OEM_2: return KeyCode::Slash;
|
||||
case VK_OEM_5: return KeyCode::Backslash;
|
||||
case VK_OEM_3: return KeyCode::Backtick;
|
||||
|
||||
default: return KeyCode::None;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
} // namespace Input
|
||||
} // namespace XCEngine
|
||||
191
engine/src/Platform/Windows/WindowsWindow.cpp
Normal file
191
engine/src/Platform/Windows/WindowsWindow.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
#include "Platform/Windows/WindowsWindow.h"
|
||||
#include <Windows.h>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Platform {
|
||||
|
||||
static const char WINDOW_CLASS_NAME[] = "XCEngineWindowClass";
|
||||
|
||||
WindowsWindow::WindowsWindow()
|
||||
: m_hwnd(nullptr)
|
||||
, m_hInstance(nullptr)
|
||||
, m_fullscreen(false)
|
||||
, m_shouldClose(false)
|
||||
, m_minimized(false) {
|
||||
}
|
||||
|
||||
WindowsWindow::~WindowsWindow() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
bool WindowsWindow::Create(const WindowDesc& desc) {
|
||||
m_hInstance = GetModuleHandle(nullptr);
|
||||
|
||||
RegisterWindowClass();
|
||||
|
||||
DWORD style = WS_OVERLAPPEDWINDOW;
|
||||
DWORD exStyle = WS_EX_APPWINDOW;
|
||||
|
||||
RECT rect = {0, 0, static_cast<LONG>(desc.width), static_cast<LONG>(desc.height)};
|
||||
AdjustWindowRect(&rect, style, FALSE);
|
||||
|
||||
m_hwnd = CreateWindowExA(
|
||||
exStyle,
|
||||
WINDOW_CLASS_NAME,
|
||||
desc.title.CStr(),
|
||||
style,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
rect.right - rect.left,
|
||||
rect.bottom - rect.top,
|
||||
nullptr,
|
||||
nullptr,
|
||||
m_hInstance,
|
||||
this
|
||||
);
|
||||
|
||||
if (!m_hwnd) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_fullscreen = desc.fullscreen;
|
||||
if (m_fullscreen) {
|
||||
SetFullscreen(true);
|
||||
}
|
||||
|
||||
ShowWindow(m_hwnd, SW_SHOWNORMAL);
|
||||
UpdateWindow(m_hwnd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WindowsWindow::Destroy() {
|
||||
if (m_hwnd) {
|
||||
DestroyWindow(m_hwnd);
|
||||
m_hwnd = nullptr;
|
||||
}
|
||||
|
||||
UnregisterClassA(WINDOW_CLASS_NAME, m_hInstance);
|
||||
m_hInstance = nullptr;
|
||||
}
|
||||
|
||||
void WindowsWindow::PumpEvents() {
|
||||
MSG msg;
|
||||
while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
|
||||
if (msg.message == WM_QUIT) {
|
||||
m_shouldClose = true;
|
||||
break;
|
||||
}
|
||||
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsWindow::SetTitle(const Containers::String& title) {
|
||||
if (m_hwnd) {
|
||||
SetWindowTextA(m_hwnd, title.CStr());
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsWindow::SetFullscreen(bool fullscreen) {
|
||||
if (!m_hwnd) return;
|
||||
|
||||
if (fullscreen) {
|
||||
MONITORINFO mi = {sizeof(mi)};
|
||||
GetWindowRect(m_hwnd, &m_oldWindowRect);
|
||||
GetMonitorInfo(MonitorFromWindow(m_hwnd, MONITOR_DEFAULTTOPRIMARY), &mi);
|
||||
SetWindowLong(m_hwnd, GWL_STYLE, WS_POPUP | WS_SYSMENU);
|
||||
SetWindowPos(m_hwnd, HWND_TOP,
|
||||
mi.rcMonitor.left, mi.rcMonitor.top,
|
||||
mi.rcMonitor.right - mi.rcMonitor.left,
|
||||
mi.rcMonitor.bottom - mi.rcMonitor.top,
|
||||
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
||||
m_fullscreen = true;
|
||||
} else {
|
||||
SetWindowLong(m_hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
|
||||
SetWindowPos(m_hwnd, HWND_NOTOPMOST,
|
||||
m_oldWindowRect.left, m_oldWindowRect.top,
|
||||
m_oldWindowRect.right - m_oldWindowRect.left,
|
||||
m_oldWindowRect.bottom - m_oldWindowRect.top,
|
||||
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
||||
m_fullscreen = false;
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsWindow::Minimize() {
|
||||
if (m_hwnd) {
|
||||
ShowWindow(m_hwnd, SW_MINIMIZE);
|
||||
m_minimized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsWindow::Maximize() {
|
||||
if (m_hwnd) {
|
||||
ShowWindow(m_hwnd, SW_MAXIMIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsWindow::Restore() {
|
||||
if (m_hwnd) {
|
||||
ShowWindow(m_hwnd, SW_RESTORE);
|
||||
m_minimized = false;
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsWindow::SetMessageCallback(std::function<void(HWND, UINT, WPARAM, LPARAM)> callback) {
|
||||
m_messageCallback = callback;
|
||||
}
|
||||
|
||||
void WindowsWindow::RegisterWindowClass() {
|
||||
WNDCLASSEXA wc = {};
|
||||
wc.cbSize = sizeof(WNDCLASSEX);
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.hInstance = m_hInstance;
|
||||
wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
||||
wc.lpszClassName = WINDOW_CLASS_NAME;
|
||||
|
||||
RegisterClassExA(&wc);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WindowsWindow::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
WindowsWindow* window = nullptr;
|
||||
|
||||
if (msg == WM_NCCREATE) {
|
||||
CREATESTRUCTA* cs = reinterpret_cast<CREATESTRUCTA*>(lParam);
|
||||
window = reinterpret_cast<WindowsWindow*>(cs->lpCreateParams);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(window));
|
||||
} else {
|
||||
window = reinterpret_cast<WindowsWindow*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
|
||||
}
|
||||
|
||||
if (window && window->m_messageCallback) {
|
||||
window->m_messageCallback(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
switch (msg) {
|
||||
case WM_CLOSE:
|
||||
if (window) window->m_shouldClose = true;
|
||||
return 0;
|
||||
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
return 0;
|
||||
|
||||
case WM_SIZE:
|
||||
if (window) {
|
||||
if (wParam == SIZE_MINIMIZED) {
|
||||
window->m_minimized = true;
|
||||
} else {
|
||||
window->m_minimized = false;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
} // namespace Platform
|
||||
} // namespace XCEngine
|
||||
Reference in New Issue
Block a user