123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394 |
- /*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
- 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_internal.h"
- #if SDL_VIDEO_DRIVER_WINRT
- /* SDL includes */
- #include "SDL_winrtevents_c.h"
- #include "SDL_winrtmouse_c.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,
- WINRT_CursorNormalizationType normalization)
- {
- 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.
- // TODO, WinRT: make sure touch input coordinate ranges are correct when using XAML support
- 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;
- // Compute coordinates normalized from 0..1.
- // If the coordinates need to be sized to the SDL window,
- // we'll do that after.
- #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
- outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width;
- outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height;
- #else
- switch (DisplayProperties::CurrentOrientation)
- {
- case DisplayOrientations::Portrait:
- outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width;
- outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height;
- break;
- case DisplayOrientations::PortraitFlipped:
- outputPosition.X = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width);
- outputPosition.Y = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height);
- break;
- case DisplayOrientations::Landscape:
- outputPosition.X = rawPosition.Y / nativeWindow->Bounds.Height;
- outputPosition.Y = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width);
- break;
- case DisplayOrientations::LandscapeFlipped:
- outputPosition.X = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height);
- outputPosition.Y = rawPosition.X / nativeWindow->Bounds.Width;
- break;
- default:
- break;
- }
- #endif
- if (normalization == TransformToSDLWindowSize) {
- outputPosition.X *= ((float32) window->w);
- outputPosition.Y *= ((float32) window->h);
- }
- 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);
- }
- }
- 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_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
- {
- if (!window) {
- return;
- }
- Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint);
- if ( ! WINRT_IsTouchEvent(pointerPoint)) {
- SDL_SendMouseButton(window, 0, SDL_PRESSED, button);
- } else {
- Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne);
- Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize);
- if (!WINRT_LeftFingerDown) {
- if (button) {
- SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y);
- SDL_SendMouseButton(window, 0, SDL_PRESSED, button);
- }
- WINRT_LeftFingerDown = pointerPoint->PointerId;
- }
- SDL_SendTouch(
- WINRT_TouchID,
- (SDL_FingerID) pointerPoint->PointerId,
- SDL_TRUE,
- normalizedPoint.X,
- normalizedPoint.Y,
- pointerPoint->Properties->Pressure);
- }
- }
- void
- WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
- {
- if (!window || WINRT_UsingRelativeMouseMode) {
- return;
- }
- Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne);
- Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize);
- if ( ! WINRT_IsTouchEvent(pointerPoint)) {
- SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y);
- } else if (pointerPoint->PointerId == WINRT_LeftFingerDown) {
- if (pointerPoint->PointerId == WINRT_LeftFingerDown) {
- SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y);
- }
- SDL_SendTouchMotion(
- WINRT_TouchID,
- (SDL_FingerID) pointerPoint->PointerId,
- normalizedPoint.X,
- normalizedPoint.Y,
- pointerPoint->Properties->Pressure);
- }
- }
- void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
- {
- if (!window) {
- return;
- }
- Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint);
- if (!WINRT_IsTouchEvent(pointerPoint)) {
- SDL_SendMouseButton(window, 0, SDL_RELEASED, button);
- } else {
- Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne);
- if (WINRT_LeftFingerDown == pointerPoint->PointerId) {
- if (button) {
- SDL_SendMouseButton(window, 0, SDL_RELEASED, button);
- }
- WINRT_LeftFingerDown = 0;
- }
-
- SDL_SendTouch(
- WINRT_TouchID,
- (SDL_FingerID) pointerPoint->PointerId,
- SDL_FALSE,
- normalizedPoint.X,
- normalizedPoint.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_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, TransformToSDLWindowSize);
- SDL_SendMouseMotion(
- window,
- 0,
- 1,
- _lround(mouseDeltaInSDLWindowCoords.X),
- _lround(mouseDeltaInSDLWindowCoords.Y));
- }
- #endif // SDL_VIDEO_DRIVER_WINRT
|