Skip to content

Commit f90ef9b

Browse files
committed
support force touch in trackpad mode
1 parent 2193780 commit f90ef9b

File tree

1 file changed

+48
-5
lines changed

1 file changed

+48
-5
lines changed

Mini vMac/TrackPad.m

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#import "TrackPad.h"
1010
#import "AppDelegate.h"
11+
@import AudioToolbox;
1112

1213
#define TRACKPAD_ACCEL_N 1
1314
#define TRACKPAD_ACCEL_T 0.2
@@ -21,6 +22,7 @@ @implementation TrackPad
2122
CGPoint previousTouchLoc;
2223
BOOL shouldClick;
2324
BOOL isDragging;
25+
BOOL supportsForceTouch, didForceClick;
2426
NSMutableSet *currentTouches;
2527
}
2628

@@ -34,6 +36,15 @@ - (instancetype)initWithFrame:(CGRect)frame {
3436
return self;
3537
}
3638

39+
- (void)willMoveToSuperview:(UIView *)newSuperview {
40+
[super willMoveToSuperview:newSuperview];
41+
@try {
42+
supportsForceTouch = (newSuperview.traitCollection.forceTouchCapability == UIForceTouchCapabilityAvailable);
43+
} @catch (NSException *exception) {
44+
supportsForceTouch = NO;
45+
}
46+
}
47+
3748
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
3849
[currentTouches unionSet:touches];
3950
if (currentTouches.count == 1) {
@@ -45,11 +56,14 @@ - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
4556

4657
- (void)firstTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
4758
CGPoint touchLoc = [touch locationInView:self];
59+
shouldClick = YES;
4860
if (!isDragging && (event.timestamp - previousTouchTime < touchTimeThreshold) &&
4961
fabs(previousTouchLoc.x - touchLoc.x) < touchDistanceThreshold &&
5062
fabs(previousTouchLoc.y - touchLoc.y) < touchDistanceThreshold) {
5163
[self startDragging];
5264
}
65+
previousTouchTime = event.timestamp;
66+
previousTouchLoc = touchLoc;
5367
}
5468

5569
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
@@ -62,21 +76,34 @@ - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
6276
NSTimeInterval accel = TRACKPAD_ACCEL_N / (TRACKPAD_ACCEL_T + ((timeDiff * timeDiff)/TRACKPAD_ACCEL_D));
6377
locDiff.x *= accel;
6478
locDiff.y *= accel;
65-
shouldClick = NO;
66-
[[AppDelegate sharedEmulator] moveMouseX:locDiff.x Y:locDiff.y];
79+
80+
if (!CGPointEqualToPoint(touchLoc, previousTouchLoc)) {
81+
shouldClick = NO;
82+
[[AppDelegate sharedEmulator] moveMouseX:locDiff.x Y:locDiff.y];
83+
}
84+
6785
previousTouchTime = event.timestamp;
6886
previousTouchLoc = touchLoc;
87+
88+
if (supportsForceTouch) {
89+
[self handleForceClick:touch];
90+
}
6991
}
7092

7193
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
7294
[currentTouches minusSet:touches];
7395
if (currentTouches.count > 0) {
7496
return;
97+
} else if (didForceClick) {
98+
AudioServicesPlaySystemSound(1519);
99+
didForceClick = NO;
100+
[self cancelScheduledClick];
101+
[self mouseUp];
102+
return;
75103
}
76104
CGPoint touchLoc = [touches.anyObject locationInView:self];
77105
if (shouldClick && (event.timestamp - previousTouchTime < touchTimeThreshold)) {
78-
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(mouseClick) object:nil];
79-
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(mouseUp) object:nil];
106+
[self cancelScheduledClick];
80107
[self performSelector:@selector(mouseClick) withObject:nil afterDelay:touchTimeThreshold];
81108
}
82109
shouldClick = NO;
@@ -90,7 +117,10 @@ - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
90117

91118
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
92119
[currentTouches minusSet:touches];
93-
[self stopDragging];
120+
isDragging = NO;
121+
shouldClick = NO;
122+
didForceClick = NO;
123+
[self mouseUp];
94124
}
95125

96126
- (void)startDragging {
@@ -105,6 +135,14 @@ - (void)stopDragging {
105135
[[AppDelegate sharedEmulator] setMouseButton:NO];
106136
}
107137

138+
- (void)handleForceClick:(UITouch *)touch {
139+
if (touch.force > 3.0 && !didForceClick) {
140+
AudioServicesPlaySystemSound(1519);
141+
didForceClick = YES;
142+
[self startDragging];
143+
}
144+
}
145+
108146
- (void)mouseClick {
109147
if (isDragging) {
110148
return;
@@ -113,6 +151,11 @@ - (void)mouseClick {
113151
[self performSelector:@selector(mouseUp) withObject:nil afterDelay:2.0/60.0];
114152
}
115153

154+
- (void)cancelScheduledClick {
155+
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(mouseClick) object:nil];
156+
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(mouseUp) object:nil];
157+
}
158+
116159
- (void)mouseUp {
117160
[[AppDelegate sharedEmulator] setMouseButton:NO];
118161
}

0 commit comments

Comments
 (0)