SDL  2.0
SDL_winrtapp_direct3d.cpp
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2018 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 /* Standard C++11 includes */
24 #include <functional>
25 #include <string>
26 #include <sstream>
27 using namespace std;
28 
29 
30 /* Windows includes */
31 #include "ppltasks.h"
32 using namespace concurrency;
33 using namespace Windows::ApplicationModel;
34 using namespace Windows::ApplicationModel::Core;
36 using namespace Windows::Devices::Input;
37 using namespace Windows::Graphics::Display;
38 using namespace Windows::Foundation;
39 using namespace Windows::System;
40 using namespace Windows::UI::Core;
41 using namespace Windows::UI::Input;
42 
43 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
44 using namespace Windows::Phone::UI::Input;
45 #endif
46 
47 
48 /* SDL includes */
49 extern "C" {
50 #include "SDL_assert.h"
51 #include "SDL_events.h"
52 #include "SDL_hints.h"
53 #include "SDL_log.h"
54 #include "SDL_main.h"
55 #include "SDL_stdinc.h"
56 #include "SDL_render.h"
57 #include "../../video/SDL_sysvideo.h"
58 //#include "../../SDL_hints_c.h"
59 #include "../../events/SDL_events_c.h"
60 #include "../../events/SDL_keyboard_c.h"
61 #include "../../events/SDL_mouse_c.h"
62 #include "../../events/SDL_windowevents_c.h"
63 #include "../../render/SDL_sysrender.h"
64 #include "../windows/SDL_windows.h"
65 }
66 
67 #include "../../video/winrt/SDL_winrtevents_c.h"
68 #include "../../video/winrt/SDL_winrtvideo_cpp.h"
69 #include "SDL_winrtapp_common.h"
70 #include "SDL_winrtapp_direct3d.h"
71 
72 #if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
73 /* Calling IDXGIDevice3::Trim on the active Direct3D 11.x device is necessary
74  * when Windows 8.1 apps are about to get suspended.
75  */
76 extern "C" void D3D11_Trim(SDL_Renderer *);
77 #endif
78 
79 
80 // Compile-time debugging options:
81 // To enable, uncomment; to disable, comment them out.
82 //#define LOG_POINTER_EVENTS 1
83 //#define LOG_WINDOW_EVENTS 1
84 //#define LOG_ORIENTATION_EVENTS 1
85 
86 
87 // HACK, DLudwig: record a reference to the global, WinRT 'app'/view.
88 // SDL/WinRT will use this throughout its code.
89 //
90 // TODO, WinRT: consider replacing SDL_WinRTGlobalApp with something
91 // non-global, such as something created inside
92 // SDL_InitSubSystem(SDL_INIT_VIDEO), or something inside
93 // SDL_CreateWindow().
94 SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr;
95 
96 ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
97 {
98 public:
99  virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
100 };
101 
102 IFrameworkView^ SDLApplicationSource::CreateView()
103 {
104  // TODO, WinRT: see if this function (CreateView) can ever get called
105  // more than once. For now, just prevent it from ever assigning
106  // SDL_WinRTGlobalApp more than once.
108  SDL_WinRTApp ^ app = ref new SDL_WinRTApp();
109  if (!SDL_WinRTGlobalApp)
110  {
111  SDL_WinRTGlobalApp = app;
112  }
113  return app;
114 }
115 
116 int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **))
117 {
118  WINRT_SDLAppEntryPoint = mainFunction;
119  auto direct3DApplicationSource = ref new SDLApplicationSource();
120  CoreApplication::Run(direct3DApplicationSource);
121  return 0;
122 }
123 
124 static void SDLCALL
125 WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue)
126 {
128 
129  /* HACK: prevent SDL from altering an app's .appxmanifest-set orientation
130  * from being changed on startup, by detecting when SDL_HINT_ORIENTATIONS
131  * is getting registered.
132  *
133  * TODO, WinRT: consider reading in an app's .appxmanifest file, and apply its orientation when 'newValue == NULL'.
134  */
135  if ((oldValue == NULL) && (newValue == NULL)) {
136  return;
137  }
138 
139  // Start with no orientation flags, then add each in as they're parsed
140  // from newValue.
141  unsigned int orientationFlags = 0;
142  if (newValue) {
143  std::istringstream tokenizer(newValue);
144  while (!tokenizer.eof()) {
145  std::string orientationName;
146  std::getline(tokenizer, orientationName, ' ');
147  if (orientationName == "LandscapeLeft") {
148  orientationFlags |= (unsigned int) DisplayOrientations::LandscapeFlipped;
149  } else if (orientationName == "LandscapeRight") {
150  orientationFlags |= (unsigned int) DisplayOrientations::Landscape;
151  } else if (orientationName == "Portrait") {
152  orientationFlags |= (unsigned int) DisplayOrientations::Portrait;
153  } else if (orientationName == "PortraitUpsideDown") {
154  orientationFlags |= (unsigned int) DisplayOrientations::PortraitFlipped;
155  }
156  }
157  }
158 
159  // If no valid orientation flags were specified, use a reasonable set of defaults:
160  if (!orientationFlags) {
161  // TODO, WinRT: consider seeing if an app's default orientation flags can be found out via some API call(s).
162  orientationFlags = (unsigned int) ( \
163  DisplayOrientations::Landscape |
164  DisplayOrientations::LandscapeFlipped |
165  DisplayOrientations::Portrait |
166  DisplayOrientations::PortraitFlipped);
167  }
168 
169  // Set the orientation/rotation preferences. Please note that this does
170  // not constitute a 100%-certain lock of a given set of possible
171  // orientations. According to Microsoft's documentation on WinRT [1]
172  // when a device is not capable of being rotated, Windows may ignore
173  // the orientation preferences, and stick to what the device is capable of
174  // displaying.
175  //
176  // [1] Documentation on the 'InitialRotationPreference' setting for a
177  // Windows app's manifest file describes how some orientation/rotation
178  // preferences may be ignored. See
179  // http://msdn.microsoft.com/en-us/library/windows/apps/hh700343.aspx
180  // for details. Microsoft's "Display orientation sample" also gives an
181  // outline of how Windows treats device rotation
182  // (http://code.msdn.microsoft.com/Display-Orientation-Sample-19a58e93).
183  WINRT_DISPLAY_PROPERTY(AutoRotationPreferences) = (DisplayOrientations) orientationFlags;
184 }
185 
186 static void
187 WINRT_ProcessWindowSizeChange() // TODO: Pass an SDL_Window-identifying thing into WINRT_ProcessWindowSizeChange()
188 {
189  CoreWindow ^ coreWindow = CoreWindow::GetForCurrentThread();
190  if (coreWindow) {
191  if (WINRT_GlobalSDLWindow) {
194 
195  int x = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Left);
196  int y = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Top);
197  int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
198  int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
199 
200 #if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) && (NTDDI_VERSION == NTDDI_WIN8)
201  /* WinPhone 8.0 always keeps its native window size in portrait,
202  regardless of orientation. This changes in WinPhone 8.1,
203  in which the native window's size changes along with
204  orientation.
205 
206  Attempt to emulate WinPhone 8.1's behavior on WinPhone 8.0, with
207  regards to window size. This fixes a rendering bug that occurs
208  when a WinPhone 8.0 app is rotated to either 90 or 270 degrees.
209  */
210  const DisplayOrientations currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation);
211  switch (currentOrientation) {
212  case DisplayOrientations::Landscape:
213  case DisplayOrientations::LandscapeFlipped: {
214  int tmp = w;
215  w = h;
216  h = tmp;
217  } break;
218  }
219 #endif
220 
221  const Uint32 latestFlags = WINRT_DetectWindowFlags(window);
222  if (latestFlags & SDL_WINDOW_MAXIMIZED) {
224  } else {
226  }
227 
229 
230  /* The window can move during a resize event, such as when maximizing
231  or resizing from a corner */
234  }
235  }
236 }
237 
238 SDL_WinRTApp::SDL_WinRTApp() :
239  m_windowClosed(false),
240  m_windowVisible(true)
241 {
242 }
243 
244 void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
245 {
246  applicationView->Activated +=
247  ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnAppActivated);
248 
249  CoreApplication::Suspending +=
250  ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending);
251 
252  CoreApplication::Resuming +=
253  ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnResuming);
254 
255  CoreApplication::Exiting +=
256  ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnExiting);
257 
258 #if NTDDI_VERSION >= NTDDI_WIN10
259  /* HACK ALERT! Xbox One doesn't seem to detect gamepads unless something
260  gets registered to receive Win10's Windows.Gaming.Input.Gamepad.GamepadAdded
261  events. We'll register an event handler for these events here, to make
262  sure that gamepad detection works later on, if requested.
263  */
264  Windows::Gaming::Input::Gamepad::GamepadAdded +=
265  ref new Windows::Foundation::EventHandler<Windows::Gaming::Input::Gamepad^>(
266  this, &SDL_WinRTApp::OnGamepadAdded
267  );
268 #endif
269 }
270 
271 #if NTDDI_VERSION > NTDDI_WIN8
272 void SDL_WinRTApp::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
273 #else
274 void SDL_WinRTApp::OnOrientationChanged(Object^ sender)
275 #endif
276 {
277 #if LOG_ORIENTATION_EVENTS==1
278  {
279  CoreWindow^ window = CoreWindow::GetForCurrentThread();
280  if (window) {
281  SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Bounds={%f,%f,%f,%f}\n",
282  __FUNCTION__,
283  WINRT_DISPLAY_PROPERTY(CurrentOrientation),
284  WINRT_DISPLAY_PROPERTY(NativeOrientation),
285  WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
286  window->Bounds.X,
287  window->Bounds.Y,
288  window->Bounds.Width,
289  window->Bounds.Height);
290  } else {
291  SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n",
292  __FUNCTION__,
293  WINRT_DISPLAY_PROPERTY(CurrentOrientation),
294  WINRT_DISPLAY_PROPERTY(NativeOrientation),
295  WINRT_DISPLAY_PROPERTY(AutoRotationPreferences));
296  }
297  }
298 #endif
299 
301 
302 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
303  // HACK: Make sure that orientation changes
304  // lead to the Direct3D renderer's viewport getting updated:
305  //
306  // For some reason, this doesn't seem to need to be done on Windows 8.x,
307  // even when going from Landscape to LandscapeFlipped. It only seems to
308  // be needed on Windows Phone, at least when I tested on my devices.
309  // I'm not currently sure why this is, but it seems to work fine. -- David L.
310  //
311  // TODO, WinRT: do more extensive research into why orientation changes on Win 8.x don't need D3D changes, or if they might, in some cases
313  if (window) {
315  int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
316  int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
318  }
319 #endif
320 
321 }
322 
323 void SDL_WinRTApp::SetWindow(CoreWindow^ window)
324 {
325 #if LOG_WINDOW_EVENTS==1
326  SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window bounds={%f, %f, %f,%f}\n",
327  __FUNCTION__,
328  WINRT_DISPLAY_PROPERTY(CurrentOrientation),
329  WINRT_DISPLAY_PROPERTY(NativeOrientation),
330  WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
331  window->Bounds.X,
332  window->Bounds.Y,
333  window->Bounds.Width,
334  window->Bounds.Height);
335 #endif
336 
337  window->SizeChanged +=
338  ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &SDL_WinRTApp::OnWindowSizeChanged);
339 
340  window->VisibilityChanged +=
341  ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged);
342 
343  window->Activated +=
344  ref new TypedEventHandler<CoreWindow^, WindowActivatedEventArgs^>(this, &SDL_WinRTApp::OnWindowActivated);
345 
346  window->Closed +=
347  ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed);
348 
349 #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
350  window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
351 #endif
352 
353  window->PointerPressed +=
354  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerPressed);
355 
356  window->PointerMoved +=
357  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerMoved);
358 
359  window->PointerReleased +=
360  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerReleased);
361 
362  window->PointerEntered +=
363  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerEntered);
364 
365  window->PointerExited +=
366  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerExited);
367 
368  window->PointerWheelChanged +=
369  ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerWheelChanged);
370 
371 #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
372  // Retrieves relative-only mouse movements:
373  Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved +=
374  ref new TypedEventHandler<MouseDevice^, MouseEventArgs^>(this, &SDL_WinRTApp::OnMouseMoved);
375 #endif
376 
377  window->KeyDown +=
378  ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyDown);
379 
380  window->KeyUp +=
381  ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyUp);
382 
383  window->CharacterReceived +=
384  ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &SDL_WinRTApp::OnCharacterReceived);
385 
386 #if NTDDI_VERSION >= NTDDI_WIN10
387  Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->BackRequested +=
388  ref new EventHandler<BackRequestedEventArgs^>(this, &SDL_WinRTApp::OnBackButtonPressed);
389 #elif WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
390  HardwareButtons::BackPressed +=
391  ref new EventHandler<BackPressedEventArgs^>(this, &SDL_WinRTApp::OnBackButtonPressed);
392 #endif
393 
394 #if NTDDI_VERSION > NTDDI_WIN8
395  DisplayInformation::GetForCurrentView()->OrientationChanged +=
396  ref new TypedEventHandler<Windows::Graphics::Display::DisplayInformation^, Object^>(this, &SDL_WinRTApp::OnOrientationChanged);
397 #else
398  DisplayProperties::OrientationChanged +=
399  ref new DisplayPropertiesEventHandler(this, &SDL_WinRTApp::OnOrientationChanged);
400 #endif
401 
402  // Register the hint, SDL_HINT_ORIENTATIONS, with SDL.
403  // TODO, WinRT: see if an app's default orientation can be found out via WinRT API(s), then set the initial value of SDL_HINT_ORIENTATIONS accordingly.
405 
406 #if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10) // for Windows 8/8.1/RT apps... (and not Phone apps)
407  // Make sure we know when a user has opened the app's settings pane.
408  // This is needed in order to display a privacy policy, which needs
409  // to be done for network-enabled apps, as per Windows Store requirements.
410  using namespace Windows::UI::ApplicationSettings;
411  SettingsPane::GetForCurrentView()->CommandsRequested +=
412  ref new TypedEventHandler<SettingsPane^, SettingsPaneCommandsRequestedEventArgs^>
413  (this, &SDL_WinRTApp::OnSettingsPaneCommandsRequested);
414 #endif
415 }
416 
417 void SDL_WinRTApp::Load(Platform::String^ entryPoint)
418 {
419 }
420 
421 void SDL_WinRTApp::Run()
422 {
425  {
426  // TODO, WinRT: pass the C-style main() a reasonably realistic
427  // representation of command line arguments.
428  int argc = 0;
429  char **argv = NULL;
430  WINRT_SDLAppEntryPoint(argc, argv);
431  }
432 }
433 
434 static bool IsSDLWindowEventPending(SDL_WindowEventID windowEventID)
435 {
436  SDL_Event events[128];
437  const int count = SDL_PeepEvents(events, sizeof(events)/sizeof(SDL_Event), SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT);
438  for (int i = 0; i < count; ++i) {
439  if (events[i].window.event == windowEventID) {
440  return true;
441  }
442  }
443  return false;
444 }
445 
446 bool SDL_WinRTApp::ShouldWaitForAppResumeEvents()
447 {
448  /* Don't wait if the app is visible: */
449  if (m_windowVisible) {
450  return false;
451  }
452 
453  /* Don't wait until the window-hide events finish processing.
454  * Do note that if an app-suspend event is sent (as indicated
455  * by SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERBACKGROUND
456  * events), then this code may be a moot point, as WinRT's
457  * own event pump (aka ProcessEvents()) will pause regardless
458  * of what we do here. This happens on Windows Phone 8, to note.
459  * Windows 8.x apps, on the other hand, may get a chance to run
460  * these.
461  */
463  return false;
465  return false;
467  return false;
468  }
469 
470  return true;
471 }
472 
473 void SDL_WinRTApp::PumpEvents()
474 {
475  if (!m_windowClosed) {
476  if (!ShouldWaitForAppResumeEvents()) {
477  /* This is the normal way in which events should be pumped.
478  * 'ProcessAllIfPresent' will make ProcessEvents() process anywhere
479  * from zero to N events, and will then return.
480  */
481  CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
482  } else {
483  /* This style of event-pumping, with 'ProcessOneAndAllPending',
484  * will cause anywhere from one to N events to be processed. If
485  * at least one event is processed, the call will return. If
486  * no events are pending, then the call will wait until one is
487  * available, and will not return (to the caller) until this
488  * happens! This should only occur when the app is hidden.
489  */
490  CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
491  }
492  }
493 }
494 
495 void SDL_WinRTApp::Uninitialize()
496 {
497 }
498 
499 #if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10)
500 void SDL_WinRTApp::OnSettingsPaneCommandsRequested(
501  Windows::UI::ApplicationSettings::SettingsPane ^p,
502  Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args)
503 {
504  using namespace Platform;
505  using namespace Windows::UI::ApplicationSettings;
506  using namespace Windows::UI::Popups;
507 
508  String ^privacyPolicyURL = nullptr; // a URL to an app's Privacy Policy
509  String ^privacyPolicyLabel = nullptr; // label/link text
510  const char *tmpHintValue = NULL; // SDL_GetHint-retrieved value, used immediately
511  wchar_t *tmpStr = NULL; // used for UTF8 to UCS2 conversion
512 
513  // Setup a 'Privacy Policy' link, if one is available (via SDL_GetHint):
515  if (tmpHintValue && tmpHintValue[0] != '\0') {
516  // Convert the privacy policy's URL to UCS2:
517  tmpStr = WIN_UTF8ToString(tmpHintValue);
518  privacyPolicyURL = ref new String(tmpStr);
519  SDL_free(tmpStr);
520 
521  // Optionally retrieve custom label-text for the link. If this isn't
522  // available, a default value will be used instead.
524  if (tmpHintValue && tmpHintValue[0] != '\0') {
525  tmpStr = WIN_UTF8ToString(tmpHintValue);
526  privacyPolicyLabel = ref new String(tmpStr);
527  SDL_free(tmpStr);
528  } else {
529  privacyPolicyLabel = ref new String(L"Privacy Policy");
530  }
531 
532  // Register the link, along with a handler to be called if and when it is
533  // clicked:
534  auto cmd = ref new SettingsCommand(L"privacyPolicy", privacyPolicyLabel,
535  ref new UICommandInvokedHandler([=](IUICommand ^) {
536  Windows::System::Launcher::LaunchUriAsync(ref new Uri(privacyPolicyURL));
537  }));
538  args->Request->ApplicationCommands->Append(cmd);
539  }
540 }
541 #endif // if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10)
542 
543 void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
544 {
545 #if LOG_WINDOW_EVENTS==1
546  SDL_Log("%s, size={%f,%f}, bounds={%f,%f,%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n",
547  __FUNCTION__,
548  args->Size.Width, args->Size.Height,
549  sender->Bounds.X, sender->Bounds.Y, sender->Bounds.Width, sender->Bounds.Height,
550  WINRT_DISPLAY_PROPERTY(CurrentOrientation),
551  WINRT_DISPLAY_PROPERTY(NativeOrientation),
552  WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
553  (WINRT_GlobalSDLWindow ? "yes" : "no"));
554 #endif
555 
557 }
558 
559 void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
560 {
561 #if LOG_WINDOW_EVENTS==1
562  SDL_Log("%s, visible?=%s, bounds={%f,%f,%f,%f}, WINRT_GlobalSDLWindow?=%s\n",
563  __FUNCTION__,
564  (args->Visible ? "yes" : "no"),
565  sender->Bounds.X, sender->Bounds.Y,
566  sender->Bounds.Width, sender->Bounds.Height,
567  (WINRT_GlobalSDLWindow ? "yes" : "no"));
568 #endif
569 
570  m_windowVisible = args->Visible;
571  if (WINRT_GlobalSDLWindow) {
572  SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid;
574  if (args->Visible) {
577  if (latestWindowFlags & SDL_WINDOW_MAXIMIZED) {
579  } else {
581  }
582  } else {
586  }
587 
588  // HACK: Prevent SDL's window-hide handling code, which currently
589  // triggers a fake window resize (possibly erronously), from
590  // marking the SDL window's surface as invalid.
591  //
592  // A better solution to this probably involves figuring out if the
593  // fake window resize can be prevented.
594  WINRT_GlobalSDLWindow->surface_valid = wasSDLWindowSurfaceValid;
595  }
596 }
597 
598 void SDL_WinRTApp::OnWindowActivated(CoreWindow^ sender, WindowActivatedEventArgs^ args)
599 {
600 #if LOG_WINDOW_EVENTS==1
601  SDL_Log("%s, WINRT_GlobalSDLWindow?=%s\n\n",
602  __FUNCTION__,
603  (WINRT_GlobalSDLWindow ? "yes" : "no"));
604 #endif
605 
606  /* There's no property in Win 8.x to tell whether a window is active or
607  not. [De]activation events are, however, sent to the app. We'll just
608  record those, in case the CoreWindow gets wrapped by an SDL_Window at
609  some future time.
610  */
611  sender->CustomProperties->Insert("SDLHelperWindowActivationState", args->WindowActivationState);
612 
614  if (window) {
615  if (args->WindowActivationState != CoreWindowActivationState::Deactivated) {
617  if (SDL_GetKeyboardFocus() != window) {
618  SDL_SetKeyboardFocus(window);
619  }
620 
621  /* Send a mouse-motion event as appropriate.
622  This doesn't work when called from OnPointerEntered, at least
623  not in WinRT CoreWindow apps (as OnPointerEntered doesn't
624  appear to be called after window-reactivation, at least not
625  in Windows 10, Build 10586.3 (November 2015 update, non-beta).
626 
627  Don't do it on WinPhone 8.0 though, as CoreWindow's 'PointerPosition'
628  property isn't available.
629  */
630 #if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION >= NTDDI_WINBLUE)
631  Point cursorPos = WINRT_TransformCursorPosition(window, sender->PointerPosition, TransformToSDLWindowSize);
632  SDL_SendMouseMotion(window, 0, 0, (int)cursorPos.X, (int)cursorPos.Y);
633 #endif
634 
635  /* TODO, WinRT: see if the Win32 bugfix from https://hg.libsdl.org/SDL/rev/d278747da408 needs to be applied (on window activation) */
636  //WIN_CheckAsyncMouseRelease(data);
637 
638  /* TODO, WinRT: implement clipboard support, if possible */
639  ///*
640  // * FIXME: Update keyboard state
641  // */
642  //WIN_CheckClipboardUpdate(data->videodata);
643 
644  // HACK: Resetting the mouse-cursor here seems to fix
645  // https://bugzilla.libsdl.org/show_bug.cgi?id=3217, whereby a
646  // WinRT app's mouse cursor may switch to Windows' 'wait' cursor,
647  // after a user alt-tabs back into a full-screened SDL app.
648  // This bug does not appear to reproduce 100% of the time.
649  // It may be a bug in Windows itself (v.10.0.586.36, as tested,
650  // and the most-recent as of this writing).
652  } else {
653  if (SDL_GetKeyboardFocus() == window) {
655  }
656  }
657  }
658 }
659 
660 void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
661 {
662 #if LOG_WINDOW_EVENTS==1
663  SDL_Log("%s\n", __FUNCTION__);
664 #endif
665  m_windowClosed = true;
666 }
667 
668 void SDL_WinRTApp::OnAppActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
669 {
670  CoreWindow::GetForCurrentThread()->Activate();
671 }
672 
673 void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
674 {
675  // Save app state asynchronously after requesting a deferral. Holding a deferral
676  // indicates that the application is busy performing suspending operations. Be
677  // aware that a deferral may not be held indefinitely. After about five seconds,
678  // the app will be forced to exit.
679 
680  // ... but first, let the app know it's about to go to the background.
681  // The separation of events may be important, given that the deferral
682  // runs in a separate thread. This'll make SDL_APP_WILLENTERBACKGROUND
683  // the only event among the two that runs in the main thread. Given
684  // that a few WinRT operations can only be done from the main thread
685  // (things that access the WinRT CoreWindow are one example of this),
686  // this could be important.
688 
689  SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
690  create_task([this, deferral]()
691  {
692  // Send an app did-enter-background event immediately to observers.
693  // CoreDispatcher::ProcessEvents, which is the backbone on which
694  // SDL_WinRTApp::PumpEvents is built, will not return to its caller
695  // once it sends out a suspend event. Any events posted to SDL's
696  // event queue won't get received until the WinRT app is resumed.
697  // SDL_AddEventWatch() may be used to receive app-suspend events on
698  // WinRT.
700 
701  // Let the Direct3D 11 renderer prepare for the app to be backgrounded.
702  // This is necessary for Windows 8.1, possibly elsewhere in the future.
703  // More details at: http://msdn.microsoft.com/en-us/library/windows/apps/Hh994929.aspx
704 #if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
705  if (WINRT_GlobalSDLWindow) {
707  if (renderer && (SDL_strcmp(renderer->info.name, "direct3d11") == 0)) {
708  D3D11_Trim(renderer);
709  }
710  }
711 #endif
712 
713  deferral->Complete();
714  });
715 }
716 
717 void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
718 {
719  // Restore any data or state that was unloaded on suspend. By default, data
720  // and state are persisted when resuming from suspend. Note that these events
721  // do not occur if the app was previously terminated.
724 }
725 
726 void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args)
727 {
729 }
730 
731 static void
732 WINRT_LogPointerEvent(const char * header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint)
733 {
734  Windows::UI::Input::PointerPoint ^ pt = args->CurrentPoint;
735  SDL_Log("%s: Position={%f,%f}, Transformed Pos={%f, %f}, MouseWheelDelta=%d, FrameId=%d, PointerId=%d, SDL button=%d\n",
736  header,
737  pt->Position.X, pt->Position.Y,
738  transformedPoint.X, transformedPoint.Y,
739  pt->Properties->MouseWheelDelta,
740  pt->FrameId,
741  pt->PointerId,
742  WINRT_GetSDLButtonForPointerPoint(pt));
743 }
744 
745 void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
746 {
747 #if LOG_POINTER_EVENTS
748  WINRT_LogPointerEvent("pointer pressed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
749 #endif
750 
751  WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
752 }
753 
754 void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
755 {
756 #if LOG_POINTER_EVENTS
757  WINRT_LogPointerEvent("pointer moved", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
758 #endif
759 
760  WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
761 }
762 
763 void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args)
764 {
765 #if LOG_POINTER_EVENTS
766  WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
767 #endif
768 
769  WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
770 }
771 
772 void SDL_WinRTApp::OnPointerEntered(CoreWindow^ sender, PointerEventArgs^ args)
773 {
774 #if LOG_POINTER_EVENTS
775  WINRT_LogPointerEvent("pointer entered", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
776 #endif
777 
778  WINRT_ProcessPointerEnteredEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
779 }
780 
781 void SDL_WinRTApp::OnPointerExited(CoreWindow^ sender, PointerEventArgs^ args)
782 {
783 #if LOG_POINTER_EVENTS
784  WINRT_LogPointerEvent("pointer exited", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
785 #endif
786 
787  WINRT_ProcessPointerExitedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
788 }
789 
790 void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args)
791 {
792 #if LOG_POINTER_EVENTS
793  WINRT_LogPointerEvent("pointer wheel changed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
794 #endif
795 
796  WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
797 }
798 
799 void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args)
800 {
801  WINRT_ProcessMouseMovedEvent(WINRT_GlobalSDLWindow, args);
802 }
803 
804 void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
805 {
806  WINRT_ProcessKeyDownEvent(args);
807 }
808 
809 void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
810 {
811  WINRT_ProcessKeyUpEvent(args);
812 }
813 
814 void SDL_WinRTApp::OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args)
815 {
816  WINRT_ProcessCharacterReceivedEvent(args);
817 }
818 
819 template <typename BackButtonEventArgs>
820 static void WINRT_OnBackButtonPressed(BackButtonEventArgs ^ args)
821 {
824 
826  args->Handled = true;
827  }
828 }
829 
830 #if NTDDI_VERSION >= NTDDI_WIN10
831 void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::UI::Core::BackRequestedEventArgs^ args)
832 
833 {
835 }
836 #elif WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
837 void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args)
838 
839 {
841 }
842 #endif
843 
844 #if NTDDI_VERSION >= NTDDI_WIN10
845 void SDL_WinRTApp::OnGamepadAdded(Platform::Object ^sender, Windows::Gaming::Input::Gamepad ^gamepad)
846 {
847  /* HACK ALERT: Nothing needs to be done here, as this method currently
848  only exists to allow something to be registered with Win10's
849  GamepadAdded event, an operation that seems to be necessary to get
850  Xinput-based detection to work on Xbox One.
851  */
852 }
853 #endif
854 
855 /* vi: set ts=4 sw=4 expandtab: */
#define WIN_UTF8ToString(S)
Definition: SDL_windows.h:47
void WINRT_UpdateWindowFlags(SDL_Window *window, Uint32 mask)
void SDL_SetKeyboardFocus(SDL_Window *window)
Definition: SDL_keyboard.c:630
SDL_RendererInfo info
GLsizei const GLchar *const * string
#define SDL_SetMainReady
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
static void WINRT_OnBackButtonPressed(BackButtonEventArgs ^ args)
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
GLfloat GLfloat GLfloat GLfloat h
GLfloat GLfloat p
static SDL_Event events[EVENT_BUF_SIZE]
Definition: testgesture.c:35
#define SDL_GetHint
GLenum GLint ref
STL namespace.
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue)
#define SDL_SetCursor
int SDL_SendWindowEvent(SDL_Window *window, Uint8 windowevent, int data1, int data2)
#define SDL_GetKeyboardFocus
uint32_t Uint32
Definition: SDL_stdinc.h:181
const char * name
Definition: SDL_render.h:80
#define SDL_HINT_WINRT_PRIVACY_POLICY_URL
A URL to a WinRT app&#39;s privacy policy.
Definition: SDL_hints.h:605
#define SDL_HINT_WINRT_PRIVACY_POLICY_LABEL
Label text for a WinRT app&#39;s privacy policy link.
Definition: SDL_hints.h:626
GLuint const GLchar * name
int SDL_SendKeyboardKey(Uint8 state, SDL_Scancode scancode)
Definition: SDL_keyboard.c:679
#define SDL_GetHintBoolean
int SDL_WinRTInitNonXAMLApp(int(*mainFunction)(int, char **))
SDL_WinRTApp SDL_WinRTGlobalApp
#define SDL_Log
int Run(void *data)
Definition: testlock.c:65
int SDL_SendMouseMotion(SDL_Window *window, SDL_MouseID mouseID, int relative, int x, int y)
Definition: SDL_mouse.c:237
#define SDL_PeepEvents
static SDL_Renderer * renderer
#define SDL_free
SDL_WindowEventID
Event subtype for window events.
Definition: SDL_video.h:146
GLubyte GLubyte GLubyte GLubyte w
Uint32 WINRT_DetectWindowFlags(SDL_Window *window)
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
static void WINRT_LogPointerEvent(const char *header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint)
SDL_Window * WINRT_GlobalSDLWindow
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define SDL_assert(condition)
Definition: SDL_assert.h:169
#define SDL_GetRenderer
#define SDL_HINT_ORIENTATIONS
A variable controlling which orientations are allowed on iOS.
Definition: SDL_hints.h:340
#define NULL
Definition: begin_code.h:164
SDL_bool
Definition: SDL_stdinc.h:139
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
The type used to identify a window.
Definition: SDL_sysvideo.h:73
#define SDL_AddHintCallback
int(* WINRT_SDLAppEntryPoint)(int, char **)
static void WINRT_ProcessWindowSizeChange()
General event structure.
Definition: SDL_events.h:525
int SDL_SendAppEvent(SDL_EventType eventType)
Definition: SDL_events.c:919
#define SDL_strcmp
void * driverdata
Definition: SDL_sysvideo.h:111
#define SDL_PRESSED
Definition: SDL_events.h:50
#define SDL_HINT_WINRT_HANDLE_BACK_BUTTON
Allows back-button-press events on Windows Phone to be marked as handled.
Definition: SDL_hints.h:678
SDL_bool surface_valid
Definition: SDL_sysvideo.h:98
#define SDL_RELEASED
Definition: SDL_events.h:49
#define SDLCALL
Definition: SDL_internal.h:45
static bool IsSDLWindowEventPending(SDL_WindowEventID windowEventID)