diff options
author | Travis Veralrud <tbveralrud+git@gmail.com> | 2022-11-25 19:18:35 -0800 |
---|---|---|
committer | RĂ©mi Verschelde <rverschelde@gmail.com> | 2023-02-15 09:45:38 +0100 |
commit | 10be2c343f6f8b9619eec9d3319a1eef57cd2b17 (patch) | |
tree | 79ad4bc02eb0e1f3122838aa70d8d83735f3932d /platform/ios | |
parent | 8c7b98d4526c6ba66d7f1636abb71ccbe54727c6 (diff) |
iOS: Fix memory leak on touch input
Replace incomplete iOS gesture with touch implementation.
Fixes #66422.
Diffstat (limited to 'platform/ios')
-rw-r--r-- | platform/ios/SCsub | 1 | ||||
-rw-r--r-- | platform/ios/godot_view.h | 5 | ||||
-rw-r--r-- | platform/ios/godot_view.mm | 82 | ||||
-rw-r--r-- | platform/ios/godot_view_gesture_recognizer.h | 46 | ||||
-rw-r--r-- | platform/ios/godot_view_gesture_recognizer.mm | 186 |
5 files changed, 27 insertions, 293 deletions
diff --git a/platform/ios/SCsub b/platform/ios/SCsub index f3925c146f..18ba6617af 100644 --- a/platform/ios/SCsub +++ b/platform/ios/SCsub @@ -17,7 +17,6 @@ ios_lib = [ "display_layer.mm", "godot_app_delegate.m", "godot_view_renderer.mm", - "godot_view_gesture_recognizer.mm", "device_metrics.m", "keyboard_input_view.mm", "key_mapping_ios.mm", diff --git a/platform/ios/godot_view.h b/platform/ios/godot_view.h index 077584baa6..b00ca37ebe 100644 --- a/platform/ios/godot_view.h +++ b/platform/ios/godot_view.h @@ -59,9 +59,4 @@ class String; - (void)stopRendering; - (void)startRendering; -- (void)godotTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; -- (void)godotTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; -- (void)godotTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; -- (void)godotTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; - @end diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm index 4b10f95ab8..fafec79bf6 100644 --- a/platform/ios/godot_view.mm +++ b/platform/ios/godot_view.mm @@ -35,7 +35,6 @@ #include "core/string/ustring.h" #import "display_layer.h" #include "display_server_ios.h" -#import "godot_view_gesture_recognizer.h" #import "godot_view_renderer.h" #import <CoreMotion/CoreMotion.h> @@ -60,8 +59,6 @@ static const float earth_gravity = 9.80665; @property(strong, nonatomic) CMMotionManager *motionManager; -@property(strong, nonatomic) GodotViewGestureRecognizer *delayGestureRecognizer; - @end @implementation GodotView @@ -148,10 +145,6 @@ static const float earth_gravity = 9.80665; [self.animationTimer invalidate]; self.animationTimer = nil; } - - if (self.delayGestureRecognizer) { - self.delayGestureRecognizer = nil; - } } - (void)godot_commonInit { @@ -171,11 +164,6 @@ static const float earth_gravity = 9.80665; self.motionManager = nil; } } - - // Initialize delay gesture recognizer - GodotViewGestureRecognizer *gestureRecognizer = [[GodotViewGestureRecognizer alloc] init]; - self.delayGestureRecognizer = gestureRecognizer; - [self addGestureRecognizer:self.delayGestureRecognizer]; } - (void)stopRendering { @@ -347,58 +335,42 @@ static const float earth_gravity = 9.80665; } } -- (void)godotTouchesBegan:(NSSet *)touchesSet withEvent:(UIEvent *)event { - NSArray *tlist = [event.allTouches allObjects]; - for (unsigned int i = 0; i < [tlist count]; i++) { - if ([touchesSet containsObject:[tlist objectAtIndex:i]]) { - UITouch *touch = [tlist objectAtIndex:i]; - int tid = [self getTouchIDForTouch:touch]; - ERR_FAIL_COND(tid == -1); - CGPoint touchPoint = [touch locationInView:self]; - DisplayServerIOS::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1); - } +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + for (UITouch *touch in touches) { + int tid = [self getTouchIDForTouch:touch]; + ERR_FAIL_COND(tid == -1); + CGPoint touchPoint = [touch locationInView:self]; + DisplayServerIOS::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, true, touch.tapCount > 1); } } -- (void)godotTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - NSArray *tlist = [event.allTouches allObjects]; - for (unsigned int i = 0; i < [tlist count]; i++) { - if ([touches containsObject:[tlist objectAtIndex:i]]) { - UITouch *touch = [tlist objectAtIndex:i]; - int tid = [self getTouchIDForTouch:touch]; - ERR_FAIL_COND(tid == -1); - CGPoint touchPoint = [touch locationInView:self]; - CGPoint prev_point = [touch previousLocationInView:self]; - CGFloat alt = [touch altitudeAngle]; - CGVector azim = [touch azimuthUnitVectorInView:self]; - DisplayServerIOS::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, [touch force] / [touch maximumPossibleForce], Vector2(azim.dx, azim.dy) * Math::cos(alt)); - } +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + for (UITouch *touch in touches) { + int tid = [self getTouchIDForTouch:touch]; + ERR_FAIL_COND(tid == -1); + CGPoint touchPoint = [touch locationInView:self]; + CGPoint prev_point = [touch previousLocationInView:self]; + CGFloat alt = [touch altitudeAngle]; + CGVector azim = [touch azimuthUnitVectorInView:self]; + DisplayServerIOS::get_singleton()->touch_drag(tid, prev_point.x * self.contentScaleFactor, prev_point.y * self.contentScaleFactor, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, [touch force] / [touch maximumPossibleForce], Vector2(azim.dx, azim.dy) * Math::cos(alt)); } } -- (void)godotTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - NSArray *tlist = [event.allTouches allObjects]; - for (unsigned int i = 0; i < [tlist count]; i++) { - if ([touches containsObject:[tlist objectAtIndex:i]]) { - UITouch *touch = [tlist objectAtIndex:i]; - int tid = [self getTouchIDForTouch:touch]; - ERR_FAIL_COND(tid == -1); - [self removeTouch:touch]; - CGPoint touchPoint = [touch locationInView:self]; - DisplayServerIOS::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false); - } +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + for (UITouch *touch in touches) { + int tid = [self getTouchIDForTouch:touch]; + ERR_FAIL_COND(tid == -1); + [self removeTouch:touch]; + CGPoint touchPoint = [touch locationInView:self]; + DisplayServerIOS::get_singleton()->touch_press(tid, touchPoint.x * self.contentScaleFactor, touchPoint.y * self.contentScaleFactor, false, false); } } -- (void)godotTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - NSArray *tlist = [event.allTouches allObjects]; - for (unsigned int i = 0; i < [tlist count]; i++) { - if ([touches containsObject:[tlist objectAtIndex:i]]) { - UITouch *touch = [tlist objectAtIndex:i]; - int tid = [self getTouchIDForTouch:touch]; - ERR_FAIL_COND(tid == -1); - DisplayServerIOS::get_singleton()->touches_canceled(tid); - } +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + for (UITouch *touch in touches) { + int tid = [self getTouchIDForTouch:touch]; + ERR_FAIL_COND(tid == -1); + DisplayServerIOS::get_singleton()->touches_canceled(tid); } [self clearTouches]; } diff --git a/platform/ios/godot_view_gesture_recognizer.h b/platform/ios/godot_view_gesture_recognizer.h deleted file mode 100644 index 57bfc75568..0000000000 --- a/platform/ios/godot_view_gesture_recognizer.h +++ /dev/null @@ -1,46 +0,0 @@ -/**************************************************************************/ -/* godot_view_gesture_recognizer.h */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -// GLViewGestureRecognizer allows iOS gestures to work correctly by -// emulating UIScrollView's UIScrollViewDelayedTouchesBeganGestureRecognizer. -// It catches all gestures incoming to UIView and delays them for 150ms -// (the same value used by UIScrollViewDelayedTouchesBeganGestureRecognizer) -// If touch cancellation or end message is fired it fires delayed -// begin touch immediately as well as last touch signal - -#import <UIKit/UIKit.h> - -@interface GodotViewGestureRecognizer : UIGestureRecognizer - -@property(nonatomic, readonly, assign) NSTimeInterval delayTimeInterval; - -- (instancetype)init; - -@end diff --git a/platform/ios/godot_view_gesture_recognizer.mm b/platform/ios/godot_view_gesture_recognizer.mm deleted file mode 100644 index 9b71228864..0000000000 --- a/platform/ios/godot_view_gesture_recognizer.mm +++ /dev/null @@ -1,186 +0,0 @@ -/**************************************************************************/ -/* godot_view_gesture_recognizer.mm */ -/**************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/**************************************************************************/ -/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/**************************************************************************/ - -#import "godot_view_gesture_recognizer.h" - -#import "godot_view.h" - -#include "core/config/project_settings.h" - -// Minimum distance for touches to move to fire -// a delay timer before scheduled time. -// Should be the low enough to not cause issues with dragging -// but big enough to allow click to work. -const CGFloat kGLGestureMovementDistance = 0.5; - -@interface GodotViewGestureRecognizer () - -@property(nonatomic, readwrite, assign) NSTimeInterval delayTimeInterval; - -@end - -@interface GodotViewGestureRecognizer () - -// Timer used to delay begin touch message. -// Should work as simple emulation of UIDelayedAction -@property(strong, nonatomic) NSTimer *delayTimer; - -// Delayed touch parameters -@property(strong, nonatomic) NSSet *delayedTouches; -@property(strong, nonatomic) UIEvent *delayedEvent; - -@end - -@implementation GodotViewGestureRecognizer - -- (GodotView *)godotView { - return (GodotView *)self.view; -} - -- (instancetype)init { - self = [super init]; - - self.cancelsTouchesInView = YES; - self.delaysTouchesBegan = YES; - self.delaysTouchesEnded = YES; - self.requiresExclusiveTouchType = NO; - - self.delayTimeInterval = GLOBAL_GET("input_devices/pointing/ios/touch_delay"); - - return self; -} - -- (void)dealloc { - if (self.delayTimer) { - [self.delayTimer invalidate]; - self.delayTimer = nil; - } - - if (self.delayedTouches) { - self.delayedTouches = nil; - } - - if (self.delayedEvent) { - self.delayedEvent = nil; - } -} - -- (void)delayTouches:(NSSet *)touches andEvent:(UIEvent *)event { - [self.delayTimer fire]; - - self.delayedTouches = touches; - self.delayedEvent = event; - - self.delayTimer = [NSTimer - scheduledTimerWithTimeInterval:self.delayTimeInterval - target:self - selector:@selector(fireDelayedTouches:) - userInfo:nil - repeats:NO]; -} - -- (void)fireDelayedTouches:(id)timer { - [self.delayTimer invalidate]; - self.delayTimer = nil; - - if (self.delayedTouches) { - [self.godotView godotTouchesBegan:self.delayedTouches withEvent:self.delayedEvent]; - } - - self.delayedTouches = nil; - self.delayedEvent = nil; -} - -- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { - NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseBegan]; - [self delayTouches:cleared andEvent:event]; - - [super touchesBegan:touches withEvent:event]; -} - -- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { - NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseMoved]; - - if (self.delayTimer) { - // We should check if movement was significant enough to fire an event - // for dragging to work correctly. - for (UITouch *touch in cleared) { - CGPoint from = [touch locationInView:self.godotView]; - CGPoint to = [touch previousLocationInView:self.godotView]; - CGFloat xDistance = from.x - to.x; - CGFloat yDistance = from.y - to.y; - - CGFloat distance = sqrt(xDistance * xDistance + yDistance * yDistance); - - // Early exit, since one of touches has moved enough to fire a drag event. - if (distance > kGLGestureMovementDistance) { - [self.delayTimer fire]; - [self.godotView godotTouchesMoved:cleared withEvent:event]; - return; - } - } - - return; - } - - [self.godotView godotTouchesMoved:cleared withEvent:event]; - - [super touchesMoved:touches withEvent:event]; -} - -- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { - [self.delayTimer fire]; - - NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseEnded]; - [self.godotView godotTouchesEnded:cleared withEvent:event]; - - [super touchesEnded:touches withEvent:event]; -} - -- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { - [self.delayTimer fire]; - [self.godotView godotTouchesCancelled:touches withEvent:event]; - - [super touchesCancelled:touches withEvent:event]; -} - -- (NSSet *)copyClearedTouches:(NSSet *)touches phase:(UITouchPhase)phaseToSave { - NSMutableSet *cleared = [touches mutableCopy]; - - for (UITouch *touch in touches) { - if (touch.view != self.view || touch.phase != phaseToSave) { - [cleared removeObject:touch]; - } - } - - return cleared; -} - -@end |