diff --git a/GlitchyEngine/src/Input.bf b/GlitchyEngine/src/Input.bf index 1c4c4c2..ace5629 100644 --- a/GlitchyEngine/src/Input.bf +++ b/GlitchyEngine/src/Input.bf @@ -6,6 +6,8 @@ namespace GlitchyEngine { public static class Input { + public static extern bool RawInput {get; set;} + public static extern bool IsKeyPressed(Key keycode); public static extern bool IsKeyReleased(Key keycode); public static extern bool IsKeyToggled(Key keycode); @@ -41,6 +43,12 @@ namespace GlitchyEngine public static extern bool IsMouseButtonReleasiong(MouseButton button); public static extern Point GetMouseMovement(); + /** + * Returns the raw mouse (that is the mouse movement taken direcly from the device instead of the movement processed by the OS). + * Requires RawInput to be true. If RawInput is false (or could not be initialized) this method will return the same value as GetMouseMovement(); + */ + public static extern Int32_2 GetRawMouseMovement(); + public static extern void NewFrame(); } } diff --git a/GlitchyEngine/src/Platform/Windows/WindowsInput.bf b/GlitchyEngine/src/Platform/Windows/WindowsInput.bf index afde72b..e41c201 100644 --- a/GlitchyEngine/src/Platform/Windows/WindowsInput.bf +++ b/GlitchyEngine/src/Platform/Windows/WindowsInput.bf @@ -12,12 +12,30 @@ namespace GlitchyEngine /// Windows (WinApi) specific implementation of the Input-class extension Input { + internal static bool sUseRawInput = true; + + public override static bool RawInput + { + get => sUseRawInput; + set + { + if(sUseRawInput == value) + return; + + sUseRawInput = value; + + //if(sUseRawInput) + // TODO: init raw input + } + } + /// Represents the state of the input devices on the windows platform (WinApi that is). struct WindowsInputState { public int8[256] KeyStates; public Point CursorPosition; public Point CursorPositionDifference; + public Int32_2 RawMovement; } static WindowsInputState* CurrentState = new WindowsInputState() ~ delete _; @@ -152,6 +170,19 @@ namespace GlitchyEngine public override static Point GetMouseMovement() => CurrentState.CursorPositionDifference; + public override static Int32_2 GetRawMouseMovement() + { + if(sUseRawInput) + { + return CurrentState.RawMovement; + } + else + { + var v = GetMouseMovement(); + + return *(Int32_2*)&v; + } + } //[CLink, CallingConvention(.Stdcall)] //static extern int16 GetKeyState(int32 keycode); @@ -160,6 +191,8 @@ namespace GlitchyEngine [CLink, CallingConvention(.Stdcall)] static extern IntBool ScreenToClient(HWnd hWnd, ref Point p); + internal static Int32_2 rawMovement; + public override static void NewFrame() { // Switch last and current states @@ -192,6 +225,8 @@ namespace GlitchyEngine // Calculate cursor movement CurrentState.CursorPositionDifference = CurrentState.CursorPosition - LastState.CursorPosition; + CurrentState.RawMovement = rawMovement; + rawMovement = .Zero; } } #endif diff --git a/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf b/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf index a9c5ca2..f64308e 100644 --- a/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf +++ b/GlitchyEngine/src/Platform/Windows/WindowsWindow.bf @@ -9,6 +9,7 @@ using GlitchyEngine.Events; using System.Diagnostics; using GlitchyEngine.Math; using GlitchyEngine.Renderer; +using DirectX.Windows.Winuser.RawInput; using static System.Windows; namespace GlitchyEngine @@ -215,6 +216,41 @@ namespace GlitchyEngine LoadWindowRectangle(); Log.EngineLogger.Trace($"Created window \"{Title}\" ({Width}, {Height})"); + + if(Input.RawInput) + { + InitRawInput(); + } + } + + [CLink, CallingConvention(.Stdcall)] + static extern IntBool RegisterRawInputDevices(RAWINPUTDEVICE* rawInputDevices, uint32 numDevices, uint32 size); + + private void InitRawInput() + { + RAWINPUTDEVICE[1] Rid; + + Rid[0].UsagePage = 0x01; // HID_USAGE_PAGE_GENERIC + Rid[0].Usage = 0x02; // HID_USAGE_GENERIC_MOUSE + Rid[0].Flags = 0;//RIDEV_NOLEGACY; // adds mouse and also ignores legacy mouse messages + Rid[0].Target = 0; + /* + Rid[1].UsagePage = 0x01; // HID_USAGE_PAGE_GENERIC + Rid[1].Usage = 0x06; // HID_USAGE_GENERIC_KEYBOARD + Rid[1].Flags = RIDEV_NOLEGACY; // adds keyboard and also ignores legacy keyboard messages + Rid[1].Target = 0; + */ + if (!RegisterRawInputDevices(&Rid, Rid.Count, sizeof(RAWINPUTDEVICE))) + { + DirectX.Common.HResult errorCode = (.)GetLastError(); + Log.EngineLogger.Error($"Failed to register raw input devices. Message({(int32)errorCode}):{errorCode}"); + // Disable raw input + Input.RawInput = false; + } + else + { + Log.EngineLogger.Trace($"Registered raw input devices."); + } } private bool _isResizingOrMoving; @@ -438,11 +474,128 @@ namespace GlitchyEngine return 0; } + // Raw Input + case 0x00FF: //WM_INPUT + { + uint32 dataSize = ?; + GetRawInputData((.)lParam, RID_INPUT, null, &dataSize, sizeof(RAWINPUTHEADER)); + + if (dataSize > 0) + { + uint8[] rawData = scope .[dataSize]; + if (GetRawInputData((.)lParam, RID_INPUT, rawData.CArray(), &dataSize, sizeof(RAWINPUTHEADER)) == dataSize) + { + RAWINPUT* raw = (.)rawData.CArray(); + if (raw.Header.Type == RIM_TYPEMOUSE) + { + int32 movementX = raw.Data.Mouse.lLastX; + int32 movementY = raw.Data.Mouse.lLastY; + + // TODO: raw.Data.Mouse.usFlags defines whether movement is abosulte, relative, etc... + Input.[Friend]rawMovement += .(movementX, movementY); + /* + var event = scope MouseMovedEvent(movementX, movementY); + window._eventCallback(event); + + // Convert button transition flags to a more manageable type + var buttonTransitions = (RawMouseButtonTransition)raw.Data.Mouse.DUMMYUNIONNAME.DUMMYSTRUCTNAME.usButtonFlags; + + if(buttonTransitions.HasFlag(.LeftDown)) + { + var buttonEvent = scope MouseButtonPressedEvent(.LeftButton); + window._eventCallback(buttonEvent); + } + else if(buttonTransitions.HasFlag(.LeftUp)) + { + var buttonEvent = scope MouseButtonReleasedEvent(.LeftButton); + window._eventCallback(buttonEvent); + } + + if(buttonTransitions.HasFlag(.RightDown)) + { + var buttonEvent = scope MouseButtonPressedEvent(.RightButton); + window._eventCallback(buttonEvent); + } + else if(buttonTransitions.HasFlag(.RightUp)) + { + var buttonEvent = scope MouseButtonReleasedEvent(.RightButton); + window._eventCallback(buttonEvent); + } + + if(buttonTransitions.HasFlag(.MiddleDown)) + { + var buttonEvent = scope MouseButtonPressedEvent(.MiddleButton); + window._eventCallback(buttonEvent); + } + else if(buttonTransitions.HasFlag(.MiddleUp)) + { + var buttonEvent = scope MouseButtonReleasedEvent(.MiddleButton); + window._eventCallback(buttonEvent); + } + + if(buttonTransitions.HasFlag(.XButton1Down)) + { + var buttonEvent = scope MouseButtonPressedEvent(.XButton1); + window._eventCallback(buttonEvent); + } + else if(buttonTransitions.HasFlag(.XButton1Up)) + { + var buttonEvent = scope MouseButtonReleasedEvent(.XButton1); + window._eventCallback(buttonEvent); + } + + if(buttonTransitions.HasFlag(.XButton2Down)) + { + var buttonEvent = scope MouseButtonPressedEvent(.XButton2); + window._eventCallback(buttonEvent); + } + else if(buttonTransitions.HasFlag(.XButton2Up)) + { + var buttonEvent = scope MouseButtonReleasedEvent(.XButton2); + window._eventCallback(buttonEvent); + } + + if(buttonTransitions.HasFlag(.MouseWheel)) + { + int32 rotation = raw.Data.Mouse.DUMMYUNIONNAME.DUMMYSTRUCTNAME.usButtonData / WHEEL_DELTA; + + var scrollEvent = scope MouseScrolledEvent(0, rotation); + window._eventCallback(scrollEvent); + } + + if(buttonTransitions.HasFlag(.MouseHWheel)) + { + int32 rotation = raw.Data.Mouse.DUMMYUNIONNAME.DUMMYSTRUCTNAME.usButtonData / WHEEL_DELTA; + + var scrollEvent = scope MouseScrolledEvent(rotation, 0); + window._eventCallback(scrollEvent); + } + */ + } + } + } + } } return DefWindowProcW(hwnd, uMsg, wParam, lParam); } + enum RawMouseButtonTransition + { + LeftDown = 0x0001, + LeftUp = 0x0002, + MiddleDown = 0x0010, + MiddleUp = 0x0020, + RightDown = 0x0004, + RightUp = 0x0008, + XButton1Down = 0x0040, + XButton1Up = 0x0080, + XButton2Down = 0x0100, + XButton2Up = 0x0200, + MouseWheel = 0x0400, + MouseHWheel = 0x0800 + } + public override void Update() { Message message = .(); diff --git a/Sandbox/src/VoxelFun/VoxelTestLayer.bf b/Sandbox/src/VoxelFun/VoxelTestLayer.bf index 5872217..78261b7 100644 --- a/Sandbox/src/VoxelFun/VoxelTestLayer.bf +++ b/Sandbox/src/VoxelFun/VoxelTestLayer.bf @@ -280,7 +280,7 @@ namespace Sandbox.VoxelFun return; } - let mouseMovement = Input.GetMouseMovement(); + let mouseMovement = Input.GetRawMouseMovement(); if(mouseMovement.X == 0 && mouseMovement.Y == 0) return;