Atlas - SDL_uikitview.m
Home / ext / SDL2 / src / video / uikit Lines: 1 | Size: 11157 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1 /* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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 "SDL_hints.h" 28#include "../../events/SDL_mouse_c.h" 29#include "../../events/SDL_touch_c.h" 30#include "../../events/SDL_events_c.h" 31 32#import "SDL_uikitappdelegate.h" 33#import "SDL_uikitmodes.h" 34#import "SDL_uikitwindow.h" 35 36/* This is defined in SDL_sysjoystick.m */ 37extern int SDL_AppleTVRemoteOpenedAsJoystick; 38 39@implementation SDL_uikitview { 40 SDL_Window *sdlwindow; 41 42 SDL_TouchID touchId; 43 UITouch * __weak firstFingerDown; 44} 45 46- (instancetype)initWithFrame:(CGRect)frame 47{ 48 if ((self = [super initWithFrame:frame])) { 49#if TARGET_OS_TV 50 /* Apple TV Remote touchpad swipe gestures. */ 51 UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)]; 52 swipeUp.direction = UISwipeGestureRecognizerDirectionUp; 53 [self addGestureRecognizer:swipeUp]; 54 55 UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)]; 56 swipeDown.direction = UISwipeGestureRecognizerDirectionDown; 57 [self addGestureRecognizer:swipeDown]; 58 59 UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)]; 60 swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; 61 [self addGestureRecognizer:swipeLeft]; 62 63 UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)]; 64 swipeRight.direction = UISwipeGestureRecognizerDirectionRight; 65 [self addGestureRecognizer:swipeRight]; 66#endif 67 68 self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 69 self.autoresizesSubviews = YES; 70 71#if !TARGET_OS_TV 72 self.multipleTouchEnabled = YES; 73#endif 74 75 touchId = 1; 76 SDL_AddTouch(touchId, ""); 77 } 78 79 return self; 80} 81 82- (void)setSDLWindow:(SDL_Window *)window 83{ 84 SDL_WindowData *data = nil; 85 86 if (window == sdlwindow) { 87 return; 88 } 89 90 /* Remove ourself from the old window. */ 91 if (sdlwindow) { 92 SDL_uikitview *view = nil; 93 data = (__bridge SDL_WindowData *) sdlwindow->driverdata; 94 95 [data.views removeObject:self]; 96 97 [self removeFromSuperview]; 98 99 /* Restore the next-oldest view in the old window. */ 100 view = data.views.lastObject; 101 102 data.viewcontroller.view = view; 103 104 data.uiwindow.rootViewController = nil; 105 data.uiwindow.rootViewController = data.viewcontroller; 106 107 [data.uiwindow layoutIfNeeded]; 108 } 109 110 /* Add ourself to the new window. */ 111 if (window) { 112 data = (__bridge SDL_WindowData *) window->driverdata; 113 114 /* Make sure the SDL window has a strong reference to this view. */ 115 [data.views addObject:self]; 116 117 /* Replace the view controller's old view with this one. */ 118 [data.viewcontroller.view removeFromSuperview]; 119 data.viewcontroller.view = self; 120 121 /* The root view controller handles rotation and the status bar. 122 * Assigning it also adds the controller's view to the window. We 123 * explicitly re-set it to make sure the view is properly attached to 124 * the window. Just adding the sub-view if the root view controller is 125 * already correct causes orientation issues on iOS 7 and below. */ 126 data.uiwindow.rootViewController = nil; 127 data.uiwindow.rootViewController = data.viewcontroller; 128 129 /* The view's bounds may not be correct until the next event cycle. That 130 * might happen after the current dimensions are queried, so we force a 131 * layout now to immediately update the bounds. */ 132 [data.uiwindow layoutIfNeeded]; 133 } 134 135 sdlwindow = window; 136} 137 138- (CGPoint)touchLocation:(UITouch *)touch shouldNormalize:(BOOL)normalize 139{ 140 CGPoint point = [touch locationInView:self]; 141 142 if (normalize) { 143 CGRect bounds = self.bounds; 144 point.x /= bounds.size.width; 145 point.y /= bounds.size.height; 146 } 147 148 return point; 149} 150 151- (float)pressureForTouch:(UITouch *)touch 152{ 153#ifdef __IPHONE_9_0 154 if ([touch respondsToSelector:@selector(force)]) { 155 return (float) touch.force; 156 } 157#endif 158 159 return 1.0f; 160} 161 162- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 163{ 164 for (UITouch *touch in touches) { 165 float pressure = [self pressureForTouch:touch]; 166 167 if (!firstFingerDown) { 168 CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO]; 169 int clicks = (int) touch.tapCount; 170 171 /* send mouse moved event */ 172 SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y); 173 174 /* send mouse down event */ 175 SDL_SendMouseButtonClicks(sdlwindow, SDL_TOUCH_MOUSEID, SDL_PRESSED, SDL_BUTTON_LEFT, clicks); 176 177 firstFingerDown = touch; 178 } 179 180 CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; 181 SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch), 182 SDL_TRUE, locationInView.x, locationInView.y, pressure); 183 } 184} 185 186- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 187{ 188 for (UITouch *touch in touches) { 189 float pressure = [self pressureForTouch:touch]; 190 191 if (touch == firstFingerDown) { 192 /* send mouse up */ 193 int clicks = (int) touch.tapCount; 194 SDL_SendMouseButtonClicks(sdlwindow, SDL_TOUCH_MOUSEID, SDL_RELEASED, SDL_BUTTON_LEFT, clicks); 195 firstFingerDown = nil; 196 } 197 198 CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; 199 SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch), 200 SDL_FALSE, locationInView.x, locationInView.y, pressure); 201 } 202} 203 204- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 205{ 206 [self touchesEnded:touches withEvent:event]; 207} 208 209- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 210{ 211 for (UITouch *touch in touches) { 212 float pressure = [self pressureForTouch:touch]; 213 214 if (touch == firstFingerDown) { 215 CGPoint locationInView = [self touchLocation:touch shouldNormalize:NO]; 216 217 /* send moved event */ 218 SDL_SendMouseMotion(sdlwindow, SDL_TOUCH_MOUSEID, 0, locationInView.x, locationInView.y); 219 } 220 221 CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; 222 SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch), 223 locationInView.x, locationInView.y, pressure); 224 } 225} 226 227#if TARGET_OS_TV || defined(__IPHONE_9_1) 228- (SDL_Scancode)scancodeFromPressType:(UIPressType)presstype 229{ 230 switch (presstype) { 231 case UIPressTypeUpArrow: 232 return SDL_SCANCODE_UP; 233 case UIPressTypeDownArrow: 234 return SDL_SCANCODE_DOWN; 235 case UIPressTypeLeftArrow: 236 return SDL_SCANCODE_LEFT; 237 case UIPressTypeRightArrow: 238 return SDL_SCANCODE_RIGHT; 239 case UIPressTypeSelect: 240 /* HIG says: "primary button behavior" */ 241 return SDL_SCANCODE_RETURN; 242 case UIPressTypeMenu: 243 /* HIG says: "returns to previous screen" */ 244 return SDL_SCANCODE_ESCAPE; 245 case UIPressTypePlayPause: 246 /* HIG says: "secondary button behavior" */ 247 return SDL_SCANCODE_PAUSE; 248 default: 249 return SDL_SCANCODE_UNKNOWN; 250 } 251} 252 253- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event 254{ 255 if (!SDL_AppleTVRemoteOpenedAsJoystick) { 256 for (UIPress *press in presses) { 257 SDL_Scancode scancode = [self scancodeFromPressType:press.type]; 258 SDL_SendKeyboardKey(SDL_PRESSED, scancode); 259 } 260 } 261 [super pressesBegan:presses withEvent:event]; 262} 263 264- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event 265{ 266 if (!SDL_AppleTVRemoteOpenedAsJoystick) { 267 for (UIPress *press in presses) { 268 SDL_Scancode scancode = [self scancodeFromPressType:press.type]; 269 SDL_SendKeyboardKey(SDL_RELEASED, scancode); 270 } 271 } 272 [super pressesEnded:presses withEvent:event]; 273} 274 275- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event 276{ 277 if (!SDL_AppleTVRemoteOpenedAsJoystick) { 278 for (UIPress *press in presses) { 279 SDL_Scancode scancode = [self scancodeFromPressType:press.type]; 280 SDL_SendKeyboardKey(SDL_RELEASED, scancode); 281 } 282 } 283 [super pressesCancelled:presses withEvent:event]; 284} 285 286- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event 287{ 288 /* This is only called when the force of a press changes. */ 289 [super pressesChanged:presses withEvent:event]; 290} 291#endif /* TARGET_OS_TV || defined(__IPHONE_9_1) */ 292 293#if TARGET_OS_TV 294-(void)swipeGesture:(UISwipeGestureRecognizer *)gesture 295{ 296 /* Swipe gestures don't trigger begin states. */ 297 if (gesture.state == UIGestureRecognizerStateEnded) { 298 if (!SDL_AppleTVRemoteOpenedAsJoystick) { 299 /* Send arrow key presses for now, as we don't have an external API 300 * which better maps to swipe gestures. */ 301 switch (gesture.direction) { 302 case UISwipeGestureRecognizerDirectionUp: 303 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_UP); 304 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_UP); 305 break; 306 case UISwipeGestureRecognizerDirectionDown: 307 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_DOWN); 308 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_DOWN); 309 break; 310 case UISwipeGestureRecognizerDirectionLeft: 311 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LEFT); 312 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LEFT); 313 break; 314 case UISwipeGestureRecognizerDirectionRight: 315 SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RIGHT); 316 SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RIGHT); 317 break; 318 } 319 } 320 } 321} 322#endif /* TARGET_OS_TV */ 323 324@end 325 326#endif /* SDL_VIDEO_DRIVER_UIKIT */ 327 328/* vi: set ts=4 sw=4 expandtab: */ 329[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.