Move mouse cursor without triggering a WM_MOUSEMOVE - winapi

I want to trap the mouse in the middle of the window (like in an FPS game) using SetCursorPos.
The problem is that when I do, my window receives a WM_MOUSEMOVE -- which at best cancels out any movement that the user intended, and at worst enters a feedback loop.
I've considered reading the position using GetCursorPos and ignoring the message if it's the same as where I'd moved it with SetCursorPos. The problem with this approach though is that the mouse is asynchronous. If the program ever gets behind, then GetCursorPos will return a value different from what I'd expected -- and so it won't know to ignore the message.
Is there a good way to deal with this problem?

This sort of input should be done with the RawInput API and the cursor hidden when you app has focus. This means it is not bounded by the screen and you don't actually deal with the mouse events.

Related

How to track mouse movements without limiting it to screen size?

I'm using WM_MOUSEMOVE to get changes in mouse position. When simulating "knobs" for example it's desired to let the user go up/down with mouse without any limits. In this cases I hide cursor and use SetCursorPos to change its position every time user moves with it and detect just the difference from the original position.
Unfortunately it doesn't seem to work - if I set the mouse position, it sometimes works, but sometimes is one or more pixels away, which is just wrong. And even bigger trouble is that after the call another WM_MOUSEMOVE seems to be delivered, which unfortunately does the same thing as it wants to move the cursor back to the original position again. So it ends up in an infinite cycle or settings mouse position and receiving messages until the user releases the mouse button.
What's the correct approach or what's the problem?
The raw input system can do this - it lets you register for raw mouse input that isn't clipped or confined to the screen boundaries.
Broadly speaking, you register for raw input using RegisterRawInputDevices(). Your window will then receive WM_INPUT messages, which you process using the GetRawInputData() function.
See Using Raw Input for an example.
I hide cursor and use SetCursorPos to change its position every time user moves with it and detect just the difference from the original position.
This is just plain wrong. Instead, use SetCapture() to capture the mouse. All movements will be reported as WM_MOUSEMOVE messages with coordinates that are relative to the specified window, even if the mouse is outside of that window, until you release the capture.
Asking the user to move the mouse continuously, even after the cursor hit the screen limit is a very bad idea in terms of User Interface, IMHO.
Some games have another approach: when the mouse hit the "limit", the game enter a special mode: things appears to function exactly as if the mouse was moving, even if the user don't move it. When the user wants to exit that mode, he just has to move the mouse of the limit.
Doing so requires a timer, armed when the mouse hit some limit, executing code periodically as if the mouse was moving. The timer is stopped when a real mouse movement makes it leaves the limit.
Ok folks, so I found a solution simple enough:
The main problem is that SetCursorPos may not set the coordinates accurately, I guess it's because of some high resolution processing, nevertheless it's probably a bug. Anyway if SetCursorPos doesn't set the coordinates correctly (but +-1 in x and/or y) it also sends WM_MOUSEMOVE to the target window. As a result the window performs the exact same operation as before and this goes on and on.
So the solution is to remove all WM_MOUSEMOVE messages right after SetCursorPos:
MSG msg;
while (::PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE)) { };
Then retrieving the current mouse cursor pos using ::GetCursorPos .
It's ugly but seems to fix the problem. It basically seems that in some position of the mouse, the system always adds or subtracts 1 in either coordinate, so this way you let system do the weird stuff and use the new coordinates without trying to persuade system that your coordinates are the correct ones :).

Fool the target app's HWND into thinking mouse moved

