src/video/uikit/SDL_uikitview.m
author Alex Szpakowski <slime73@gmail.com>
Sat, 24 Sep 2016 18:46:34 -0300
changeset 10366 e1b52e69578b
parent 10340 5724f5087acd
child 10710 a6babd973955
permissions -rw-r--r--
Use OS-provided click counts on macOS and iOS for mouse press and release events.
slouken@6079
     1
 /*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
slouken@5262
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@5262
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@5262
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@5262
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@6044
    22
slouken@6044
    23
#if SDL_VIDEO_DRIVER_UIKIT
slouken@2765
    24
slouken@6518
    25
#include "SDL_uikitview.h"
slouken@2765
    26
slouken@4490
    27
#include "../../events/SDL_mouse_c.h"
jimtla@4677
    28
#include "../../events/SDL_touch_c.h"
slime73@9532
    29
#include "../../events/SDL_events_c.h"
slouken@4490
    30
slime73@9532
    31
#import "SDL_uikitappdelegate.h"
slime73@9532
    32
#import "SDL_uikitmodes.h"
slime73@9532
    33
#import "SDL_uikitwindow.h"
slouken@2765
    34
slime73@9501
    35
@implementation SDL_uikitview {
slime73@9532
    36
    SDL_Window *sdlwindow;
slime73@9501
    37
slime73@9501
    38
    SDL_TouchID touchId;
slime73@9532
    39
    UITouch * __weak firstFingerDown;
slime73@9501
    40
}
slouken@2765
    41
slime73@9532
    42
- (instancetype)initWithFrame:(CGRect)frame
kees@6003
    43
{
slime73@9532
    44
    if ((self = [super initWithFrame:frame])) {
slime73@9532
    45
        self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
slime73@9532
    46
        self.autoresizesSubviews = YES;
slouken@2765
    47
slime73@10340
    48
#if !TARGET_OS_TV
slime73@9505
    49
        self.multipleTouchEnabled = YES;
slime73@10340
    50
#endif
slouken@5445
    51
slime73@9505
    52
        touchId = 1;
slime73@9505
    53
        SDL_AddTouch(touchId, "");
slime73@9505
    54
    }
slouken@4661
    55
slouken@5131
    56
    return self;
slouken@2765
    57
}
slouken@2765
    58
slime73@9532
    59
- (void)setSDLWindow:(SDL_Window *)window
slime73@9527
    60
{
slime73@9532
    61
    SDL_WindowData *data = nil;
slime73@9532
    62
slime73@9532
    63
    if (window == sdlwindow) {
slime73@9532
    64
        return;
slime73@9532
    65
    }
slime73@9532
    66
slime73@9727
    67
    /* Remove ourself from the old window. */
slime73@9532
    68
    if (sdlwindow) {
slime73@9532
    69
        SDL_uikitview *view = nil;
slime73@9532
    70
        data = (__bridge SDL_WindowData *) sdlwindow->driverdata;
slime73@9532
    71
slime73@9532
    72
        [data.views removeObject:self];
slime73@9532
    73
slime73@9532
    74
        [self removeFromSuperview];
slime73@9532
    75
slime73@9532
    76
        /* Restore the next-oldest view in the old window. */
slime73@9727
    77
        view = data.views.lastObject;
slime73@9532
    78
slime73@9532
    79
        data.viewcontroller.view = view;
slime73@9532
    80
slime73@9551
    81
        data.uiwindow.rootViewController = nil;
slime73@9551
    82
        data.uiwindow.rootViewController = data.viewcontroller;
slime73@9532
    83
slime73@9532
    84
        [data.uiwindow layoutIfNeeded];
slime73@9532
    85
    }
slime73@9532
    86
slime73@9727
    87
    /* Add ourself to the new window. */
