my mouse not click on anything
That is to be expected. The code is passing 0
as the recipient of SendMessageW
, which isn't a valid window handle. With proper error handling this would have been easy to see:
int main() {
::SetLastError(0);
auto const result = ::SendMessageW(0, WM_LBUTTONDOWN, 0, 0);
if (result == 0) {
auto const err = ::GetLastError();
if (err != ERROR_SUCCESS) {
printf("SendMessageW failed: %u\n", err);
}
}
}
When executed, this program prints the following:
SendMessageW failed: 1400
Error code 1400 has the symbolic constant ERROR_INVALID_WINDOW_HANDLE
, and translates to "Invalid window handle." Precisely what one would expect, when passing an invalid window handle.
Now that you know what's wrong, it would be tempting to fix the immediate issue, and continue down that route. But that's not going to work. As we all (should) know (by now): You can't simulate keyboard input with PostMessage. The same principles apply to mouse input, and exchanging PostMessage
with SendMessage
merely makes sure that the calling thread stops making forward progress when the destination thread hangs. Replaying input is not the same as reprocessing it covers more issues you'll invariably run into when pursuing a solution that isn't.
What you'll want to do instead depends on the ultimate goal. If the question is to be taken at face value, assuming that it doesn't conceal any additional requirements, the solution is to synthesize input using the SendInput
API:
int main() {
::Sleep(2000);
// Inject "mouse click" using `SendInput`
INPUT inp[] = { { .type = INPUT_MOUSE, .mi = { .dwFlags = MOUSEEVENTF_LEFTDOWN } },
{ .type = INPUT_MOUSE, .mi = { .dwFlags = MOUSEEVENTF_LEFTUP } } };
constexpr auto count = ARRAYSIZE(inp);
auto const result = ::SendInput(count, inp, sizeof(INPUT));
if (result == 0) {
auto const err = ::GetLastError();
printf("SendInput failed: %u\n", err);
}
}
There are a few details here that aren't immediately obvious:
- The
INPUT
structures are zero-initialized except for the fields explicitly named (this is using C++20 designated initializer syntax, just because lengthy sequences of 0,
don't cut it for readability).
- Since the
MOUSEEVENTF_ABSOLUTE
flag isn't set, the mouse input event is injected using the current mouse position.
- A "mouse click" consists of two input events: Mouse down, followed by mouse up.
SendInput
is an improved version of mouse_event
, that allows injecting multi-event input as an atomic operation, so they won't get interspersed with events from other input sources. Is it a bug to pass a single-element array to SendInput? covers the details.
As far as the system is concerned, injected input is treated no different from input generated by a physical input device. In case of a "mouse click at the current mouse cursor position" the consequence is, that the window under the current mouse position becomes the foreground window, and the previous foreground window loses foreground activation.
If that is not something you want, your only other option (ignoring custom automation interfaces) is to use UI Automation.
If the ultimate goal is to cheat a game into thinking that you totally rock, then that's a whole different challenge. I covered the complexities involved previously here.