SDL  2.0
SDL_winrtpointerinput.cpp
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "../../SDL_internal.h"
22 
23 #if SDL_VIDEO_DRIVER_WINRT
24 
25 /* SDL includes */
26 #include "SDL_winrtevents_c.h"
27 #include "SDL_winrtmouse_c.h"
28 #include "SDL_winrtvideo_cpp.h"
29 #include "SDL_assert.h"
30 #include "SDL_system.h"
31 
32 extern "C" {
33 #include "../SDL_sysvideo.h"
34 #include "../../events/SDL_events_c.h"
35 #include "../../events/SDL_mouse_c.h"
36 #include "../../events/SDL_touch_c.h"
37 }
38 
39 /* File-specific globals: */
40 static SDL_TouchID WINRT_TouchID = 1;
41 
42 
43 void
45 {
46  SDL_AddTouch(WINRT_TouchID, SDL_TOUCH_DEVICE_DIRECT, "");
47 }
48 
49 
50 //
51 // Applies necessary geometric transformations to raw cursor positions:
52 //
53 Windows::Foundation::Point
54 WINRT_TransformCursorPosition(SDL_Window * window,
55  Windows::Foundation::Point rawPosition,
56  WINRT_CursorNormalizationType normalization)
57 {
58  using namespace Windows::UI::Core;
59  using namespace Windows::Graphics::Display;
60 
61  if (!window) {
62  return rawPosition;
63  }
64 
65  SDL_WindowData * windowData = (SDL_WindowData *) window->driverdata;
66  if (windowData->coreWindow == nullptr) {
67  // For some reason, the window isn't associated with a CoreWindow.
68  // This might end up being the case as XAML support is extended.
69  // For now, if there's no CoreWindow attached to the SDL_Window,
70  // don't do any transforms.
71 
72  // TODO, WinRT: make sure touch input coordinate ranges are correct when using XAML support
73  return rawPosition;
74  }
75 
76  // The CoreWindow can only be accessed on certain thread(s).
77  SDL_assert(CoreWindow::GetForCurrentThread() != nullptr);
78 
79  CoreWindow ^ nativeWindow = windowData->coreWindow.Get();
80  Windows::Foundation::Point outputPosition;
81 
82  // Compute coordinates normalized from 0..1.
83  // If the coordinates need to be sized to the SDL window,
84  // we'll do that after.
85 #if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION > NTDDI_WIN8)
86  outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width;
87  outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height;
88 #else
89  switch (WINRT_DISPLAY_PROPERTY(CurrentOrientation))
90  {
91  case DisplayOrientations::Portrait:
92  outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width;
93  outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height;
94  break;
95  case DisplayOrientations::PortraitFlipped:
96  outputPosition.X = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width);
97  outputPosition.Y = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height);
98  break;
99  case DisplayOrientations::Landscape:
100  outputPosition.X = rawPosition.Y / nativeWindow->Bounds.Height;
101  outputPosition.Y = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width);
102  break;
103  case DisplayOrientations::LandscapeFlipped:
104  outputPosition.X = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height);
105  outputPosition.Y = rawPosition.X / nativeWindow->Bounds.Width;
106  break;
107  default:
108  break;
109  }
110 #endif
111 
112  if (normalization == TransformToSDLWindowSize) {
113  outputPosition.X *= ((float32) window->w);
114  outputPosition.Y *= ((float32) window->h);
115  }
116 
117  return outputPosition;
118 }
119 
120 static inline int
121 _lround(float arg)
122 {
123  if (arg >= 0.0f) {
124  return (int)floor(arg + 0.5f);
125  } else {
126  return (int)ceil(arg - 0.5f);
127  }
128 }
129 
130 Uint8
131 WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt)
132 {
133  using namespace Windows::UI::Input;
134 
135 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
136  return SDL_BUTTON_LEFT;
137 #else
138  switch (pt->Properties->PointerUpdateKind)
139  {
140  case PointerUpdateKind::LeftButtonPressed:
141  case PointerUpdateKind::LeftButtonReleased:
142  return SDL_BUTTON_LEFT;
143 
144  case PointerUpdateKind::RightButtonPressed:
145  case PointerUpdateKind::RightButtonReleased:
146  return SDL_BUTTON_RIGHT;
147 
148  case PointerUpdateKind::MiddleButtonPressed:
149  case PointerUpdateKind::MiddleButtonReleased:
150  return SDL_BUTTON_MIDDLE;
151 
152  case PointerUpdateKind::XButton1Pressed:
153  case PointerUpdateKind::XButton1Released:
154  return SDL_BUTTON_X1;
155 
156  case PointerUpdateKind::XButton2Pressed:
157  case PointerUpdateKind::XButton2Released:
158  return SDL_BUTTON_X2;
159 
160  default:
161  break;
162  }
163 #endif
164 
165  return 0;
166 }
167 
168 //const char *
169 //WINRT_ConvertPointerUpdateKindToString(Windows::UI::Input::PointerUpdateKind kind)
170 //{
171 // using namespace Windows::UI::Input;
172 //
173 // switch (kind)
174 // {
175 // case PointerUpdateKind::Other:
176 // return "Other";
177 // case PointerUpdateKind::LeftButtonPressed:
178 // return "LeftButtonPressed";
179 // case PointerUpdateKind::LeftButtonReleased:
180 // return "LeftButtonReleased";
181 // case PointerUpdateKind::RightButtonPressed:
182 // return "RightButtonPressed";
183 // case PointerUpdateKind::RightButtonReleased:
184 // return "RightButtonReleased";
185 // case PointerUpdateKind::MiddleButtonPressed:
186 // return "MiddleButtonPressed";
187 // case PointerUpdateKind::MiddleButtonReleased:
188 // return "MiddleButtonReleased";
189 // case PointerUpdateKind::XButton1Pressed:
190 // return "XButton1Pressed";
191 // case PointerUpdateKind::XButton1Released:
192 // return "XButton1Released";
193 // case PointerUpdateKind::XButton2Pressed:
194 // return "XButton2Pressed";
195 // case PointerUpdateKind::XButton2Released:
196 // return "XButton2Released";
197 // }
198 //
199 // return "";
200 //}
201 
202 static bool
203 WINRT_IsTouchEvent(Windows::UI::Input::PointerPoint ^pointerPoint)
204 {
205 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
206  return true;
207 #else
208  using namespace Windows::Devices::Input;
209  switch (pointerPoint->PointerDevice->PointerDeviceType) {
210  case PointerDeviceType::Touch:
211  case PointerDeviceType::Pen:
212  return true;
213  default:
214  return false;
215  }
216 #endif
217 }
218 
219 void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
220 {
221  if (!window) {
222  return;
223  }
224 
225  Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint);
226 
227  if ( ! WINRT_IsTouchEvent(pointerPoint)) {
229  } else {
230  Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne);
231  Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize);
232 
234  WINRT_TouchID,
235  (SDL_FingerID) pointerPoint->PointerId,
236  window,
237  SDL_TRUE,
238  normalizedPoint.X,
239  normalizedPoint.Y,
240  pointerPoint->Properties->Pressure);
241  }
242 }
243 
244 void
245 WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
246 {
248  return;
249  }
250 
251  Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne);
252  Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize);
253 
254  if ( ! WINRT_IsTouchEvent(pointerPoint)) {
255  SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y);
256  } else {
258  WINRT_TouchID,
259  (SDL_FingerID) pointerPoint->PointerId,
260  window,
261  normalizedPoint.X,
262  normalizedPoint.Y,
263  pointerPoint->Properties->Pressure);
264  }
265 }
266 
267 void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
268 {
269  if (!window) {
270  return;
271  }
272 
273  Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint);
274 
275  if (!WINRT_IsTouchEvent(pointerPoint)) {
277  } else {
278  Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne);
279 
281  WINRT_TouchID,
282  (SDL_FingerID) pointerPoint->PointerId,
283  window,
284  SDL_FALSE,
285  normalizedPoint.X,
286  normalizedPoint.Y,
287  pointerPoint->Properties->Pressure);
288  }
289 }
290 
291 void WINRT_ProcessPointerEnteredEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
292 {
293  if (!window) {
294  return;
295  }
296 
297  if (!WINRT_IsTouchEvent(pointerPoint)) {
299  }
300 }
301 
302 void WINRT_ProcessPointerExitedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
303 {
304  if (!window) {
305  return;
306  }
307 
308  if (!WINRT_IsTouchEvent(pointerPoint)) {
310  }
311 }
312 
313 void
314 WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
315 {
316  if (!window) {
317  return;
318  }
319 
320  float motion = (float) pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA;
321  SDL_SendMouseWheel(window, 0, 0, (float) motion, SDL_MOUSEWHEEL_NORMAL);
322 }
323 
324 void
325 WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args)
326 {
328  return;
329  }
330 
331  // DLudwig, 2012-12-28: On some systems, namely Visual Studio's Windows
332  // Simulator, as well as Windows 8 in a Parallels 8 VM, MouseEventArgs'
333  // MouseDelta field often reports very large values. More information
334  // on this can be found at the following pages on MSDN:
335  // - http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/a3c789fa-f1c5-49c4-9c0a-7db88d0f90f8
336  // - https://connect.microsoft.com/VisualStudio/Feedback/details/756515
337  //
338  // The values do not appear to be as large when running on some systems,
339  // most notably a Surface RT. Furthermore, the values returned by
340  // CoreWindow's PointerMoved event, and sent to this class' OnPointerMoved
341  // method, do not ever appear to be large, even when MouseEventArgs'
342  // MouseDelta is reporting to the contrary.
343  //
344  // On systems with the large-values behavior, it appears that the values
345  // get reported as if the screen's size is 65536 units in both the X and Y
346  // dimensions. This can be viewed by using Windows' now-private, "Raw Input"
347  // APIs. (GetRawInputData, RegisterRawInputDevices, WM_INPUT, etc.)
348  //
349  // MSDN's documentation on MouseEventArgs' MouseDelta field (at
350  // http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.input.mouseeventargs.mousedelta ),
351  // does not seem to indicate (to me) that its values should be so large. It
352  // says that its values should be a "change in screen location". I could
353  // be misinterpreting this, however a post on MSDN from a Microsoft engineer (see:
354  // http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/09a9868e-95bb-4858-ba1a-cb4d2c298d62 ),
355  // indicates that these values are in DIPs, which is the same unit used
356  // by CoreWindow's PointerMoved events (via the Position field in its CurrentPoint
357  // property. See http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.input.pointerpoint.position.aspx
358  // for details.)
359  //
360  // To note, PointerMoved events are sent a 'RawPosition' value (via the
361  // CurrentPoint property in MouseEventArgs), however these do not seem
362  // to exhibit the same large-value behavior.
363  //
364  // The values passed via PointerMoved events can't always be used for relative
365  // mouse motion, unfortunately. Its values are bound to the cursor's position,
366  // which stops when it hits one of the screen's edges. This can be a problem in
367  // first person shooters, whereby it is normal for mouse motion to travel far
368  // along any one axis for a period of time. MouseMoved events do not have the
369  // screen-bounding limitation, and can be used regardless of where the system's
370  // cursor is.
371  //
372  // One possible workaround would be to programmatically set the cursor's
373  // position to the screen's center (when SDL's relative mouse mode is enabled),
374  // however WinRT does not yet seem to have the ability to set the cursor's
375  // position via a public API. Win32 did this via an API call, SetCursorPos,
376  // however WinRT makes this function be private. Apps that use it won't get
377  // approved for distribution in the Windows Store. I've yet to be able to find
378  // a suitable, store-friendly counterpart for WinRT.
379  //
380  // There may be some room for a workaround whereby OnPointerMoved's values
381  // are compared to the values from OnMouseMoved in order to detect
382  // when this bug is active. A suitable transformation could then be made to
383  // OnMouseMoved's values. For now, however, the system-reported values are sent
384  // to SDL with minimal transformation: from native screen coordinates (in DIPs)
385  // to SDL window coordinates.
386  //
387  const Windows::Foundation::Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y);
388  const Windows::Foundation::Point mouseDeltaInSDLWindowCoords = WINRT_TransformCursorPosition(window, mouseDeltaInDIPs, TransformToSDLWindowSize);
390  window,
391  0,
392  1,
393  _lround(mouseDeltaInSDLWindowCoords.X),
394  _lround(mouseDeltaInSDLWindowCoords.Y));
395 }
396 
397 #endif // SDL_VIDEO_DRIVER_WINRT
SDL_TOUCH_DEVICE_DIRECT
@ SDL_TOUCH_DEVICE_DIRECT
Definition: SDL_touch.h:47
Uint8
uint8_t Uint8
Definition: SDL_stdinc.h:179
SDL_winrtmouse_c.h
if
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
Definition: pixman-arm-neon-asm.h:469
NULL
#define NULL
Definition: begin_code.h:167
SDL_BUTTON_RIGHT
#define SDL_BUTTON_RIGHT
Definition: SDL_mouse.h:284
SDL_WindowData
Definition: SDL_androidwindow.h:39
SDL_FingerID
Sint64 SDL_FingerID
Definition: SDL_touch.h:42
SDL_SendTouch
int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, SDL_bool down, float x, float y, float pressure)
Definition: SDL_touch.c:242
SDL_winrtvideo_cpp.h
WINRT_InitTouch
void WINRT_InitTouch(_THIS)
SDL_RELEASED
#define SDL_RELEASED
Definition: SDL_events.h:49
SDL_SetMouseFocus
void SDL_SetMouseFocus(SDL_Window *window)
Definition: SDL_mouse.c:203
SDL_BUTTON_X1
#define SDL_BUTTON_X1
Definition: SDL_mouse.h:285
SDL_Window
The type used to identify a window.
Definition: SDL_sysvideo.h:75
SDL_PRESSED
#define SDL_PRESSED
Definition: SDL_events.h:50
SDL_AddTouch
int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char *name)
Definition: SDL_touch.c:155
SDL_BUTTON_LEFT
#define SDL_BUTTON_LEFT
Definition: SDL_mouse.h:282
window
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
f
GLfloat f
Definition: SDL_opengl_glext.h:1873
SDL_SendMouseMotion
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:293
SDL_BUTTON_MIDDLE
#define SDL_BUTTON_MIDDLE
Definition: SDL_mouse.h:283
SDL_assert.h
_THIS
#define _THIS
Definition: SDL_alsa_audio.h:31
SDL_TRUE
@ SDL_TRUE
Definition: SDL_stdinc.h:164
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_TouchID
Sint64 SDL_TouchID
Definition: SDL_touch.h:41
SDL_SendMouseWheel
int SDL_SendMouseWheel(SDL_Window *window, SDL_MouseID mouseID, float x, float y, SDL_MouseWheelDirection direction)
Definition: SDL_mouse.c:600
SDL_system.h
SDL_SendTouchMotion
int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window *window, float x, float y, float pressure)
Definition: SDL_touch.c:356
SDL_winrtevents_c.h
SDL_MOUSEWHEEL_NORMAL
@ SDL_MOUSEWHEEL_NORMAL
Definition: SDL_mouse.h:68
SDL_BUTTON_X2
#define SDL_BUTTON_X2
Definition: SDL_mouse.h:286
SDL_FALSE
@ SDL_FALSE
Definition: SDL_stdinc.h:163
WINRT_UsingRelativeMouseMode
SDL_bool WINRT_UsingRelativeMouseMode
floor
double floor(double x)
Definition: s_floor.c:33
button
SDL_Texture * button
Definition: testgamecontroller.c:67
SDL_SendMouseButton
int SDL_SendMouseButton(SDL_Window *window, SDL_MouseID mouseID, Uint8 state, Uint8 button)
Definition: SDL_mouse.c:594