src/video/windowsrt/SDL_WinRTApp.cpp
author David Ludwig <dludwig@pobox.com>
Tue, 08 Jan 2013 23:11:22 -0500
changeset 8384 bc7a52629e1e
parent 8383 1f415392ccf0
child 8385 e954dfbf2ecc
permissions -rw-r--r--
WinRT: converted tabs to spaces in src/video/windowsrt/*
     1 #include "SDLmain_WinRT_common.h"
     2 #include "SDL_WinRTApp.h"
     3 
     4 extern "C" {
     5 #include "SDL_assert.h"
     6 #include "SDL_stdinc.h"
     7 #include "../SDL_sysvideo.h"
     8 #include "../../events/SDL_mouse_c.h"
     9 #include "../../events/SDL_keyboard_c.h"
    10 #include "../../events/SDL_windowevents_c.h"
    11 #include "SDL_events.h"
    12 #include "SDL_log.h"
    13 }
    14 
    15 // TODO, WinRT: Remove reference(s) to BasicTimer.h
    16 //#include "BasicTimer.h"
    17 
    18 // HACK, DLudwig: The C-style main() will get loaded via the app's
    19 // WinRT-styled main(), which is part of SDLmain_for_WinRT.cpp.
    20 // This seems wrong on some level, but does seem to work.
    21 typedef int (*SDL_WinRT_MainFunction)(int, char **);
    22 static SDL_WinRT_MainFunction SDL_WinRT_main = nullptr;
    23 
    24 // HACK, DLudwig: record a reference to the global, Windows RT 'app'/view.
    25 // SDL/WinRT will use this throughout its code.
    26 //
    27 // TODO, WinRT: consider replacing SDL_WinRTGlobalApp with something
    28 // non-global, such as something created inside
    29 // SDL_InitSubSystem(SDL_INIT_VIDEO), or something inside
    30 // SDL_CreateWindow().
    31 SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr;
    32 
    33 
    34 using namespace Windows::ApplicationModel;
    35 using namespace Windows::ApplicationModel::Core;
    36 using namespace Windows::ApplicationModel::Activation;
    37 using namespace Windows::Devices::Input;
    38 using namespace Windows::UI::Core;
    39 using namespace Windows::System;
    40 using namespace Windows::Foundation;
    41 using namespace Windows::Graphics::Display;
    42 using namespace concurrency;
    43 
    44 SDL_WinRTApp::SDL_WinRTApp() :
    45     m_windowClosed(false),
    46     m_windowVisible(true),
    47     m_sdlWindowData(NULL),
    48     m_useRelativeMouseMode(false)
    49 {
    50 }
    51 
    52 void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
    53 {
    54     applicationView->Activated +=
    55         ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &SDL_WinRTApp::OnActivated);
    56 
    57     CoreApplication::Suspending +=
    58         ref new EventHandler<SuspendingEventArgs^>(this, &SDL_WinRTApp::OnSuspending);
    59 
    60     CoreApplication::Resuming +=
    61         ref new EventHandler<Platform::Object^>(this, &SDL_WinRTApp::OnResuming);
    62 
    63     m_renderer = ref new SDL_winrtrenderer();
    64 }
    65 
    66 void SDL_WinRTApp::SetWindow(CoreWindow^ window)
    67 {
    68     window->SizeChanged += 
    69         ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &SDL_WinRTApp::OnWindowSizeChanged);
    70 
    71     window->VisibilityChanged +=
    72         ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &SDL_WinRTApp::OnVisibilityChanged);
    73 
    74     window->Closed += 
    75         ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &SDL_WinRTApp::OnWindowClosed);
    76 
    77     window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
    78 
    79     window->PointerPressed +=
    80         ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerPressed);
    81 
    82     window->PointerReleased +=
    83         ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerReleased);
    84 
    85     window->PointerMoved +=
    86         ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &SDL_WinRTApp::OnPointerMoved);
    87 
    88     // Retrieves relative-only mouse movements:
    89     Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved +=
    90         ref new TypedEventHandler<MouseDevice^, MouseEventArgs^>(this, &SDL_WinRTApp::OnMouseMoved);
    91 
    92     window->KeyDown +=
    93         ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyDown);
    94 
    95     window->KeyUp +=
    96         ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &SDL_WinRTApp::OnKeyUp);
    97 
    98 
    99     m_renderer->Initialize(CoreWindow::GetForCurrentThread());
   100 }
   101 
   102 void SDL_WinRTApp::Load(Platform::String^ entryPoint)
   103 {
   104 }
   105 
   106 void SDL_WinRTApp::Run()
   107 {
   108     if (SDL_WinRT_main)
   109     {
   110         // TODO, WinRT: pass the C-style main() a reasonably realistic
   111         // representation of command line arguments.
   112         int argc = 0;
   113         char **argv = NULL;
   114         SDL_WinRT_main(argc, argv);
   115     }
   116 }
   117 
   118 void SDL_WinRTApp::PumpEvents()
   119 {
   120     if (!m_windowClosed)
   121     {
   122         if (m_windowVisible)
   123         {
   124             CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
   125         }
   126         else
   127         {
   128             CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
   129         }
   130     }
   131 }
   132 
   133 void SDL_WinRTApp::UpdateWindowFramebuffer(SDL_Surface * surface, SDL_Rect * rects, int numrects)
   134 {
   135     if (!m_windowClosed && m_windowVisible)
   136     {
   137         m_renderer->Render(surface, rects, numrects);
   138         m_renderer->Present(); // This call is synchronized to the display frame rate.
   139     }
   140 }
   141 
   142 void SDL_WinRTApp::Uninitialize()
   143 {
   144 }
   145 
   146 void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
   147 {
   148     m_renderer->UpdateForWindowSizeChange();
   149 }
   150 
   151 void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
   152 {
   153     m_windowVisible = args->Visible;
   154 }
   155 
   156 void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
   157 {
   158     m_windowClosed = true;
   159 }
   160 
   161 void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
   162 {
   163     if (m_sdlWindowData)
   164     {
   165         SDL_SendMouseButton(m_sdlWindowData->sdlWindow, SDL_PRESSED, SDL_BUTTON_LEFT);
   166     }
   167 }
   168 
   169 void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args)
   170 {
   171     if (m_sdlWindowData)
   172     {
   173         SDL_SendMouseButton(m_sdlWindowData->sdlWindow, SDL_RELEASED, SDL_BUTTON_LEFT);
   174     }
   175 }
   176 
   177 static inline int _lround(float arg) {
   178     if (arg >= 0.0f) {
   179         return (int)floor(arg + 0.5f);
   180     } else {
   181         return (int)ceil(arg - 0.5f);
   182     }
   183 }
   184 
   185 void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args)
   186 {
   187     if (m_sdlWindowData && m_useRelativeMouseMode) {
   188         // DLudwig, 2012-12-28: On some systems, namely Visual Studio's Windows
   189         // Simulator, as well as Windows 8 in a Parallels 8 VM, MouseEventArgs'
   190         // MouseDelta field often reports very large values.  More information
   191         // on this can be found at the following pages on MSDN:
   192         //  - http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/a3c789fa-f1c5-49c4-9c0a-7db88d0f90f8
   193         //  - https://connect.microsoft.com/VisualStudio/Feedback/details/756515
   194         //
   195         // The values do not appear to be as large when running on some systems,
   196         // most notably a Surface RT.  Furthermore, the values returned by
   197         // CoreWindow's PointerMoved event, and sent to this class' OnPointerMoved
   198         // method, do not ever appear to be large, even when MouseEventArgs'
   199         // MouseDelta is reporting to the contrary.
   200         //
   201         // On systems with the large-values behavior, it appears that the values
   202         // get reported as if the screen's size is 65536 units in both the X and Y
   203         // dimensions.  This can be viewed by using Windows' now-private, "Raw Input"
   204         // APIs.  (GetRawInputData, RegisterRawInputDevices, WM_INPUT, etc.)
   205         //
   206         // MSDN's documentation on MouseEventArgs' MouseDelta field (at
   207         // http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.input.mouseeventargs.mousedelta ),
   208         // does not seem to indicate (to me) that its values should be so large.  It
   209         // says that its values should be a "change in screen location".  I could
   210         // be misinterpreting this, however a post on MSDN from a Microsoft engineer (see: 
   211         // http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/09a9868e-95bb-4858-ba1a-cb4d2c298d62 ),
   212         // indicates that these values are in DIPs, which is the same unit used
   213         // by CoreWindow's PointerMoved events (via the Position field in its CurrentPoint
   214         // property.  See http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.input.pointerpoint.position.aspx
   215         // for details.)
   216         //
   217         // To note, PointerMoved events are sent a 'RawPosition' value (via the
   218         // CurrentPoint property in MouseEventArgs), however these do not seem
   219         // to exhibit the same large-value behavior.
   220         //
   221         // The values passed via PointerMoved events can't always be used for relative
   222         // mouse motion, unfortunately.  Its values are bound to the cursor's position,
   223         // which stops when it hits one of the screen's edges.  This can be a problem in
   224         // first person shooters, whereby it is normal for mouse motion to travel far
   225         // along any one axis for a period of time.  MouseMoved events do not have the
   226         // screen-bounding limitation, and can be used regardless of where the system's
   227         // cursor is.
   228         //
   229         // One possible workaround would be to programmatically set the cursor's
   230         // position to the screen's center (when SDL's relative mouse mode is enabled),
   231         // however Windows RT does not yet seem to have the ability to set the cursor's
   232         // position via a public API.  Win32 did this via an API call, SetCursorPos,
   233         // however WinRT makes this function be private.  Apps that use it won't get
   234         // approved for distribution in the Windows Store.  I've yet to be able to find
   235         // a suitable, store-friendly counterpart for WinRT.
   236         //
   237         // There may be some room for a workaround whereby OnPointerMoved's values
   238         // are compared to the values from OnMouseMoved in order to detect
   239         // when this bug is active.  A suitable transformation could then be made to
   240         // OnMouseMoved's values.  For now, however, the system-reported values are sent
   241         // to SDL with minimal transformation: from native screen coordinates (in DIPs)
   242         // to SDL window coordinates.
   243         //
   244         const Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y);
   245         const Point mouseDeltaInSDLWindowCoords = TransformCursor(mouseDeltaInDIPs);
   246         SDL_SendMouseMotion(
   247             m_sdlWindowData->sdlWindow,
   248             1,
   249             _lround(mouseDeltaInSDLWindowCoords.X),
   250             _lround(mouseDeltaInSDLWindowCoords.Y));
   251     }
   252 }
   253 
   254 // Applies necessary geometric transformations to raw cursor positions:
   255 Point SDL_WinRTApp::TransformCursor(Point rawPosition)
   256 {
   257     if ( ! m_sdlWindowData || ! m_sdlWindowData->sdlWindow ) {
   258         return rawPosition;
   259     }
   260     CoreWindow ^ nativeWindow = CoreWindow::GetForCurrentThread();
   261     Point outputPosition;
   262     outputPosition.X = rawPosition.X * (((float32)m_sdlWindowData->sdlWindow->w) / nativeWindow->Bounds.Width);
   263     outputPosition.Y = rawPosition.Y * (((float32)m_sdlWindowData->sdlWindow->h) / nativeWindow->Bounds.Height);
   264     return outputPosition;
   265 }
   266 
   267 void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
   268 {
   269     if (m_sdlWindowData && ! m_useRelativeMouseMode)
   270     {
   271         Point transformedPoint = TransformCursor(args->CurrentPoint->Position);
   272         SDL_SendMouseMotion(m_sdlWindowData->sdlWindow, 0, (int)transformedPoint.X, (int)transformedPoint.Y);
   273     }
   274 }
   275 
   276 static SDL_Scancode WinRT_Keycodes[] = {
   277     SDL_SCANCODE_UNKNOWN, // VirtualKey.None -- 0
   278     SDL_SCANCODE_UNKNOWN, // VirtualKey.LeftButton -- 1
   279     SDL_SCANCODE_UNKNOWN, // VirtualKey.RightButton -- 2
   280     SDL_SCANCODE_CANCEL, // VirtualKey.Cancel -- 3
   281     SDL_SCANCODE_UNKNOWN, // VirtualKey.MiddleButton -- 4
   282     SDL_SCANCODE_UNKNOWN, // VirtualKey.XButton1 -- 5
   283     SDL_SCANCODE_UNKNOWN, // VirtualKey.XButton2 -- 6
   284     SDL_SCANCODE_UNKNOWN, // -- 7
   285     SDL_SCANCODE_UNKNOWN, // VirtualKey.Back -- 8  (maybe SDL_SCANCODE_AC_BACK ?)
   286     SDL_SCANCODE_TAB, // VirtualKey.Tab -- 9
   287     SDL_SCANCODE_UNKNOWN, // -- 10
   288     SDL_SCANCODE_UNKNOWN, // -- 11
   289     SDL_SCANCODE_CLEAR, // VirtualKey.Clear -- 12
   290     SDL_SCANCODE_RETURN, // VirtualKey.Enter -- 13
   291     SDL_SCANCODE_UNKNOWN, // -- 14
   292     SDL_SCANCODE_UNKNOWN, // -- 15
   293     SDL_SCANCODE_LSHIFT, // VirtualKey.Shift -- 16
   294     SDL_SCANCODE_LCTRL, // VirtualKey.Control -- 17
   295     SDL_SCANCODE_MENU, // VirtualKey.Menu -- 18
   296     SDL_SCANCODE_PAUSE, // VirtualKey.Pause -- 19
   297     SDL_SCANCODE_CAPSLOCK, // VirtualKey.CapitalLock -- 20
   298     SDL_SCANCODE_UNKNOWN, // VirtualKey.Kana or VirtualKey.Hangul -- 21
   299     SDL_SCANCODE_UNKNOWN, // -- 22
   300     SDL_SCANCODE_UNKNOWN, // VirtualKey.Junja -- 23
   301     SDL_SCANCODE_UNKNOWN, // VirtualKey.Final -- 24
   302     SDL_SCANCODE_UNKNOWN, // VirtualKey.Hanja or VirtualKey.Kanji -- 25
   303     SDL_SCANCODE_UNKNOWN, // -- 26
   304     SDL_SCANCODE_ESCAPE, // VirtualKey.Escape -- 27
   305     SDL_SCANCODE_UNKNOWN, // VirtualKey.Convert -- 28
   306     SDL_SCANCODE_UNKNOWN, // VirtualKey.NonConvert -- 29
   307     SDL_SCANCODE_UNKNOWN, // VirtualKey.Accept -- 30
   308     SDL_SCANCODE_UNKNOWN, // VirtualKey.ModeChange -- 31  (maybe SDL_SCANCODE_MODE ?)
   309     SDL_SCANCODE_SPACE, // VirtualKey.Space -- 32
   310     SDL_SCANCODE_PAGEUP, // VirtualKey.PageUp -- 33
   311     SDL_SCANCODE_PAGEDOWN, // VirtualKey.PageDown -- 34
   312     SDL_SCANCODE_END, // VirtualKey.End -- 35
   313     SDL_SCANCODE_HOME, // VirtualKey.Home -- 36
   314     SDL_SCANCODE_LEFT, // VirtualKey.Left -- 37
   315     SDL_SCANCODE_UP, // VirtualKey.Up -- 38
   316     SDL_SCANCODE_RIGHT, // VirtualKey.Right -- 39
   317     SDL_SCANCODE_DOWN, // VirtualKey.Down -- 40
   318     SDL_SCANCODE_SELECT, // VirtualKey.Select -- 41
   319     SDL_SCANCODE_UNKNOWN, // VirtualKey.Print -- 42  (maybe SDL_SCANCODE_PRINTSCREEN ?)
   320     SDL_SCANCODE_EXECUTE, // VirtualKey.Execute -- 43
   321     SDL_SCANCODE_UNKNOWN, // VirtualKey.Snapshot -- 44
   322     SDL_SCANCODE_INSERT, // VirtualKey.Insert -- 45
   323     SDL_SCANCODE_DELETE, // VirtualKey.Delete -- 46
   324     SDL_SCANCODE_HELP, // VirtualKey.Help -- 47
   325     SDL_SCANCODE_0, // VirtualKey.Number0 -- 48
   326     SDL_SCANCODE_1, // VirtualKey.Number1 -- 49
   327     SDL_SCANCODE_2, // VirtualKey.Number2 -- 50
   328     SDL_SCANCODE_3, // VirtualKey.Number3 -- 51
   329     SDL_SCANCODE_4, // VirtualKey.Number4 -- 52
   330     SDL_SCANCODE_5, // VirtualKey.Number5 -- 53
   331     SDL_SCANCODE_6, // VirtualKey.Number6 -- 54
   332     SDL_SCANCODE_7, // VirtualKey.Number7 -- 55
   333     SDL_SCANCODE_8, // VirtualKey.Number8 -- 56
   334     SDL_SCANCODE_9, // VirtualKey.Number9 -- 57
   335     SDL_SCANCODE_UNKNOWN, // -- 58
   336     SDL_SCANCODE_UNKNOWN, // -- 59
   337     SDL_SCANCODE_UNKNOWN, // -- 60
   338     SDL_SCANCODE_UNKNOWN, // -- 61
   339     SDL_SCANCODE_UNKNOWN, // -- 62
   340     SDL_SCANCODE_UNKNOWN, // -- 63
   341     SDL_SCANCODE_UNKNOWN, // -- 64
   342     SDL_SCANCODE_A, // VirtualKey.A -- 65
   343     SDL_SCANCODE_B, // VirtualKey.B -- 66
   344     SDL_SCANCODE_C, // VirtualKey.C -- 67
   345     SDL_SCANCODE_D, // VirtualKey.D -- 68
   346     SDL_SCANCODE_E, // VirtualKey.E -- 69
   347     SDL_SCANCODE_F, // VirtualKey.F -- 70
   348     SDL_SCANCODE_G, // VirtualKey.G -- 71
   349     SDL_SCANCODE_H, // VirtualKey.H -- 72
   350     SDL_SCANCODE_I, // VirtualKey.I -- 73
   351     SDL_SCANCODE_J, // VirtualKey.J -- 74
   352     SDL_SCANCODE_K, // VirtualKey.K -- 75
   353     SDL_SCANCODE_L, // VirtualKey.L -- 76
   354     SDL_SCANCODE_M, // VirtualKey.M -- 77
   355     SDL_SCANCODE_N, // VirtualKey.N -- 78
   356     SDL_SCANCODE_O, // VirtualKey.O -- 79
   357     SDL_SCANCODE_P, // VirtualKey.P -- 80
   358     SDL_SCANCODE_Q, // VirtualKey.Q -- 81
   359     SDL_SCANCODE_R, // VirtualKey.R -- 82
   360     SDL_SCANCODE_S, // VirtualKey.S -- 83
   361     SDL_SCANCODE_T, // VirtualKey.T -- 84
   362     SDL_SCANCODE_U, // VirtualKey.U -- 85
   363     SDL_SCANCODE_V, // VirtualKey.V -- 86
   364     SDL_SCANCODE_W, // VirtualKey.W -- 87
   365     SDL_SCANCODE_X, // VirtualKey.X -- 88
   366     SDL_SCANCODE_Y, // VirtualKey.Y -- 89
   367     SDL_SCANCODE_Z, // VirtualKey.Z -- 90
   368     SDL_SCANCODE_UNKNOWN, // VirtualKey.LeftWindows -- 91  (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_LGUI ?)
   369     SDL_SCANCODE_UNKNOWN, // VirtualKey.RightWindows -- 92  (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_RGUI ?)
   370     SDL_SCANCODE_APPLICATION, // VirtualKey.Application -- 93
   371     SDL_SCANCODE_UNKNOWN, // -- 94
   372     SDL_SCANCODE_SLEEP, // VirtualKey.Sleep -- 95
   373     SDL_SCANCODE_KP_0, // VirtualKey.NumberPad0 -- 96
   374     SDL_SCANCODE_KP_1, // VirtualKey.NumberPad1 -- 97
   375     SDL_SCANCODE_KP_2, // VirtualKey.NumberPad2 -- 98
   376     SDL_SCANCODE_KP_3, // VirtualKey.NumberPad3 -- 99
   377     SDL_SCANCODE_KP_4, // VirtualKey.NumberPad4 -- 100
   378     SDL_SCANCODE_KP_5, // VirtualKey.NumberPad5 -- 101
   379     SDL_SCANCODE_KP_6, // VirtualKey.NumberPad6 -- 102
   380     SDL_SCANCODE_KP_7, // VirtualKey.NumberPad7 -- 103
   381     SDL_SCANCODE_KP_8, // VirtualKey.NumberPad8 -- 104
   382     SDL_SCANCODE_KP_9, // VirtualKey.NumberPad9 -- 105
   383     SDL_SCANCODE_KP_MULTIPLY, // VirtualKey.Multiply -- 106
   384     SDL_SCANCODE_KP_PLUS, // VirtualKey.Add -- 107
   385     SDL_SCANCODE_UNKNOWN, // VirtualKey.Separator -- 108
   386     SDL_SCANCODE_KP_MINUS, // VirtualKey.Subtract -- 109
   387     SDL_SCANCODE_UNKNOWN, // VirtualKey.Decimal -- 110  (maybe SDL_SCANCODE_DECIMALSEPARATOR, SDL_SCANCODE_KP_DECIMAL, or SDL_SCANCODE_KP_PERIOD ?)
   388     SDL_SCANCODE_KP_DIVIDE, // VirtualKey.Divide -- 111
   389     SDL_SCANCODE_F1, // VirtualKey.F1 -- 112
   390     SDL_SCANCODE_F2, // VirtualKey.F2 -- 113
   391     SDL_SCANCODE_F3, // VirtualKey.F3 -- 114
   392     SDL_SCANCODE_F4, // VirtualKey.F4 -- 115
   393     SDL_SCANCODE_F5, // VirtualKey.F5 -- 116
   394     SDL_SCANCODE_F6, // VirtualKey.F6 -- 117
   395     SDL_SCANCODE_F7, // VirtualKey.F7 -- 118
   396     SDL_SCANCODE_F8, // VirtualKey.F8 -- 119
   397     SDL_SCANCODE_F9, // VirtualKey.F9 -- 120
   398     SDL_SCANCODE_F10, // VirtualKey.F10 -- 121
   399     SDL_SCANCODE_F11, // VirtualKey.F11 -- 122
   400     SDL_SCANCODE_F12, // VirtualKey.F12 -- 123
   401     SDL_SCANCODE_F13, // VirtualKey.F13 -- 124
   402     SDL_SCANCODE_F14, // VirtualKey.F14 -- 125
   403     SDL_SCANCODE_F15, // VirtualKey.F15 -- 126
   404     SDL_SCANCODE_F16, // VirtualKey.F16 -- 127
   405     SDL_SCANCODE_F17, // VirtualKey.F17 -- 128
   406     SDL_SCANCODE_F18, // VirtualKey.F18 -- 129
   407     SDL_SCANCODE_F19, // VirtualKey.F19 -- 130
   408     SDL_SCANCODE_F20, // VirtualKey.F20 -- 131
   409     SDL_SCANCODE_F21, // VirtualKey.F21 -- 132
   410     SDL_SCANCODE_F22, // VirtualKey.F22 -- 133
   411     SDL_SCANCODE_F23, // VirtualKey.F23 -- 134
   412     SDL_SCANCODE_F24, // VirtualKey.F24 -- 135
   413     SDL_SCANCODE_UNKNOWN, // -- 136
   414     SDL_SCANCODE_UNKNOWN, // -- 137
   415     SDL_SCANCODE_UNKNOWN, // -- 138
   416     SDL_SCANCODE_UNKNOWN, // -- 139
   417     SDL_SCANCODE_UNKNOWN, // -- 140
   418     SDL_SCANCODE_UNKNOWN, // -- 141
   419     SDL_SCANCODE_UNKNOWN, // -- 142
   420     SDL_SCANCODE_UNKNOWN, // -- 143
   421     SDL_SCANCODE_NUMLOCKCLEAR, // VirtualKey.NumberKeyLock -- 144
   422     SDL_SCANCODE_SCROLLLOCK, // VirtualKey.Scroll -- 145
   423     SDL_SCANCODE_UNKNOWN, // -- 146
   424     SDL_SCANCODE_UNKNOWN, // -- 147
   425     SDL_SCANCODE_UNKNOWN, // -- 148
   426     SDL_SCANCODE_UNKNOWN, // -- 149
   427     SDL_SCANCODE_UNKNOWN, // -- 150
   428     SDL_SCANCODE_UNKNOWN, // -- 151
   429     SDL_SCANCODE_UNKNOWN, // -- 152
   430     SDL_SCANCODE_UNKNOWN, // -- 153
   431     SDL_SCANCODE_UNKNOWN, // -- 154
   432     SDL_SCANCODE_UNKNOWN, // -- 155
   433     SDL_SCANCODE_UNKNOWN, // -- 156
   434     SDL_SCANCODE_UNKNOWN, // -- 157
   435     SDL_SCANCODE_UNKNOWN, // -- 158
   436     SDL_SCANCODE_UNKNOWN, // -- 159
   437     SDL_SCANCODE_LSHIFT, // VirtualKey.LeftShift -- 160
   438     SDL_SCANCODE_RSHIFT, // VirtualKey.RightShift -- 161
   439     SDL_SCANCODE_LCTRL, // VirtualKey.LeftControl -- 162
   440     SDL_SCANCODE_RCTRL, // VirtualKey.RightControl -- 163
   441     SDL_SCANCODE_MENU, // VirtualKey.LeftMenu -- 164
   442     SDL_SCANCODE_MENU, // VirtualKey.RightMenu -- 165
   443 };
   444 
   445 static SDL_Scancode
   446 TranslateKeycode(int keycode)
   447 {
   448     SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
   449     if (keycode < SDL_arraysize(WinRT_Keycodes)) {
   450         scancode = WinRT_Keycodes[keycode];
   451     }
   452     if (scancode == SDL_SCANCODE_UNKNOWN) {
   453         SDL_Log("WinRT TranslateKeycode, unknown keycode=%d\n", (int)keycode);
   454     }
   455     return scancode;
   456 }
   457 
   458 void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
   459 {
   460 #if 0
   461     SDL_Log("key down, handled=%s, ext?=%s, released?=%s, menu key down?=%s, repeat count=%d, scan code=%d, was down?=%s, vkey=%d\n",
   462         (args->Handled ? "1" : "0"),
   463         (args->KeyStatus.IsExtendedKey ? "1" : "0"),
   464         (args->KeyStatus.IsKeyReleased ? "1" : "0"),
   465         (args->KeyStatus.IsMenuKeyDown ? "1" : "0"),
   466         args->KeyStatus.RepeatCount,
   467         args->KeyStatus.ScanCode,
   468         (args->KeyStatus.WasKeyDown ? "1" : "0"),
   469         args->VirtualKey);
   470     //args->Handled = true;
   471     //VirtualKey vkey = args->VirtualKey;
   472 #endif
   473     SDL_SendKeyboardKey(SDL_PRESSED, TranslateKeycode((int)args->VirtualKey));
   474 }
   475 
   476 void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
   477 {
   478 #if 0
   479     SDL_Log("key up, handled=%s, ext?=%s, released?=%s, menu key down?=%s, repeat count=%d, scan code=%d, was down?=%s, vkey=%d\n",
   480         (args->Handled ? "1" : "0"),
   481         (args->KeyStatus.IsExtendedKey ? "1" : "0"),
   482         (args->KeyStatus.IsKeyReleased ? "1" : "0"),
   483         (args->KeyStatus.IsMenuKeyDown ? "1" : "0"),
   484         args->KeyStatus.RepeatCount,
   485         args->KeyStatus.ScanCode,
   486         (args->KeyStatus.WasKeyDown ? "1" : "0"),
   487         args->VirtualKey);
   488     //args->Handled = true;
   489 #endif
   490     SDL_SendKeyboardKey(SDL_RELEASED, TranslateKeycode((int)args->VirtualKey));
   491 }
   492 
   493 void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
   494 {
   495     CoreWindow::GetForCurrentThread()->Activate();
   496 }
   497 
   498 static int SDLCALL RemoveAppSuspendAndResumeEvents(void * userdata, SDL_Event * event)
   499 {
   500     if (event->type == SDL_WINDOWEVENT)
   501     {
   502         switch (event->window.event)
   503         {
   504             case SDL_WINDOWEVENT_MINIMIZED:
   505             case SDL_WINDOWEVENT_RESTORED:
   506                 // Return 0 to indicate that the event should be removed from the
   507                 // event queue:
   508                 return 0;
   509             default:
   510                 break;
   511         }
   512     }
   513 
   514     // Return 1 to indicate that the event should stay in the event queue:
   515     return 1;
   516 }
   517 
   518 void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
   519 {
   520     // Save app state asynchronously after requesting a deferral. Holding a deferral
   521     // indicates that the application is busy performing suspending operations. Be
   522     // aware that a deferral may not be held indefinitely. After about five seconds,
   523     // the app will be forced to exit.
   524     SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
   525     create_task([this, deferral]()
   526     {
   527         // Send a window-minimized event immediately to observers.
   528         // CoreDispatcher::ProcessEvents, which is the backbone on which
   529         // SDL_WinRTApp::PumpEvents is built, will not return to its caller
   530         // once it sends out a suspend event.  Any events posted to SDL's
   531         // event queue won't get received until the WinRT app is resumed.
   532         // SDL_AddEventWatch() may be used to receive app-suspend events on
   533         // WinRT.
   534         //
   535         // In order to prevent app-suspend events from being received twice:
   536         // first via a callback passed to SDL_AddEventWatch, and second via
   537         // SDL's event queue, the event will be sent to SDL, then immediately
   538         // removed from the queue.
   539         if (m_sdlWindowData)
   540         {
   541             SDL_SendWindowEvent(m_sdlWindowData->sdlWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0);   // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
   542             SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
   543         }
   544         deferral->Complete();
   545     });
   546 }
   547 
   548 void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
   549 {
   550     // Restore any data or state that was unloaded on suspend. By default, data
   551     // and state are persisted when resuming from suspend. Note that this event
   552     // does not occur if the app was previously terminated.
   553     if (m_sdlWindowData)
   554     {
   555         SDL_SendWindowEvent(m_sdlWindowData->sdlWindow, SDL_WINDOWEVENT_RESTORED, 0, 0);    // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
   556 
   557         // Remove the app-resume event from the queue, as is done with the
   558         // app-suspend event.
   559         //
   560         // TODO, WinRT: consider posting this event to the queue even though
   561         // its counterpart, the app-suspend event, effectively has to be
   562         // processed immediately.
   563         SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
   564     }
   565 }
   566 
   567 SDL_DisplayMode SDL_WinRTApp::GetMainDisplayMode()
   568 {
   569     SDL_DisplayMode mode;
   570     SDL_zero(mode);
   571     mode.format = SDL_PIXELFORMAT_RGB888;
   572     mode.w = (int) CoreWindow::GetForCurrentThread()->Bounds.Width;
   573     mode.h = (int) CoreWindow::GetForCurrentThread()->Bounds.Height;
   574     mode.refresh_rate = 0;  // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps)
   575     mode.driverdata = NULL;
   576     return mode;
   577 }
   578 
   579 const SDL_WindowData * SDL_WinRTApp::GetSDLWindowData() const
   580 {
   581     return m_sdlWindowData;
   582 }
   583 
   584 bool SDL_WinRTApp::HasSDLWindowData() const
   585 {
   586     return (m_sdlWindowData != NULL);
   587 }
   588 
   589 void SDL_WinRTApp::SetRelativeMouseMode(bool enable)
   590 {
   591     m_useRelativeMouseMode = enable;
   592 }
   593 
   594 void SDL_WinRTApp::SetSDLWindowData(const SDL_WindowData* windowData)
   595 {
   596     m_sdlWindowData = windowData;
   597 }
   598 
   599 void SDL_WinRTApp::ResizeMainTexture(int w, int h)
   600 {
   601     m_renderer->ResizeMainTexture(w, h);
   602 }
   603 
   604 IFrameworkView^ Direct3DApplicationSource::CreateView()
   605 {
   606     // TODO, WinRT: see if this function (CreateView) can ever get called
   607     // more than once.  For now, just prevent it from ever assigning
   608     // SDL_WinRTGlobalApp more than once.
   609     SDL_assert(!SDL_WinRTGlobalApp);
   610     SDL_WinRTApp ^ app = ref new SDL_WinRTApp();
   611     if (!SDL_WinRTGlobalApp)
   612     {
   613         SDL_WinRTGlobalApp = app;
   614     }
   615     return app;
   616 }
   617 
   618 __declspec(dllexport) int SDL_WinRT_RunApplication(SDL_WinRT_MainFunction mainFunction)
   619 {
   620     SDL_WinRT_main = mainFunction;
   621     auto direct3DApplicationSource = ref new Direct3DApplicationSource();
   622     CoreApplication::Run(direct3DApplicationSource);
   623     return 0;
   624 }