I am trying to emulate simple mouse movement in a window belonging to another process. My app uses global hooks to inject DLL into the target process (WH_CBT and WH_GETMESSAGE) and the injection works like a charm. The intention is to fool the target process into thinking the mouse went over a portion of the screen. When I do a movement with the physical mouse, this triggers a certain app behavior (e.g. a tooltip is being shown). I would prefer if the actual mouse pointer remained in its current position when I perform the "trick".
I have established message monitoring with Spy++. Sending (or posting) plain WM_MOUSEMOVE messages to the target HWND is registered by Spy++ but has no desired effect. When the mouse is physically moved, the app does its thing. I have tried sending some other messages in conjunction to WM_MOUSEMOVE (e.g. WM_SETCURSOR) but things didn't improve. I have even hijacked GetCursorPos in the target process to return the same coordinate as posted in WM_MOUSEMOVE (former is screen, latter is client) but this didn't help either.
When I do a simple SetCursorPos, the app does what it's supposed to do. What other magic am I missing that the SetCursorPos is doing? The messages captured by Spy++ look more or less the same in both scenarios.
Any suggestions on how to send mouse movement are welcome. I do not want to use SendInput, mouse_event or other APIs. I need to target a specific HWND for a very brief period of time.
Usually a tooltip is shown as a result of the WM_NOTIFY message, which is sent with the TTN_SHOW notification code. Have you tried it?

How does a GUI Framework work?

I have been all over the web looking for an answer to this, and my question is this:
How does a GUI framework work? for instance how does Qt work, is there any books or wibsites on the topic of writing a GUI framework from scratch? and also does the framework have to call methods from the operating systems GUI framework?
-- Thank you to any one who takes the time to try to answer this question, and forgive me if i misspelled anything.
In the old days we did a lot of GUI programming from scratch. It is not as hard as it seems, but it requires a few weeks to come with results.
First you need a good drawing library. Minimal functionality for this library is drawing clipped rectangles (using patterns), lines, bitmaps, and fonts. You can cheat by creating fonts as bitmaps, and clipped rectangle is just a bunch of horizontal lines.
Now you need at least drivers for mouse, keyboard, and timer (if not already provided by the operating system). In general, you will need to detect keys, symbol keys (such as shift, etc.), mouse moves and mouse clicks. Basic timer functions will allow you to detect double clicks.
Then you need to create a window data structure. This data structure needs to have coordinates i.e. a rectangle, link to parent window (if not top window), and window function i.e. the function that will be called when this window should handle some events.
Once you can draw on screen you need some rectangle algebra functions. You need at least good function to calculate intersection of rectangles, and a quick resolution of relative to absolute coordinates. For example - if your child window has parent then its' x and y should recursively be added to parent x and y until you reach top window.
At this point you have your:
- primitive graphical functions,
- window structure,
- mouse driver, keyboard driver, and timer,
- rectangle arithmetic.
Now you can write your main event harvesting function. This function will run all the time. It's purpose will be to detect events and send messages to correct windows. What is an event? Well, when you start your program, store mouse x and y coordinates. Then in a loop check if they have changed. If they have changed, find the window at that position ... and send WM_MOUSEMOVE event to it. Your harvesting function should handle:
- mouse moves
- mouse clicks
- mouse double clicks (remember last click and position, measure time and decide if it is a double click or not)
- timer events
- keyboard buffer changes
...
Now you should be able to send events to windows. But you really need a mechanism for it. It is a combination of message queue, and window procedure. It usually works like this: each window has a window procedure which commonly accepts four arguments: message id (i.e. is it mouse move, is it paint message), window handle, parameter 1 and parameter 2. You can call this window procedure directly using something like a send_message functions. Or you can send this window a message via post_message function. This will put message to the queue and window will process messages one by one, eventually receiving this one. So why should you call one messages directly and put others to the queue? Because of priority. You see, a keyboard click can wait some time before being processed. But a window redraw must complete immediately to prevent flicker and wrong data on screen.
So your harvest_events function sends messages to windows using post_message, and send_message. And your window message pump gets them using typical message pump like this:
while (pmsg = get_message() != NULL) send_message(pmsg->id, pmsg->hwnd, pmsg->p1, pmsg->p2);
get_message simply obtains message from the queue, and calls send message. Simple, huh? Well, not quite so. This way you would only receive driver messages to windows, but you also need some functions to redraw windows, move them, etc.. When you create move_window function, resize_window, show_window, and hide_window function, your window coordinates will change. Parts of other windows will be uncovered (if top window is moved or closed).You need to calculate which windows are affected by coordinate changes and send paint message to those windows (to repaint only the parts that were uncovered - remember, you have clipping drawing functions so this will work).
These functions introduces messages msg_paint, msg_move, msg_resize, msg_hide...
Last, you need to maintain hierarchy of windows. Your top window should be the desktop. It should have child windows (application top windows). These windows may have further child windows (buttons, edit boxes, etc.) The obvious structure for holding these is the window tree. When you detect mouse click you have to traverse window tree and do it in a smart way (finding out who has focus, who is modal, etc.) to send message to the right window. And when you draw you also must traverse all children to see who is uncovered and who is not. Last but not least, you need to handle mouse rectangle as top window to prevent flickering the mouse as windows are re-drawn or (using timers and msg_paint events) animated.
That's roughly it.
A GUI framework like Qt generally works by taking the existing OS's primitive objects (windows, fonts, bitmaps, etc), wrapping them in more platform-neutral and less clunky classes/structures/handles, and giving you the functionality you'll need to manipulate them. Yes, that almost always involves using the OS's own functions, but it doesn't HAVE to -- if you're designing an API to draw an OpenGL UI, for example, most of the underlying OS's GUI stuff won't even work, and you'll be doing just about everything on your own.
Either way, it's not for the faint of heart. If you have to ask how a GUI framework works, you're not even close to ready to design one. You're better off sticking with an existing framework and extending it to do the spiffy stuff it doesn't do already.

