From 7e06b806ac6bcfea4466a9c48960a01768413f19 Mon Sep 17 00:00:00 2001 From: David Ludwig Date: Mon, 2 Sep 2013 15:23:33 -0400 Subject: [PATCH] WinRT: misc code cleanups regarding touch and mouse events, and also SDL-internal globals --- .../SDL/SDL_VS2012-WinPhone.vcxproj | 7 + .../SDL/SDL_VS2012-WinPhone.vcxproj.filters | 6 + VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj | 9 + .../SDL/SDL_VS2012-WinRT.vcxproj.filters | 6 + src/core/winrt/SDL_winrtapp.cpp | 5 +- src/core/winrt/SDL_winrtapp.h | 2 + src/core/winrt/SDL_winrtxaml.cpp | 11 +- src/core/winrt/SDL_winrtxaml_cpp.h | 33 ++ src/video/winrt/SDL_winrtevents.cpp | 19 +- src/video/winrt/SDL_winrtevents_c.h | 3 +- src/video/winrt/SDL_winrtmouse.cpp | 329 +--------------- src/video/winrt/SDL_winrtmouse.h | 13 +- src/video/winrt/SDL_winrtpointerinput.cpp | 372 ++++++++++++++++++ src/video/winrt/SDL_winrtvideo.cpp | 15 +- src/video/winrt/SDL_winrtvideo_cpp.h | 13 + 15 files changed, 483 insertions(+), 360 deletions(-) create mode 100644 src/core/winrt/SDL_winrtxaml_cpp.h create mode 100644 src/video/winrt/SDL_winrtpointerinput.cpp diff --git a/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj b/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj index 1db16b019a72e..231f4afe86213 100644 --- a/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj +++ b/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj @@ -198,6 +198,7 @@ + @@ -381,6 +382,12 @@ true true + + true + true + true + true + true true diff --git a/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj.filters b/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj.filters index 4c726d7a33fd9..0f039415efb06 100644 --- a/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj.filters +++ b/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj.filters @@ -336,6 +336,9 @@ Source Files + + Source Files + @@ -599,6 +602,9 @@ Source Files + + Source Files + diff --git a/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj index 97286011f5527..613775e9ff8ea 100644 --- a/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj +++ b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj @@ -176,6 +176,14 @@ true true + + true + true + true + true + true + true + true true @@ -244,6 +252,7 @@ + diff --git a/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj.filters b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj.filters index 847d900e0ee0e..927ce6c7370c0 100644 --- a/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj.filters +++ b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj.filters @@ -270,6 +270,9 @@ Source Files + + Source Files + Source Files @@ -602,6 +605,9 @@ Source Files + + Source Files + diff --git a/src/core/winrt/SDL_winrtapp.cpp b/src/core/winrt/SDL_winrtapp.cpp index aecab9a62d62a..6b4de54b1fede 100644 --- a/src/core/winrt/SDL_winrtapp.cpp +++ b/src/core/winrt/SDL_winrtapp.cpp @@ -37,12 +37,9 @@ extern "C" { } #include "../../video/winrt/SDL_winrtevents_c.h" +#include "../../video/winrt/SDL_winrtvideo_cpp.h" #include "SDL_winrtapp.h" -extern SDL_Window * WINRT_GlobalSDLWindow; -extern SDL_VideoDevice * WINRT_GlobalSDLVideoDevice; -extern SDL_DisplayMode WINRT_CalcDisplayModeUsingNativeWindow(); - // Compile-time debugging options: // To enable, uncomment; to disable, comment them out. diff --git a/src/core/winrt/SDL_winrtapp.h b/src/core/winrt/SDL_winrtapp.h index 93fd61ade8801..d9cf33e9e0789 100644 --- a/src/core/winrt/SDL_winrtapp.h +++ b/src/core/winrt/SDL_winrtapp.h @@ -38,3 +38,5 @@ ref class SDL_WinRTApp sealed : public Windows::ApplicationModel::Core::IFramewo bool m_windowClosed; bool m_windowVisible; }; + +extern SDL_WinRTApp ^ SDL_WinRTGlobalApp; diff --git a/src/core/winrt/SDL_winrtxaml.cpp b/src/core/winrt/SDL_winrtxaml.cpp index 811f332d4112f..8b78a1f187537 100644 --- a/src/core/winrt/SDL_winrtxaml.cpp +++ b/src/core/winrt/SDL_winrtxaml.cpp @@ -30,18 +30,13 @@ /* SDL includes */ #include "SDL.h" -//#include "SDL_error.h" -//#include "SDL_log.h" -//#include "SDL_main.h" -//#include "SDL_system.h" #include "../../video/winrt/SDL_winrtevents_c.h" +#include "../../video/winrt/SDL_winrtvideo_cpp.h" +#include "SDL_winrtxaml_cpp.h" -/* External globals: */ -extern SDL_Window * WINRT_GlobalSDLWindow; - -/* Internal globals: */ +/* SDL-internal globals: */ SDL_bool WINRT_XAMLWasEnabled = SDL_FALSE; int (*WINRT_XAMLAppMainFunction)(int, char **) = NULL; diff --git a/src/core/winrt/SDL_winrtxaml_cpp.h b/src/core/winrt/SDL_winrtxaml_cpp.h new file mode 100644 index 0000000000000..e0997beccd9f5 --- /dev/null +++ b/src/core/winrt/SDL_winrtxaml_cpp.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_config.h" + +#ifndef _SDL_winrtxaml_h +#define _SDL_winrtxaml_h + +#include "SDL_types.h" + +#ifdef __cplusplus +extern SDL_bool WINRT_XAMLWasEnabled; +extern int (*WINRT_XAMLAppMainFunction)(int, char **); +#endif // ifdef __cplusplus + +#endif // ifndef _SDL_winrtxaml_h diff --git a/src/video/winrt/SDL_winrtevents.cpp b/src/video/winrt/SDL_winrtevents.cpp index 10f4137af584d..94d71590a3ed3 100644 --- a/src/video/winrt/SDL_winrtevents.cpp +++ b/src/video/winrt/SDL_winrtevents.cpp @@ -22,9 +22,19 @@ #if SDL_VIDEO_DRIVER_WINRT -/* SDL includes */ +/* + * Windows includes: + */ +#include +using namespace Windows::UI::Core; +using Windows::UI::Core::CoreCursor; + +/* + * SDL includes: + */ #include "SDL_winrtevents_c.h" #include "../../core/winrt/SDL_winrtapp.h" +#include "../../core/winrt/SDL_winrtxaml_cpp.h" #include "SDL_assert.h" #include "SDL_system.h" @@ -34,10 +44,8 @@ extern "C" { } -/* Forward declarations and globals */ -extern SDL_WinRTApp ^ SDL_WinRTGlobalApp; -extern int (*WINRT_XAMLAppMainFunction)(int, char **); -extern void WINRT_YieldXAMLThread(); +/* Forward declarations */ +static void WINRT_YieldXAMLThread(); /* Global event management */ @@ -135,7 +143,6 @@ WINRT_CycleXAMLThread() } } - #endif /* SDL_VIDEO_DRIVER_WINRT */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtevents_c.h b/src/video/winrt/SDL_winrtevents_c.h index b8f132fd50e24..4d9ae6d4d29b3 100644 --- a/src/video/winrt/SDL_winrtevents_c.h +++ b/src/video/winrt/SDL_winrtevents_c.h @@ -32,6 +32,7 @@ extern "C" { extern "C" { #endif +extern void WINRT_InitTouch(_THIS); extern void WINRT_PumpEvents(_THIS); #ifdef __cplusplus @@ -60,6 +61,6 @@ extern Windows::Foundation::Point WINRT_TransformCursorPosition(SDL_Window * win /* XAML Thread Management */ extern void WINRT_CycleXAMLThread(); -#endif +#endif // ifdef __cplusplus_winrt /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtmouse.cpp b/src/video/winrt/SDL_winrtmouse.cpp index d639210a5dfed..6f385bab019e3 100644 --- a/src/video/winrt/SDL_winrtmouse.cpp +++ b/src/video/winrt/SDL_winrtmouse.cpp @@ -47,9 +47,7 @@ extern "C" { #include "SDL_winrtmouse.h" -static SDL_bool WINRT_UseRelativeMouseMode = SDL_FALSE; -static SDL_TouchID WINRT_TouchID = 1; -static unsigned int WINRT_LeftFingerDown = 0; +extern "C" SDL_bool WINRT_UsingRelativeMouseMode = SDL_FALSE; static SDL_Cursor * @@ -131,7 +129,7 @@ WINRT_ShowCursor(SDL_Cursor * cursor) static int WINRT_SetRelativeMouseMode(SDL_bool enabled) { - WINRT_UseRelativeMouseMode = enabled; + WINRT_UsingRelativeMouseMode = enabled; return 0; } @@ -156,9 +154,6 @@ WINRT_InitMouse(_THIS) SDL_SetDefaultCursor(WINRT_CreateDefaultCursor()); #endif - - /* Init touch: */ - SDL_AddTouch(WINRT_TouchID, ""); } void @@ -166,326 +161,6 @@ WINRT_QuitMouse(_THIS) { } -// Applies necessary geometric transformations to raw cursor positions: -Windows::Foundation::Point -WINRT_TransformCursorPosition(SDL_Window * window, Windows::Foundation::Point rawPosition) -{ - using namespace Windows::Graphics::Display; - - if (!window) { - return rawPosition; - } - - SDL_WindowData * windowData = (SDL_WindowData *) window->driverdata; - if (windowData->coreWindow == nullptr) { - // For some reason, the window isn't associated with a CoreWindow. - // This might end up being the case as XAML support is extended. - // For now, if there's no CoreWindow attached to the SDL_Window, - // don't do any transforms. - return rawPosition; - } - - // The CoreWindow can only be accessed on certain thread(s). - SDL_assert(CoreWindow::GetForCurrentThread() != nullptr); - - CoreWindow ^ nativeWindow = windowData->coreWindow.Get(); - Windows::Foundation::Point outputPosition; - -#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP - outputPosition.X = rawPosition.X * (((float32)window->w) / nativeWindow->Bounds.Width); - outputPosition.Y = rawPosition.Y * (((float32)window->h) / nativeWindow->Bounds.Height); -#else - switch (DisplayProperties::CurrentOrientation) - { - case DisplayOrientations::Portrait: - outputPosition.X = rawPosition.X * (((float32)window->w) / nativeWindow->Bounds.Width); - outputPosition.Y = rawPosition.Y * (((float32)window->h) / nativeWindow->Bounds.Height); - break; - case DisplayOrientations::PortraitFlipped: - outputPosition.X = (float32)window->w - rawPosition.X * (((float32)window->w) / nativeWindow->Bounds.Width); - outputPosition.Y = (float32)window->h - rawPosition.Y * (((float32)window->h) / nativeWindow->Bounds.Height); - break; - case DisplayOrientations::Landscape: - outputPosition.X = rawPosition.Y * (((float32)window->w) / nativeWindow->Bounds.Height); - outputPosition.Y = (float32)window->h - rawPosition.X * (((float32)window->h) / nativeWindow->Bounds.Width); - break; - case DisplayOrientations::LandscapeFlipped: - outputPosition.X = (float32)window->w - rawPosition.Y * (((float32)window->w) / nativeWindow->Bounds.Height); - outputPosition.Y = rawPosition.X * (((float32)window->h) / nativeWindow->Bounds.Width); - break; - default: - break; - } -#endif - - return outputPosition; -} - -static inline int -_lround(float arg) -{ - if (arg >= 0.0f) { - return (int)floor(arg + 0.5f); - } else { - return (int)ceil(arg - 0.5f); - } -} - -void -WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args) -{ - if (!window || !WINRT_UseRelativeMouseMode) { - return; - } - - // 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 WinRT 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 - // to SDL with minimal transformation: from native screen coordinates (in DIPs) - // to SDL window coordinates. - // - const Windows::Foundation::Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y); - const Windows::Foundation::Point mouseDeltaInSDLWindowCoords = WINRT_TransformCursorPosition(window, mouseDeltaInDIPs); - SDL_SendMouseMotion( - window, - 0, - 1, - _lround(mouseDeltaInSDLWindowCoords.X), - _lround(mouseDeltaInSDLWindowCoords.Y)); -} - -Uint8 -WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt) -{ - using namespace Windows::UI::Input; - -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - return SDL_BUTTON_LEFT; -#else - switch (pt->Properties->PointerUpdateKind) - { - case PointerUpdateKind::LeftButtonPressed: - case PointerUpdateKind::LeftButtonReleased: - return SDL_BUTTON_LEFT; - - case PointerUpdateKind::RightButtonPressed: - case PointerUpdateKind::RightButtonReleased: - return SDL_BUTTON_RIGHT; - - case PointerUpdateKind::MiddleButtonPressed: - case PointerUpdateKind::MiddleButtonReleased: - return SDL_BUTTON_MIDDLE; - - case PointerUpdateKind::XButton1Pressed: - case PointerUpdateKind::XButton1Released: - return SDL_BUTTON_X1; - - case PointerUpdateKind::XButton2Pressed: - case PointerUpdateKind::XButton2Released: - return SDL_BUTTON_X2; - - default: - break; - } -#endif - - return 0; -} - -//const char * -//WINRT_ConvertPointerUpdateKindToString(Windows::UI::Input::PointerUpdateKind kind) -//{ -// using namespace Windows::UI::Input; -// -// switch (kind) -// { -// case PointerUpdateKind::Other: -// return "Other"; -// case PointerUpdateKind::LeftButtonPressed: -// return "LeftButtonPressed"; -// case PointerUpdateKind::LeftButtonReleased: -// return "LeftButtonReleased"; -// case PointerUpdateKind::RightButtonPressed: -// return "RightButtonPressed"; -// case PointerUpdateKind::RightButtonReleased: -// return "RightButtonReleased"; -// case PointerUpdateKind::MiddleButtonPressed: -// return "MiddleButtonPressed"; -// case PointerUpdateKind::MiddleButtonReleased: -// return "MiddleButtonReleased"; -// case PointerUpdateKind::XButton1Pressed: -// return "XButton1Pressed"; -// case PointerUpdateKind::XButton1Released: -// return "XButton1Released"; -// case PointerUpdateKind::XButton2Pressed: -// return "XButton2Pressed"; -// case PointerUpdateKind::XButton2Released: -// return "XButton2Released"; -// } -// -// return ""; -//} - -static bool -WINRT_IsTouchEvent(Windows::UI::Input::PointerPoint ^pointerPoint) -{ -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - return true; -#else - using namespace Windows::Devices::Input; - switch (pointerPoint->PointerDevice->PointerDeviceType) { - case PointerDeviceType::Touch: - case PointerDeviceType::Pen: - return true; - default: - return false; - } -#endif -} - -void -WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) -{ - if (!window || WINRT_UseRelativeMouseMode) { - return; - } - - Windows::Foundation::Point transformedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position); - - if (pointerPoint->PointerId == WINRT_LeftFingerDown) { - SDL_SendMouseMotion(window, 0, 0, (int)transformedPoint.X, (int)transformedPoint.Y); - } - - if (WINRT_IsTouchEvent(pointerPoint)) { - SDL_SendTouchMotion( - WINRT_TouchID, - (SDL_FingerID) pointerPoint->PointerId, - transformedPoint.X, - transformedPoint.Y, - pointerPoint->Properties->Pressure); - } -} - -void -WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) -{ - if (!window) { - return; - } - - // FIXME: This may need to accumulate deltas up to WHEEL_DELTA - short motion = pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA; - SDL_SendMouseWheel(window, 0, 0, motion); -} - -void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) -{ - if (!window) { - return; - } - - Windows::Foundation::Point transformedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position); - - if (WINRT_LeftFingerDown == pointerPoint->PointerId) { - Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); - if (button) { - SDL_SendMouseButton(window, 0, SDL_RELEASED, button); - } - WINRT_LeftFingerDown = 0; - } - - if (WINRT_IsTouchEvent(pointerPoint)) { - SDL_SendTouch( - WINRT_TouchID, - (SDL_FingerID) pointerPoint->PointerId, - SDL_FALSE, - transformedPoint.X, - transformedPoint.Y, - pointerPoint->Properties->Pressure); - } -} - -void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) -{ - if (!window) { - return; - } - - Windows::Foundation::Point transformedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position); - - if (!WINRT_LeftFingerDown) { - Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); - if (button) { -#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP - SDL_SendMouseMotion(window, 0, 0, (int)transformedPoint.X, (int)transformedPoint.Y); -#endif - SDL_SendMouseButton(window, 0, SDL_PRESSED, button); - } - - WINRT_LeftFingerDown = pointerPoint->PointerId; - } - - if (WINRT_IsTouchEvent(pointerPoint)) { - SDL_SendTouch( - WINRT_TouchID, - (SDL_FingerID) pointerPoint->PointerId, - SDL_TRUE, - transformedPoint.X, - transformedPoint.Y, - pointerPoint->Properties->Pressure); - } -} - #endif /* SDL_VIDEO_DRIVER_WINRT */ /* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtmouse.h b/src/video/winrt/SDL_winrtmouse.h index 50bdbe24d1e84..24c6e015e9d52 100644 --- a/src/video/winrt/SDL_winrtmouse.h +++ b/src/video/winrt/SDL_winrtmouse.h @@ -20,11 +20,20 @@ */ #include "SDL_config.h" -#ifndef _SDL_windowsmouse_h -#define _SDL_windowsmouse_h +#ifndef _SDL_winrtmouse_h +#define _SDL_winrtmouse_h + +#ifdef __cplusplus +extern "C" { +#endif extern void WINRT_InitMouse(_THIS); extern void WINRT_QuitMouse(_THIS); +extern SDL_bool WINRT_UsingRelativeMouseMode; + +#ifdef __cplusplus +} +#endif #endif /* _SDL_windowsmouse_h */ diff --git a/src/video/winrt/SDL_winrtpointerinput.cpp b/src/video/winrt/SDL_winrtpointerinput.cpp new file mode 100644 index 0000000000000..ee1dc80e5f30b --- /dev/null +++ b/src/video/winrt/SDL_winrtpointerinput.cpp @@ -0,0 +1,372 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "SDL_config.h" + +#if SDL_VIDEO_DRIVER_WINRT + +/* SDL includes */ +#include "SDL_winrtevents_c.h" +#include "SDL_winrtmouse.h" +#include "SDL_winrtvideo_cpp.h" +#include "SDL_assert.h" +#include "SDL_system.h" + +extern "C" { +#include "../SDL_sysvideo.h" +#include "../../events/SDL_events_c.h" +#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_touch_c.h" +} + +/* File-specific globals: */ +static SDL_TouchID WINRT_TouchID = 1; +static unsigned int WINRT_LeftFingerDown = 0; + + +void +WINRT_InitTouch(_THIS) +{ + SDL_AddTouch(WINRT_TouchID, ""); +} + + +// Applies necessary geometric transformations to raw cursor positions: +Windows::Foundation::Point +WINRT_TransformCursorPosition(SDL_Window * window, Windows::Foundation::Point rawPosition) +{ + using namespace Windows::UI::Core; + using namespace Windows::Graphics::Display; + + if (!window) { + return rawPosition; + } + + SDL_WindowData * windowData = (SDL_WindowData *) window->driverdata; + if (windowData->coreWindow == nullptr) { + // For some reason, the window isn't associated with a CoreWindow. + // This might end up being the case as XAML support is extended. + // For now, if there's no CoreWindow attached to the SDL_Window, + // don't do any transforms. + return rawPosition; + } + + // The CoreWindow can only be accessed on certain thread(s). + SDL_assert(CoreWindow::GetForCurrentThread() != nullptr); + + CoreWindow ^ nativeWindow = windowData->coreWindow.Get(); + Windows::Foundation::Point outputPosition; + +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP + outputPosition.X = rawPosition.X * (((float32)window->w) / nativeWindow->Bounds.Width); + outputPosition.Y = rawPosition.Y * (((float32)window->h) / nativeWindow->Bounds.Height); +#else + switch (DisplayProperties::CurrentOrientation) + { + case DisplayOrientations::Portrait: + outputPosition.X = rawPosition.X * (((float32)window->w) / nativeWindow->Bounds.Width); + outputPosition.Y = rawPosition.Y * (((float32)window->h) / nativeWindow->Bounds.Height); + break; + case DisplayOrientations::PortraitFlipped: + outputPosition.X = (float32)window->w - rawPosition.X * (((float32)window->w) / nativeWindow->Bounds.Width); + outputPosition.Y = (float32)window->h - rawPosition.Y * (((float32)window->h) / nativeWindow->Bounds.Height); + break; + case DisplayOrientations::Landscape: + outputPosition.X = rawPosition.Y * (((float32)window->w) / nativeWindow->Bounds.Height); + outputPosition.Y = (float32)window->h - rawPosition.X * (((float32)window->h) / nativeWindow->Bounds.Width); + break; + case DisplayOrientations::LandscapeFlipped: + outputPosition.X = (float32)window->w - rawPosition.Y * (((float32)window->w) / nativeWindow->Bounds.Height); + outputPosition.Y = rawPosition.X * (((float32)window->h) / nativeWindow->Bounds.Width); + break; + default: + break; + } +#endif + + return outputPosition; +} + +static inline int +_lround(float arg) +{ + if (arg >= 0.0f) { + return (int)floor(arg + 0.5f); + } else { + return (int)ceil(arg - 0.5f); + } +} + +void +WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args) +{ + if (!window || !WINRT_UsingRelativeMouseMode) { + return; + } + + // 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 WinRT 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 + // to SDL with minimal transformation: from native screen coordinates (in DIPs) + // to SDL window coordinates. + // + const Windows::Foundation::Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y); + const Windows::Foundation::Point mouseDeltaInSDLWindowCoords = WINRT_TransformCursorPosition(window, mouseDeltaInDIPs); + SDL_SendMouseMotion( + window, + 0, + 1, + _lround(mouseDeltaInSDLWindowCoords.X), + _lround(mouseDeltaInSDLWindowCoords.Y)); +} + +Uint8 +WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt) +{ + using namespace Windows::UI::Input; + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + return SDL_BUTTON_LEFT; +#else + switch (pt->Properties->PointerUpdateKind) + { + case PointerUpdateKind::LeftButtonPressed: + case PointerUpdateKind::LeftButtonReleased: + return SDL_BUTTON_LEFT; + + case PointerUpdateKind::RightButtonPressed: + case PointerUpdateKind::RightButtonReleased: + return SDL_BUTTON_RIGHT; + + case PointerUpdateKind::MiddleButtonPressed: + case PointerUpdateKind::MiddleButtonReleased: + return SDL_BUTTON_MIDDLE; + + case PointerUpdateKind::XButton1Pressed: + case PointerUpdateKind::XButton1Released: + return SDL_BUTTON_X1; + + case PointerUpdateKind::XButton2Pressed: + case PointerUpdateKind::XButton2Released: + return SDL_BUTTON_X2; + + default: + break; + } +#endif + + return 0; +} + +//const char * +//WINRT_ConvertPointerUpdateKindToString(Windows::UI::Input::PointerUpdateKind kind) +//{ +// using namespace Windows::UI::Input; +// +// switch (kind) +// { +// case PointerUpdateKind::Other: +// return "Other"; +// case PointerUpdateKind::LeftButtonPressed: +// return "LeftButtonPressed"; +// case PointerUpdateKind::LeftButtonReleased: +// return "LeftButtonReleased"; +// case PointerUpdateKind::RightButtonPressed: +// return "RightButtonPressed"; +// case PointerUpdateKind::RightButtonReleased: +// return "RightButtonReleased"; +// case PointerUpdateKind::MiddleButtonPressed: +// return "MiddleButtonPressed"; +// case PointerUpdateKind::MiddleButtonReleased: +// return "MiddleButtonReleased"; +// case PointerUpdateKind::XButton1Pressed: +// return "XButton1Pressed"; +// case PointerUpdateKind::XButton1Released: +// return "XButton1Released"; +// case PointerUpdateKind::XButton2Pressed: +// return "XButton2Pressed"; +// case PointerUpdateKind::XButton2Released: +// return "XButton2Released"; +// } +// +// return ""; +//} + +static bool +WINRT_IsTouchEvent(Windows::UI::Input::PointerPoint ^pointerPoint) +{ +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + return true; +#else + using namespace Windows::Devices::Input; + switch (pointerPoint->PointerDevice->PointerDeviceType) { + case PointerDeviceType::Touch: + case PointerDeviceType::Pen: + return true; + default: + return false; + } +#endif +} + +void +WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window || WINRT_UsingRelativeMouseMode) { + return; + } + + Windows::Foundation::Point transformedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position); + + if (pointerPoint->PointerId == WINRT_LeftFingerDown) { + SDL_SendMouseMotion(window, 0, 0, (int)transformedPoint.X, (int)transformedPoint.Y); + } + + if (WINRT_IsTouchEvent(pointerPoint)) { + SDL_SendTouchMotion( + WINRT_TouchID, + (SDL_FingerID) pointerPoint->PointerId, + transformedPoint.X, + transformedPoint.Y, + pointerPoint->Properties->Pressure); + } +} + +void +WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window) { + return; + } + + // FIXME: This may need to accumulate deltas up to WHEEL_DELTA + short motion = pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA; + SDL_SendMouseWheel(window, 0, 0, motion); +} + +void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window) { + return; + } + + Windows::Foundation::Point transformedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position); + + if (WINRT_LeftFingerDown == pointerPoint->PointerId) { + Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); + if (button) { + SDL_SendMouseButton(window, 0, SDL_RELEASED, button); + } + WINRT_LeftFingerDown = 0; + } + + if (WINRT_IsTouchEvent(pointerPoint)) { + SDL_SendTouch( + WINRT_TouchID, + (SDL_FingerID) pointerPoint->PointerId, + SDL_FALSE, + transformedPoint.X, + transformedPoint.Y, + pointerPoint->Properties->Pressure); + } +} + +void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window) { + return; + } + + Windows::Foundation::Point transformedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position); + + if (!WINRT_LeftFingerDown) { + Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); + if (button) { +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + SDL_SendMouseMotion(window, 0, 0, (int)transformedPoint.X, (int)transformedPoint.Y); +#endif + SDL_SendMouseButton(window, 0, SDL_PRESSED, button); + } + + WINRT_LeftFingerDown = pointerPoint->PointerId; + } + + if (WINRT_IsTouchEvent(pointerPoint)) { + SDL_SendTouch( + WINRT_TouchID, + (SDL_FingerID) pointerPoint->PointerId, + SDL_TRUE, + transformedPoint.X, + transformedPoint.Y, + pointerPoint->Properties->Pressure); + } +} + +#endif // SDL_VIDEO_DRIVER_WINRT diff --git a/src/video/winrt/SDL_winrtvideo.cpp b/src/video/winrt/SDL_winrtvideo.cpp index 621b2edaab327..5e5c75e2b2c37 100644 --- a/src/video/winrt/SDL_winrtvideo.cpp +++ b/src/video/winrt/SDL_winrtvideo.cpp @@ -45,15 +45,13 @@ extern "C" { } #include "../../core/winrt/SDL_winrtapp.h" +#include "../../core/winrt/SDL_winrtxaml_cpp.h" #include "SDL_winrtvideo_cpp.h" #include "SDL_winrtevents_c.h" #include "SDL_winrtmouse.h" #include "SDL_main.h" #include "SDL_system.h" -extern SDL_WinRTApp ^ SDL_WinRTGlobalApp; -extern SDL_bool WINRT_XAMLWasEnabled; - /* Initialization/Query functions */ static int WINRT_VideoInit(_THIS); @@ -68,19 +66,11 @@ static void WINRT_DestroyWindow(_THIS, SDL_Window * window); static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info); -/* The global, WinRT, SDL Window. - For now, SDL/WinRT only supports one window (due to platform limitations of - WinRT. -*/ +/* SDL-internal globals: */ SDL_Window * WINRT_GlobalSDLWindow = NULL; - - -/* The global, WinRT, video device. -*/ SDL_VideoDevice * WINRT_GlobalSDLVideoDevice = NULL; - /* WinRT driver bootstrap functions */ static int @@ -140,6 +130,7 @@ WINRT_VideoInit(_THIS) return -1; } WINRT_InitMouse(_this); + WINRT_InitTouch(_this); return 0; } diff --git a/src/video/winrt/SDL_winrtvideo_cpp.h b/src/video/winrt/SDL_winrtvideo_cpp.h index eb4d788fa374e..a36cc308d1aa2 100644 --- a/src/video/winrt/SDL_winrtvideo_cpp.h +++ b/src/video/winrt/SDL_winrtvideo_cpp.h @@ -29,6 +29,19 @@ #include "SDL_events.h" +/* The global, WinRT, SDL Window. + For now, SDL/WinRT only supports one window (due to platform limitations of + WinRT. +*/ +extern SDL_Window * WINRT_GlobalSDLWindow; + +/* The global, WinRT, video device. */ +extern SDL_VideoDevice * WINRT_GlobalSDLVideoDevice; + +/* Computes the current display mode for Plain Direct3D (non-XAML) apps */ +extern SDL_DisplayMode WINRT_CalcDisplayModeUsingNativeWindow(); + + #ifdef __cplusplus_winrt /* Internal window data */