From 39b98c1cc697087c9bf8b26cc943afa25613344b Mon Sep 17 00:00:00 2001 From: Vincent Bénony Date: Tue, 1 Dec 2015 19:14:54 +0100 Subject: IOS: Fixes rotation and event handling --- backends/platform/iphone/iphone_common.h | 8 +- backends/platform/iphone/iphone_main.mm | 36 ++- backends/platform/iphone/iphone_video.h | 4 - backends/platform/iphone/iphone_video.mm | 389 +++++++++++++++++-------------- backends/platform/iphone/osys_events.cpp | 211 +++++++++++------ backends/platform/iphone/osys_main.h | 3 +- 6 files changed, 383 insertions(+), 268 deletions(-) diff --git a/backends/platform/iphone/iphone_common.h b/backends/platform/iphone/iphone_common.h index 59dca84b85..1f7c891447 100644 --- a/backends/platform/iphone/iphone_common.h +++ b/backends/platform/iphone/iphone_common.h @@ -36,7 +36,8 @@ enum InputEvent { kInputKeyPressed, kInputApplicationSuspended, kInputApplicationResumed, - kInputSwipe + kInputSwipe, + kInputTap }; enum ScreenOrientation { @@ -52,6 +53,11 @@ enum UIViewSwipeDirection { kUIViewSwipeRight = 8 }; +enum UIViewTapDescription { + kUIViewTapSingle = 1, + kUIViewTapDouble = 2, +}; + enum GraphicsModes { kGraphicsModeLinear = 0, kGraphicsModeNone = 1 diff --git a/backends/platform/iphone/iphone_main.mm b/backends/platform/iphone/iphone_main.mm index 3707f10a29..e8ea060679 100644 --- a/backends/platform/iphone/iphone_main.mm +++ b/backends/platform/iphone/iphone_main.mm @@ -30,8 +30,21 @@ void iphone_main(int argc, char *argv[]); +@interface ScummVMViewController : UIViewController + +@end + +@implementation ScummVMViewController + +- (BOOL)prefersStatusBarHidden { + return YES; +} + +@end + @interface iPhoneMain : UIApplication { UIWindow *_window; + ScummVMViewController *_controller; iPhoneView *_view; } @@ -80,19 +93,24 @@ int main(int argc, char **argv) { - (void)applicationDidFinishLaunching:(UIApplication *)application { CGRect rect = [[UIScreen mainScreen] bounds]; - // hide the status bar - [application setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO]; - [application setStatusBarHidden:YES animated:YES]; + // Create the directory for savegames + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *documentPath = [NSString stringWithUTF8String:iPhone_getDocumentsDir()]; + NSString *savePath = [documentPath stringByAppendingPathComponent:@"savegames"]; + if (![fm fileExistsAtPath:savePath]) { + [fm createDirectoryAtPath:savePath withIntermediateDirectories:YES attributes:nil error:nil]; + } _window = [[UIWindow alloc] initWithFrame:rect]; [_window retain]; + _controller = [[ScummVMViewController alloc] init]; + _view = [[iPhoneView alloc] initWithFrame:rect]; _view.multipleTouchEnabled = YES; + _controller.view = _view; - [_window setContentView:_view]; - - [_window addSubview:_view]; + [_window setRootViewController:_controller]; [_window makeKeyAndVisible]; [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; @@ -120,12 +138,6 @@ int main(int argc, char **argv) { - (void)applicationResume:(struct __GSEvent *)event { [_view applicationResume]; - - // Workaround, need to "hide" and unhide the statusbar to properly remove it, - // since the Springboard has put it back without apparently flagging our application. - [self setStatusBarHidden:YES animated:YES]; - [self setStatusBarStyle:UIStatusBarStyleBlackTranslucent animated:NO]; - [self setStatusBarHidden:YES animated:YES]; } - (void)didRotate:(NSNotification *)notification { diff --git a/backends/platform/iphone/iphone_video.h b/backends/platform/iphone/iphone_video.h index 7dbf3c57ab..5c9766a116 100644 --- a/backends/platform/iphone/iphone_video.h +++ b/backends/platform/iphone/iphone_video.h @@ -50,8 +50,6 @@ GLuint _overlayTexture; GLuint _mouseCursorTexture; - UIDeviceOrientation _orientation; - GLint _renderBufferWidth; GLint _renderBufferHeight; @@ -80,8 +78,6 @@ - (VideoContext *)getVideoContext; -- (void)drawRect:(CGRect)frame; - - (void)createScreenTexture; - (void)initSurface; - (void)setViewTransformation; diff --git a/backends/platform/iphone/iphone_video.mm b/backends/platform/iphone/iphone_video.mm index 5048b57328..7fa478bcaa 100644 --- a/backends/platform/iphone/iphone_video.mm +++ b/backends/platform/iphone/iphone_video.mm @@ -26,6 +26,7 @@ #include "iphone_video.h" #include "graphics/colormasks.h" +#include "common/system.h" iPhoneView *g_iPhoneViewInstance = nil; static int g_fullWidth; @@ -38,6 +39,8 @@ static long g_lastTick = 0; static int g_frames = 0; #endif +extern bool iphone_touchpadModeEnabled(); + #define printOpenGLError() printOglError(__FILE__, __LINE__) int printOglError(const char *file, int line) { @@ -102,8 +105,10 @@ const char *iPhone_getDocumentsDir() { CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; eaglLayer.opaque = YES; - eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGB565, kEAGLDrawablePropertyColorFormat, nil]; + eaglLayer.drawableProperties = @{ + kEAGLDrawablePropertyRetainedBacking: @NO, + kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGB565 + }; _context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; @@ -132,11 +137,14 @@ const char *iPhone_getDocumentsDir() { NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); return; } + uint maxValue = MAX(_renderBufferWidth, _renderBufferHeight), maxValuePOT = getSizeNextPOT(maxValue); + uint minValue = MIN(_renderBufferWidth, _renderBufferHeight), minValuePOT = getSizeNextPOT(minValue); + + _videoContext.overlayWidth = maxValue; + _videoContext.overlayHeight = minValue; - _videoContext.overlayHeight = _renderBufferWidth; - _videoContext.overlayWidth = _renderBufferHeight; - uint overlayTextureWidth = getSizeNextPOT(_videoContext.overlayHeight); - uint overlayTextureHeight = getSizeNextPOT(_videoContext.overlayWidth); + uint overlayTextureWidth = maxValuePOT; + uint overlayTextureHeight = minValuePOT; // Since the overlay size won't change the whole run, we can // precalculate the texture coordinates for the overlay texture here @@ -158,31 +166,65 @@ const char *iPhone_getDocumentsDir() { } } +- (void)setupGestureRecognizers { + UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeRight:)]; + swipeRight.direction = UISwipeGestureRecognizerDirectionRight; + swipeRight.numberOfTouchesRequired = 2; + + UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeLeft:)]; + swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; + swipeLeft.numberOfTouchesRequired = 2; + + UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeUp:)]; + swipeUp.direction = UISwipeGestureRecognizerDirectionUp; + swipeUp.numberOfTouchesRequired = 2; + + UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersSwipeDown:)]; + swipeDown.direction = UISwipeGestureRecognizerDirectionDown; + swipeDown.numberOfTouchesRequired = 2; + + UITapGestureRecognizer *doubleTapTwoFingers = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(twoFingersDoubleTap:)]; + doubleTapTwoFingers.numberOfTapsRequired = 2; + doubleTapTwoFingers.numberOfTouchesRequired = 2; + + [self addGestureRecognizer:swipeRight]; + [self addGestureRecognizer:swipeLeft]; + [self addGestureRecognizer:swipeUp]; + [self addGestureRecognizer:swipeDown]; + [self addGestureRecognizer:doubleTapTwoFingers]; +} + +- (CGFloat)optimalScale { + CGFloat screenScale = [[UIScreen mainScreen] scale]; + if (screenScale < 2) return screenScale; + + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + return 1; + } + + CGSize screenSize = [[UIScreen mainScreen] nativeBounds].size; + CGFloat mxSize = MAX(screenSize.width, screenSize.height); + + if (mxSize <= 1136) { + // iPhone 4S / 5 / 5S / 5C + return 1; + } + else { + // iPhone 6 / 6S / 6+ / 6S+ + return 2; + } +} + - (id)initWithFrame:(struct CGRect)frame { self = [super initWithFrame: frame]; - _contentScaleFactor = 1; - if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { - if ([self respondsToSelector:@selector(setContentScaleFactor:)]) { - // Horrible and crazy method to get the proper return value of - // scale when the SDK used for building does not know anything - // about the selector scale... - NSMethodSignature *scaleSignature = [UIScreen instanceMethodSignatureForSelector:@selector(scale)]; - NSInvocation *scaleInvocation = [NSInvocation invocationWithMethodSignature:scaleSignature]; - [scaleInvocation setTarget:[UIScreen mainScreen]]; - [scaleInvocation setSelector:@selector(scale)]; - [scaleInvocation invoke]; - - NSInteger returnLength = [[scaleInvocation methodSignature] methodReturnLength]; - if (returnLength == sizeof(CGFloat)) { - [scaleInvocation getReturnValue:&_contentScaleFactor]; - [self setContentScaleFactor:_contentScaleFactor]; - } - } - } + [self setupGestureRecognizers]; - g_fullWidth = (int)frame.size.width; - g_fullHeight = (int)frame.size.height; + g_fullWidth = (int)MAX(frame.size.width, frame.size.height); + g_fullHeight = (int)MIN(frame.size.width, frame.size.height); + + _contentScaleFactor = [self optimalScale]; + [self setContentScaleFactor:_contentScaleFactor]; g_iPhoneViewInstance = self; @@ -199,34 +241,34 @@ const char *iPhone_getDocumentsDir() { _eventLock = [[NSLock alloc] init]; _gameScreenVertCoords[0] = _gameScreenVertCoords[1] = - _gameScreenVertCoords[2] = _gameScreenVertCoords[3] = - _gameScreenVertCoords[4] = _gameScreenVertCoords[5] = - _gameScreenVertCoords[6] = _gameScreenVertCoords[7] = 0; + _gameScreenVertCoords[2] = _gameScreenVertCoords[3] = + _gameScreenVertCoords[4] = _gameScreenVertCoords[5] = + _gameScreenVertCoords[6] = _gameScreenVertCoords[7] = 0; _gameScreenTexCoords[0] = _gameScreenTexCoords[1] = - _gameScreenTexCoords[2] = _gameScreenTexCoords[3] = - _gameScreenTexCoords[4] = _gameScreenTexCoords[5] = - _gameScreenTexCoords[6] = _gameScreenTexCoords[7] = 0; + _gameScreenTexCoords[2] = _gameScreenTexCoords[3] = + _gameScreenTexCoords[4] = _gameScreenTexCoords[5] = + _gameScreenTexCoords[6] = _gameScreenTexCoords[7] = 0; _overlayVertCoords[0] = _overlayVertCoords[1] = - _overlayVertCoords[2] = _overlayVertCoords[3] = - _overlayVertCoords[4] = _overlayVertCoords[5] = - _overlayVertCoords[6] = _overlayVertCoords[7] = 0; + _overlayVertCoords[2] = _overlayVertCoords[3] = + _overlayVertCoords[4] = _overlayVertCoords[5] = + _overlayVertCoords[6] = _overlayVertCoords[7] = 0; _overlayTexCoords[0] = _overlayTexCoords[1] = - _overlayTexCoords[2] = _overlayTexCoords[3] = - _overlayTexCoords[4] = _overlayTexCoords[5] = - _overlayTexCoords[6] = _overlayTexCoords[7] = 0; + _overlayTexCoords[2] = _overlayTexCoords[3] = + _overlayTexCoords[4] = _overlayTexCoords[5] = + _overlayTexCoords[6] = _overlayTexCoords[7] = 0; _mouseVertCoords[0] = _mouseVertCoords[1] = - _mouseVertCoords[2] = _mouseVertCoords[3] = - _mouseVertCoords[4] = _mouseVertCoords[5] = - _mouseVertCoords[6] = _mouseVertCoords[7] = 0; + _mouseVertCoords[2] = _mouseVertCoords[3] = + _mouseVertCoords[4] = _mouseVertCoords[5] = + _mouseVertCoords[6] = _mouseVertCoords[7] = 0; _mouseTexCoords[0] = _mouseTexCoords[1] = - _mouseTexCoords[2] = _mouseTexCoords[3] = - _mouseTexCoords[4] = _mouseTexCoords[5] = - _mouseTexCoords[6] = _mouseTexCoords[7] = 0; + _mouseTexCoords[2] = _mouseTexCoords[3] = + _mouseTexCoords[4] = _mouseTexCoords[5] = + _mouseTexCoords[6] = _mouseTexCoords[7] = 0; // Initialize the OpenGL ES context [self createContext]; @@ -247,8 +289,8 @@ const char *iPhone_getDocumentsDir() { [super dealloc]; } -- (void)drawRect:(CGRect)frame { #if 0 +- (void)drawRect:(CGRect)frame { if (g_lastTick == 0) { g_lastTick = time(0); } @@ -259,8 +301,8 @@ const char *iPhone_getDocumentsDir() { printf("FPS: %i\n", g_frames); g_frames = 0; } -#endif } +#endif - (void)setFilterModeForTexture:(GLuint)tex { if (!tex) @@ -412,69 +454,72 @@ const char *iPhone_getDocumentsDir() { glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); printOpenGLError(); } -- (void)setUpOrientation:(UIDeviceOrientation)orientation width:(int *)width height:(int *)height { - _orientation = orientation; +- (void)createScreenTexture { + const uint screenTexWidth = getSizeNextPOT(_videoContext.screenWidth); + const uint screenTexHeight = getSizeNextPOT(_videoContext.screenHeight); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); + _gameScreenTexCoords[2] = _gameScreenTexCoords[6] = _videoContext.screenWidth / (GLfloat)screenTexWidth; + _gameScreenTexCoords[5] = _gameScreenTexCoords[7] = _videoContext.screenHeight / (GLfloat)screenTexHeight; - // We always force the origin (0,0) to be in the upper left corner. - switch (_orientation) { - case UIDeviceOrientationLandscapeRight: - glRotatef( 90, 0, 0, 1); printOpenGLError(); - glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 0, 1); printOpenGLError(); + _videoContext.screenTexture.create(screenTexWidth, screenTexHeight, Graphics::createPixelFormat<565>()); +} - *width = _renderBufferHeight; - *height = _renderBufferWidth; - break; +- (void)initSurface { + if (_context) { + glDeleteTextures(1, &_screenTexture); printOpenGLError(); + glDeleteTextures(1, &_overlayTexture); printOpenGLError(); - case UIDeviceOrientationLandscapeLeft: - glRotatef(-90, 0, 0, 1); printOpenGLError(); - glOrthof(0, _renderBufferHeight, _renderBufferWidth, 0, 0, 1); printOpenGLError(); + glDeleteRenderbuffersOES(1, &_viewRenderbuffer); + glDeleteFramebuffersOES(1, &_viewFramebuffer); - *width = _renderBufferHeight; - *height = _renderBufferWidth; - break; + glGenFramebuffersOES(1, &_viewFramebuffer); printOpenGLError(); + glGenRenderbuffersOES(1, &_viewRenderbuffer); printOpenGLError(); - case UIDeviceOrientationPortrait: - default: - // We must force the portrait orientation here, since we might not know - // the real orientation. - _orientation = UIDeviceOrientationPortrait; + glBindFramebufferOES(GL_FRAMEBUFFER_OES, _viewFramebuffer); printOpenGLError(); + glBindRenderbufferOES(GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); + [_context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:(id)self.layer]; - glOrthof(0, _renderBufferWidth, _renderBufferHeight, 0, 0, 1); printOpenGLError(); + glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, _viewRenderbuffer); printOpenGLError(); - *width = _renderBufferWidth; - *height = _renderBufferHeight; - break; - } -} + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &_renderBufferWidth); printOpenGLError(); + glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &_renderBufferHeight); printOpenGLError(); -- (void)createScreenTexture { - const uint screenTexWidth = getSizeNextPOT(_videoContext.screenWidth); - const uint screenTexHeight = getSizeNextPOT(_videoContext.screenHeight); + if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES) { + NSLog(@"Failed to make complete framebuffer object %x.", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES)); + return; + } - _gameScreenTexCoords[2] = _gameScreenTexCoords[6] = _videoContext.screenWidth / (GLfloat)screenTexWidth; - _gameScreenTexCoords[5] = _gameScreenTexCoords[7] = _videoContext.screenHeight / (GLfloat)screenTexHeight; + glViewport(0, 0, _renderBufferWidth, _renderBufferHeight); printOpenGLError(); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); printOpenGLError(); - _videoContext.screenTexture.create(screenTexWidth, screenTexHeight, Graphics::createPixelFormat<565>()); -} + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -- (void)initSurface { - int screenWidth, screenHeight; - [self setUpOrientation:[[UIDevice currentDevice] orientation] width:&screenWidth height:&screenHeight]; + glEnable(GL_TEXTURE_2D); printOpenGLError(); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); printOpenGLError(); + glEnableClientState(GL_VERTEX_ARRAY); printOpenGLError(); + } - if (_screenTexture > 0) { - glDeleteTextures(1, &_screenTexture); printOpenGLError(); + BOOL isLandscape = (self.bounds.size.width > self.bounds.size.height); // UIDeviceOrientationIsLandscape([[UIDevice currentDevice] orientation]); + +// glMatrixMode(GL_PROJECTION); +// glLoadIdentity(); + + int screenWidth, screenHeight; + if (isLandscape) { + screenWidth = MAX(_renderBufferWidth, _renderBufferHeight); + screenHeight = MIN(_renderBufferWidth, _renderBufferHeight); +// glOrthof(0, screenWidth, screenHeight, 0, 0, 1); printOpenGLError(); + } + else { + screenWidth = MIN(_renderBufferWidth, _renderBufferHeight); + screenHeight = MAX(_renderBufferWidth, _renderBufferHeight); +// glOrthof(0, screenHeight, screenWidth, 0, 0, 1); printOpenGLError(); } glGenTextures(1, &_screenTexture); printOpenGLError(); [self setFilterModeForTexture:_screenTexture]; - if (_overlayTexture > 0) { - glDeleteTextures(1, &_overlayTexture); printOpenGLError(); - } - glGenTextures(1, &_overlayTexture); printOpenGLError(); [self setFilterModeForTexture:_overlayTexture]; @@ -482,10 +527,10 @@ const char *iPhone_getDocumentsDir() { [self clearColorBuffer]; - if (_keyboardView != nil) { - [_keyboardView removeFromSuperview]; - [[_keyboardView inputView] removeFromSuperview]; - } +// if (_keyboardView != nil) { +// [_keyboardView removeFromSuperview]; +// [[_keyboardView inputView] removeFromSuperview]; +// } GLfloat adjustedWidth = _videoContext.screenWidth; GLfloat adjustedHeight = _videoContext.screenHeight; @@ -498,7 +543,7 @@ const char *iPhone_getDocumentsDir() { float overlayPortraitRatio; - if (_orientation == UIDeviceOrientationLandscapeLeft || _orientation == UIDeviceOrientationLandscapeRight) { + if (isLandscape) { GLfloat gameScreenRatio = adjustedWidth / adjustedHeight; GLfloat screenRatio = (GLfloat)screenWidth / (GLfloat)screenHeight; @@ -524,6 +569,8 @@ const char *iPhone_getDocumentsDir() { yOffset = (screenHeight - rectHeight) / 2; } + [_keyboardView hideKeyboard]; + //printf("Rect: %i, %i, %i, %i\n", xOffset, yOffset, rectWidth, rectHeight); _gameScreenRect = CGRectMake(xOffset, yOffset, rectWidth, rectHeight); overlayPortraitRatio = 1.0f; @@ -537,14 +584,13 @@ const char *iPhone_getDocumentsDir() { if (_keyboardView == nil) { _keyboardView = [[SoftKeyboard alloc] initWithFrame:keyFrame]; [_keyboardView setInputDelegate:self]; + [self addSubview:[_keyboardView inputView]]; + [self addSubview: _keyboardView]; } - [self addSubview:[_keyboardView inputView]]; - [self addSubview: _keyboardView]; - [[_keyboardView inputView] becomeFirstResponder]; + [_keyboardView showKeyboard]; overlayPortraitRatio = (_videoContext.overlayHeight * ratio) / _videoContext.overlayWidth; } - _overlayRect = CGRectMake(0, 0, screenWidth, screenHeight * overlayPortraitRatio); _gameScreenVertCoords[0] = _gameScreenVertCoords[4] = CGRectGetMinX(_gameScreenRect); @@ -555,6 +601,10 @@ const char *iPhone_getDocumentsDir() { _overlayVertCoords[2] = _overlayVertCoords[6] = CGRectGetMaxX(_overlayRect); _overlayVertCoords[5] = _overlayVertCoords[7] = CGRectGetMaxY(_overlayRect); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrthof(0, screenWidth, screenHeight, 0, 0, 1); + [self setViewTransformation]; [self updateMouseCursorScaling]; } @@ -601,40 +651,12 @@ const char *iPhone_getDocumentsDir() { return true; } -/** - * Converts portrait mode coordinates into rotated mode coordinates. - */ -- (bool)convertToRotatedCoords:(CGPoint)point result:(CGPoint *)result { - switch (_orientation) { - case UIDeviceOrientationLandscapeLeft: - result->x = point.y; - result->y = _renderBufferWidth - point.x; - return true; - - case UIDeviceOrientationLandscapeRight: - result->x = _renderBufferHeight - point.y; - result->y = point.x; - return true; - - case UIDeviceOrientationPortrait: - result->x = point.x; - result->y = point.y; - return true; - - default: - return false; - } -} - - (bool)getMouseCoords:(CGPoint)point eventX:(int *)x eventY:(int *)y { // We scale the input according to our scale factor to get actual screen // cooridnates. point.x *= _contentScaleFactor; point.y *= _contentScaleFactor; - if (![self convertToRotatedCoords:point result:&point]) - return false; - CGRect *area; int width, height, offsetY; if (_videoContext.overlayVisible) { @@ -657,62 +679,58 @@ const char *iPhone_getDocumentsDir() { // thus we need to add it here. *y = (int)(point.y * height + offsetY); - // Clip coordinates - if (*x < 0 || *x > width || *y < 0 || *y > height) - return false; + if (!iphone_touchpadModeEnabled()) { + // Clip coordinates + if (*x < 0 || *x > width || *y < 0 || *y > height) + return false; + } return true; } - (void)deviceOrientationChanged:(UIDeviceOrientation)orientation { - switch (orientation) { - case UIDeviceOrientationLandscapeLeft: - case UIDeviceOrientationLandscapeRight: - case UIDeviceOrientationPortrait: - _orientation = orientation; - break; + [self addEvent:InternalEvent(kInputOrientationChanged, orientation, 0)]; +} - default: - return; +- (UITouch *)secondTouchOtherTouchThan:(UITouch *)touch in:(NSSet *)set { + NSArray *all = [set allObjects]; + for (UITouch *t in all) { + if (t != touch) { + return t; + } } - - [self addEvent:InternalEvent(kInputOrientationChanged, orientation, 0)]; + return nil; } - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - NSSet *allTouches = [event allTouches]; int x, y; - switch ([allTouches count]) { - case 1: { - UITouch *touch = [touches anyObject]; - CGPoint point = [touch locationInView:self]; + NSSet *allTouches = [event allTouches]; + if (allTouches.count == 1) { + _firstTouch = [allTouches anyObject]; + CGPoint point = [_firstTouch locationInView:self]; if (![self getMouseCoords:point eventX:&x eventY:&y]) return; - _firstTouch = touch; [self addEvent:InternalEvent(kInputMouseDown, x, y)]; - break; - } - - case 2: { - UITouch *touch = [touches anyObject]; - CGPoint point = [touch locationInView:self]; - if (![self getMouseCoords:point eventX:&x eventY:&y]) - return; + } + else if (allTouches.count == 2) { + _secondTouch = [self secondTouchOtherTouchThan:_firstTouch in:allTouches]; + if (_secondTouch) { + CGPoint point = [_secondTouch locationInView:self]; + if (![self getMouseCoords:point eventX:&x eventY:&y]) + return; - _secondTouch = touch; - [self addEvent:InternalEvent(kInputMouseSecondDown, x, y)]; - break; + [self addEvent:InternalEvent(kInputMouseSecondDown, x, y)]; } } } - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - //NSSet *allTouches = [event allTouches]; int x, y; - for (UITouch *touch in touches) { + NSSet *allTouches = [event allTouches]; + for (UITouch *touch in allTouches) { if (touch == _firstTouch) { CGPoint point = [touch locationInView:self]; if (![self getMouseCoords:point eventX:&x eventY:&y]) @@ -723,55 +741,64 @@ const char *iPhone_getDocumentsDir() { CGPoint point = [touch locationInView:self]; if (![self getMouseCoords:point eventX:&x eventY:&y]) return; - + [self addEvent:InternalEvent(kInputMouseSecondDragged, x, y)]; } } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - NSSet *allTouches = [event allTouches]; int x, y; - switch ([allTouches count]) { - case 1: { - UITouch *touch = [[allTouches allObjects] objectAtIndex:0]; + NSSet *allTouches = [event allTouches]; + if (allTouches.count == 1) { + UITouch *touch = [allTouches anyObject]; CGPoint point = [touch locationInView:self]; - if (![self getMouseCoords:point eventX:&x eventY:&y]) + if (![self getMouseCoords:point eventX:&x eventY:&y]) { return; - - [self addEvent:InternalEvent(kInputMouseUp, x, y)]; - break; } - case 2: { + [self addEvent:InternalEvent(kInputMouseUp, x, y)]; + } + else if (allTouches.count == 2) { UITouch *touch = [[allTouches allObjects] objectAtIndex:1]; CGPoint point = [touch locationInView:self]; if (![self getMouseCoords:point eventX:&x eventY:&y]) return; [self addEvent:InternalEvent(kInputMouseSecondUp, x, y)]; - break; - } } + _firstTouch = nil; + _secondTouch = nil; } - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + _firstTouch = nil; + _secondTouch = nil; } -- (void)handleKeyPress:(unichar)c { - [self addEvent:InternalEvent(kInputKeyPressed, c, 0)]; +- (void)twoFingersSwipeRight:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeRight, 2)]; +} + +- (void)twoFingersSwipeLeft:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeLeft, 2)]; +} + +- (void)twoFingersSwipeUp:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeUp, 2)]; } -- (BOOL)canHandleSwipes { - return TRUE; +- (void)twoFingersSwipeDown:(UISwipeGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputSwipe, kUIViewSwipeDown, 2)]; } -- (int)swipe:(int)num withEvent:(struct __GSEvent *)event { - //printf("swipe: %i\n", num); +- (void)twoFingersDoubleTap:(UITapGestureRecognizer *)recognizer { + [self addEvent:InternalEvent(kInputTap, kUIViewTapDouble, 2)]; +} - [self addEvent:InternalEvent(kInputSwipe, num, 0)]; - return 0; +- (void)handleKeyPress:(unichar)c { + [self addEvent:InternalEvent(kInputKeyPressed, c, 0)]; } - (void)applicationSuspend { diff --git a/backends/platform/iphone/osys_events.cpp b/backends/platform/iphone/osys_events.cpp index 95ca25a2d2..19da580c80 100644 --- a/backends/platform/iphone/osys_events.cpp +++ b/backends/platform/iphone/osys_events.cpp @@ -64,6 +64,17 @@ bool OSystem_IPHONE::pollEvent(Common::Event &event) { if (!handleEvent_mouseDragged(event, internalEvent.value1, internalEvent.value2)) return false; break; + + case kInputOrientationChanged: + handleEvent_orientationChanged(internalEvent.value1); + return false; + break; + + case kInputApplicationSuspended: + suspendLoop(); + return false; + break; + case kInputMouseSecondDragged: if (!handleEvent_mouseSecondDragged(event, internalEvent.value1, internalEvent.value2)) return false; @@ -78,29 +89,25 @@ bool OSystem_IPHONE::pollEvent(Common::Event &event) { if (!handleEvent_secondMouseUp(event, internalEvent.value1, internalEvent.value2)) return false; break; - case kInputOrientationChanged: - handleEvent_orientationChanged(internalEvent.value1); - return false; - break; - - case kInputApplicationSuspended: - suspendLoop(); - return false; - break; - + case kInputKeyPressed: handleEvent_keyPressed(event, internalEvent.value1); break; - + case kInputSwipe: - if (!handleEvent_swipe(event, internalEvent.value1)) + if (!handleEvent_swipe(event, internalEvent.value1, internalEvent.value2)) + return false; + break; + + case kInputTap: + if (!handleEvent_tap(event, (UIViewTapDescription) internalEvent.value1, internalEvent.value2)) return false; break; default: break; } - + return true; } return false; @@ -419,71 +426,137 @@ void OSystem_IPHONE::handleEvent_keyPressed(Common::Event &event, int keyPresse _queuedEventTime = getMillis() + kQueuedInputEventDelay; } -bool OSystem_IPHONE::handleEvent_swipe(Common::Event &event, int direction) { - Common::KeyCode keycode = Common::KEYCODE_INVALID; - switch (_screenOrientation) { - case kScreenOrientationPortrait: - switch ((UIViewSwipeDirection)direction) { - case kUIViewSwipeUp: - keycode = Common::KEYCODE_UP; - break; - case kUIViewSwipeDown: - keycode = Common::KEYCODE_DOWN; +bool OSystem_IPHONE::handleEvent_swipe(Common::Event &event, int direction, int touches) { + if (touches == 1) { + Common::KeyCode keycode = Common::KEYCODE_INVALID; + switch (_screenOrientation) { + case kScreenOrientationPortrait: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_DOWN; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_RIGHT; + break; + default: + return false; + } break; - case kUIViewSwipeLeft: - keycode = Common::KEYCODE_LEFT; + case kScreenOrientationLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_DOWN; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_UP; + break; + default: + return false; + } break; - case kUIViewSwipeRight: - keycode = Common::KEYCODE_RIGHT; + case kScreenOrientationFlippedLandscape: + switch ((UIViewSwipeDirection)direction) { + case kUIViewSwipeUp: + keycode = Common::KEYCODE_RIGHT; + break; + case kUIViewSwipeDown: + keycode = Common::KEYCODE_LEFT; + break; + case kUIViewSwipeLeft: + keycode = Common::KEYCODE_UP; + break; + case kUIViewSwipeRight: + keycode = Common::KEYCODE_DOWN; + break; + default: + return false; + } break; - default: - return false; } - break; - case kScreenOrientationLandscape: + + event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0; + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + + return true; + } + else if (touches == 2) { switch ((UIViewSwipeDirection)direction) { - case kUIViewSwipeUp: - keycode = Common::KEYCODE_LEFT; - break; - case kUIViewSwipeDown: - keycode = Common::KEYCODE_RIGHT; - break; - case kUIViewSwipeLeft: - keycode = Common::KEYCODE_DOWN; - break; - case kUIViewSwipeRight: - keycode = Common::KEYCODE_UP; - break; - default: + case kUIViewSwipeUp: { + _mouseClickAndDragEnabled = !_mouseClickAndDragEnabled; + const char *dialogMsg; + if (_mouseClickAndDragEnabled) { + _touchpadModeEnabled = false; + dialogMsg = _("Mouse-click-and-drag mode enabled."); + } else + dialogMsg = _("Mouse-click-and-drag mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); return false; } - break; - case kScreenOrientationFlippedLandscape: - switch ((UIViewSwipeDirection)direction) { - case kUIViewSwipeUp: - keycode = Common::KEYCODE_RIGHT; - break; - case kUIViewSwipeDown: - keycode = Common::KEYCODE_LEFT; - break; - case kUIViewSwipeLeft: - keycode = Common::KEYCODE_UP; - break; - case kUIViewSwipeRight: - keycode = Common::KEYCODE_DOWN; - break; - default: + + case kUIViewSwipeDown: { + // Swipe down + event.type = Common::EVENT_MAINMENU; + _queuedInputEvent.type = Common::EVENT_INVALID; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + + case kUIViewSwipeRight: { + // Swipe right + _touchpadModeEnabled = !_touchpadModeEnabled; + const char *dialogMsg; + if (_touchpadModeEnabled) + dialogMsg = _("Touchpad mode enabled."); + else + dialogMsg = _("Touchpad mode disabled."); + GUI::TimedMessageDialog dialog(dialogMsg, 1500); + dialog.runModal(); return false; } - break; - } - event.kbd.keycode = _queuedInputEvent.kbd.keycode = keycode; - event.kbd.ascii = _queuedInputEvent.kbd.ascii = 0; - event.type = Common::EVENT_KEYDOWN; - _queuedInputEvent.type = Common::EVENT_KEYUP; - event.kbd.flags = _queuedInputEvent.kbd.flags = 0; - _queuedEventTime = getMillis() + kQueuedInputEventDelay; + default: + break; + } + } + return false; +} - return true; +bool OSystem_IPHONE::handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches) { + if (touches == 1) { + if (type == kUIViewTapDouble) { + event.type = Common::EVENT_RBUTTONDOWN; + _queuedInputEvent.type = Common::EVENT_RBUTTONUP; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + } + else if (touches == 2) { + if (type == kUIViewTapDouble) { + event.kbd.keycode = _queuedInputEvent.kbd.keycode = Common::KEYCODE_ESCAPE; + event.kbd.ascii = _queuedInputEvent.kbd.ascii = Common::ASCII_ESCAPE; + event.type = Common::EVENT_KEYDOWN; + _queuedInputEvent.type = Common::EVENT_KEYUP; + event.kbd.flags = _queuedInputEvent.kbd.flags = 0; + _queuedEventTime = getMillis() + kQueuedInputEventDelay; + return true; + } + } + return false; } diff --git a/backends/platform/iphone/osys_main.h b/backends/platform/iphone/osys_main.h index f308a83b05..04a531613f 100644 --- a/backends/platform/iphone/osys_main.h +++ b/backends/platform/iphone/osys_main.h @@ -206,7 +206,8 @@ protected: static void AQBufferCallback(void *in, AudioQueueRef inQ, AudioQueueBufferRef outQB); static int timerHandler(int t); - bool handleEvent_swipe(Common::Event &event, int direction); + bool handleEvent_swipe(Common::Event &event, int direction, int touches); + bool handleEvent_tap(Common::Event &event, UIViewTapDescription type, int touches); void handleEvent_keyPressed(Common::Event &event, int keyPressed); void handleEvent_orientationChanged(int orientation); -- cgit v1.2.3