src/video/winrt/SDL_winrtpointerinput.cpp
changeset 8521 cefdaf414ead
parent 8516 f3e0e381bdcd
child 8534 50177f518fdb
equal deleted inserted replaced
8520:66c31b377506 8521:cefdaf414ead
    45 WINRT_InitTouch(_THIS)
    45 WINRT_InitTouch(_THIS)
    46 {
    46 {
    47     SDL_AddTouch(WINRT_TouchID, "");
    47     SDL_AddTouch(WINRT_TouchID, "");
    48 }
    48 }
    49 
    49 
    50 
       
    51 // Applies necessary geometric transformations to raw cursor positions:
    50 // Applies necessary geometric transformations to raw cursor positions:
    52 Windows::Foundation::Point
    51 Windows::Foundation::Point
    53 WINRT_TransformCursorPosition(SDL_Window * window, Windows::Foundation::Point rawPosition)
    52 WINRT_TransformCursorPosition(SDL_Window * window, Windows::Foundation::Point rawPosition)
    54 {
    53 {
    55     using namespace Windows::UI::Core;
    54     using namespace Windows::UI::Core;
   110     if (arg >= 0.0f) {
   109     if (arg >= 0.0f) {
   111         return (int)floor(arg + 0.5f);
   110         return (int)floor(arg + 0.5f);
   112     } else {
   111     } else {
   113         return (int)ceil(arg - 0.5f);
   112         return (int)ceil(arg - 0.5f);
   114     }
   113     }
   115 }
       
   116 
       
   117 void
       
   118 WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args)
       
   119 {
       
   120     if (!window || !WINRT_UsingRelativeMouseMode) {
       
   121         return;
       
   122     }
       
   123 
       
   124     // DLudwig, 2012-12-28: On some systems, namely Visual Studio's Windows
       
   125     // Simulator, as well as Windows 8 in a Parallels 8 VM, MouseEventArgs'
       
   126     // MouseDelta field often reports very large values.  More information
       
   127     // on this can be found at the following pages on MSDN:
       
   128     //  - http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/a3c789fa-f1c5-49c4-9c0a-7db88d0f90f8
       
   129     //  - https://connect.microsoft.com/VisualStudio/Feedback/details/756515
       
   130     //
       
   131     // The values do not appear to be as large when running on some systems,
       
   132     // most notably a Surface RT.  Furthermore, the values returned by
       
   133     // CoreWindow's PointerMoved event, and sent to this class' OnPointerMoved
       
   134     // method, do not ever appear to be large, even when MouseEventArgs'
       
   135     // MouseDelta is reporting to the contrary.
       
   136     //
       
   137     // On systems with the large-values behavior, it appears that the values
       
   138     // get reported as if the screen's size is 65536 units in both the X and Y
       
   139     // dimensions.  This can be viewed by using Windows' now-private, "Raw Input"
       
   140     // APIs.  (GetRawInputData, RegisterRawInputDevices, WM_INPUT, etc.)
       
   141     //
       
   142     // MSDN's documentation on MouseEventArgs' MouseDelta field (at
       
   143     // http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.input.mouseeventargs.mousedelta ),
       
   144     // does not seem to indicate (to me) that its values should be so large.  It
       
   145     // says that its values should be a "change in screen location".  I could
       
   146     // be misinterpreting this, however a post on MSDN from a Microsoft engineer (see: 
       
   147     // http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/09a9868e-95bb-4858-ba1a-cb4d2c298d62 ),
       
   148     // indicates that these values are in DIPs, which is the same unit used
       
   149     // by CoreWindow's PointerMoved events (via the Position field in its CurrentPoint
       
   150     // property.  See http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.input.pointerpoint.position.aspx
       
   151     // for details.)
       
   152     //
       
   153     // To note, PointerMoved events are sent a 'RawPosition' value (via the
       
   154     // CurrentPoint property in MouseEventArgs), however these do not seem
       
   155     // to exhibit the same large-value behavior.
       
   156     //
       
   157     // The values passed via PointerMoved events can't always be used for relative
       
   158     // mouse motion, unfortunately.  Its values are bound to the cursor's position,
       
   159     // which stops when it hits one of the screen's edges.  This can be a problem in
       
   160     // first person shooters, whereby it is normal for mouse motion to travel far
       
   161     // along any one axis for a period of time.  MouseMoved events do not have the
       
   162     // screen-bounding limitation, and can be used regardless of where the system's
       
   163     // cursor is.
       
   164     //
       
   165     // One possible workaround would be to programmatically set the cursor's
       
   166     // position to the screen's center (when SDL's relative mouse mode is enabled),
       
   167     // however WinRT does not yet seem to have the ability to set the cursor's
       
   168     // position via a public API.  Win32 did this via an API call, SetCursorPos,
       
   169     // however WinRT makes this function be private.  Apps that use it won't get
       
   170     // approved for distribution in the Windows Store.  I've yet to be able to find
       
   171     // a suitable, store-friendly counterpart for WinRT.
       
   172     //
       
   173     // There may be some room for a workaround whereby OnPointerMoved's values
       
   174     // are compared to the values from OnMouseMoved in order to detect
       
   175     // when this bug is active.  A suitable transformation could then be made to
       
   176     // OnMouseMoved's values.  For now, however, the system-reported values are sent
       
   177     // to SDL with minimal transformation: from native screen coordinates (in DIPs)
       
   178     // to SDL window coordinates.
       
   179     //
       
   180     const Windows::Foundation::Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y);
       
   181     const Windows::Foundation::Point mouseDeltaInSDLWindowCoords = WINRT_TransformCursorPosition(window, mouseDeltaInDIPs);
       
   182     SDL_SendMouseMotion(
       
   183         window,
       
   184         0,
       
   185         1,
       
   186         _lround(mouseDeltaInSDLWindowCoords.X),
       
   187         _lround(mouseDeltaInSDLWindowCoords.Y));
       
   188 }
   114 }
   189 
   115 
   190 Uint8
   116 Uint8
   191 WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt)
   117 WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt)
   192 {
   118 {
   274             return false;
   200             return false;
   275     }
   201     }
   276 #endif
   202 #endif
   277 }
   203 }
   278 
   204 
       
   205 void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
       
   206 {
       
   207     if (!window) {
       
   208         return;
       
   209     }
       
   210 
       
   211     Windows::Foundation::Point transformedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position);
       
   212 
       
   213     if (!WINRT_LeftFingerDown) {
       
   214         Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint);
       
   215         if (button) {
       
   216 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
       
   217             SDL_SendMouseMotion(window, 0, 0, (int)transformedPoint.X, (int)transformedPoint.Y);
       
   218 #endif
       
   219             SDL_SendMouseButton(window, 0, SDL_PRESSED, button);
       
   220         }
       
   221 
       
   222         WINRT_LeftFingerDown = pointerPoint->PointerId;
       
   223     }
       
   224 
       
   225     if (WINRT_IsTouchEvent(pointerPoint)) {
       
   226         SDL_SendTouch(
       
   227             WINRT_TouchID,
       
   228             (SDL_FingerID) pointerPoint->PointerId,
       
   229             SDL_TRUE,
       
   230             transformedPoint.X,
       
   231             transformedPoint.Y,
       
   232             pointerPoint->Properties->Pressure);
       
   233     }
       
   234 }
       
   235 
   279 void
   236 void
   280 WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
   237 WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
   281 {
   238 {
   282     if (!window || WINRT_UsingRelativeMouseMode) {
   239     if (!window || WINRT_UsingRelativeMouseMode) {
   283         return;
   240         return;
   295             (SDL_FingerID) pointerPoint->PointerId,
   252             (SDL_FingerID) pointerPoint->PointerId,
   296             transformedPoint.X,
   253             transformedPoint.X,
   297             transformedPoint.Y,
   254             transformedPoint.Y,
   298             pointerPoint->Properties->Pressure);
   255             pointerPoint->Properties->Pressure);
   299     }
   256     }
   300 }
       
   301 
       
   302 void
       
   303 WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
       
   304 {
       
   305     if (!window) {
       
   306         return;
       
   307     }
       
   308 
       
   309     // FIXME: This may need to accumulate deltas up to WHEEL_DELTA
       
   310     short motion = pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA;
       
   311     SDL_SendMouseWheel(window, 0, 0, motion);
       
   312 }
   257 }
   313 
   258 
   314 void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
   259 void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
   315 {
   260 {
   316     if (!window) {
   261     if (!window) {
   336             transformedPoint.Y,
   281             transformedPoint.Y,
   337             pointerPoint->Properties->Pressure);
   282             pointerPoint->Properties->Pressure);
   338     }
   283     }
   339 }
   284 }
   340 
   285 
   341 void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
   286 void
       
   287 WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
   342 {
   288 {
   343     if (!window) {
   289     if (!window) {
   344         return;
   290         return;
   345     }
   291     }
   346 
   292 
   347     Windows::Foundation::Point transformedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position);
   293     // FIXME: This may need to accumulate deltas up to WHEEL_DELTA
   348 
   294     short motion = pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA;
   349     if (!WINRT_LeftFingerDown) {
   295     SDL_SendMouseWheel(window, 0, 0, motion);
   350         Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint);
   296 }
   351         if (button) {
   297 
   352 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
   298 void
   353             SDL_SendMouseMotion(window, 0, 0, (int)transformedPoint.X, (int)transformedPoint.Y);
   299 WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args)
   354 #endif
   300 {
   355             SDL_SendMouseButton(window, 0, SDL_PRESSED, button);
   301     if (!window || !WINRT_UsingRelativeMouseMode) {
   356         }
   302         return;
   357 
   303     }
   358         WINRT_LeftFingerDown = pointerPoint->PointerId;
   304 
   359     }
   305     // DLudwig, 2012-12-28: On some systems, namely Visual Studio's Windows
   360 
   306     // Simulator, as well as Windows 8 in a Parallels 8 VM, MouseEventArgs'
   361     if (WINRT_IsTouchEvent(pointerPoint)) {
   307     // MouseDelta field often reports very large values.  More information
   362         SDL_SendTouch(
   308     // on this can be found at the following pages on MSDN:
   363             WINRT_TouchID,
   309     //  - http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/a3c789fa-f1c5-49c4-9c0a-7db88d0f90f8
   364             (SDL_FingerID) pointerPoint->PointerId,
   310     //  - https://connect.microsoft.com/VisualStudio/Feedback/details/756515
   365             SDL_TRUE,
   311     //
   366             transformedPoint.X,
   312     // The values do not appear to be as large when running on some systems,
   367             transformedPoint.Y,
   313     // most notably a Surface RT.  Furthermore, the values returned by
   368             pointerPoint->Properties->Pressure);
   314     // CoreWindow's PointerMoved event, and sent to this class' OnPointerMoved
   369     }
   315     // method, do not ever appear to be large, even when MouseEventArgs'
       
   316     // MouseDelta is reporting to the contrary.
       
   317     //
       
   318     // On systems with the large-values behavior, it appears that the values
       
   319     // get reported as if the screen's size is 65536 units in both the X and Y
       
   320     // dimensions.  This can be viewed by using Windows' now-private, "Raw Input"
       
   321     // APIs.  (GetRawInputData, RegisterRawInputDevices, WM_INPUT, etc.)
       
   322     //
       
   323     // MSDN's documentation on MouseEventArgs' MouseDelta field (at
       
   324     // http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.input.mouseeventargs.mousedelta ),
       
   325     // does not seem to indicate (to me) that its values should be so large.  It
       
   326     // says that its values should be a "change in screen location".  I could
       
   327     // be misinterpreting this, however a post on MSDN from a Microsoft engineer (see: 
       
   328     // http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/09a9868e-95bb-4858-ba1a-cb4d2c298d62 ),
       
   329     // indicates that these values are in DIPs, which is the same unit used
       
   330     // by CoreWindow's PointerMoved events (via the Position field in its CurrentPoint
       
   331     // property.  See http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.input.pointerpoint.position.aspx
       
   332     // for details.)
       
   333     //
       
   334     // To note, PointerMoved events are sent a 'RawPosition' value (via the
       
   335     // CurrentPoint property in MouseEventArgs), however these do not seem
       
   336     // to exhibit the same large-value behavior.
       
   337     //
       
   338     // The values passed via PointerMoved events can't always be used for relative
       
   339     // mouse motion, unfortunately.  Its values are bound to the cursor's position,
       
   340     // which stops when it hits one of the screen's edges.  This can be a problem in
       
   341     // first person shooters, whereby it is normal for mouse motion to travel far
       
   342     // along any one axis for a period of time.  MouseMoved events do not have the
       
   343     // screen-bounding limitation, and can be used regardless of where the system's
       
   344     // cursor is.
       
   345     //
       
   346     // One possible workaround would be to programmatically set the cursor's
       
   347     // position to the screen's center (when SDL's relative mouse mode is enabled),
       
   348     // however WinRT does not yet seem to have the ability to set the cursor's
       
   349     // position via a public API.  Win32 did this via an API call, SetCursorPos,
       
   350     // however WinRT makes this function be private.  Apps that use it won't get
       
   351     // approved for distribution in the Windows Store.  I've yet to be able to find
       
   352     // a suitable, store-friendly counterpart for WinRT.
       
   353     //
       
   354     // There may be some room for a workaround whereby OnPointerMoved's values
       
   355     // are compared to the values from OnMouseMoved in order to detect
       
   356     // when this bug is active.  A suitable transformation could then be made to
       
   357     // OnMouseMoved's values.  For now, however, the system-reported values are sent
       
   358     // to SDL with minimal transformation: from native screen coordinates (in DIPs)
       
   359     // to SDL window coordinates.
       
   360     //
       
   361     const Windows::Foundation::Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y);
       
   362     const Windows::Foundation::Point mouseDeltaInSDLWindowCoords = WINRT_TransformCursorPosition(window, mouseDeltaInDIPs);
       
   363     SDL_SendMouseMotion(
       
   364         window,
       
   365         0,
       
   366         1,
       
   367         _lround(mouseDeltaInSDLWindowCoords.X),
       
   368         _lround(mouseDeltaInSDLWindowCoords.Y));
   370 }
   369 }
   371 
   370 
   372 #endif // SDL_VIDEO_DRIVER_WINRT
   371 #endif // SDL_VIDEO_DRIVER_WINRT