| | |
| | | #include "../../events/SDL_touch_c.h" |
| | | #include "../../events/SDL_events_c.h" |
| | | |
| | | #import "SDL_uikitappdelegate.h" |
| | | #import "SDL_uikitmodes.h" |
| | | #import "SDL_uikitwindow.h" |
| | | #include "SDL_uikitappdelegate.h" |
| | | #include "SDL_uikitevents.h" |
| | | #include "SDL_uikitmodes.h" |
| | | #include "SDL_uikitwindow.h" |
| | | |
| | | /* The maximum number of mouse buttons we support */ |
| | | #define MAX_MOUSE_BUTTONS 5 |
| | | |
| | | /* This is defined in SDL_sysjoystick.m */ |
| | | #if !SDL_JOYSTICK_DISABLED |
| | | extern int SDL_AppleTVRemoteOpenedAsJoystick; |
| | | #endif |
| | | |
| | | @implementation SDL_uikitview { |
| | | SDL_Window *sdlwindow; |
| | |
| | | UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipeGesture:)]; |
| | | swipeRight.direction = UISwipeGestureRecognizerDirectionRight; |
| | | [self addGestureRecognizer:swipeRight]; |
| | | #elif defined(__IPHONE_13_4) |
| | | if (@available(iOS 13.4, *)) { |
| | | UIPanGestureRecognizer *mouseWheelRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(mouseWheelGesture:)]; |
| | | mouseWheelRecognizer.allowedScrollTypesMask = UIScrollTypeMaskDiscrete; |
| | | mouseWheelRecognizer.allowedTouchTypes = @[ @(UITouchTypeIndirectPointer) ]; |
| | | mouseWheelRecognizer.cancelsTouchesInView = NO; |
| | | mouseWheelRecognizer.delaysTouchesBegan = NO; |
| | | mouseWheelRecognizer.delaysTouchesEnded = NO; |
| | | [self addGestureRecognizer:mouseWheelRecognizer]; |
| | | } |
| | | #endif |
| | | |
| | | self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; |
| | |
| | | #if !TARGET_OS_TV |
| | | self.multipleTouchEnabled = YES; |
| | | SDL_AddTouch(directTouchId, SDL_TOUCH_DEVICE_DIRECT, ""); |
| | | #endif |
| | | |
| | | #if !TARGET_OS_TV && defined(__IPHONE_13_4) |
| | | if (@available(iOS 13.4, *)) { |
| | | [self addInteraction:[[UIPointerInteraction alloc] initWithDelegate:self]]; |
| | | } |
| | | #endif |
| | | } |
| | | |
| | |
| | | sdlwindow = window; |
| | | } |
| | | |
| | | #if !TARGET_OS_TV && defined(__IPHONE_13_4) |
| | | - (UIPointerRegion *)pointerInteraction:(UIPointerInteraction *)interaction regionForRequest:(UIPointerRegionRequest *)request defaultRegion:(UIPointerRegion *)defaultRegion API_AVAILABLE(ios(13.4)){ |
| | | if (request != nil && !SDL_HasGCMouse()) { |
| | | CGPoint origin = self.bounds.origin; |
| | | CGPoint point = request.location; |
| | | |
| | | point.x -= origin.x; |
| | | point.y -= origin.y; |
| | | |
| | | SDL_SendMouseMotion(sdlwindow, 0, 0, (int)point.x, (int)point.y); |
| | | } |
| | | return [UIPointerRegion regionWithRect:self.bounds identifier:nil]; |
| | | } |
| | | |
| | | - (UIPointerStyle *)pointerInteraction:(UIPointerInteraction *)interaction styleForRegion:(UIPointerRegion *)region API_AVAILABLE(ios(13.4)){ |
| | | if (SDL_ShowCursor(-1)) { |
| | | return nil; |
| | | } else { |
| | | return [UIPointerStyle hiddenPointerStyle]; |
| | | } |
| | | } |
| | | #endif /* !TARGET_OS_TV && __IPHONE_13_4 */ |
| | | |
| | | - (SDL_TouchDeviceType)touchTypeForTouch:(UITouch *)touch |
| | | { |
| | | #ifdef __IPHONE_9_0 |
| | |
| | | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event |
| | | { |
| | | for (UITouch *touch in touches) { |
| | | SDL_TouchDeviceType touchType = [self touchTypeForTouch:touch]; |
| | | SDL_TouchID touchId = [self touchIdForType:touchType]; |
| | | float pressure = [self pressureForTouch:touch]; |
| | | BOOL handled = NO; |
| | | |
| | | if (SDL_AddTouch(touchId, touchType, "") < 0) { |
| | | continue; |
| | | #if !TARGET_OS_TV && defined(__IPHONE_13_4) |
| | | if (@available(iOS 13.4, *)) { |
| | | if (touch.type == UITouchTypeIndirectPointer) { |
| | | if (!SDL_HasGCMouse()) { |
| | | int i; |
| | | |
| | | for (i = 1; i <= MAX_MOUSE_BUTTONS; ++i) { |
| | | if ((event.buttonMask & SDL_BUTTON(i)) != 0) { |
| | | Uint8 button; |
| | | |
| | | switch (i) { |
| | | case 1: |
| | | button = SDL_BUTTON_LEFT; |
| | | break; |
| | | case 2: |
| | | button = SDL_BUTTON_RIGHT; |
| | | break; |
| | | case 3: |
| | | button = SDL_BUTTON_MIDDLE; |
| | | break; |
| | | default: |
| | | button = (Uint8)i; |
| | | break; |
| | | } |
| | | SDL_SendMouseButton(sdlwindow, 0, SDL_PRESSED, button); |
| | | } |
| | | } |
| | | } |
| | | handled = YES; |
| | | } |
| | | } |
| | | #endif |
| | | if (!handled) { |
| | | SDL_TouchDeviceType touchType = [self touchTypeForTouch:touch]; |
| | | SDL_TouchID touchId = [self touchIdForType:touchType]; |
| | | float pressure = [self pressureForTouch:touch]; |
| | | |
| | | /* FIXME, need to send: int clicks = (int) touch.tapCount; ? */ |
| | | if (SDL_AddTouch(touchId, touchType, "") < 0) { |
| | | continue; |
| | | } |
| | | |
| | | CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; |
| | | SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch), sdlwindow, |
| | | SDL_TRUE, locationInView.x, locationInView.y, pressure); |
| | | /* FIXME, need to send: int clicks = (int) touch.tapCount; ? */ |
| | | |
| | | CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; |
| | | SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch), sdlwindow, |
| | | SDL_TRUE, locationInView.x, locationInView.y, pressure); |
| | | } |
| | | } |
| | | } |
| | | |
| | | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event |
| | | { |
| | | for (UITouch *touch in touches) { |
| | | SDL_TouchDeviceType touchType = [self touchTypeForTouch:touch]; |
| | | SDL_TouchID touchId = [self touchIdForType:touchType]; |
| | | float pressure = [self pressureForTouch:touch]; |
| | | BOOL handled = NO; |
| | | |
| | | if (SDL_AddTouch(touchId, touchType, "") < 0) { |
| | | continue; |
| | | #if !TARGET_OS_TV && defined(__IPHONE_13_4) |
| | | if (@available(iOS 13.4, *)) { |
| | | if (touch.type == UITouchTypeIndirectPointer) { |
| | | if (!SDL_HasGCMouse()) { |
| | | int i; |
| | | |
| | | for (i = 1; i <= MAX_MOUSE_BUTTONS; ++i) { |
| | | if ((event.buttonMask & SDL_BUTTON(i)) != 0) { |
| | | Uint8 button; |
| | | |
| | | switch (i) { |
| | | case 1: |
| | | button = SDL_BUTTON_LEFT; |
| | | break; |
| | | case 2: |
| | | button = SDL_BUTTON_RIGHT; |
| | | break; |
| | | case 3: |
| | | button = SDL_BUTTON_MIDDLE; |
| | | break; |
| | | default: |
| | | button = (Uint8)i; |
| | | break; |
| | | } |
| | | SDL_SendMouseButton(sdlwindow, 0, SDL_RELEASED, button); |
| | | } |
| | | } |
| | | } |
| | | handled = YES; |
| | | } |
| | | } |
| | | #endif |
| | | if (!handled) { |
| | | SDL_TouchDeviceType touchType = [self touchTypeForTouch:touch]; |
| | | SDL_TouchID touchId = [self touchIdForType:touchType]; |
| | | float pressure = [self pressureForTouch:touch]; |
| | | |
| | | /* FIXME, need to send: int clicks = (int) touch.tapCount; ? */ |
| | | if (SDL_AddTouch(touchId, touchType, "") < 0) { |
| | | continue; |
| | | } |
| | | |
| | | CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; |
| | | SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch), sdlwindow, |
| | | SDL_FALSE, locationInView.x, locationInView.y, pressure); |
| | | /* FIXME, need to send: int clicks = (int) touch.tapCount; ? */ |
| | | |
| | | CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; |
| | | SDL_SendTouch(touchId, (SDL_FingerID)((size_t)touch), sdlwindow, |
| | | SDL_FALSE, locationInView.x, locationInView.y, pressure); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event |
| | | { |
| | | for (UITouch *touch in touches) { |
| | | SDL_TouchDeviceType touchType = [self touchTypeForTouch:touch]; |
| | | SDL_TouchID touchId = [self touchIdForType:touchType]; |
| | | float pressure = [self pressureForTouch:touch]; |
| | | BOOL handled = NO; |
| | | |
| | | if (SDL_AddTouch(touchId, touchType, "") < 0) { |
| | | continue; |
| | | #if !TARGET_OS_TV && defined(__IPHONE_13_4) |
| | | if (@available(iOS 13.4, *)) { |
| | | if (touch.type == UITouchTypeIndirectPointer) { |
| | | /* Already handled in pointerInteraction callback */ |
| | | handled = YES; |
| | | } |
| | | } |
| | | #endif |
| | | if (!handled) { |
| | | SDL_TouchDeviceType touchType = [self touchTypeForTouch:touch]; |
| | | SDL_TouchID touchId = [self touchIdForType:touchType]; |
| | | float pressure = [self pressureForTouch:touch]; |
| | | |
| | | CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; |
| | | SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch), sdlwindow, |
| | | locationInView.x, locationInView.y, pressure); |
| | | if (SDL_AddTouch(touchId, touchType, "") < 0) { |
| | | continue; |
| | | } |
| | | |
| | | CGPoint locationInView = [self touchLocation:touch shouldNormalize:YES]; |
| | | SDL_SendTouchMotion(touchId, (SDL_FingerID)((size_t)touch), sdlwindow, |
| | | locationInView.x, locationInView.y, pressure); |
| | | } |
| | | } |
| | | } |
| | | |
| | | #if TARGET_OS_TV || defined(__IPHONE_9_1) |
| | | - (SDL_Scancode)scancodeFromPressType:(UIPressType)presstype |
| | | - (SDL_Scancode)scancodeFromPress:(UIPress*)press |
| | | { |
| | | switch (presstype) { |
| | | case UIPressTypeUpArrow: |
| | | return SDL_SCANCODE_UP; |
| | | case UIPressTypeDownArrow: |
| | | return SDL_SCANCODE_DOWN; |
| | | case UIPressTypeLeftArrow: |
| | | return SDL_SCANCODE_LEFT; |
| | | case UIPressTypeRightArrow: |
| | | return SDL_SCANCODE_RIGHT; |
| | | case UIPressTypeSelect: |
| | | /* HIG says: "primary button behavior" */ |
| | | return SDL_SCANCODE_RETURN; |
| | | case UIPressTypeMenu: |
| | | /* HIG says: "returns to previous screen" */ |
| | | return SDL_SCANCODE_ESCAPE; |
| | | case UIPressTypePlayPause: |
| | | /* HIG says: "secondary button behavior" */ |
| | | return SDL_SCANCODE_PAUSE; |
| | | default: |
| | | return SDL_SCANCODE_UNKNOWN; |
| | | #ifdef __IPHONE_13_4 |
| | | if ([press respondsToSelector:@selector((key))]) { |
| | | if (press.key != nil) { |
| | | return (SDL_Scancode)press.key.keyCode; |
| | | } |
| | | } |
| | | #endif |
| | | |
| | | #if !SDL_JOYSTICK_DISABLED |
| | | /* Presses from Apple TV remote */ |
| | | if (!SDL_AppleTVRemoteOpenedAsJoystick) { |
| | | switch (press.type) { |
| | | case UIPressTypeUpArrow: |
| | | return SDL_SCANCODE_UP; |
| | | case UIPressTypeDownArrow: |
| | | return SDL_SCANCODE_DOWN; |
| | | case UIPressTypeLeftArrow: |
| | | return SDL_SCANCODE_LEFT; |
| | | case UIPressTypeRightArrow: |
| | | return SDL_SCANCODE_RIGHT; |
| | | case UIPressTypeSelect: |
| | | /* HIG says: "primary button behavior" */ |
| | | return SDL_SCANCODE_RETURN; |
| | | case UIPressTypeMenu: |
| | | /* HIG says: "returns to previous screen" */ |
| | | return SDL_SCANCODE_ESCAPE; |
| | | case UIPressTypePlayPause: |
| | | /* HIG says: "secondary button behavior" */ |
| | | return SDL_SCANCODE_PAUSE; |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | #endif /* !SDL_JOYSTICK_DISABLED */ |
| | | |
| | | return SDL_SCANCODE_UNKNOWN; |
| | | } |
| | | |
| | | - (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event |
| | | { |
| | | if (!SDL_AppleTVRemoteOpenedAsJoystick) { |
| | | if (!SDL_HasGCKeyboard()) { |
| | | for (UIPress *press in presses) { |
| | | SDL_Scancode scancode = [self scancodeFromPressType:press.type]; |
| | | SDL_Scancode scancode = [self scancodeFromPress:press]; |
| | | SDL_SendKeyboardKey(SDL_PRESSED, scancode); |
| | | } |
| | | } |
| | |
| | | |
| | | - (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event |
| | | { |
| | | if (!SDL_AppleTVRemoteOpenedAsJoystick) { |
| | | if (!SDL_HasGCKeyboard()) { |
| | | for (UIPress *press in presses) { |
| | | SDL_Scancode scancode = [self scancodeFromPressType:press.type]; |
| | | SDL_Scancode scancode = [self scancodeFromPress:press]; |
| | | SDL_SendKeyboardKey(SDL_RELEASED, scancode); |
| | | } |
| | | } |
| | |
| | | |
| | | - (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(UIPressesEvent *)event |
| | | { |
| | | if (!SDL_AppleTVRemoteOpenedAsJoystick) { |
| | | if (!SDL_HasGCKeyboard()) { |
| | | for (UIPress *press in presses) { |
| | | SDL_Scancode scancode = [self scancodeFromPressType:press.type]; |
| | | SDL_Scancode scancode = [self scancodeFromPress:press]; |
| | | SDL_SendKeyboardKey(SDL_RELEASED, scancode); |
| | | } |
| | | } |
| | |
| | | /* This is only called when the force of a press changes. */ |
| | | [super pressesChanged:presses withEvent:event]; |
| | | } |
| | | |
| | | #endif /* TARGET_OS_TV || defined(__IPHONE_9_1) */ |
| | | |
| | | -(void)mouseWheelGesture:(UIPanGestureRecognizer *)gesture |
| | | { |
| | | if (gesture.state == UIGestureRecognizerStateBegan || |
| | | gesture.state == UIGestureRecognizerStateChanged || |
| | | gesture.state == UIGestureRecognizerStateEnded) { |
| | | CGPoint velocity = [gesture velocityInView:self]; |
| | | |
| | | if (velocity.x > 0.0f) { |
| | | velocity.x = -1.0; |
| | | } else if (velocity.x < 0.0f) { |
| | | velocity.x = 1.0f; |
| | | } |
| | | if (velocity.y > 0.0f) { |
| | | velocity.y = -1.0; |
| | | } else if (velocity.y < 0.0f) { |
| | | velocity.y = 1.0f; |
| | | } |
| | | if (velocity.x != 0.0f || velocity.y != 0.0f) { |
| | | SDL_SendMouseWheel(sdlwindow, 0, velocity.x, velocity.y, SDL_MOUSEWHEEL_NORMAL); |
| | | } |
| | | } |
| | | } |
| | | |
| | | #if TARGET_OS_TV |
| | | -(void)swipeGesture:(UISwipeGestureRecognizer *)gesture |
| | | { |
| | | /* Swipe gestures don't trigger begin states. */ |
| | | if (gesture.state == UIGestureRecognizerStateEnded) { |
| | | #if !SDL_JOYSTICK_DISABLED |
| | | if (!SDL_AppleTVRemoteOpenedAsJoystick) { |
| | | /* Send arrow key presses for now, as we don't have an external API |
| | | * which better maps to swipe gestures. */ |
| | | switch (gesture.direction) { |
| | | case UISwipeGestureRecognizerDirectionUp: |
| | | SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_UP); |
| | | SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_UP); |
| | | SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_UP); |
| | | break; |
| | | case UISwipeGestureRecognizerDirectionDown: |
| | | SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_DOWN); |
| | | SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_DOWN); |
| | | SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_DOWN); |
| | | break; |
| | | case UISwipeGestureRecognizerDirectionLeft: |
| | | SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_LEFT); |
| | | SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_LEFT); |
| | | SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_LEFT); |
| | | break; |
| | | case UISwipeGestureRecognizerDirectionRight: |
| | | SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_RIGHT); |
| | | SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_RIGHT); |
| | | SDL_SendKeyboardKeyAutoRelease(SDL_SCANCODE_RIGHT); |
| | | break; |
| | | } |
| | | } |
| | | #endif /* !SDL_JOYSTICK_DISABLED */ |
| | | } |
| | | } |
| | | #endif /* TARGET_OS_TV */ |