SDL_winrtapp_direct3d.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "../../SDL_internal.h"
  19. /* Standard C++11 includes */
  20. #include <functional>
  21. #include <string>
  22. #include <sstream>
  23. using namespace std;
  24. /* Windows includes */
  25. #include "ppltasks.h"
  26. using namespace concurrency;
  27. using namespace Windows::ApplicationModel;
  28. using namespace Windows::ApplicationModel::Core;
  29. using namespace Windows::ApplicationModel::Activation;
  30. using namespace Windows::Devices::Input;
  31. using namespace Windows::Graphics::Display;
  32. using namespace Windows::Foundation;
  33. using namespace Windows::System;
  34. using namespace Windows::UI::Core;
  35. using namespace Windows::UI::Input;
  36. #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
  37. using namespace Windows::Phone::UI::Input;
  38. #endif
  39. /* SDL includes */
  40. extern "C" {
  41. #include "../../SDL_internal.h"
  42. #include "SDL_assert.h"
  43. #include "SDL_events.h"
  44. #include "SDL_hints.h"
  45. #include "SDL_log.h"
  46. #include "SDL_main.h"
  47. #include "SDL_stdinc.h"
  48. #include "SDL_render.h"
  49. #include "../../video/SDL_sysvideo.h"
  50. //#include "../../SDL_hints_c.h"
  51. #include "../../events/SDL_events_c.h"
  52. #include "../../events/SDL_keyboard_c.h"
  53. #include "../../events/SDL_mouse_c.h"
  54. #include "../../events/SDL_windowevents_c.h"
  55. #include "../../render/SDL_sysrender.h"
  56. #include "../windows/SDL_windows.h"
  57. }
  58. #include "../../video/winrt/SDL_winrtevents_c.h"
  59. #include "../../video/winrt/SDL_winrtvideo_cpp.h"
  60. #include "SDL_winrtapp_common.h"
  61. #include "SDL_winrtapp_direct3d.h"
  62. // Compile-time debugging options:
  63. // To enable, uncomment; to disable, comment them out.
  64. //#define LOG_POINTER_EVENTS 1
  65. //#define LOG_WINDOW_EVENTS 1
  66. //#define LOG_ORIENTATION_EVENTS 1
  67. // HACK, DLudwig: record a reference to the global, WinRT 'app'/view.
  68. // SDL/WinRT will use this throughout its code.
  69. //
  70. // TODO, WinRT: consider replacing SDL_WinRTGlobalApp with something
  71. // non-global, such as something created inside
  72. // SDL_InitSubSystem(SDL_INIT_VIDEO), or something inside
  73. // SDL_CreateWindow().
  74. SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr;
  75. ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
  76. {
  77. public:
  78. virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
  79. };
  80. IFrameworkView^ SDLApplicationSource::CreateView()
  81. {
  82. // TODO, WinRT: see if this function (CreateView) can ever get called
  83. // more than once. For now, just prevent it from ever assigning
  84. // SDL_WinRTGlobalApp more than once.
  85. SDL_assert(!SDL_WinRTGlobalApp);
  86. SDL_WinRTApp ^ app = ref new SDL_WinRTApp();
  87. if (!SDL_WinRTGlobalApp)
  88. {
  89. SDL_WinRTGlobalApp = app;
  90. }
  91. return app;
  92. }
  93. int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **))
  94. {
  95. WINRT_SDLAppEntryPoint = mainFunction;
  96. auto direct3DApplicationSource = ref new SDLApplicationSource();
  97. CoreApplication::Run(direct3DApplicationSource);
  98. return 0;
  99. }
  100. static void WINRT_SetDisplayOrientationsPreference(void *userdata, const char *name, const char *oldValue, const char *newValue)
  101. {
  102. SDL_assert(SDL_strcmp(name, SDL_HINT_ORIENTATIONS) == 0);
  103. // Start with no orientation flags, then add each in as they're parsed
  104. // from newValue.
  105. unsigned int orientationFlags = 0;
  106. if (newValue) {
  107. std::istringstream tokenizer(newValue);
  108. while (!tokenizer.eof()) {
  109. std::string orientationName;
  110. std::getline(tokenizer, orientationName, ' ');
  111. if (orientationName == "LandscapeLeft") {
  112. orientationFlags |= (unsigned int) DisplayOrientations::LandscapeFlipped;
  113. } else if (orientationName == "LandscapeRight") {
  114. orientationFlags |= (unsigned int) DisplayOrientations::Landscape;
  115. } else if (orientationName == "Portrait") {
  116. orientationFlags |= (unsigned int) DisplayOrientations::Portrait;
  117. } else if (orientationName == "PortraitUpsideDown") {
  118. orientationFlags |= (unsigned int) DisplayOrientations::PortraitFlipped;
  119. }
  120. }
  121. }
  122. // If no valid orientation flags were specified, use a reasonable set of defaults:
  123. if (!orientationFlags) {
  124. // TODO, WinRT: consider seeing if an app's default orientation flags can be found out via some API call(s).
  125. orientationFlags = (unsigned int) ( \
  126. DisplayOrientations::Landscape |
  127. DisplayOrientations::LandscapeFlipped |
  128. DisplayOrientations::Portrait |
  129. DisplayOrientations::PortraitFlipped);
  130. }
  131. // Set the orientation/rotation preferences. Please note that this does
  132. // not constitute a 100%-certain lock of a given set of possible
  133. // orientations. According to Microsoft's documentation on WinRT [1]
  134. // when a device is not capable of being rotated, Windows may ignore
  135. // the orientation preferences, and stick to what the device is capable of
  136. // displaying.
  137. //
  138. // [1] Documentation on the 'InitialRotationPreference' setting for a
  139. // Windows app's manifest file describes how some orientation/rotation
  140. // preferences may be ignored. See
  141. // http://msdn.microsoft.com/en-us/library/windows/apps/hh700343.aspx
  142. // for details. Microsoft's "Display orientation sample" also gives an
  143. // outline of how Windows treats device rotation
  144. // (http://code.msdn.microsoft.com/Display-Orientation-Sample-19a58e93).
  145. DisplayProperties::AutoRotationPreferences = (DisplayOrientations) orientationFlags;
  146. }
  147. static void
  148. WINRT_ProcessWindowSizeChange()
  149. {
  150. // Make the new window size be the one true fullscreen mode.
  151. // This change was initially done, in part, to allow the Direct3D 11.1
  152. // renderer to receive window-resize events as a device rotates.
  153. // Before, rotating a device from landscape, to portrait, and then
  154. // back to landscape would cause the Direct3D 11.1 swap buffer to
  155. // not get resized appropriately. SDL would, on the rotation from
  156. // landscape to portrait, re-resize the SDL window to it's initial
  157. // size (landscape). On the subsequent rotation, SDL would drop the
  158. // window-resize event as it appeared the SDL window didn't change
  159. // size, and the Direct3D 11.1 renderer wouldn't resize its swap
  160. // chain.
  161. SDL_DisplayMode newDisplayMode;
  162. if (WINRT_CalcDisplayModeUsingNativeWindow(&newDisplayMode) != 0) {
  163. return;
  164. }
  165. // Make note of the old display mode, and it's old driverdata.
  166. SDL_DisplayMode oldDisplayMode;
  167. SDL_zero(oldDisplayMode);
  168. if (WINRT_GlobalSDLVideoDevice) {
  169. oldDisplayMode = WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode;
  170. }
  171. // Setup the new display mode in the appropriate spots.
  172. if (WINRT_GlobalSDLVideoDevice) {
  173. // Make a full copy of the display mode for display_modes[0],
  174. // one with with a separately malloced 'driverdata' field.
  175. // SDL_VideoQuit(), if called, will attempt to free the driverdata
  176. // fields in 'desktop_mode' and each entry in the 'display_modes'
  177. // array.
  178. if (WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata) {
  179. // Free the previous mode's memory
  180. SDL_free(WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata);
  181. WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata = NULL;
  182. }
  183. if (WINRT_DuplicateDisplayMode(&(WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0]), &newDisplayMode) != 0) {
  184. // Uh oh, something went wrong. A malloc call probably failed.
  185. SDL_free(newDisplayMode.driverdata);
  186. return;
  187. }
  188. // Install 'newDisplayMode' into 'current_mode' and 'desktop_mode'.
  189. WINRT_GlobalSDLVideoDevice->displays[0].current_mode = newDisplayMode;
  190. WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode = newDisplayMode;
  191. }
  192. if (WINRT_GlobalSDLWindow) {
  193. // Send a window-resize event to the rest of SDL, and to apps:
  194. SDL_SendWindowEvent(
  195. WINRT_GlobalSDLWindow,
  196. SDL_WINDOWEVENT_RESIZED,
  197. newDisplayMode.w,
  198. newDisplayMode.h);
  199. #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
  200. // HACK: On Windows Phone, make sure that orientation changes from
  201. // Landscape to LandscapeFlipped, Portrait to PortraitFlipped,
  202. // or vice-versa on either of those two, lead to the Direct3D renderer
  203. // getting updated.
  204. const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation;
  205. const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)newDisplayMode.driverdata)->currentOrientation;
  206. if ((oldOrientation == DisplayOrientations::Landscape && newOrientation == DisplayOrientations::LandscapeFlipped) ||
  207. (oldOrientation == DisplayOrientations::LandscapeFlipped && newOrientation == DisplayOrientations::Landscape) ||
  208. (oldOrientation == DisplayOrientations::Portrait && newOrientation == DisplayOrientations::PortraitFlipped) ||
  209. (oldOrientation == DisplayOrientations::PortraitFlipped && newOrientation == DisplayOrientations::Portrait))
  210. {
  211. // One of the reasons this event is getting sent out is because SDL
  212. // will ignore requests to send out SDL_WINDOWEVENT_RESIZED events
  213. // if and when the event size doesn't change (and the Direct3D 11.1
  214. // renderer doesn't get the memo).
  215. //
  216. // Make sure that the display/window size really didn't change. If
  217. // it did, then a SDL_WINDOWEVENT_SIZE_CHANGED event got sent, and
  218. // the Direct3D 11.1 renderer picked it up, presumably.
  219. if (oldDisplayMode.w == newDisplayMode.w &&
  220. oldDisplayMode.h == newDisplayMode.h)
  221. {
  222. SDL_SendWindowEvent(
  223. WINRT_GlobalSDLWindow,
  224. SDL_WINDOWEVENT_SIZE_CHANGED,
  225. newDisplayMode.w,
  226. newDisplayMode.h);
  227. }
  228. }
  229. #endif
  230. }
  231. // Finally, free the 'driverdata' field of the old 'desktop_mode'.
  232. if (oldDisplayMode.driverdata) {
  233. SDL_free(oldDisplayMode.driverdata);
  234. oldDisplayMode.driverdata = NULL;
  235. }
  236. }
  237. SDL_WinRTApp::SDL_WinRTApp() :
  238. m_windowClosed(false),
  239. m_windowVisible(true)
  240. {
  241. }
  242. void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
  243. {
  244. applicationView->Activated +=
  245. ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnActivated);
  246. CoreApplication::Suspending +=
  247. ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending);
  248. CoreApplication::Resuming +=
  249. ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnResuming);
  250. CoreApplication::Exiting +=
  251. ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnExiting);
  252. DisplayProperties::OrientationChanged +=
  253. ref new DisplayPropertiesEventHandler(this, &SDL_WinRTApp::OnOrientationChanged);
  254. // Register the hint, SDL_HINT_ORIENTATIONS, with SDL. This needs to be
  255. // done before the hint's callback is registered (as of Feb 22, 2013),
  256. // otherwise the hint callback won't get registered.
  257. //
  258. // 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.
  259. //SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight Portrait PortraitUpsideDown"); // DavidL: this is no longer needed (for SDL_AddHintCallback)
  260. SDL_AddHintCallback(SDL_HINT_ORIENTATIONS, WINRT_SetDisplayOrientationsPreference, NULL);
  261. }
  262. void SDL_WinRTApp::OnOrientationChanged(Object^ sender)
  263. {
  264. #if LOG_ORIENTATION_EVENTS==1
  265. CoreWindow^ window = CoreWindow::GetForCurrentThread();
  266. if (window) {
  267. SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Size={%f,%f}\n",
  268. __FUNCTION__,
  269. (int)DisplayProperties::CurrentOrientation,
  270. (int)DisplayProperties::NativeOrientation,
  271. (int)DisplayProperties::AutoRotationPreferences,
  272. window->Bounds.Width,
  273. window->Bounds.Height);
  274. } else {
  275. SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n",
  276. __FUNCTION__,
  277. (int)DisplayProperties::CurrentOrientation,
  278. (int)DisplayProperties::NativeOrientation,
  279. (int)DisplayProperties::AutoRotationPreferences);
  280. }
  281. #endif
  282. #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
  283. // On Windows Phone, treat an orientation change as a change in window size.
  284. // The native window's size doesn't seem to change, however SDL will simulate
  285. // a window size change.
  286. WINRT_ProcessWindowSizeChange();
  287. #endif
  288. }
  289. void SDL_WinRTApp::SetWindow(CoreWindow^ window)
  290. {
  291. #if LOG_WINDOW_EVENTS==1
  292. SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window Size={%f,%f}\n",
  293. __FUNCTION__,
  294. (int)DisplayProperties::CurrentOrientation,
  295. (int)DisplayProperties::NativeOrientation,
  296. (int)DisplayProperties::AutoRotationPreferences,
  297. window->Bounds.Width,
  298. window->Bounds.Height);
  299. #endif
  300. window->SizeChanged +=
  301. ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &SDL_WinRTApp::OnWindowSizeChanged);
  302. window->VisibilityChanged +=
  303. ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged);
  304. window->Closed +=
  305. ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed);
  306. #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
  307. window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
  308. #endif
  309. window->PointerPressed +=
  310. ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerPressed);
  311. window->PointerMoved +=
  312. ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerMoved);
  313. window->PointerReleased +=
  314. ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerReleased);
  315. window->PointerWheelChanged +=
  316. ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerWheelChanged);
  317. #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
  318. // Retrieves relative-only mouse movements:
  319. Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved +=
  320. ref new TypedEventHandler<MouseDevice^, MouseEventArgs^>(this, &SDL_WinRTApp::OnMouseMoved);
  321. #endif
  322. window->KeyDown +=
  323. ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyDown);
  324. window->KeyUp +=
  325. ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyUp);
  326. #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
  327. HardwareButtons::BackPressed +=
  328. ref new EventHandler<BackPressedEventArgs^>(this, &SDL_WinRTApp::OnBackButtonPressed);
  329. #endif
  330. #if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps)
  331. // Make sure we know when a user has opened the app's settings pane.
  332. // This is needed in order to display a privacy policy, which needs
  333. // to be done for network-enabled apps, as per Windows Store requirements.
  334. using namespace Windows::UI::ApplicationSettings;
  335. SettingsPane::GetForCurrentView()->CommandsRequested +=
  336. ref new TypedEventHandler<SettingsPane^, SettingsPaneCommandsRequestedEventArgs^>
  337. (this, &SDL_WinRTApp::OnSettingsPaneCommandsRequested);
  338. #endif
  339. }
  340. void SDL_WinRTApp::Load(Platform::String^ entryPoint)
  341. {
  342. }
  343. void SDL_WinRTApp::Run()
  344. {
  345. SDL_SetMainReady();
  346. if (WINRT_SDLAppEntryPoint)
  347. {
  348. // TODO, WinRT: pass the C-style main() a reasonably realistic
  349. // representation of command line arguments.
  350. int argc = 0;
  351. char **argv = NULL;
  352. WINRT_SDLAppEntryPoint(argc, argv);
  353. }
  354. }
  355. void SDL_WinRTApp::PumpEvents()
  356. {
  357. if (!m_windowClosed)
  358. {
  359. if (m_windowVisible)
  360. {
  361. CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
  362. }
  363. else
  364. {
  365. CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
  366. }
  367. }
  368. }
  369. void SDL_WinRTApp::Uninitialize()
  370. {
  371. }
  372. #if WINAPI_FAMILY == WINAPI_FAMILY_APP
  373. void SDL_WinRTApp::OnSettingsPaneCommandsRequested(
  374. Windows::UI::ApplicationSettings::SettingsPane ^p,
  375. Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args)
  376. {
  377. using namespace Platform;
  378. using namespace Windows::UI::ApplicationSettings;
  379. using namespace Windows::UI::Popups;
  380. String ^privacyPolicyURL = nullptr; // a URL to an app's Privacy Policy
  381. String ^privacyPolicyLabel = nullptr; // label/link text
  382. const char *tmpHintValue = NULL; // SDL_GetHint-retrieved value, used immediately
  383. wchar_t *tmpStr = NULL; // used for UTF8 to UCS2 conversion
  384. // Setup a 'Privacy Policy' link, if one is available (via SDL_GetHint):
  385. tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_URL);
  386. if (tmpHintValue && tmpHintValue[0] != '\0') {
  387. // Convert the privacy policy's URL to UCS2:
  388. tmpStr = WIN_UTF8ToString(tmpHintValue);
  389. privacyPolicyURL = ref new String(tmpStr);
  390. SDL_free(tmpStr);
  391. // Optionally retrieve custom label-text for the link. If this isn't
  392. // available, a default value will be used instead.
  393. tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_LABEL);
  394. if (tmpHintValue && tmpHintValue[0] != '\0') {
  395. tmpStr = WIN_UTF8ToString(tmpHintValue);
  396. privacyPolicyLabel = ref new String(tmpStr);
  397. SDL_free(tmpStr);
  398. } else {
  399. privacyPolicyLabel = ref new String(L"Privacy Policy");
  400. }
  401. // Register the link, along with a handler to be called if and when it is
  402. // clicked:
  403. auto cmd = ref new SettingsCommand(L"privacyPolicy", privacyPolicyLabel,
  404. ref new UICommandInvokedHandler([=](IUICommand ^) {
  405. Windows::System::Launcher::LaunchUriAsync(ref new Uri(privacyPolicyURL));
  406. }));
  407. args->Request->ApplicationCommands->Append(cmd);
  408. }
  409. }
  410. #endif // if WINAPI_FAMILY == WINAPI_FAMILY_APP
  411. void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
  412. {
  413. #if LOG_WINDOW_EVENTS==1
  414. SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, WINRT_GlobalSDLWindow?=%s\n",
  415. __FUNCTION__,
  416. args->Size.Width, args->Size.Height,
  417. (int)DisplayProperties::CurrentOrientation,
  418. (int)DisplayProperties::NativeOrientation,
  419. (int)DisplayProperties::AutoRotationPreferences,
  420. (WINRT_GlobalSDLWindow ? "yes" : "no"));
  421. #endif
  422. WINRT_ProcessWindowSizeChange();
  423. }
  424. void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
  425. {
  426. #if LOG_WINDOW_EVENTS==1
  427. SDL_Log("%s, visible?=%s, WINRT_GlobalSDLWindow?=%s\n",
  428. __FUNCTION__,
  429. (args->Visible ? "yes" : "no"),
  430. (WINRT_GlobalSDLWindow ? "yes" : "no"));
  431. #endif
  432. m_windowVisible = args->Visible;
  433. if (WINRT_GlobalSDLWindow) {
  434. SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid;
  435. if (args->Visible) {
  436. SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0);
  437. } else {
  438. SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0);
  439. }
  440. // HACK: Prevent SDL's window-hide handling code, which currently
  441. // triggers a fake window resize (possibly erronously), from
  442. // marking the SDL window's surface as invalid.
  443. //
  444. // A better solution to this probably involves figuring out if the
  445. // fake window resize can be prevented.
  446. WINRT_GlobalSDLWindow->surface_valid = wasSDLWindowSurfaceValid;
  447. }
  448. }
  449. void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
  450. {
  451. #if LOG_WINDOW_EVENTS==1
  452. SDL_Log("%s\n", __FUNCTION__);
  453. #endif
  454. m_windowClosed = true;
  455. }
  456. void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
  457. {
  458. CoreWindow::GetForCurrentThread()->Activate();
  459. }
  460. static int SDLCALL RemoveAppSuspendAndResumeEvents(void * userdata, SDL_Event * event)
  461. {
  462. if (event->type == SDL_WINDOWEVENT)
  463. {
  464. switch (event->window.event)
  465. {
  466. case SDL_WINDOWEVENT_MINIMIZED:
  467. case SDL_WINDOWEVENT_RESTORED:
  468. // Return 0 to indicate that the event should be removed from the
  469. // event queue:
  470. return 0;
  471. default:
  472. break;
  473. }
  474. }
  475. // Return 1 to indicate that the event should stay in the event queue:
  476. return 1;
  477. }
  478. void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
  479. {
  480. // Save app state asynchronously after requesting a deferral. Holding a deferral
  481. // indicates that the application is busy performing suspending operations. Be
  482. // aware that a deferral may not be held indefinitely. After about five seconds,
  483. // the app will be forced to exit.
  484. SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
  485. create_task([this, deferral]()
  486. {
  487. // Send a window-minimized event immediately to observers.
  488. // CoreDispatcher::ProcessEvents, which is the backbone on which
  489. // SDL_WinRTApp::PumpEvents is built, will not return to its caller
  490. // once it sends out a suspend event. Any events posted to SDL's
  491. // event queue won't get received until the WinRT app is resumed.
  492. // SDL_AddEventWatch() may be used to receive app-suspend events on
  493. // WinRT.
  494. //
  495. // In order to prevent app-suspend events from being received twice:
  496. // first via a callback passed to SDL_AddEventWatch, and second via
  497. // SDL's event queue, the event will be sent to SDL, then immediately
  498. // removed from the queue.
  499. if (WINRT_GlobalSDLWindow)
  500. {
  501. SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
  502. SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
  503. }
  504. SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND);
  505. SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND);
  506. deferral->Complete();
  507. });
  508. }
  509. void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
  510. {
  511. SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND);
  512. SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND);
  513. // Restore any data or state that was unloaded on suspend. By default, data
  514. // and state are persisted when resuming from suspend. Note that this event
  515. // does not occur if the app was previously terminated.
  516. if (WINRT_GlobalSDLWindow)
  517. {
  518. SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_RESTORED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
  519. // Remove the app-resume event from the queue, as is done with the
  520. // app-suspend event.
  521. //
  522. // TODO, WinRT: consider posting this event to the queue even though
  523. // its counterpart, the app-suspend event, effectively has to be
  524. // processed immediately.
  525. SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
  526. }
  527. }
  528. void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args)
  529. {
  530. SDL_SendAppEvent(SDL_APP_TERMINATING);
  531. }
  532. static void
  533. WINRT_LogPointerEvent(const char * header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint)
  534. {
  535. Windows::UI::Input::PointerPoint ^ pt = args->CurrentPoint;
  536. SDL_Log("%s: Position={%f,%f}, Transformed Pos={%f, %f}, MouseWheelDelta=%d, FrameId=%d, PointerId=%d, SDL button=%d\n",
  537. header,
  538. pt->Position.X, pt->Position.Y,
  539. transformedPoint.X, transformedPoint.Y,
  540. pt->Properties->MouseWheelDelta,
  541. pt->FrameId,
  542. pt->PointerId,
  543. WINRT_GetSDLButtonForPointerPoint(pt));
  544. }
  545. void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
  546. {
  547. #if LOG_POINTER_EVENTS
  548. WINRT_LogPointerEvent("pointer pressed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
  549. #endif
  550. WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
  551. }
  552. void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
  553. {
  554. #if LOG_POINTER_EVENTS
  555. WINRT_LogPointerEvent("pointer moved", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
  556. #endif
  557. WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
  558. }
  559. void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args)
  560. {
  561. #if LOG_POINTER_EVENTS
  562. WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
  563. #endif
  564. WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
  565. }
  566. void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args)
  567. {
  568. #if LOG_POINTER_EVENTS
  569. WINRT_LogPointerEvent("pointer wheel changed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize));
  570. #endif
  571. WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint);
  572. }
  573. void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args)
  574. {
  575. WINRT_ProcessMouseMovedEvent(WINRT_GlobalSDLWindow, args);
  576. }
  577. void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
  578. {
  579. WINRT_ProcessKeyDownEvent(args);
  580. }
  581. void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
  582. {
  583. WINRT_ProcessKeyUpEvent(args);
  584. }
  585. #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
  586. void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args)
  587. {
  588. SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_AC_BACK);
  589. SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_AC_BACK);
  590. const char *hint = SDL_GetHint(SDL_HINT_WINRT_HANDLE_BACK_BUTTON);
  591. if (hint) {
  592. if (*hint == '1') {
  593. args->Handled = true;
  594. }
  595. }
  596. }
  597. #endif