From 19967813993a55d1958fa4bebc6fb1658d121849 Mon Sep 17 00:00:00 2001 From: David Ludwig Date: Fri, 28 Dec 2012 13:24:36 -0500 Subject: [PATCH] WinRT: added support for SDL_SetRelativeMouseMode --- src/video/windowsrt/SDL_WinRTApp.cpp | 77 +++++++++++++++++++++++++- src/video/windowsrt/SDL_WinRTApp.h | 3 + src/video/windowsrt/SDL_winrtmouse.cpp | 14 ++--- 3 files changed, 85 insertions(+), 9 deletions(-) diff --git a/src/video/windowsrt/SDL_WinRTApp.cpp b/src/video/windowsrt/SDL_WinRTApp.cpp index 0ab809b61..a3cd3a663 100644 --- a/src/video/windowsrt/SDL_WinRTApp.cpp +++ b/src/video/windowsrt/SDL_WinRTApp.cpp @@ -33,6 +33,7 @@ SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr; using namespace Windows::ApplicationModel; using namespace Windows::ApplicationModel::Core; using namespace Windows::ApplicationModel::Activation; +using namespace Windows::Devices::Input; using namespace Windows::UI::Core; using namespace Windows::System; using namespace Windows::Foundation; @@ -42,7 +43,8 @@ using namespace concurrency; SDL_WinRTApp::SDL_WinRTApp() : m_windowClosed(false), m_windowVisible(true), - m_sdlWindowData(NULL) + m_sdlWindowData(NULL), + m_useRelativeMouseMode(false) { } @@ -82,6 +84,10 @@ void SDL_WinRTApp::SetWindow(CoreWindow^ window) window->PointerMoved += ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerMoved); + // Retrieves relative-only mouse movements: + Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnMouseMoved); + window->KeyDown += ref new TypedEventHandler(this, &SDL_WinRTApp::OnKeyDown); @@ -167,6 +173,68 @@ void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args) } } +void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args) +{ + if (m_sdlWindowData && m_useRelativeMouseMode) { + // DLudwig, 2012-12-28: On some systems, namely Visual Studio's Windows + // Simulator, as well as Windows 8 in a Parallels 8 VM, MouseEventArgs' + // MouseDelta field often reports very large values. More information + // on this can be found at the following pages on MSDN: + // - http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/a3c789fa-f1c5-49c4-9c0a-7db88d0f90f8 + // - https://connect.microsoft.com/VisualStudio/Feedback/details/756515 + // + // The values do not appear to be as large when running on some systems, + // most notably a Surface RT. Furthermore, the values returned by + // CoreWindow's PointerMoved event, and sent to this class' OnPointerMoved + // method, do not ever appear to be large, even when MouseEventArgs' + // MouseDelta is reporting to the contrary. + // + // On systems with the large-values behavior, it appears that the values + // get reported as if the screen's size is 65536 units in both the X and Y + // dimensions. This can be viewed by using Windows' now-private, "Raw Input" + // APIs. (GetRawInputData, RegisterRawInputDevices, WM_INPUT, etc.) + // + // MSDN's documentation on MouseEventArgs' MouseDelta field (at + // http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.input.mouseeventargs.mousedelta ), + // does not seem to indicate (to me) that its values should be so large. It + // says that its values should be a "change in screen location". I could + // be misinterpreting this, however a post on MSDN from a Microsoft engineer (see: + // http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/09a9868e-95bb-4858-ba1a-cb4d2c298d62 ), + // indicates that these values are in DIPs, which is the same unit used + // by CoreWindow's PointerMoved events (via the Position field in its CurrentPoint + // property. See http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.input.pointerpoint.position.aspx + // for details.) + // + // To note, PointerMoved events are sent a 'RawPosition' value (via the + // CurrentPoint property in MouseEventArgs), however these do not seem + // to exhibit the same large-value behavior. + // + // The values passed via PointerMoved events can't always be used for relative + // mouse motion, unfortunately. Its values are bound to the cursor's position, + // which stops when it hits one of the screen's edges. This can be a problem in + // first person shooters, whereby it is normal for mouse motion to travel far + // along any one axis for a period of time. MouseMoved events do not have the + // screen-bounding limitation, and can be used regardless of where the system's + // cursor is. + // + // One possible workaround would be to programmatically set the cursor's + // position to the screen's center (when SDL's relative mouse mode is enabled), + // however Windows RT does not yet seem to have the ability to set the cursor's + // position via a public API. Win32 did this via an API call, SetCursorPos, + // however WinRT makes this function be private. Apps that use it won't get + // approved for distribution in the Windows Store. I've yet to be able to find + // a suitable, store-friendly counterpart for WinRT. + // + // There may be some room for a workaround whereby OnPointerMoved's values + // are compared to the values from OnMouseMoved in order to detect + // when this bug is active. A suitable transformation could then be made to + // OnMouseMoved's values. For now, however, the system-reported values are sent + // without transformation. + // + SDL_SendMouseMotion(m_sdlWindowData->sdlWindow, 1, args->MouseDelta.X, args->MouseDelta.Y); + } +} + // Applies necessary geometric transformations to raw cursor positions: Point SDL_WinRTApp::TransformCursor(Point rawPosition) { @@ -182,7 +250,7 @@ Point SDL_WinRTApp::TransformCursor(Point rawPosition) void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args) { - if (m_sdlWindowData) + if (m_sdlWindowData && ! m_useRelativeMouseMode) { Point transformedPoint = TransformCursor(args->CurrentPoint->Position); SDL_SendMouseMotion(m_sdlWindowData->sdlWindow, 0, (int)transformedPoint.X, (int)transformedPoint.Y); @@ -456,6 +524,11 @@ bool SDL_WinRTApp::HasSDLWindowData() const return (m_sdlWindowData != NULL); } +void SDL_WinRTApp::SetRelativeMouseMode(bool enable) +{ + m_useRelativeMouseMode = enable; +} + void SDL_WinRTApp::SetSDLWindowData(const SDL_WindowData* windowData) { m_sdlWindowData = windowData; diff --git a/src/video/windowsrt/SDL_WinRTApp.h b/src/video/windowsrt/SDL_WinRTApp.h index f00417327..36575d385 100644 --- a/src/video/windowsrt/SDL_WinRTApp.h +++ b/src/video/windowsrt/SDL_WinRTApp.h @@ -25,6 +25,7 @@ internal: void PumpEvents(); const SDL_WindowData * GetSDLWindowData() const; bool HasSDLWindowData() const; + void SetRelativeMouseMode(bool enable); void SetSDLWindowData(const SDL_WindowData * windowData); void UpdateWindowFramebuffer(SDL_Surface * surface, SDL_Rect * rects, int numrects); void ResizeMainTexture(int w, int h); @@ -42,6 +43,7 @@ protected: void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); void OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args); + void OnMouseMoved(Windows::Devices::Input::MouseDevice^ mouseDevice, Windows::Devices::Input::MouseEventArgs^ args); void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args); @@ -50,6 +52,7 @@ private: bool m_windowClosed; bool m_windowVisible; const SDL_WindowData* m_sdlWindowData; + bool m_useRelativeMouseMode; }; ref class Direct3DApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource diff --git a/src/video/windowsrt/SDL_winrtmouse.cpp b/src/video/windowsrt/SDL_winrtmouse.cpp index f4bbea6e8..2b44400e7 100644 --- a/src/video/windowsrt/SDL_winrtmouse.cpp +++ b/src/video/windowsrt/SDL_winrtmouse.cpp @@ -108,12 +108,12 @@ WINRT_ShowCursor(SDL_Cursor * cursor) return 0; } -//static int -//WINRT_SetRelativeMouseMode(SDL_bool enabled) -//{ -// //return -1; -// return 0; -//} +static int +WINRT_SetRelativeMouseMode(SDL_bool enabled) +{ + SDL_WinRTGlobalApp->SetRelativeMouseMode(enabled ? true : false); + return 0; +} void WINRT_InitMouse(_THIS) @@ -131,7 +131,7 @@ WINRT_InitMouse(_THIS) mouse->ShowCursor = WINRT_ShowCursor; mouse->FreeCursor = WINRT_FreeCursor; //mouse->WarpMouse = WINRT_WarpMouse; - //mouse->SetRelativeMouseMode = WINRT_SetRelativeMouseMode; // DLudwig: 'relative mouse mode' support is pending + mouse->SetRelativeMouseMode = WINRT_SetRelativeMouseMode; SDL_SetDefaultCursor(WINRT_CreateDefaultCursor()); }