I have a problem with my mouse. Every now and then it will double click when I only single click. I know this is a problem with the mouse, and I've contacted the manufacturer, still waiting for a reply. But in the meantime I was wondering if there was a way that I could find out when the left mouse button had been clicked twice within a very short period (probably 1-10 milliseconds) of time, and disable the second click.
I mostly know how to use hooks, so that's not the problem, my main question is how to stop an event from happening, if that's possible.
The information on how to prevent the mouse message from being processed is in the documentation of the "LowLevelMouseProc callback function" in MSDN:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644986(v=vs.85).aspx
Specifically, it says: "If the hook procedure processed the message, it may return a nonzero value to prevent the system from passing the message to the rest of the hook chain or the target window procedure." So, if you know about windows hooks, you know how to do it.
EDIT: Actually, now that I think more about it, you don't want to discard any event. You simply want to transform the doubleclick event into just another left-button-down event. I believe you can do it from within the hook handler, and it will work. Have you tried it?
In C#'s WinForms, you write an event handler involving the mouse receiving a MouseEventArgs object. Inside it, you can access certain info such as the number of times it was clicked, for example.
protected void RowClicked(object sender, MouseEventArgs evt)
{
// Trigger it when the mouse was clicked only once
if( evt.Button.Clicks == 1 ) {
// ... more things ...
}
return;
}
Other GUI libraries have other possibilities. That said, your problem has nothing to do with GUI libraries. You have to change the sensitivity of your mouse, in the configuration options of your operating system. For example, in the Windows' control panel, you can change how much time has to pass between a click and another one to be considered a doble-click. In lUbuntu, you can do the very same, in System menu >> Preferences >> Keyboard and Mouse.
Related
I have a paper-button with the on-tap function that opens a paper-dialog that contains a "Accept" paper-button that will close it when clicked.
The problem i'm getting is if depending on my screen resolution, and the dialog's "Accept" button is over the initial button to open the dialog, when clicked, the dialog opens and closes. I'm assuming the on-tap event is being fired to both.
I've tried these 2 methods but they do not seem to help.
event.cancelBubble = true;
event.stopPropagation();
The problem is that a capacitive screens or even mouses can generate multiple tap event on the same spot within a few milisec.
The mouses because a quick change in a high and low voltage (logical 1 and 0) generating an AC signal wich can jump trough on a capacitator (which can be the button two contactor between the air) if the conditions matching. But the onclick event is already catching this case and you does not require to do anything to solve it.
The capacitve screens are capacitators and just rolling your finger should trigger multiple tap events because your skin has different depth of insulation and hard to mark the tap begin and end in some cases.
This physical problem should be solved by the platform, but it is not in every situation currently (but most of the devices are filtering this). Im usally solving this isse with a transparent overlay element wich can catch the pointer events for a little duration so I could catch the "prelling" of a button or the capacitive screen for a few ms.
If a 10-20ms is enough for you then wait a frame in your on-tap function with requestAnimationFrame and then show the dialog. Cheap trick, but it does what it has to, but ultimately you can wait a fix timeout to show the dialog, because you have 100ms to respond a user interaction.
You cannot fix this by manipulating the browser events options though because as I know you dont have option to how much time need to pass until the next same event should happend. But if you wait a frame thats could behave like you add a delay between the events.
For a long time I have been wondering how modal dialog is implemented.
Let me take Qt as an example. (Nearly all GUI toolkit has this mechanism)
In the main event loop, a slot is called, and in this slot a modal dialog is opened. Before the dialog is closed, the slot doesn't return control to the main event loop. So I thought that the main event loop is blocked and become unresponsive. Apparently this is not true, since when you open a modal dialog, the background main window is still working, like repainting its UI or keep displaying a curve or some graph. It just becomes not to accept any user input.
I did an experiment. I didn't open a modal dialog in the slot, but start a new thread there, and wait for the thread to finish in that slot. This definitely blocked the main event loop.
How modal dialog is implemented after all? How does it keep main event loop unblocked but at the same time blocked the calling slot?
There is only ever a need for a single event loop, and it does not block when a modal dialog appears. Though, I suppose, different toolkits may handle this differently. You would need to consult the documentation to know for sure. Conceptually, however, it all works in the same way.
Every event has a source where the event occured. When a modal dialog appears, the event loop either ignores or redirects all events that originate outside of the dialog. There's really no magic to it. Generally speaking, it's like an if statement in the event loop code that says "if (modal_is_shown() and !event_is_in_modal_window()) {ignore_and_wait_for_next_event()}". Of course, the logic is a bit more complicated, but that's the gist of it.
If you're looking for examples here's another one:
In Tk, there is only ever one event loop. Modal behavior (doesn't have to be dialog, can also be tooltips, textbox etc) is simply implemented by making the main window ignore mouse and keyboard events. All other events like redraws etc. can still be serviced because the event loop is still running.
Tk implements this via the [grab] function. Calling grab on a UI object makes it the only object able to respond to keyboard and mouse events. Essentially blocking all other objects. This doesn't mess with the event loop. It merely temporarily disables event handlers until the grab is released.
It should be noted that Unix-like operating systems running X also has grab built in to the windowing system. So it's not necessarily implemented merely by UI toolkit libraries but is sometimes also a built in feature of the OS. Again, this is implemented by simple blocking/disabling of events instead of instantiating separate event loops. I believe this also used to be the case for the older MacOS before OSX. Not sure about OSX or Windows though. Even though modality is often implemented by the OS itself, toolkits like Qt and Tk often implement their own mechanisms to standardize behaviors across different platforms.
So the conclusion is, it is not necessary to block the main event loop to implement modality. You just need to block the events and/or event handlers.
The answer by https://stackoverflow.com/users/893/greg-hewgill is correct.
However, reading the follow-up discussion between him and https://stackoverflow.com/users/188326/solotim , I feel that there is room for further clarification, by means of prose and some pseudo-code.
I'll handle the prose part with a fact-list:
The main message loop does not run until the modal activity is finished
However, events are still delivered while the modal activity is running
This is because there is a nested event loop within the modal activity.
So far I just repeated Greg's answer, please bear with me as it is for continuity's sake. Below is where I hope to contribute additional, useful info.
The nested event loop is part of the GUI toolkit, and as such, it knows the callback functions related to every window in existence
When the nested event loop raises an event (such as a repaint event directed to the main window), it invokes the callback function associated with that event. Note that "callback" here may refer to a method of a class representing a window, in object-oriented systems.
the callback function does what is needed (e.g., repaint), and returns right back to the nested message loop (the one within the modal activity)
Last, but not least, here's pseudo-code to hopefully illustrate further, using a fictitious "GuiToolkit":
void GuiToolkit::RunModal( ModalWindow *m )
{
// main event loop
while( !GuiToolkit::IsFinished() && m->IsOpen() )
{
GuiToolkit::ProcessEvent(); // this will call
// MainWindow::OnRepaint
// as needed, via the virtual
// method of the base class
// NonModalWindow::OnRepaint
}
}
class AboutDialog: public ModalWindow
{
}
class MainWindow: public NonModalWindow
{
virtual void OnRepaint()
{
...
}
virtual void OnAboutBox()
{
AboutDialog about;
GuiToolkit::RunModal(&about); // blocks here!!
}
}
main()
{
MainWindow window;
GuiToolkit::Register( &window ) // GuiToolkit knows how to
// invoke methods of window
// main event loop
while( !GuiToolkit::IsFinished() )
{
GuiToolkit::ProcessEvent(); // this will call
// MainWindow::OnAboutBox
// at some point
}
}
In general, a modal dialog box of this type is implemented by running its own message loop instead of your application's message loop. Messages directed to your main window (such as timer or paint messages) will still get delivered, even during the modal operation.
In some situations, you may have to be careful that you don't recursively do the same thing repeatedly. For example, if you trigger a modal dialog box on a timer message combined with some persistent flag, you'll want to make sure you don't keep bringing up the same dialog box repeatedly whenever the timer message fires.
I need to capture the event that an app throws when you click on the screen, on a list. When I click on the screen, actionPerformeed(ActionEvent e) returns -1, I suppose that it is the default event.
In non-touch devices, the launched event by pressing the central button is Canvas.FIRE, why not in tactile devices?
How can I do that?
The actionEvent source argument will be from the list. Action events are designed to encapsulate the trigger for the action (e.g. key/touch) since that is irrelevant. There is no need to distinguish the trigger since you can always extract the lists selected item and use that.
There are use cases where one would like to know the location touched within the cell renderer but that is a special case unrelated to the question.
As you can see in my previous question, I am currently struggling with single and double click events – I wanted to perform an action after a click and a completely different action after a double click. The problem is that the low-level events only tell me things like this was a mouse down or this was a mouse up and the total click count is == 2. It’s hard to discriminate between a single and a double click this way, since when the mouse comes up after a single click, I have to wait a while to make sure there’s not a second click coming.
Now I am wondering how different GUI toolkits handle this, as there’s no magical way around. You can’t have separate high-level single-click and double-click events without having the single-click event delayed or something, can you?
(It looks like the usual way to solve this is to have the single and double click actions related, like selection on the first click and app launch on the second. That way it does not matter that the single-click action is triggered along with the double-click one. Am I right?)
You always need some sort of timer to distinguish between single and double click. Think about it: you cannot predict whether a second click will happen once the first occurred, you just have to wait and see.
On iOS, you can have gesture recognizers. And if you only register a single tap recognizer it fires right away, but as soon you also register a double tap recognizer you notice that a single tap doesn't fire right away but only after a noticeable delay. Made me change to a a single tap with two fingers in one app because the delay is really annoying.
You could work around the delay if your single click action is undoable or cancelable: do the action when click count == 1, and if click count == 2, revert the action of the single click. Might result in undesired/unexpected UI behavior, though (from a user perspective).
In MFC a double-mouse click event triggers the following sequence of messages
WM_LBUTTONDOWN
WM_LBUTTONUP
WM_LBUTTONDBCLK
WM_LBUTTONUP
So responding to the WM_LBUTTONDBCLK message allows you to detect a double-click. But if I just want to detect a single-click how to I distinguish it?
But just looking at the WM_LBUTTONUP message isn't enough as it could be a single-click or it could be the first click of a double-click.
How can I successfully identify just a single-click?
(Please allow me to call these events Mouse Up and Mouse Down. My MFC is a little rusty. And there's this stuff called .NET who's been messing up my terminology lately ;-)
Short story: You don't simply want to know about Mouse Click. You need more.
Long story:
Although this is counter-intuitive, it appears that simply wanting a mouse-click is fairly uncommon. Most often, you'll want to perform some processing on Mouse Down and do some further processing on Mouse Up. The trick is that simply tracking Mouse Up messages is not enough: Mouse Down may not have happened in your window. Do you consider it a valid click then? Especially considering that the Mouse Down processing (such as selecting an item) did not occur.
Going further up the reasoning, you should not rely on receiving a Mouse Up after you processed Mouse Down: User may have moved the mouse and released the button somewhere else (think drag'n'drop), in which case, you don't receive the MouseUp event... unless you capture the mouse on MouseDown to make sure you get mouse event up to Mouse Up even if the mouse left your window.
All in all, you end up tracking Mouse Down, capture the mouse and when you receive Mouse Up, just check if you own the capture. If not, the mouse was either double-clicked (no 2nd mouse down) or Mouse Down happened somewhere else hence you most likely don't care about this Mouse Up.
In conclusion: There's no MouseClick message simply because you wouldn't go very far with it: You need to handle more messages and implement more mechanics anyway.
Oh! And if your dealing with an existing control which already handles all this items and selection stuff, such as a listview, chances are it provides with a similar custom notification such as Item Activate or Item Selection Changed.
I just tried this in Delphi, the behavior is the same: even when a double click is happening, a single click event is issued right after the first one of the two.
I solved it using a timer, which works like this:
deactivate timer on WM_LBUTTONDBLCLK (and set bDbl to true)
activate timer on WM_LBUTTONUP if bDbl==false
deactivate on WM_LBUTTONUP if bDbl==true (and reset bDbl)
I set the interval of the timer to the time returned by GetDoubleClickTime.
MSDN says:
The GetDoubleClickTime function
retrieves the current double-click
time for the mouse. A double-click is
a series of two clicks of the mouse
button, the second occurring within a
specified time after the first. The
double-click time is the maximum
number of milliseconds that may occur
between the first and second click of
a double-click.
If the timer happens to fire then you have the real click. In my case the double click interval is 500ms, so any "real click" will be delayed this long.
You could check WM_LBUTTONDOWN has not been called more than once before WM_LBUTTONUP. In practice Windows does this for you, in that if you get a WM_LBUTTONDBCLK you tend not to get a WM_LBUTTONUP.
You can use PreTranslateMessage() to count the messages as they appear. If you've received only the mouse messages corresponding to a single-click, and the system-configured time for double-clicking has expired, you can safely assume it's a single-click.
As far as I know there is no way to know that this is the case as it is happening, which makes sense -- until the time is expired, there's no way to know that a second click is or isn't coming.
that's a little tricky.
I would detect the WM_LBUTTONDOWN & WM_LBUTTONUP combo, store that event somewhere and set a timeout for a second or so. If there isn't a WM_LBUTTONDBCLK during that timeout then you have a single click.
This might imply you need to have another thread running but I think you could accomplish it with one thread.
I think the solution is to start a timer after the first click & then check the elapsed time after at the next immediate click, this will tell you if it is a single click or double click.
You typically look at #MLButtonUp and you would not have single click and double click behavior on the same mouse button.