slime73@9532
    88
    if (window) {
slime73@9532
    89
        data = (__bridge SDL_WindowData *) window->driverdata;
slime73@9532
    90
slime73@9532
    91
        /* Make sure the SDL window has a strong reference to this view. */
slime73@9532
    92
        [data.views addObject:self];
slime73@9532
    93
slime73@9532
    94
        /* Replace the view controller's old view with this one. */
slime73@9532
    95
        [data.viewcontroller.view removeFromSuperview];
slime73@9532
    96
        data.viewcontroller.view = self;
slime73@9532
    97
slime73@9551
    98
        /* The root view controller handles rotation and the status bar.
slime73@9551
    99
         * Assigning it also adds the controller's view to the window. We
slime73@9551
   100
         * explicitly re-set it to make sure the view is properly attached to
slime73@9551
   101
         * the window. Just adding the sub-view if the root view controller is
slime73@9551
   102
         * already correct causes orientation issues on iOS 7 and below. */
slime73@9551
   103
        data.uiwindow.rootViewController = nil;
slime73@9551
   104
        data.uiwindow.rootViewController = data.viewcontroller;
slime73@9532
   105
slime73@9532
   106
        /* The view's bounds may not be correct until the next event cycle. That
slime73@9532
   107
         * might happen after the current dimensions are queried, so we force a
slime73@9532
   108
         * layout now to immediately update the bounds. */
slime73@9532
   109
        [data.uiwindow layoutIfNeeded];
slime73@9532
   110
    }
slime73@9532
   111
slime73@9532
   112
    sdlwindow = window;
slime73@9527
   113
}
slime73@9527
   114
slouken@6436
   115
- (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize
slouken@6079
   116
{
slime73@9524
   117
    CGPoint point = [touch locationInView:self];
slouken@6436
   118
slouken@6436
   119
    if (normalize) {
slime73@9501
   120
        CGRect bounds = self.bounds;
slouken@6439
   121
        point.x /= bounds.size.width;
slouken@6439
   122
        point.y /= bounds.size.height;
slouken@6436
   123
    }
slime73@9488
   124
slouken@6079
   125
    return point;
slouken@6079
   126
}
slouken@6079
   127
slime73@9861
   128
- (float)pressureForTouch:(UITouch *)touch
slime73@9861
   129
{
slime73@9861
   130
#ifdef __IPHONE_9_0
slime73@9861
   131
    if ([touch respondsToSelector:@selector(force)]) {
slime73@9861
   132
        return (float) touch.force;
slime73@9861
   133
    }
slime73@9861
   134
#endif
slime73@9861
   135
slime73@9861
   136
    return 1.0f;
slime73@9861
   137
}
slime73@9861
   138
kees@6003
   139
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
kees@6003
   140
{
slime73@9487
   141
    for (UITouch *touch in touches) {
slime73@9861
   142
        float pressure = [self pressureForTouch:touch];
slime73@9861
   143
slime73@9532
   144
        if (!firstFingerDown) {
slouken@6597
   145
            CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
slime73@10366
   146
            int clicks = (int) touch.tapCount;
kees@6001
   147
slime73@9532
   148
            /* send mouse moved event */
slime73@9529
   149
            SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
slouken@4488
   150
slouken@6597
   151
            /* send mouse down event */
slime73@10366
   152
            SDL_SendMouseButtonClicks(sdlwindow, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT, clicks);
jim@4660
   153
slime73@9532
   154
            firstFingerDown = touch;
slouken@6597
   155
        }
slouken@6597
   156
slouken@6436
   157
        CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
icculus@7050
   158
        SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
slime73@9861
   159
                      SDL_TRUE, locationInView.x, locationInView.y, pressure);
slouken@5131
   160
    }
slouken@2765
   161
}
slouken@2765
   162
kees@6003
   163
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
kees@6003
   164
{
slime73@9487
   165
    for (UITouch *touch in touches) {
slime73@9861
   166
        float pressure = [self pressureForTouch:touch];
slime73@9861
   167
slime73@9532
   168
        if (touch == firstFingerDown) {
slouken@6597
   169
            /* send mouse up */
slime73@10366
   170
            int clicks = (int) touch.tapCount;
slime73@10366
   171
            SDL_SendMouseButtonClicks(sdlwindow, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT, clicks);
slime73@9532
   172
            firstFingerDown = nil;
slouken@6597
   173
        }
slouken@4661
   174
slouken@6436
   175
        CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
slime73@9501
   176
        SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch),
slime73@9861
   177
                      SDL_FALSE, locationInView.x, locationInView.y, pressure);
slouken@5131
   178
    }
slouken@2765
   179
}
slouken@2765
   180
kees@6003
   181
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
kees@6003
   182
{
slime73@9524
   183
    [self touchesEnded:touches withEvent:event];
slouken@2765
   184
}
slouken@2765
   185
