Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I override the 3-finger tap behavior in a NSTextView?

On Mac OS X, doing a 3-finger tap on a word pops up a window with a definition of the word.

Image showing a pop up window showing a word definition.

This idiom is also used in Xcode, where doing a 3-finger tap over a symbol shows its documentation, much like if it had been alt+clicked.

Image showing a pop up window showing symbol documentation.

I would like to do something similar to that and display definitions when users of my application do a 3-finger tap on certain tokens in a NSTextView. However, I can't find how to detect that a tap has been done with 3 fingers. Could someone help me with that?

EDIT If this reminds anything to anyone, three events (caught by overriding [NSApplication sendEvent:]) are triggered when you do this kind of tap:

NSEvent: type=SysDefined loc=(270.918,250.488) time=417954.6 flags=0x100 win=0x0 winNum=28293 ctxt=0x0 subtype=6 data1=1818981744 data2=1818981744
NSEvent: type=SysDefined loc=(270.918,250.488) time=417954.6 flags=0x100 win=0x0 winNum=28293 ctxt=0x0 subtype=9 data1=1818981744 data2=1818981744
NSEvent: type=Kitdefined loc=(0,263) time=417954.8 flags=0x100 win=0x0 winNum=28306 ctxt=0x0 subtype=4 data1=1135411200 data2=1132691456
like image 351
zneak Avatar asked Dec 10 '13 23:12

zneak


2 Answers

Reacting on a triple tap in a NSTextView can most easily be done by overriding quickLookWithEvent:.

-(void)quickLookWithEvent:(NSEvent *)event
{
    NSLog(@"Look at me! %@", event);
}

It also taught me that you can triple tap anything to invoke Quick Look on it.

like image 187
zneak Avatar answered Oct 24 '22 09:10

zneak


Subclass NSTextView and override mouse down event (this is where the view usually handle the click/tap events):

-(void)mouseDown:(NSEvent*)event
{
  if (event.clickCount == 3)
  {
    //Do your thing
  }
}

Hope this helps.

If the triple click does not work for you (I am not currently in from of my mac to check), you could try something else. I know it works in iOS, I don't know about the trackpad gestures.

You could try adding a UITapGestureRecognizer to your view:

UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(viewTapped:)];
tapGesture.numberOfTouchesRequired = 3;

//....

-(void)viewTapped:(UITapGestureRecognizer*)tap
{
  if(tap.state == UIGestureRecognizerStateRecognized)
  {
    //you detected a three finger tap, do work
  } 
}

LATER EDIT:

I found this article in the apple documentation. Based on a sample from this article, here is some code which should be useful (from listing 8-5):

- (void)touchesBeganWithEvent:(NSEvent *)event {
    if (!self.isEnabled) return;

    NSSet *touches = [event touchesMatchingPhase:NSTouchPhaseTouching inView:self.view];

    if (touches.count == 3) 
    {
       //Three finger touch detected
    }

    [super touchesBeganWithEvent:event];
}
like image 30
nestedloop Avatar answered Oct 24 '22 09:10

nestedloop