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