Win32 WM_SETCURSOR, WM_MOUSEMOVE always in pair?

I'm working on a Win32 control. There could be hundreds of "items" on this control. Those are not windows, but internal objects (eg: rectangles). Depending on the mouse position I want to change the mouse cursor. That is fine, I can use WM_SETCURSOR.
At the same time based on mouse move I want to display a status bar which shows details about the object currently under the mouse. For that I can use WM_MOUSEMOVE.
Because there could be hundreds of items, traveling all of them to find one under the mouse, well it's not efficient, especially two times (one for set cursor, one for mouse move).
To make it short, do you know if WM_SETCURSOR and WM_MOUSEMOVE are ALWAYS in pair? In that case I can calculate what I want during WM_SETCURSOR. The other option would be to set the mouse cursor during WM_MOUSEMOVE, but as far as I know that it's not a good solution (will flicker).
Thanks
While they might currently always come as a matched pair, you probably can't rely on this behaviour.
You can set the cursor during WM_MOUSEMOVE (using SetCursor), and it won't flicker, as long as (IIRC), you return TRUE from WM_SETCURSOR without doing anything (i.e. you eat the message), and your window doesn't have a class cursor assigned to it.
You might also try GetMessagePos() (gives cursor screen coordinates), then MapWindowPoints() and see if it's in hot rectangle, or something similar.
Most important of all is that your window message handlers shouldn't worry about holding or calculating anything. You should simply signal your application's logic that the mouse is potentially over new area and make it find the object(s). Once you find the hot area (or more than one), cache its (their) boundaries and check the following mouse moves against those. Once the mouse moves out from one of them, you can rebuild your hot-object-list.
You don't have to be hunting for the hot area all over the control on every mouse move.
In case when there can be many objects sharing the same area, there's the question of z-order. Think about it when you're creating those objects and handle their movement.
Also you should think about an efficient data structure holding the object coordinates so you don't have to check every single object every time you're looking for the hot one.
Just my two euros. ;)
Is there any way to cache the last item that was found, and shortcut the lookup if the cursor is in the same place? That would be the most robust solution.

Detecting a single mouse click in MFC

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.

Resources