NSEvent; how to distinguish between a single and double click?

So this is a poser.


I have an event handling method (mouseUp) that checks the event's click count:

switch event.clickCount{
                case 1:
                    // tell the delegate to handle a single click.
                    singleDelegate?(event, viewPt)
                case 2:
                    //tell the delegate to handle a double click.
                    doubleDelegate?(event, viewPt)
                default:
                    break
                }


and what is happening is that when there is a double click, I get 2 events. 1 event for a single click, and another for the double click.

how does one detect the double-click without getting a single click in error? Seems like it should be pretty straight forward, no?

here's what i found online worked into my code:


switch event.clickCount{
                case 1:
                    clickTimer = Timer.scheduledTimer(withTimeInterval: 0.2,  repeats: false) { timer in
                       singleDelegate?(event, viewPt)
                    }
                case 2:
                    clickTimer?.invalidate()
                    clickTimer = nil
                    doubleDelegate?(event, viewPt)
                default:
                    break
                }


it creates a timer, that waits for 0.2 seconds... 0.15 is too short in testing.

and then if it's not interrupted, it fires a single click message.


the double click testing, if true, interrupts the Timer.


this is a HORRIBLE solution. There is noticable latency in single click behavior. I hate this. This is a rediculous requirement for supporting discreet single or double clicks. I am going to need a solution that has No latency. Any ideas would be appreciated.

First, you should use NSEvent.doubleClickInterval rather than a hard-coded 0.2.


Second, what you seek is literally impossible. How can the computer possibly know at the time of the first click whether or not there will be a second click coming in the near future. The computer can't know the future. The only way you, your program, the OS, or anything can know if a click is part of a double-click is to wait until either a second click or the double-click interval has expired, just as you've done.

Hi Ken,

I did use the NSEvent.DoubleClickTimeInterval

it was no different, and seemed (though not scientifically measured) to be worse.


I do not think it's impossible to get No single click events in the the case of a double click. I mean, NSEvent now has Delta values. it's 2018, everything is magical and handled for you... except this. (bit of sarcasm there, btw)


Look, I'm not insane, I realise that there will be "some" latency involved with testing for a double click. The problem is: I click, release, move the mouse, and THEN the single click method is called. The latency is obscene. It makes a real-time ui look like it cannot keep up with the user.

at 0.15 seconds, double clicks still get single click events.


I do not think it's too much to ask for advice on tuning that, or barring that... Apple itself doing a better job of distinguishing double click events from single click events. Apple engineers have options and access that 3rd party devs do not have. And in the case of loops, they offlined the whole thing, and if the legends are true, they built customized code. a Whole hierarchy of objects that address specific use cases, a series of objects that make decisions and an interface that hides that complexity from the developer all in order to make looping through a series of objects as fast as it can be.


so here's what I'm doing to work around this issue:

it happens that my UI has the ability to become discreet... That is: I can test if only a portion of my button is clicked before calling the singleClick method. So I'm going to do that. It's a thing Apple does with IOS UIs I've taken to calling : Bracketing. use a simple test to eliminate complicated choices. This will not always be possible, but at least I can do it now.

The other thing that's required for a second click to be considered part of a double-click is that it be close (within a few points) of the first click. So, you could set up an event monitor or something to watch for mouse movement (drags, since the button will be down) and fire the single-click action if it moves too far.

For tableView, there is doubleAction. Must probably work like the timer.


To avoid the problem of singleclick before double, I sometimes prefer to use cmd-click.

that's interesting. Might shave off a few micro-seconds. if i find myself unable to do anything else, I might try working with that.

I suspect that the correct answer is: avoid a single control that responds to both single and double clicks.

It's not a good answer.

Well, in some cases it is really useful. Think of tableViews, we do it all the time.

sure. but the behaviors associated with clicking and double clicking, work well together.


if you click a Tablecell, you want to select it.

if you double click it, you want to select it and then edit it.


I've got non-related behaviors I'm trying to stack up:

a button that clicks for a single click, and opens a popup for a double click. command clicking goes against my *single button* ui, so what can I do? I get stuck with latency :\ or I find a way to discreetly tear apart the behavior. That's what i'm doing now. In essence, I put a button in my button, that responds to clicks, and my button responds to double clicks. It's a very heavy weight solution to this problem, but i do not see anything more elegant.

I was going to mke the same comment.


If single and double click, single should only select but not launch action that involves user.

That's the case for table views.


What do you mean : command clicking goes against my *single button* ui

This is part of the correct answer. This is a solved problem, and the solution has been around for a long time. It's just not the solution you would like it to be.


As Ken said, you cannot see into the future. The consequence is that you can't detect a double click except by waiting. This has one of three conequences, depending on the circumstances:


1. The single click action can be a separate action that is compatible with the (possible upcoming) double-click. This is the behavior you see in the Finder: the first (single) click selects, the second (double) click opens. The event-handling in this case doesn't need to defer the handling of the first click, because it does the same thing whether a double-click is coming or not.


2. You can avoid designing a UI where a single click does something inconsistent with a double click (and the single click therefore has to wait before it can carry out its action).


3. If single and double clicks do different things, you can process a single click immediately, then undo what it did if it happens to turn into a double click. This is actually a pretty awful choice, but you can occasionally see behavior like this when using right-click context menus.


If you're faced with #2, then that's a pretty good indication that a double click is a bad UI choice for that context. You're better off finding an alternative UI. It's been long understood that double clicks are a problematic UI gesture in many situations. Many users just hate double clicking regardless. It should be reserved for power users (whatever that means), and not be the only way to get something done.


>> I did use the NSEvent.DoubleClickTimeInterval

>> it was no different, and seemed (though not scientifically measured) to be worse.


It's likely "worse" because the default double click interval is something like 0.25 seconds, which is longer than the value you tried. The point Ken was making is that you should use this value anyway, because it's something the user can set in System Preferences. A user who has trouble double-clicking quickly might use a longer interval. It's basically an accessibility feature to honor the system value.

Have you considered click-and-hold for the pop-up, instead of double-click? That's a behavior that shows up in numerous Apple apps.

Ken,

I'm really after a bullet proof solution that doesn't limit the possibilities. a click-and-hold is appropriate for some things, such as a popup menu, but chances are I'll be seeing more popovers than popups.


it really sounds like I need to make a set of guidelines... make your double-click action behave well with the click action. that sort of thing. I'm just flabberghasted that I have to take such a large hit time wise in order to discreetly respond to single clicks and double clicks. Knowing that this is a boundary helps a little. I can just avoid paying the cost by designing around it.

NSEvent; how to distinguish between a single and double click?
 
 
Q