diff --git a/Source/Engine/Input/Input.cpp b/Source/Engine/Input/Input.cpp
index 0faa26f39..5c24f2c49 100644
--- a/Source/Engine/Input/Input.cpp
+++ b/Source/Engine/Input/Input.cpp
@@ -174,7 +174,9 @@ void InputSettings::Deserialize(DeserializeStream& stream, ISerializeModifier* m
void Mouse::OnMouseMoved(const Float2& newPosition)
{
_prevState.MousePosition = newPosition;
+ _prevState.MouseWasReset = true;
_state.MousePosition = newPosition;
+ _state.MouseWasReset = true;
}
void Mouse::OnMouseDown(const Float2& position, const MouseButton button, Window* target)
@@ -221,6 +223,14 @@ void Mouse::OnMouseMove(const Float2& position, Window* target)
e.MouseData.Position = position;
}
+void Mouse::OnMouseMoveDelta(const Vector2& delta, Window* target)
+{
+ Event& e = _queue.AddOne();
+ e.Type = EventType::MouseMoveDelta;
+ e.Target = target;
+ e.MouseData.Position = delta;
+}
+
void Mouse::OnMouseLeave(Window* target)
{
Event& e = _queue.AddOne();
@@ -245,6 +255,7 @@ void Mouse::ResetState()
_state.Clear();
}
+#include "Engine/Core/Log.h"
bool Mouse::Update(EventQueue& queue)
{
// Move the current state to the previous
@@ -256,6 +267,7 @@ bool Mouse::Update(EventQueue& queue)
// Handle events
_state.MouseWheelDelta = 0;
+ _state.MouseDelta = Vector2::Zero;
for (int32 i = 0; i < _queue.Count(); i++)
{
const Event& e = _queue[i];
@@ -286,6 +298,11 @@ bool Mouse::Update(EventQueue& queue)
_state.MousePosition = e.MouseData.Position;
break;
}
+ case EventType::MouseMoveDelta:
+ {
+ _state.MouseDelta += e.MouseData.Position;
+ break;
+ }
case EventType::MouseLeave:
{
break;
diff --git a/Source/Engine/Input/InputDevice.h b/Source/Engine/Input/InputDevice.h
index 20c66d2ff..63bfc3273 100644
--- a/Source/Engine/Input/InputDevice.h
+++ b/Source/Engine/Input/InputDevice.h
@@ -25,6 +25,7 @@ public:
MouseDoubleClick,
MouseWheel,
MouseMove,
+ MouseMoveDelta,
MouseLeave,
TouchDown,
TouchMove,
diff --git a/Source/Engine/Input/Mouse.h b/Source/Engine/Input/Mouse.h
index cb43ed1e1..a4ad64931 100644
--- a/Source/Engine/Input/Mouse.h
+++ b/Source/Engine/Input/Mouse.h
@@ -24,6 +24,16 @@ public:
///
Float2 MousePosition;
+ ///
+ /// The mouse position delta.
+ ///
+ Vector2 MouseDelta;
+
+ ///
+ /// Set when application moved the mouse.
+ ///
+ bool MouseWasReset;
+
///
/// The mouse wheel delta.
///
@@ -73,7 +83,7 @@ public:
///
API_PROPERTY() FORCE_INLINE Float2 GetPositionDelta() const
{
- return _state.MousePosition - _prevState.MousePosition;
+ return _state.MouseDelta;
}
///
@@ -158,6 +168,13 @@ public:
/// The target window to receive this event, otherwise input system will pick the window automatically.
void OnMouseMove(const Float2& position, Window* target = nullptr);
+ ///
+ /// Called when mouse moves.
+ ///
+ /// The mouse position.
+ /// The target window to receive this event, otherwise input system will pick the window automatically.
+ void OnMouseMoveDelta(const Vector2& delta, Window* target = nullptr);
+
///
/// Called when mouse leaves the input source area.
///
diff --git a/Source/Engine/Platform/Windows/WindowsInput.cpp b/Source/Engine/Platform/Windows/WindowsInput.cpp
index 5d4b3e12f..7924d1988 100644
--- a/Source/Engine/Platform/Windows/WindowsInput.cpp
+++ b/Source/Engine/Platform/Windows/WindowsInput.cpp
@@ -10,6 +10,7 @@
#include "Engine/Input/Gamepad.h"
#include "Engine/Engine/Engine.h"
#include "Engine/Profiler/ProfilerCPU.h"
+#include "Engine/Core/Math/Int2.h"
#include "../Win32/IncludeWindowsHeaders.h"
#define DIRECTINPUT_VERSION 0x0800
@@ -107,12 +108,36 @@ namespace WindowsInputImpl
bool XInputGamepads[XUSER_MAX_COUNT] = { false };
WindowsMouse* Mouse = nullptr;
WindowsKeyboard* Keyboard = nullptr;
+ bool RawInput = true;
}
+#include
void WindowsInput::Init()
{
Input::Mouse = WindowsInputImpl::Mouse = New();
Input::Keyboard = WindowsInputImpl::Keyboard = New();
+
+ if (WindowsInputImpl::RawInput)
+ {
+ RAWINPUTDEVICE Rid[2];
+
+ // register mouse
+ Rid[0].usUsagePage = HID_USAGE_PAGE_GENERIC;
+ Rid[0].usUsage = HID_USAGE_GENERIC_MOUSE;
+ Rid[0].dwFlags = (RIDEV_NOLEGACY*0); // adds mouse and also ignores legacy mouse messages
+ Rid[0].hwndTarget = 0;
+
+ // register keyboard
+ Rid[1].usUsagePage = HID_USAGE_PAGE_GENERIC;
+ Rid[1].usUsage = HID_USAGE_GENERIC_KEYBOARD;
+ Rid[1].dwFlags = (RIDEV_NOLEGACY*0); // adds keyboard and also ignores legacy keyboard messages
+ Rid[1].hwndTarget = 0;
+
+ if (!RegisterRawInputDevices(Rid, 2, sizeof(Rid[0])))
+ {
+ //registration failed. Call GetLastError for the cause of the error
+ }
+ }
}
void WindowsInput::Update()
@@ -138,6 +163,8 @@ void WindowsInput::Update()
}
}
}
+
+ // TODO: handle raw input device detection here
}
bool WindowsInput::WndProc(Window* window, Windows::UINT msg, Windows::WPARAM wParam, Windows::LPARAM lParam)
@@ -149,6 +176,76 @@ bool WindowsInput::WndProc(Window* window, Windows::UINT msg, Windows::WPARAM wP
return false;
}
+bool OnRawInput(Vector2 mousePosition, Window* window, HRAWINPUT input)
+{
+ uint32 dataSize;
+ static BYTE* dataBuffer = nullptr;
+ static uint32 dataBufferSize = 0;
+
+ GetRawInputData(input, RID_INPUT, nullptr, &dataSize, sizeof(RAWINPUTHEADER));
+ if (dataSize > dataBufferSize)
+ {
+ if (dataBuffer != nullptr)
+ delete[] dataBuffer;
+ dataBuffer = new BYTE[dataSize];
+ dataBufferSize = dataSize;
+ }
+
+ GetRawInputData(input, RID_INPUT, dataBuffer, &dataSize, sizeof(RAWINPUTHEADER));
+
+ if (((RAWINPUT*)dataBuffer)->header.dwType == RIM_TYPEKEYBOARD)
+ {
+ RAWKEYBOARD rawKeyboard = ((RAWINPUT*)dataBuffer)->data.keyboard;
+
+ if ((rawKeyboard.Flags & RI_KEY_BREAK) != 0)
+ Input::Keyboard->OnKeyUp(static_cast(rawKeyboard.VKey), window);
+ else
+ Input::Keyboard->OnKeyDown(static_cast(rawKeyboard.VKey), window);
+ }
+ else if (((RAWINPUT*)dataBuffer)->header.dwType == RIM_TYPEMOUSE)
+ {
+ const RAWMOUSE rawMouse = ((RAWINPUT*)dataBuffer)->data.mouse;
+ Vector2 mousePos;
+ if ((rawMouse.usFlags & MOUSE_MOVE_ABSOLUTE) != 0)
+ {
+ const bool virtualDesktop = (rawMouse.usFlags & MOUSE_VIRTUAL_DESKTOP) != 0;
+ const int width = GetSystemMetrics(virtualDesktop ? SM_CXVIRTUALSCREEN : SM_CXSCREEN);
+ const int height = GetSystemMetrics(virtualDesktop ? SM_CYVIRTUALSCREEN : SM_CYSCREEN);
+ mousePos = Vector2(Int2(
+ static_cast((rawMouse.lLastX / 65535.0f) * width),
+ static_cast((rawMouse.lLastY / 65535.0f) * height)));
+
+ Input::Mouse->OnMouseMove(mousePos, window);
+ }
+ else
+ {
+ // FIXME: This is wrong. The current mouse position does not include
+ // delta movement accumulated during this frame.
+ mousePos = mousePosition;
+
+ const Vector2 mouseDelta(Int2(rawMouse.lLastX, rawMouse.lLastY));
+ mousePos += mouseDelta;
+
+ if (!mouseDelta.IsZero())
+ {
+ //Input::Mouse->OnMouseMove(mousePos, window);
+ Input::Mouse->OnMouseMoveDelta(mouseDelta, window);
+ }
+ }
+
+ if ((rawMouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_DOWN) != 0)
+ Input::Mouse->OnMouseDown(mousePos, MouseButton::Left, window);
+ if ((rawMouse.usButtonFlags & RI_MOUSE_LEFT_BUTTON_UP) != 0)
+ Input::Mouse->OnMouseUp(mousePos, MouseButton::Left, window);
+ if ((rawMouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_DOWN) != 0)
+ Input::Mouse->OnMouseDown(mousePos, MouseButton::Right, window);
+ if ((rawMouse.usButtonFlags & RI_MOUSE_RIGHT_BUTTON_UP) != 0)
+ Input::Mouse->OnMouseUp(mousePos, MouseButton::Right, window);
+ }
+
+ return true;
+}
+
bool WindowsKeyboard::WndProc(Window* window, const Windows::UINT msg, Windows::WPARAM wParam, Windows::LPARAM lParam)
{
bool result = false;
@@ -197,6 +294,21 @@ bool WindowsMouse::WndProc(Window* window, const UINT msg, WPARAM wParam, LPARAM
{
case WM_MOUSEMOVE:
{
+ if (!WindowsInputImpl::RawInput)
+ {
+ static Vector2 lastPos = mousePos;
+ if (_state.MouseWasReset)
+ {
+ lastPos = _state.MousePosition;
+ _state.MouseWasReset = false;
+ }
+
+ Vector2 deltaPos = mousePos - lastPos;
+ if (!deltaPos.IsZero())
+ OnMouseMoveDelta(deltaPos, window);
+ lastPos = mousePos;
+ }
+
OnMouseMove(mousePos, window);
result = true;
break;
@@ -293,6 +405,11 @@ bool WindowsMouse::WndProc(Window* window, const UINT msg, WPARAM wParam, LPARAM
result = true;
break;
}
+ case WM_INPUT:
+ {
+ result = OnRawInput(_state.MousePosition, window, reinterpret_cast(lParam));
+ break;
+ }
}
return result;