Re: Handling "Smart Zoom" gesture?
Re: Handling "Smart Zoom" gesture?
- Subject: Re: Handling "Smart Zoom" gesture?
- From: Graham Cox <email@hidden>
- Date: Fri, 29 Jun 2012 12:57:37 +1000
On 28/06/2012, at 5:31 PM, Quincey Morris wrote:
> On Jun 28, 2012, at 00:14 , Graham Cox wrote:
>
>> Specifically, the problem is that the -clickCount property of an NSEvent is only applicable to mouse events, not touch events. So what's the right way to trap this specific gesture? I have read the various touch-input documentation but nothing became obvious.
>
> The 10.6 document seems to imply that tapping isn't a gesture, so I'd assume you'd have to implement the NSResponder methods 'touches…WithEvent:' and use the event times to decide (a) if precisely 2 touches begin/end more or less simultaneously and (b) if a second 2-touch tap begins within a time interval after the 1st one [iOS defaults to 0.5 sec for this interval. Perhaps on the Mac you'd use something conditioned by the double-click time instead. I dunno.] and (c) if both 2-touch taps last less than some time interval [otherwise they'd represent a long press].
>
> Something like that?
>
>
OK, that's pretty much what I'm doing, but it doesn't work all that well yet. The gesture is recognised, but only sometimes, so the effect for the user is that the gesture response is flaky.
I'm not sure what I need to do to improve this.
I've written a system somewhat similar (but simpler) than the iOS gesture recognizer system, where each gesture is recognized by an object, and as soon as it recognizes the gesture, it informs its delegate and tells the other recognizers in the set to fugeddaboudit. But in fact, I only have the one recognizer in there.
Here's the code, which happens to be in my recognizer object, but this can be thought of as being implemented by a view:
- (void) touchesBeganWithEvent:(NSEvent*) event
{
NSSet* touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:self.view];
if([touches count] == 2 )
{
if( self.state == DKWaitingForTap )
{
mFirstTapTime = [NSDate timeIntervalSinceReferenceDate];
[NSTimer scheduledTimerWithTimeInterval:[NSEvent doubleClickInterval] + 0.1 target:self selector:@selector(timeOut:) userInfo:nil repeats:NO];
self.state = DKGotFirstTap;
}
else if( self.state == DKGotFirstTap )
{
NSTimeInterval dt = [NSDate timeIntervalSinceReferenceDate] - mFirstTapTime;
if( dt <= [NSEvent doubleClickInterval])
{
self.state = DKGotSecondTap;
[self notifyDelegate]; // will eventually call -reset which puts the state back if timer or ended event doesn't do it first
}
}
}
}
- (void) touchesEndedWithEvent:(NSEvent *)event
{
if( self.state != DKWaitingForTap )
{
NSTimeInterval dt = [NSDate timeIntervalSinceReferenceDate] - mFirstTapTime;
if( dt > [NSEvent doubleClickInterval])
[self reset];
}
}
- (void) touchesMovedWithEvent:(NSEvent*) event
{
[self reset];
}
- (void) touchesCancelledWithEvent:(NSEvent*) event
{
[self reset];
}
- (void) reset
{
self.state = DKWaitingForTap;
}
- (void) timeOut:(NSTimer*) timer;
{
[self reset];
}
As you can see, I don't bother to track the touches - I only determine that there are two, and use a simple state machine to detect a double-tap. On the second tap the touches will be new objects anyway, so there isn't any mileage in trying to match them up with the touches of the first event. There's also a timer that resets the state if the second tap is never received.
It works, but since the results are flaky, this is obviously not good enough. Has anyone actually implemented something like this, and can see where I have gone wrong?
--Graham
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden