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