src/video/winrt/SDL_winrtpointerinput.cpp
author David Ludwig <dludwig@pobox.com>
Fri, 06 Sep 2013 21:00:52 -0400
changeset 8521 cefdaf414ead
parent 8516 f3e0e381bdcd
child 8534 50177f518fdb
permissions -rw-r--r--
WinRT: minor code cleanup regarding events

Some event handling functions got sorted in a somewhat consistent manner, and
in some cases, were also segregated a bit from app-lifecycle code.
dludwig@8515
     1
/*
dludwig@8515
     2
  Simple DirectMedia Layer
dludwig@8515
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
dludwig@8515
     4
dludwig@8515
     5
  This software is provided 'as-is', without any express or implied
dludwig@8515
     6
  warranty.  In no event will the authors be held liable for any damages
dludwig@8515
     7
  arising from the use of this software.
dludwig@8515
     8
dludwig@8515
     9
  Permission is granted to anyone to use this software for any purpose,
dludwig@8515
    10
  including commercial applications, and to alter it and redistribute it
dludwig@8515
    11
  freely, subject to the following restrictions:
dludwig@8515
    12
dludwig@8515
    13
  1. The origin of this software must not be misrepresented; you must not
dludwig@8515
    14
     claim that you wrote the original software. If you use this software
dludwig@8515
    15
     in a product, an acknowledgment in the product documentation would be
dludwig@8515
    16
     appreciated but is not required.
dludwig@8515
    17
  2. Altered source versions must be plainly marked as such, and must not be
dludwig@8515
    18
     misrepresented as being the original software.
dludwig@8515
    19
  3. This notice may not be removed or altered from any source distribution.
dludwig@8515
    20
*/
dludwig@8515
    21
#include "SDL_config.h"
dludwig@8515
    22
dludwig@8515
    23
#if SDL_VIDEO_DRIVER_WINRT
dludwig@8515
    24
dludwig@8515
    25
/* SDL includes */
dludwig@8515
    26
#include "SDL_winrtevents_c.h"
dludwig@8516
    27
#include "SDL_winrtmouse_c.h"
dludwig@8515
    28
#include "SDL_winrtvideo_cpp.h"
dludwig@8515
    29
#include "SDL_assert.h"
dludwig@8515
    30
#include "SDL_system.h"
dludwig@8515
    31
dludwig@8515
    32
extern "C" {
dludwig@8515
    33
#include "../SDL_sysvideo.h"
dludwig@8515
    34
#include "../../events/SDL_events_c.h"
dludwig@8515
    35
#include "../../events/SDL_mouse_c.h"
dludwig@8515
    36
#include "../../events/SDL_touch_c.h"
dludwig@8515
    37
}
dludwig@8515
    38
dludwig@8515
    39
/* File-specific globals: */
dludwig@8515
    40
static SDL_TouchID WINRT_TouchID = 1;
dludwig@8515
    41
static unsigned int WINRT_LeftFingerDown = 0;
dludwig@8515
    42
dludwig@8515
    43
dludwig@8515
    44
void
dludwig@8515
    45
WINRT_InitTouch(_THIS)
dludwig@8515
    46
{
dludwig@8515
    47
    SDL_AddTouch(WINRT_TouchID, "");
dludwig@8515
    48
}
dludwig@8515
    49
dludwig@8515
    50
// Applies necessary geometric transformations to raw cursor positions:
dludwig@8515
    51
Windows::Foundation::Point
dludwig@8515
    52
