Resolving order of events - single and double clicks
Moderators: CEGUI MVP, CEGUI Team
Resolving order of events - single and double clicks
My buttons subscribe to both singe and double clicks (it is a game context, and single-click selects the entity while double-clicking focuses the camera on it).
However, when double-clicking the button it seems like the events are resolved into a single-click event followed by a double-click. Am I missing something? How is this usually resolved?
However, when double-clicking the button it seems like the events are resolved into a single-click event followed by a double-click. Am I missing something? How is this usually resolved?
That is typically how double-click events work. Technically speaking, you are single-clicking twice. You can observe this same behavior in most software. It should be obvious why this occurs; if you delay the single-click event to see if a double-click is going to occur, you create too much lag for single-click events and your system will appear to be slow.
You did not really explain what it is you are trying to do, so it is hard to recommend a "resolution" for an unknown problem.
You did not really explain what it is you are trying to do, so it is hard to recommend a "resolution" for an unknown problem.
Well, some code is perhaps in order:
Notice that I'm subscribing to "click" as opposed to "mouseDown" or similar events. To me this suggests that single- and double-clicking (and triple-clicking for that matter) are treated as separate events (a single click isn't dispatched until the double-click interval has been exceeded). Still, when running this will create first a click then a double-click.
I doubt this is intended behaviour unless I'm missing something that all old hands know about?
Code: Select all
struct TestHandler
{
bool onClick( CEGUI::EventArgs const & )
{
MessageBeep( MB_CANCELTRYCONTINUE );
return true;
}
bool onDoubleClick( CEGUI::EventArgs const & )
{
MessageBeep( MB_ICONEXCLAMATION );
return true;
}
};
static TestHandler th;
pIcon->subscribeEvent( PushButton::EventMouseClicked, Event::Subscriber(&TestHandler::onClick, &th) );
pIcon->subscribeEvent( PushButton::EventMouseDoubleClick, Event::Subscriber(&TestHandler::onDoubleClick, &th) );
Notice that I'm subscribing to "click" as opposed to "mouseDown" or similar events. To me this suggests that single- and double-clicking (and triple-clicking for that matter) are treated as separate events (a single click isn't dispatched until the double-click interval has been exceeded). Still, when running this will create first a click then a double-click.
I doubt this is intended behaviour unless I'm missing something that all old hands know about?
Your code did not present any new information. I understand what you are saying, but unfortunately (afaik) the behavior you are expecting is not built into cegui. A click is defined as a "mouse_down + mouse_up" sequence, and nothing more (according to the documentation).
Again, these are not really "separate" events. Logically they are "chained" events: a double-click relies on a sinigle-click, a triple-click relies on a double-click. And thus one only fires after the other has occured. I am assuming this is how the cegui devs envisioned it when they built this functionality.
I can see the need for separating them if you where trying to attach unrelated actions to each sequence in the chain. Unfortunately I cannot provide much insight into how this would be accomplished in cegui. You may want to look into adding a child-class that overloads the appropriate methods (ex: PushButton::onClicked) and add the functionality you desire. You will probably have to wait until CE can comment on this for anything more substantial.
Again, these are not really "separate" events. Logically they are "chained" events: a double-click relies on a sinigle-click, a triple-click relies on a double-click. And thus one only fires after the other has occured. I am assuming this is how the cegui devs envisioned it when they built this functionality.
I can see the need for separating them if you where trying to attach unrelated actions to each sequence in the chain. Unfortunately I cannot provide much insight into how this would be accomplished in cegui. You may want to look into adding a child-class that overloads the appropriate methods (ex: PushButton::onClicked) and add the functionality you desire. You will probably have to wait until CE can comment on this for anything more substantial.
Been checking around some more, and I found a threadon the Ogre forum that talks about this behaviour.
I'm feeling a little at a loss as how to manage this. I apparently must intercept all events reaching the button and time them manually to determine if a single- or multi-click has occurred?
I'd be grateful for any suggestions.
kungfoomasta wrote:CEGUI supports up to triple click, so if you mouse_down on a widget 3 times times, it will receive the following events:
mouse_down
mouse_click
mouse_double_click
mouse_triple_click
It's also worthwhile to note they reset the timer after ever click.
Is a non-exclusive method hard to achieve in an elegant fashion? It seems like the above behavior would limit having unique event handlers for click/double click/triple click.
...
My only issue is that requiring users to figure out their own single/double/triple click events and injecting them would lower the usability of the library. If you wiki'd your code in determining single/double/triple clicks, it wouldn't be so bad to require injection of these events. Also, is your code exclusive? Do you detect a double click before a triple click? (not desired!)
I'm feeling a little at a loss as how to manage this. I apparently must intercept all events reaching the button and time them manually to determine if a single- or multi-click has occurred?
I'd be grateful for any suggestions.
- CrazyEddie
- CEGUI Project Lead
- Posts: 6760
- Joined: Wed Jan 12, 2005 12:06
- Location: England
- Contact:
The situation is as described in that quoted post, and for the reason given by Jamarr. We can't inhibit the generation of events earlier in the sequence based on the possibility that there might be a further event later - if we did do that, and the timeouts were set to relatively long periods, it's possible to have over a second of latency before you ever get a notification for a basic click.
Questions: if a click is down-up and a double click is down-up-down how can you possibly know at the time of the 'up' whether there will be a subsequent 'down'? How long are you supposed to wait before deciding the second 'down' is not coming? Do you think such latency would be acceptable to most people?
I'm not sure what to suggest beyond implementing in your own event handling the exact same mechanism you'd want us to implement internally (and in doing so, demonstrating all the difficulties that come with it ).
CE.
Questions: if a click is down-up and a double click is down-up-down how can you possibly know at the time of the 'up' whether there will be a subsequent 'down'? How long are you supposed to wait before deciding the second 'down' is not coming? Do you think such latency would be acceptable to most people?
I'm not sure what to suggest beyond implementing in your own event handling the exact same mechanism you'd want us to implement internally (and in doing so, demonstrating all the difficulties that come with it ).
CE.
Useful Links: Forum Guidelines | Documentation | Tutorials | HOWTO | Videos | Donate to CEGUI | CEGUI Twitter
I do see the problem. This seems to be one of those design decisions that has to be taken and that will affect the rest of the system. I will think about solutions, and hopefully report back what I find. I think this is not something only I would consider an important problem/limitation/obstacle and it would be very nice to have an in-library solution for it, perhaps something like an adaptor or whatnot.
I wish I was more knowledgeable about CEGUI so I could say that I would be able to contribute something constructively rather than just sound like a newbie refused his candy though...
Cheers CE
I wish I was more knowledgeable about CEGUI so I could say that I would be able to contribute something constructively rather than just sound like a newbie refused his candy though...
Cheers CE
Mikademus wrote:I do see the problem. This seems to be one of those design decisions that has to be taken and that will affect the rest of the system. I will think about solutions, and hopefully report back what I find. I think this is not something only I would consider an important problem/limitation/obstacle and it would be very nice to have an in-library solution for it, perhaps something like an adaptor or whatnot.
I wish I was more knowledgeable about CEGUI so I could say that I would be able to contribute something constructively rather than just sound like a newbie refused his candy though...
Cheers CE
You would probably win a nobel prize for solving this problem. I can't think of a single application or operating system that doesn't behave exactly like this. Now granted, I have obviously not used every application or operating system, but I can't see any other possible way to do it beyond coding in a time machine
It would be ideal if there where two properties in cegui, a delay and max-clicks that could be utilized for such behavior. By default these would be set to 0 and 1 or 2 depending on the element.
For example, you set the delay to .25s and max-clicks to 3. When the first click is registered, instead of fireing the event you put it into a pending event queue. If an additional click is detected within the delay, you increment a click-counter and reset the timer. Once .25s has elapsed, or max-clicks reached, then fire the "MouseClick' event with an additional member on MouseEventArgs that specifies the number of sequential clicks. This way users can add an arbitrary number of sequential click-handlers.
Of course cegui would have to have some kind of event queue such that waiting events can be checked and fired whenever injectTiimePulse() is called. I don't need this functionality myself, nor can I even come up with a good example for using this, but I can conceptually see how it might be useful heh...
For example, you set the delay to .25s and max-clicks to 3. When the first click is registered, instead of fireing the event you put it into a pending event queue. If an additional click is detected within the delay, you increment a click-counter and reset the timer. Once .25s has elapsed, or max-clicks reached, then fire the "MouseClick' event with an additional member on MouseEventArgs that specifies the number of sequential clicks. This way users can add an arbitrary number of sequential click-handlers.
Of course cegui would have to have some kind of event queue such that waiting events can be checked and fired whenever injectTiimePulse() is called. I don't need this functionality myself, nor can I even come up with a good example for using this, but I can conceptually see how it might be useful heh...
The problem is, in either case, you are going to wind up doing something that the user doesn't think should occur.
In the current view, if a user is performing a double click in his mind, he does not want a mouse down, mouse up, and click to occur. The user doesn't generally think of a double click as anything other than an autonomous action.
Of course if you change it to wait for a time out, you confuse the user for the exact seem reason, just with a different noticeable result. If a user is performing a single click in his mind, he does not want a double click or a triple click or an N-click. When there is a delay, he is not going to understand that a one second delay between his input and an action is because the system isn't sure he is making a multi-click.
Both have down sides. There is no way around it.
The best thing to do is to ensure the chain of clicks remain related. For instance, single clicking an entity in a scene selects an entity. Double clicking the entity focuses the camera on it. This is a logical chain.
However, doing something weird such as a single click causes an entity to self destruct and a double click causes an entity to select would not be.
It is 100% a human interfacing problem.
In the current view, if a user is performing a double click in his mind, he does not want a mouse down, mouse up, and click to occur. The user doesn't generally think of a double click as anything other than an autonomous action.
Of course if you change it to wait for a time out, you confuse the user for the exact seem reason, just with a different noticeable result. If a user is performing a single click in his mind, he does not want a double click or a triple click or an N-click. When there is a delay, he is not going to understand that a one second delay between his input and an action is because the system isn't sure he is making a multi-click.
Both have down sides. There is no way around it.
The best thing to do is to ensure the chain of clicks remain related. For instance, single clicking an entity in a scene selects an entity. Double clicking the entity focuses the camera on it. This is a logical chain.
However, doing something weird such as a single click causes an entity to self destruct and a double click causes an entity to select would not be.
It is 100% a human interfacing problem.
LennyH, unfortunately there isn't a Nobel Prize for Clever Algorithms; but you probably meant that to properly solve this we'd need time-travelling capabilities, which wouldn't likely be accepted by the scientific community for a long time since it among other things would void relativity and science as known today.
Anywho, yeah, the problem is unsolvable IF we cannot accept delays. However, I certainly can accept the prise of a, say, 150 millisecond delay between a click and action if the pay-off is a clear distinction between click events. I very much doubt the user will be confused by this.
Therefore I appreciate Jamarr's suggestion. There is already a "disableDoubleClick" (iirc) method for controls, perhaps we could have a similar "delayedEventResolution" method that when turned on inhibits firing of events until after the timeout delay between clicks has been exceeded. (We'd probably also need a disableTripleClick, or setMaxClicks, method to avoid unnecessary delays).
Anywho, yeah, the problem is unsolvable IF we cannot accept delays. However, I certainly can accept the prise of a, say, 150 millisecond delay between a click and action if the pay-off is a clear distinction between click events. I very much doubt the user will be confused by this.
Therefore I appreciate Jamarr's suggestion. There is already a "disableDoubleClick" (iirc) method for controls, perhaps we could have a similar "delayedEventResolution" method that when turned on inhibits firing of events until after the timeout delay between clicks has been exceeded. (We'd probably also need a disableTripleClick, or setMaxClicks, method to avoid unnecessary delays).
LennyH wrote:It's an unsolvable problem, in general. For you, specifically, that is a solution. But when dealing with end users, any arbitrary decision pretty much means somebody is going to be unhappy
I totally disagree with you. This is a very well-structured problem and you have two distinct scenarios. On the one hand you have situations that need "raw access" all sub-events (Windows' click-select-click-execute f.i.); then on the other hand you have situations where you need "cooked" events. Both may be called for in the same application.
These two event dispatching modes can both be accommodated in the same framework, the second by activating a modifier on the event queue/dispatch for a control (f.i. as per the suggestion in my post above). It would satisfy BOTH needs. There is nothing to lose and everything to gain by having a general-purpose library allow several operation modes, especially when it won't be against or affect the purpose of the library.
- CrazyEddie
- CEGUI Project Lead
- Posts: 6760
- Joined: Wed Jan 12, 2005 12:06
- Location: England
- Contact:
It's certainly an interesting discussion, if nothing else
Useful Links: Forum Guidelines | Documentation | Tutorials | HOWTO | Videos | Donate to CEGUI | CEGUI Twitter
Who is online
Users browsing this forum: No registered users and 12 guests