kees@6003
   186
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
kees@6003
   187
{
slime73@9487
   188
    for (UITouch *touch in touches) {
slime73@9861
   189
        float pressure = [self pressureForTouch:touch];
slime73@9861
   190
slime73@9532
   191
        if (touch == firstFingerDown) {
slouken@6597
   192
            CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO];
slouken@4488
   193
slouken@6597
   194
            /* send moved event */
slime73@9529
   195
            SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y);
slouken@6597
   196
        }
jim@4660
   197
slouken@6436
   198
        CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES];
slime73@9501
   199
        SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch),
slime73@9861
   200
                            locationInView.x, locationInView.y, pressure);
slouken@5131
   201
    }
slouken@2765
   202
}
slouken@2765
   203
slime73@10340
   204
#if TARGET_OS_TV || defined(__IPHONE_9_1)
slime73@10340
   205
- (SDL_Scancode)scancodeFromPressType:(UIPressType)presstype
slime73@10340
   206
{
slime73@10340
   207
    switch (presstype) {
slime73@10340
   208
    case UIPressTypeUpArrow:
slime73@10340
   209
        return SDL_SCANCODE_UP;
slime73@10340
   210
    case UIPressTypeDownArrow:
slime73@10340
   211
        return SDL_SCANCODE_DOWN;
slime73@10340
   212
    case UIPressTypeLeftArrow:
slime73@10340
   213
        return SDL_SCANCODE_LEFT;
slime73@10340
   214
    case UIPressTypeRightArrow:
slime73@10340
   215
        return SDL_SCANCODE_RIGHT;
slime73@10340
   216
    case UIPressTypeSelect:
slime73@10340
   217
        /* HIG says: "primary button behavior" */
slime73@10340
   218
        return SDL_SCANCODE_SELECT;
slime73@10340
   219
    case UIPressTypeMenu:
slime73@10340
   220
        /* HIG says: "returns to previous screen" */
slime73@10340
   221
        return SDL_SCANCODE_MENU;
slime73@10340
   222
    case UIPressTypePlayPause:
slime73@10340
   223
        /* HIG says: "secondary button behavior" */
slime73@10340
   224
        return SDL_SCANCODE_PAUSE;
slime73@10340
   225
    default:
slime73@10340
   226
        return SDL_SCANCODE_UNKNOWN;
slime73@10340
   227
    }
slime73@10340
   228
}
slime73@10340
   229
slime73@10340
   230
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
slime73@10340
   231
{
slime73@10340
   232
    for (UIPress *press in presses) {
slime73@10340
   233
        SDL_Scancode scancode = [self scancodeFromPressType:press.type];
slime73@10340
   234
        SDL_SendKeyboardKey(SDL_PRESSED, scancode);
slime73@10340
   235
    }
slime73@10340
   236
slime73@10340
   237
    [super pressesBegan:presses withEvent:event];
slime73@10340
   238
}
slime73@10340
   239
slime73@10340
   240
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
slime73@10340
   241
{
slime73@10340
   242
    for (UIPress *press in presses) {
slime73@10340
   243
        SDL_Scancode scancode = [self scancodeFromPressType:press.type];
slime73@10340
   244
        SDL_SendKeyboardKey(SDL_RELEASED, scancode);
slime73@10340
   245
    }
slime73@10340
   246
slime73@10340
   247
    [super pressesEnded:presses withEvent:event];
slime73@10340
   248
}
slime73@10340
   249
slime73@10340
   250
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
slime73@10340
   251
{
slime73@10340
   252
    for (UIPress *press in presses) {
slime73@10340
   253
        SDL_Scancode scancode = [self scancodeFromPressType:press.type];
slime73@10340
   254
        SDL_SendKeyboardKey(SDL_RELEASED, scancode);
slime73@10340
   255
    }
slime73@10340
   256
slime73@10340
   257
    [super pressesCancelled:presses withEvent:event];
slime73@10340
   258
}
slime73@10340
   259
slime73@10340
   260
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event
slime73@10340
   261
{
slime73@10340
   262
    /* This is only called when the force of a press changes. */
slime73@10340
   263
    [super pressesChanged:presses withEvent:event];
slime73@10340
   264
}
slime73@10340
   265
#endif /* TARGET_OS_TV || defined(__IPHONE_9_1) */
slime73@10340
   266
slouken@2765
   267
@end
slouken@2765
   268
slouken@6044
   269
#endif /* SDL_VIDEO_DRIVER_UIKIT */
slouken@6044
   270
slouken@5132
   271
/* vi: set ts=4 sw=4 expandtab: */