WINRT_TransformCursorPosition(SDL_Window * window, Windows::Foundation::Point rawPosition)
dludwig@8515
    53
{
dludwig@8515
    54
    using namespace Windows::UI::Core;
dludwig@8515
    55
    using namespace Windows::Graphics::Display;
dludwig@8515
    56
dludwig@8515
    57
    if (!window) {
dludwig@8515
    58
        return rawPosition;
dludwig@8515
    59
    }
dludwig@8515
    60
dludwig@8515
    61
    SDL_WindowData * windowData = (SDL_WindowData *) window->driverdata;
dludwig@8515
    62
    if (windowData->coreWindow == nullptr) {
dludwig@8515
    63
        // For some reason, the window isn't associated with a CoreWindow.
dludwig@8515
    64
        // This might end up being the case as XAML support is extended.
dludwig@8515
    65
        // For now, if there's no CoreWindow attached to the SDL_Window,
dludwig@8515
    66
        // don't do any transforms.
dludwig@8515
    67
        return rawPosition;
dludwig@8515
    68
    }
dludwig@8515
    69
dludwig@8515
    70
    // The CoreWindow can only be accessed on certain thread(s).
dludwig@8515
    71
    SDL_assert(CoreWindow::GetForCurrentThread() != nullptr);
dludwig@8515
    72
dludwig@8515
    73
    CoreWindow ^ nativeWindow = windowData->coreWindow.Get();
dludwig@8515
    74
    Windows::Foundation::Point outputPosition;
dludwig@8515
    75
dludwig@8515
    76
#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
dludwig@8515
    77
    outputPosition.X = rawPosition.X * (((float32)window->w) / nativeWindow->Bounds.Width);
dludwig@8515
    78
    outputPosition.Y = rawPosition.Y * (((float32)window->h) / nativeWindow->Bounds.Height);
dludwig@8515
    79
#else
dludwig@8515
    80
    switch (DisplayProperties::CurrentOrientation)
dludwig@8515
    81
    {
dludwig@8515
    82
        case DisplayOrientations::Portrait:
dludwig@8515
    83
            outputPosition.X = rawPosition.X * (((float32)window->w) / nativeWindow->Bounds.Width);
dludwig@8515
    84
            outputPosition.Y = rawPosition.Y * (((float32)window->h) / nativeWindow->Bounds.Height);
dludwig@8515
    85
            break;
dludwig@8515
    86
        case DisplayOrientations::PortraitFlipped:
dludwig@8515
    87
            outputPosition.X = (float32)window->w - rawPosition.X * (((float32)window->w) / nativeWindow->Bounds.Width);
dludwig@8515
    88
            outputPosition.Y = (float32)window->h - rawPosition.Y * (((float32)window->h) / nativeWindow->Bounds.Height);
dludwig@8515
    89
            break;
dludwig@8515
    90
        case DisplayOrientations::Landscape:
dludwig@8515
    91
            outputPosition.X = rawPosition.Y * (((float32)window->w) / nativeWindow->Bounds.Height);
dludwig@8515
    92
            outputPosition.Y = (float32)window->h - rawPosition.X * (((float32)window->h) / nativeWindow->Bounds.Width);
dludwig@8515
    93
            break;
dludwig@8515
    94
        case DisplayOrientations::LandscapeFlipped:
dludwig@8515
    95
            outputPosition.X = (float32)window->w - rawPosition.Y * (((float32)window->w) / nativeWindow->Bounds.Height);
dludwig@8515
    96
            outputPosition.Y = rawPosition.X * (((float32)window->h) / nativeWindow->Bounds.Width);
dludwig@8515
    97
            break;
dludwig@8515
    98
        default:
dludwig@8515
    99
            break;
dludwig@8515
   100
    }
dludwig@8515
   101
#endif
dludwig@8515
   102
dludwig@8515
   103
    return outputPosition;
dludwig@8515
   104
}
dludwig@8515
   105
dludwig@8515
   106
static inline int
dludwig@8515
   107
_lround(float arg)
dludwig@8515
   108
{
dludwig@8515
   109
    if (arg >= 0.0f) {
dludwig@8515
   110
        return (int)floor(arg + 0.5f);
dludwig@8515
   111
    } else {
dludwig@8515
   112
        return (int)ceil(arg - 0.5f);
dludwig@8515
   113
    }
dludwig@8515
   114
}
dludwig@8515
   115
dludwig@8515
   116
Uint8
dludwig@8515
   117
WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt)
dludwig@8515
   118
{
dludwig@8515
   119
    using namespace Windows::UI::Input;
dludwig@8515
   120
dludwig@8515
   121
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
dludwig@8515
   122
    return SDL_BUTTON_LEFT;
dludwig@8515
   123
#else
dludwig@8515
   124
    switch (pt->Properties->PointerUpdateKind)
dludwig@8515
   125
    {
dludwig@8515
   126
        case PointerUpdateKind::LeftButtonPressed:
dludwig@8515
   127
        case PointerUpdateKind::LeftButtonReleased:
dludwig@8515
   128
            return SDL_BUTTON_LEFT;
dludwig@8515
   129
dludwig@8515
   130
        case PointerUpdateKind::RightButtonPressed:
dludwig@8515
   131
        case PointerUpdateKind::RightButtonReleased:
dludwig@8515
   132
            return SDL_BUTTON_RIGHT;
dludwig@8515
   133
dludwig@8515
   134
        case PointerUpdateKind::MiddleButtonPressed:
dludwig@8515
   135
        case PointerUpdateKind::MiddleButtonReleased:
dludwig@8515
   136
            return SDL_BUTTON_MIDDLE;
dludwig@8515
   137
dludwig@8515
   138
        case PointerUpdateKind::XButton1Pressed:
dludwig@8515
   139
        case PointerUpdateKind::XButton1Released:
dludwig@8515
   140
            return SDL_BUTTON_X1;
dludwig@8515
   141
dludwig@8515
   142
        case PointerUpdateKind::XButton2Pressed:
dludwig@8515
   143
        case PointerUpdateKind::XButton2Released:
dludwig@8515
   144
            return SDL_BUTTON_X2;
dludwig@8515
   145
dludwig@8515
   146
        default:
dludwig@8515
   147
            break;
dludwig@8515
   148
    }
dludwig@8515
   149
#endif
dludwig@8515
   150
dludwig@8515
   151
    return 0;
dludwig@8515
   152
}
dludwig@8515
   153
dludwig@8515
   154
//const char *
dludwig@8515
   155
//WINRT_ConvertPointerUpdateKindToString(Windows::UI::Input::PointerUpdateKind kind)
dludwig@8515
   156
//{
dludwig@8515
   157
//    using namespace Windows::UI::Input;
dludwig@8515
   158
//
dludwig@8515
   159
//    switch (kind)
dludwig@8515
   160
//    {
dludwig@8515
   161
//        case PointerUpdateKind::Other:
dludwig@8515
   162
//            return "Other";
dludwig@8515
   163
//        case PointerUpdateKind::LeftButtonPressed:
dludwig@8515
   164
//            return "LeftButtonPressed";
dludwig@8515
   165
//        case PointerUpdateKind::LeftButtonReleased:
dludwig@8515
   166
//            return "LeftButtonReleased";
dludwig@8515
   167
//        case PointerUpdateKind::RightButtonPressed:
dludwig@8515
   168
//            return "RightButtonPressed";
dludwig@8515
   169
//        case PointerUpdateKind::RightButtonReleased:
dludwig@8515
   170
//            return "RightButtonReleased";
dludwig@8515
   171
//        case PointerUpdateKind::MiddleButtonPressed:
dludwig@8515
   172
//            return "MiddleButtonPressed";
dludwig@8515
   173
//        case PointerUpdateKind::MiddleButtonReleased:
dludwig@8515
   174
//            return "MiddleButtonReleased";
dludwig@8515
   175
//        case PointerUpdateKind::XButton1Pressed:
dludwig@8515
   176
//            return "XButton1Pressed";
dludwig@8515
   177
//        case PointerUpdateKind::XButton1Released:
dludwig@8515
   178
//            return "XButton1Released";
dludwig@8515
   179
//        case PointerUpdateKind::XButton2Pressed:
dludwig@8515
   180
//            return "XButton2Pressed";
dludwig@8515
   181
//        case PointerUpdateKind::XButton2Released:
dludwig@8515
   182
