2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
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.
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:
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.
21 #include "../../SDL_internal.h"
23 /* Standard C++11 includes */
30 /* Windows includes */
32 using namespace concurrency;
33 using namespace Windows::ApplicationModel;
34 using namespace Windows::ApplicationModel::Core;
35 using namespace Windows::ApplicationModel::Activation;
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;
43 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
44 using namespace Windows::Phone::UI::Input;
50 #include "../../SDL_internal.h"
51 #include "SDL_assert.h"
52 #include "SDL_events.h"
53 #include "SDL_hints.h"
56 #include "SDL_stdinc.h"
57 #include "SDL_render.h"
58 #include "../../video/SDL_sysvideo.h"
59 //#include "../../SDL_hints_c.h"
60 #include "../../events/SDL_events_c.h"
61 #include "../../events/SDL_keyboard_c.h"
62 #include "../../events/SDL_mouse_c.h"
63 #include "../../events/SDL_windowevents_c.h"
64 #include "../../render/SDL_sysrender.h"
65 #include "../windows/SDL_windows.h"
68 #include "../../video/winrt/SDL_winrtevents_c.h"
69 #include "../../video/winrt/SDL_winrtvideo_cpp.h"
70 #include "SDL_winrtapp_common.h"
71 #include "SDL_winrtapp_direct3d.h"
73 #if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
74 /* Calling IDXGIDevice3::Trim on the active Direct3D 11.x device is necessary
75 * when Windows 8.1 apps are about to get suspended.
77 extern "C" void D3D11_Trim(SDL_Renderer *);
81 // Compile-time debugging options:
82 // To enable, uncomment; to disable, comment them out.
83 //#define LOG_POINTER_EVENTS 1
84 //#define LOG_WINDOW_EVENTS 1
85 //#define LOG_ORIENTATION_EVENTS 1
88 // HACK, DLudwig: record a reference to the global, WinRT 'app'/view.
89 // SDL/WinRT will use this throughout its code.
91 // TODO, WinRT: consider replacing SDL_WinRTGlobalApp with something
92 // non-global, such as something created inside
93 // SDL_InitSubSystem(SDL_INIT_VIDEO), or something inside
94 // SDL_CreateWindow().
95 SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr;
97 ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
100 virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
103 IFrameworkView^ SDLApplicationSource::CreateView()
105 // TODO, WinRT: see if this function (CreateView) can ever get called
106 // more than once. For now, just prevent it from ever assigning
107 // SDL_WinRTGlobalApp more than once.
108 SDL_assert(!SDL_WinRTGlobalApp);
109 SDL_WinRTApp ^ app = ref new SDL_WinRTApp();
110 if (!SDL_WinRTGlobalApp)
112 SDL_WinRTGlobalApp = app;
117 int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **))
119 WINRT_SDLAppEntryPoint = mainFunction;
120 auto direct3DApplicationSource = ref new SDLApplicationSource();
121 CoreApplication::Run(direct3DApplicationSource);
125 static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue)
127 SDL_assert(SDL_strcmp(name, SDL_HINT_ORIENTATIONS) == 0);
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.
133 * TODO, WinRT: consider reading in an app's .appxmanifest file, and apply its orientation when 'newValue == NULL'.
135 if ((oldValue == NULL) && (newValue == NULL)) {
139 // Start with no orientation flags, then add each in as they're parsed
141 unsigned int orientationFlags = 0;
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;
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);
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
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;
187 WINRT_ProcessWindowSizeChange() // TODO: Pass an SDL_Window-identifying thing into WINRT_ProcessWindowSizeChange()
189 CoreWindow ^ coreWindow = CoreWindow::GetForCurrentThread();
191 if (WINRT_GlobalSDLWindow) {
192 SDL_Window * window = WINRT_GlobalSDLWindow;
193 SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
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);
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
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.
210 const DisplayOrientations currentOrientation = WINRT_DISPLAY_PROPERTY(CurrentOrientation);
211 switch (currentOrientation) {
212 case DisplayOrientations::Landscape:
213 case DisplayOrientations::LandscapeFlipped: {
221 const Uint32 latestFlags = WINRT_DetectWindowFlags(window);
222 if (latestFlags & SDL_WINDOW_MAXIMIZED) {
223 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
225 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESTORED, 0, 0);
228 WINRT_UpdateWindowFlags(window, SDL_WINDOW_FULLSCREEN_DESKTOP);
230 /* The window can move during a resize event, such as when maximizing
231 or resizing from a corner */
232 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, x, y);
233 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, w, h);
238 SDL_WinRTApp::SDL_WinRTApp() :
239 m_windowClosed(false),
240 m_windowVisible(true)
244 void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
246 applicationView->Activated +=
247 ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnAppActivated);
249 CoreApplication::Suspending +=
250 ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending);
252 CoreApplication::Resuming +=
253 ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnResuming);
255 CoreApplication::Exiting +=
256 ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnExiting);
259 #if NTDDI_VERSION > NTDDI_WIN8
260 void SDL_WinRTApp::OnOrientationChanged(DisplayInformation^ sender, Object^ args)
262 void SDL_WinRTApp::OnOrientationChanged(Object^ sender)
265 #if LOG_ORIENTATION_EVENTS==1
267 CoreWindow^ window = CoreWindow::GetForCurrentThread();
269 SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Bounds={%f,%f,%f,%f}\n",
271 WINRT_DISPLAY_PROPERTY(CurrentOrientation),
272 WINRT_DISPLAY_PROPERTY(NativeOrientation),
273 WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
276 window->Bounds.Width,
277 window->Bounds.Height);
279 SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n",
281 WINRT_DISPLAY_PROPERTY(CurrentOrientation),
282 WINRT_DISPLAY_PROPERTY(NativeOrientation),
283 WINRT_DISPLAY_PROPERTY(AutoRotationPreferences));
288 WINRT_ProcessWindowSizeChange();
290 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
291 // HACK: Make sure that orientation changes
292 // lead to the Direct3D renderer's viewport getting updated:
294 // For some reason, this doesn't seem to need to be done on Windows 8.x,
295 // even when going from Landscape to LandscapeFlipped. It only seems to
296 // be needed on Windows Phone, at least when I tested on my devices.
297 // I'm not currently sure why this is, but it seems to work fine. -- David L.
299 // 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
300 SDL_Window * window = WINRT_GlobalSDLWindow;
302 SDL_WindowData * data = (SDL_WindowData *)window->driverdata;
303 int w = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Width);
304 int h = WINRT_DIPS_TO_PHYSICAL_PIXELS(data->coreWindow->Bounds.Height);
305 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SIZE_CHANGED, w, h);
311 void SDL_WinRTApp::SetWindow(CoreWindow^ window)
313 #if LOG_WINDOW_EVENTS==1
314 SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window bounds={%f, %f, %f,%f}\n",
316 WINRT_DISPLAY_PROPERTY(CurrentOrientation),
317 WINRT_DISPLAY_PROPERTY(NativeOrientation),
318 WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
321 window->Bounds.Width,
322 window->Bounds.Height);
325 window->SizeChanged +=
326 ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &SDL_WinRTApp::OnWindowSizeChanged);
328 window->VisibilityChanged +=
329 ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged);
332 ref new TypedEventHandler<CoreWindow^, WindowActivatedEventArgs^>(this, &SDL_WinRTApp::OnWindowActivated);
335 ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed);
337 #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
338 window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
341 window->PointerPressed +=
342 ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerPressed);
344 window->PointerMoved +=
345 ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerMoved);
347 window->PointerReleased +=
348 ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerReleased);
350 window->PointerEntered +=
351 ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerEntered);
353 window->PointerExited +=
354 ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerExited);
356 window->PointerWheelChanged +=
357 ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerWheelChanged);
359 #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
360 // Retrieves relative-only mouse movements:
361 Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved +=
362 ref new TypedEventHandler<MouseDevice^, MouseEventArgs^>(this, &SDL_WinRTApp::OnMouseMoved);
366 ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyDown);
369 ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyUp);
371 window->CharacterReceived +=
372 ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &SDL_WinRTApp::OnCharacterReceived);
374 #if NTDDI_VERSION >= NTDDI_WIN10
375 Windows::UI::Core::SystemNavigationManager::GetForCurrentView()->BackRequested +=
376 ref new EventHandler<BackRequestedEventArgs^>(this, &SDL_WinRTApp::OnBackButtonPressed);
377 #elif WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
378 HardwareButtons::BackPressed +=
379 ref new EventHandler<BackPressedEventArgs^>(this, &SDL_WinRTApp::OnBackButtonPressed);
382 #if NTDDI_VERSION > NTDDI_WIN8
383 DisplayInformation::GetForCurrentView()->OrientationChanged +=
384 ref new TypedEventHandler<Windows::Graphics::Display::DisplayInformation^, Object^>(this, &SDL_WinRTApp::OnOrientationChanged);
386 DisplayProperties::OrientationChanged +=
387 ref new DisplayPropertiesEventHandler(this, &SDL_WinRTApp::OnOrientationChanged);
390 // Register the hint, SDL_HINT_ORIENTATIONS, with SDL.
391 // 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.
392 SDL_AddHintCallback(SDL_HINT_ORIENTATIONS, WINRT_SetDisplayOrientationsPreference, NULL);
394 #if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10) // for Windows 8/8.1/RT apps... (and not Phone apps)
395 // Make sure we know when a user has opened the app's settings pane.
396 // This is needed in order to display a privacy policy, which needs
397 // to be done for network-enabled apps, as per Windows Store requirements.
398 using namespace Windows::UI::ApplicationSettings;
399 SettingsPane::GetForCurrentView()->CommandsRequested +=
400 ref new TypedEventHandler<SettingsPane^, SettingsPaneCommandsRequestedEventArgs^>
401 (this, &SDL_WinRTApp::OnSettingsPaneCommandsRequested);
405 void SDL_WinRTApp::Load(Platform::String^ entryPoint)
409 void SDL_WinRTApp::Run()
412 if (WINRT_SDLAppEntryPoint)
414 // TODO, WinRT: pass the C-style main() a reasonably realistic
415 // representation of command line arguments.
418 WINRT_SDLAppEntryPoint(argc, argv);
422 static bool IsSDLWindowEventPending(SDL_WindowEventID windowEventID)
424 SDL_Event events[128];
425 const int count = SDL_PeepEvents(events, sizeof(events)/sizeof(SDL_Event), SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT);
426 for (int i = 0; i < count; ++i) {
427 if (events[i].window.event == windowEventID) {
434 bool SDL_WinRTApp::ShouldWaitForAppResumeEvents()
436 /* Don't wait if the app is visible: */
437 if (m_windowVisible) {
441 /* Don't wait until the window-hide events finish processing.
442 * Do note that if an app-suspend event is sent (as indicated
443 * by SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERBACKGROUND
444 * events), then this code may be a moot point, as WinRT's
445 * own event pump (aka ProcessEvents()) will pause regardless
446 * of what we do here. This happens on Windows Phone 8, to note.
447 * Windows 8.x apps, on the other hand, may get a chance to run
450 if (IsSDLWindowEventPending(SDL_WINDOWEVENT_HIDDEN)) {
452 } else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_FOCUS_LOST)) {
454 } else if (IsSDLWindowEventPending(SDL_WINDOWEVENT_MINIMIZED)) {
461 void SDL_WinRTApp::PumpEvents()
463 if (!m_windowClosed) {
464 if (!ShouldWaitForAppResumeEvents()) {
465 /* This is the normal way in which events should be pumped.
466 * 'ProcessAllIfPresent' will make ProcessEvents() process anywhere
467 * from zero to N events, and will then return.
469 CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
471 /* This style of event-pumping, with 'ProcessOneAndAllPending',
472 * will cause anywhere from one to N events to be processed. If
473 * at least one event is processed, the call will return. If
474 * no events are pending, then the call will wait until one is
475 * available, and will not return (to the caller) until this
476 * happens! This should only occur when the app is hidden.
478 CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
483 void SDL_WinRTApp::Uninitialize()
487 #if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10)
488 void SDL_WinRTApp::OnSettingsPaneCommandsRequested(
489 Windows::UI::ApplicationSettings::SettingsPane ^p,
490 Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args)
492 using namespace Platform;
493 using namespace Windows::UI::ApplicationSettings;
494 using namespace Windows::UI::Popups;
496 String ^privacyPolicyURL = nullptr; // a URL to an app's Privacy Policy
497 String ^privacyPolicyLabel = nullptr; // label/link text
498 const char *tmpHintValue = NULL; // SDL_GetHint-retrieved value, used immediately
499 wchar_t *tmpStr = NULL; // used for UTF8 to UCS2 conversion
501 // Setup a 'Privacy Policy' link, if one is available (via SDL_GetHint):
502 tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_URL);
503 if (tmpHintValue && tmpHintValue[0] != '\0') {
504 // Convert the privacy policy's URL to UCS2:
505 tmpStr = WIN_UTF8ToString(tmpHintValue);
506 privacyPolicyURL = ref new String(tmpStr);
509 // Optionally retrieve custom label-text for the link. If this isn't
510 // available, a default value will be used instead.
511 tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_LABEL);
512 if (tmpHintValue && tmpHintValue[0] != '\0') {
513 tmpStr = WIN_UTF8ToString(tmpHintValue);
514 privacyPolicyLabel = ref new String(tmpStr);
517 privacyPolicyLabel = ref new String(L"Privacy Policy");
520 // Register the link, along with a handler to be called if and when it is
522 auto cmd = ref new SettingsCommand(L"privacyPolicy", privacyPolicyLabel,
523 ref new UICommandInvokedHandler([=](IUICommand ^) {
524 Windows::System::Launcher::LaunchUriAsync(ref new Uri(privacyPolicyURL));
526 args->Request->ApplicationCommands->Append(cmd);
529 #endif // if (WINAPI_FAMILY == WINAPI_FAMILY_APP) && (NTDDI_VERSION < NTDDI_WIN10)
531 void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
533 #if LOG_WINDOW_EVENTS==1
534 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",
536 args->Size.Width, args->Size.Height,
537 sender->Bounds.X, sender->Bounds.Y, sender->Bounds.Width, sender->Bounds.Height,
538 WINRT_DISPLAY_PROPERTY(CurrentOrientation),
539 WINRT_DISPLAY_PROPERTY(NativeOrientation),
540 WINRT_DISPLAY_PROPERTY(AutoRotationPreferences),
541 (WINRT_GlobalSDLWindow ? "yes" : "no"));
544 WINRT_ProcessWindowSizeChange();
547 void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
549 #if LOG_WINDOW_EVENTS==1
550 SDL_Log("%s, visible?=%s, bounds={%f,%f,%f,%f}, WINRT_GlobalSDLWindow?=%s\n",
552 (args->Visible ? "yes" : "no"),
553 sender->Bounds.X, sender->Bounds.Y,
554 sender->Bounds.Width, sender->Bounds.Height,
555 (WINRT_GlobalSDLWindow ? "yes" : "no"));
558 m_windowVisible = args->Visible;
559 if (WINRT_GlobalSDLWindow) {
560 SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid;
561 Uint32 latestWindowFlags = WINRT_DetectWindowFlags(WINRT_GlobalSDLWindow);
563 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0);
564 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_GAINED, 0, 0);
565 if (latestWindowFlags & SDL_WINDOW_MAXIMIZED) {
566 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
568 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0);
571 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0);
572 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_FOCUS_LOST, 0, 0);
573 SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
576 // HACK: Prevent SDL's window-hide handling code, which currently
577 // triggers a fake window resize (possibly erronously), from
578 // marking the SDL window's surface as invalid.
580 // A better solution to this probably involves figuring out if the
581 // fake window resize can be prevented.
582 WINRT_GlobalSDLWindow->surface_valid = wasSDLWindowSurfaceValid;
586 void SDL_WinRTApp::OnWindowActivated(CoreWindow^ sender, WindowActivatedEventArgs^ args)
588 #if LOG_WINDOW_EVENTS==1
589 SDL_Log("%s, WINRT_GlobalSDLWindow?=%s\n\n",
591 (WINRT_GlobalSDLWindow ? "yes" : "no"));
594 /* There's no property in Win 8.x to tell whether a window is active or
595 not. [De]activation events are, however, sent to the app. We'll just
596 record those, in case the CoreWindow gets wrapped by an SDL_Window at
599 sender->CustomProperties->Insert("SDLHelperWindowActivationState", args->WindowActivationState);
601 SDL_Window * window = WINRT_GlobalSDLWindow;
603 if (args->WindowActivationState != CoreWindowActivationState::Deactivated) {
604 SDL_SendWindowEvent(window, SDL_WINDOWEVENT_SHOWN, 0, 0);
605 if (SDL_GetKeyboardFocus() != window) {
606 SDL_SetKeyboardFocus(window);
609 /* Send a mouse-motion event as appropriate.
610 This doesn't work when called from OnPointerEntered, at least
611 not in WinRT CoreWindow apps (as OnPointerEntered doesn't
612 appear to be called after window-reactivation, at least not
613 in Windows 10, Build 10586.3 (November 2015 update, non-beta).
615 Don't do it on WinPhone 8.0 though, as CoreWindow's 'PointerPosition'
616 property isn't available.
618 #if (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP) || (NTDDI_VERSION >= NTDDI_WINBLUE)
619 Point cursorPos = WINRT_TransformCursorPosition(window, sender->PointerPosition, TransformToSDLWindowSize);
620 SDL_SendMouseMotion(window, 0, 0, (int)cursorPos.X, (int)cursorPos.Y);
623 /* TODO, WinRT: see if the Win32 bugfix from https://hg.libsdl.org/SDL/rev/d278747da408 needs to be applied (on window activation) */
624 //WIN_CheckAsyncMouseRelease(data);
626 /* TODO, WinRT: implement clipboard support, if possible */
628 // * FIXME: Update keyboard state
630 //WIN_CheckClipboardUpdate(data->videodata);
632 // HACK: Resetting the mouse-cursor here seems to fix
633 // https://bugzilla.libsdl.org/show_bug.cgi?id=3217, whereby a
634 // WinRT app's mouse cursor may switch to Windows' 'wait' cursor,
635 // after a user alt-tabs back into a full-screened SDL app.
636 // This bug does not appear to reproduce 100% of the time.
637 // It may be a bug in Windows itself (v.10.0.586.36, as tested,
638 // and the most-recent as of this writing).
641 if (SDL_GetKeyboardFocus() == window) {
642 SDL_SetKeyboardFocus(NULL);
648 void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
650 #if LOG_WINDOW_EVENTS==1
651 SDL_Log("%s\n", __FUNCTION__);
653 m_windowClosed = true;
656 void SDL_WinRTApp::OnAppActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
658 CoreWindow::GetForCurrentThread()->Activate();
661 void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
663 // Save app state asynchronously after requesting a deferral. Holding a deferral
664 // indicates that the application is busy performing suspending operations. Be
665 // aware that a deferral may not be held indefinitely. After about five seconds,
666 // the app will be forced to exit.
668 // ... but first, let the app know it's about to go to the background.
669 // The separation of events may be important, given that the deferral
670 // runs in a separate thread. This'll make SDL_APP_WILLENTERBACKGROUND
671 // the only event among the two that runs in the main thread. Given
672 // that a few WinRT operations can only be done from the main thread
673 // (things that access the WinRT CoreWindow are one example of this),
674 // this could be important.
675 SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
677 SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
678 create_task([this, deferral]()
680 // Send an app did-enter-background event immediately to observers.
681 // CoreDispatcher::ProcessEvents, which is the backbone on which
682 // SDL_WinRTApp::PumpEvents is built, will not return to its caller
683 // once it sends out a suspend event. Any events posted to SDL's
684 // event queue won't get received until the WinRT app is resumed.
685 // SDL_AddEventWatch() may be used to receive app-suspend events on
687 SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
689 // Let the Direct3D 11 renderer prepare for the app to be backgrounded.
690 // This is necessary for Windows 8.1, possibly elsewhere in the future.
691 // More details at: http://msdn.microsoft.com/en-us/library/windows/apps/Hh994929.aspx
692 #if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
693 if (WINRT_GlobalSDLWindow) {
694 SDL_Renderer * renderer = SDL_GetRenderer(WINRT_GlobalSDLWindow);
695 if (renderer && (SDL_strcmp(renderer->info.name, "direct3d11") == 0)) {
696 D3D11_Trim(renderer);
701 deferral->Complete();
705 void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
707 // Restore any data or state that was unloaded on suspend. By default, data
708 // and state are persisted when resuming from suspend. Note that these events
709 // do not occur if the app was previously terminated.
710 SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
711 SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
714 void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args)
716 SDL_SendAppEvent(SDL_APP_TERMINATING);
720 WINRT_LogPointerEvent(const char * header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint)
722 Windows::UI::Input::PointerPoint ^ pt = args->CurrentPoint;
723 SDL_Log("%s: Position={%f,%f}, Transformed Pos={%f, %f}, MouseWheelDelta=%d, FrameId=%d, PointerId=%d, SDL button=%d\n",
725 pt->Position.X, pt->Position.Y,
726 transformedPoint.X, transformedPoint.Y,
727 pt->Properties->MouseWheelDelta,
730 WINRT_GetSDLButtonForPointerPoint(pt));
733 void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
735 #if LOG_POINTER_EVENTS
736 WINRT_LogPointerEvent("pointer pressed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
739 WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
742 void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
744 #if LOG_POINTER_EVENTS
745 WINRT_LogPointerEvent("pointer moved", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
748 WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
751 void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args)
753 #if LOG_POINTER_EVENTS
754 WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
757 WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
760 void SDL_WinRTApp::OnPointerEntered(CoreWindow^ sender, PointerEventArgs^ args)
762 #if LOG_POINTER_EVENTS
763 WINRT_LogPointerEvent("pointer entered", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
766 WINRT_ProcessPointerEnteredEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
769 void SDL_WinRTApp::OnPointerExited(CoreWindow^ sender, PointerEventArgs^ args)
771 #if LOG_POINTER_EVENTS
772 WINRT_LogPointerEvent("pointer exited", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
775 WINRT_ProcessPointerExitedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
778 void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args)
780 #if LOG_POINTER_EVENTS
781 WINRT_LogPointerEvent("pointer wheel changed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
784 WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
787 void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args)
789 WINRT_ProcessMouseMovedEvent(WINRT_GlobalSDLWindow, args);
792 void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
794 WINRT_ProcessKeyDownEvent(args);
797 void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
799 WINRT_ProcessKeyUpEvent(args);
802 void SDL_WinRTApp::OnCharacterReceived(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CharacterReceivedEventArgs^ args)
804 WINRT_ProcessCharacterReceivedEvent(args);
807 template <typename BackButtonEventArgs>
808 static void WINRT_OnBackButtonPressed(BackButtonEventArgs ^ args)
810 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_AC_BACK);
811 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_AC_BACK);
813 const char *hint = SDL_GetHint(SDL_HINT_WINRT_HANDLE_BACK_BUTTON);
816 args->Handled = true;
821 #if NTDDI_VERSION == NTDDI_WIN10
822 void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::UI::Core::BackRequestedEventArgs^ args)
825 WINRT_OnBackButtonPressed(args);
827 #elif WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
828 void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args)
831 WINRT_OnBackButtonPressed(args);