//            return "XButton2Released";
dludwig@8515
   183
//    }
dludwig@8515
   184
//
dludwig@8515
   185
//    return "";
dludwig@8515
   186
//}
dludwig@8515
   187
dludwig@8515
   188
static bool
dludwig@8515
   189
WINRT_IsTouchEvent(Windows::UI::Input::PointerPoint ^pointerPoint)
dludwig@8515
   190
{
dludwig@8515
   191
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
dludwig@8515
   192
    return true;
dludwig@8515
   193
#else
dludwig@8515
   194
    using namespace Windows::Devices::Input;
dludwig@8515
   195
    switch (pointerPoint->PointerDevice->PointerDeviceType) {
dludwig@8515
   196
        case PointerDeviceType::Touch:
dludwig@8515
   197
        case PointerDeviceType::Pen:
dludwig@8515
   198
            return true;
dludwig@8515
   199
        default:
dludwig@8515
   200
            return false;
dludwig@8515
   201
    }
dludwig@8515
   202
#endif
dludwig@8515
   203
}
dludwig@8515
   204
dludwig@8515
   205
void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
dludwig@8515
   206
{
dludwig@8515
   207
    if (!window) {
dludwig@8515
   208
        return;
dludwig@8515
   209
    }
dludwig@8515
   210
dludwig@8515
   211
    Windows::Foundation::Point transformedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position);
dludwig@8515
   212
dludwig@8515
   213
    if (!WINRT_LeftFingerDown) {
dludwig@8515
   214
        Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint);
dludwig@8515
   215
        if (button) {
dludwig@8515
   216
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
dludwig@8515
   217
            SDL_SendMouseMotion(window, 0, 0, (int)transformedPoint.X, (int)transformedPoint.Y);
dludwig@8515
   218
#endif
dludwig@8515
   219
            SDL_SendMouseButton(window, 0, SDL_PRESSED, button);
dludwig@8515
   220
        }
dludwig@8515
   221
dludwig@8515
   222
        WINRT_LeftFingerDown = pointerPoint->PointerId;
dludwig@8515
   223
    }
dludwig@8515
   224
dludwig@8515
   225
    if (WINRT_IsTouchEvent(pointerPoint)) {
dludwig@8515
   226
        SDL_SendTouch(
dludwig@8515
   227
            WINRT_TouchID,
dludwig@8515
   228
            (SDL_FingerID) pointerPoint->PointerId,
dludwig@8515
   229
            SDL_TRUE,
dludwig@8515
   230
            transformedPoint.X,
dludwig@8515
   231
            transformedPoint.Y,
dludwig@8515
   232
            pointerPoint->Properties->Pressure);
dludwig@8515
   233
    }
dludwig@8515
   234
}
dludwig@8521
   235
dludwig@8521
   236
void
dludwig@8521
   237
WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
dludwig@8521
   238
{
dludwig@8521
   239
    if (!window || WINRT_UsingRelativeMouseMode) {
dludwig@8521
   240
        return;
dludwig@8521
   241
    }
dludwig@8521
   242
dludwig@8521
   243
    Windows::Foundation::Point transformedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position);
dludwig@8521
   244
dludwig@8521
   245
    if (pointerPoint->PointerId == WINRT_LeftFingerDown) {
dludwig@8521
   246
        SDL_SendMouseMotion(window, 0, 0, (int)transformedPoint.X, (int)transformedPoint.Y);
dludwig@8521
   247
    }
dludwig@8521
   248
dludwig@8521
   249
    if (WINRT_IsTouchEvent(pointerPoint)) {
dludwig@8521
   250
        SDL_SendTouchMotion(
dludwig@8521
   251
            WINRT_TouchID,
dludwig@8521
   252
            (SDL_FingerID) pointerPoint->PointerId,
dludwig@8521
   253
            transformedPoint.X,
dludwig@8521
   254
            transformedPoint.Y,
dludwig@8521
   255
            pointerPoint->Properties->Pressure);
dludwig@8521
   256
    }
dludwig@8521
   257
}
dludwig@8521
   258
dludwig@8521
   259
void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
dludwig@8521
   260
{
dludwig@8521
   261
    if (!window) {
dludwig@8521
   262
        return;
dludwig@8521
   263
    }
dludwig@8521
   264
dludwig@8521
   265
    Windows::Foundation::Point transformedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position);
dludwig@8521
   266
dludwig@8521
   267
    if (WINRT_LeftFingerDown == pointerPoint->PointerId) {
dludwig@8521
   268
        Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint);
dludwig@8521
   269
        if (button) {
dludwig@8521
   270
            SDL_SendMouseButton(window, 0, SDL_RELEASED, button);
dludwig@8521
   271
        }
dludwig@8521
   272
        WINRT_LeftFingerDown = 0;
dludwig@8521
   273
    }
dludwig@8521
   274
dludwig@8521
   275
    if (WINRT_IsTouchEvent(pointerPoint)) {
dludwig@8521
   276
        SDL_SendTouch(
dludwig@8521
   277
            WINRT_TouchID,
dludwig@8521
   278
            (SDL_FingerID) pointerPoint->PointerId,
dludwig@8521
   279
            SDL_FALSE,
dludwig@8521
   280
            transformedPoint.X,
dludwig@8521
   281
            transformedPoint.Y,
dludwig@8521
   282
            pointerPoint->Properties->Pressure);
dludwig@8521
   283
    }
dludwig@8521
   284
}
dludwig@8521
   285
dludwig@8521
   286
void
dludwig@8521
   287
WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint)
dludwig@8521
   288
{
dludwig@8521
   289
    if (!window) {
dludwig@8521
   290
        return;
dludwig@8521
   291
    }
dludwig@8521
   292
dludwig@8521
   293
    // FIXME: This may need to accumulate deltas up to WHEEL_DELTA
dludwig@8521
   294
    short motion = pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA;
dludwig@8521
   295
    SDL_SendMouseWheel(window, 0, 0, motion);
dludwig@8521
   296
}
dludwig@8521
   297
dludwig@8521
   298
void
dludwig@8521
   299
WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args)
dludwig@8521
   300
{
dludwig@8521
   301
    if (!window || !WINRT_UsingRelativeMouseMode) {
dludwig@8521
   302
        return;
dludwig@8521
   303
    }
dludwig@8521
   304
dludwig@8521
   305
    // DLudwig, 2012-12-28: On some systems, namely Visual Studio's Windows
dludwig@8521
   306
    // Simulator, as well as Windows 8 in a Parallels 8 VM, MouseEventArgs'
dludwig@8521
   307
    // MouseDelta field often reports very large values.  More information
dludwig@8521
   308
    // on this can be found at the following pages on MSDN:
dludwig@8521
   309
    //  - http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/a3c789fa-f1c5-49c4-9c0a-7db88d0f90f8
dludwig@8521
   310
    //  - https://connect.microsoft.com/VisualStudio/Feedback/details/756515
dludwig@8521
   311
    //
dludwig@8521
   312
    // The values do not appear to be as large when running on some systems,
dludwig@8521
   313
    // most notably a Surface RT.  Furthermore, the values returned by
dludwig@8521
   314
    // CoreWindow's PointerMoved event, and sent to this class' OnPointerMoved
dludwig@8521
   315
    // method, do not ever appear to be large, even when MouseEventArgs'
dludwig@8521
   316
    // MouseDelta is reporting to the contrary.
dludwig@8521
   317
    //
dludwig@8521
   318
    // On systems with the large-values behavior, it appears that the values
dludwig@8521
   319
    // get reported as if the screen's size is 65536 units in both the X and Y
dludwig@8521
   320
    // dimensions.  This can be viewed by using Windows' now-private, "Raw Input"
dludwig@8521
   321
    // APIs.  (GetRawInputData, RegisterRawInputDevices, WM_INPUT, etc.)
dludwig@8521
   322
    //
dludwig@8521
   323
    // MSDN's documentation on MouseEventArgs' MouseDelta field (at
dludwig@8521
   324
    // http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.input.mouseeventargs.mousedelta ),
dludwig@8521
   325
    // does not seem to indicate (to me) that its values should be so large.  It
dludwig@8521
   326
    // says that its values should be a "change in screen location".  I could
dludwig@8521
   327
    // be misinterpreting this, however a post on MSDN from a Microsoft engineer (see: 
dludwig@8521
   328
    // http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/09a9868e-95bb-4858-ba1a-cb4d2c298d62 ),
dludwig@8521
   329
    // indicates that these values are in DIPs, which is the same unit used
dludwig@8521
   330
    // by CoreWindow's PointerMoved events (via the Position field in its CurrentPoint
dludwig@8521
   331
    // property.  See http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.input.pointerpoint.position.aspx
dludwig@8521
   332
    // for details.)
dludwig@8521
   333
    //
dludwig@8521
   334
    // To note, PointerMoved events are sent a 'RawPosition' value (via the
dludwig@8521
   335
    // CurrentPoint property in MouseEventArgs), however these do not seem
dludwig@8521
   336
    // to exhibit the same large-value behavior.
dludwig@8521
   337
    //
dludwig@8521
   338
    // The values passed via PointerMoved events can't always be used for relative
dludwig@8521
   339
    // mouse motion, unfortunately.  Its values are bound to the cursor's position,
dludwig@8521
   340
    // which stops when it hits one of the screen's edges.  This can be a problem in
dludwig@8521
   341
    // first person shooters, whereby it is normal for mouse motion to travel far
dludwig@8521
   342
    // along any one axis for a period of time.  MouseMoved events do not have the
dludwig@8521
   343
    // screen-bounding limitation, and can be used regardless of where the system's
dludwig@8521
   344
    // cursor is.
dludwig@8521
   345
    //
dludwig@8521
   346
    // One possible workaround would be to programmatically set the cursor's
dludwig@8521
   347
    // position to the screen's center (when SDL's relative mouse mode is enabled),
dludwig@8521
   348
    // however WinRT does not yet seem to have the ability to set the cursor's
dludwig@8521
   349
    // position via a public API.  Win32 did this via an API call, SetCursorPos,
dludwig@8521
   350
    // however WinRT makes this function be private.  Apps that use it won't get
dludwig@8521
   351
    // approved for distribution in the Windows Store.  I've yet to be able to find
dludwig@8521
   352
    // a suitable, store-friendly counterpart for WinRT.
dludwig@8521
   353
    //
dludwig@8521
   354
    // There may be some room for a workaround whereby OnPointerMoved's values
dludwig@8521
   355
    // are compared to the values from OnMouseMoved in order to detect
dludwig@8521
   356
    // when this bug is active.  A suitable transformation could then be made to
dludwig@8521
   357
    // OnMouseMoved's values.  For now, however, the system-reported values are sent
dludwig@8521
   358
    // to SDL with minimal transformation: from native screen coordinates (in DIPs)
dludwig@8521
   359
    // to SDL window coordinates.
dludwig@8521
   360
    //
dludwig@8521
   361
    const Windows::Foundation::Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y);
dludwig@8521
   362
    const Windows::Foundation::Point mouseDeltaInSDLWindowCoords = WINRT_TransformCursorPosition(window, mouseDeltaInDIPs);
dludwig@8521
   363
    SDL_SendMouseMotion(
dludwig@8521
   364
        window,
dludwig@8521
   365
        0,
dludwig@8521
   366
        1,
dludwig@8521
   367
        _lround(mouseDeltaInSDLWindowCoords.X),
dludwig@8521
   368
        _lround(mouseDeltaInSDLWindowCoords.Y));
dludwig@8521
   369
}
dludwig@8515
   370
dludwig@8515
   371
#endif // SDL_VIDEO_DRIVER_WINRT