Why PostMessage with WM_LBUTTONDBLCLK does not work? - c++

I run this code:
LPPOINT pp = new POINT;
GetCursorPos(pp);
while(1){
PostMessage(GetDesktopWindow(), WM_LBUTTONDBLCLK, 0, MAKELPARAM(pp->x, pp->y));
Sleep(1000);
}
It does not click on the point indicated by the cursor, but opens and closes the Start menu
.Please tell me what's wrong

Sending WM_LBUTTONDBLCLK to an arbitrary window handle or to the desktop will not simulate a mouse click.
You can use SendInput, however, which can simulate a mouse click given screen coordinates (not a window handle, or window or client coordinates). This code will simulate a left-button click at the current cursor position:
INPUT in[2]; // 0 = left dn, 1 = left up
ZeroMemory(in, sizeof(INPUT) * 2);
in[0].type = INPUT_MOUSE;
in[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
in[1].type = INPUT_MOUSE;
in[1].mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(2, in, sizeof(INPUT));
Note that you can also use mouse_event, but SendInput is preferred according to the official documentation on MSDN.

Related

SendInput Coordinates Confusion

I am trying to understand how SendInput() works with mouse input. As an example, I have a dual monitor display. My 2160p monitor is "above" the 1440p primary monitor. I am trying to send mouse input to the bottom right corner of the above 2160 monitor. Unfortunately, the cursor just ends up in the bottom right corner of my 1440p primary monitor instead.
I know that the top left corner of my primary monitor is (0,0), and the bottom right is (2560,1440). From what I understand, all coordinates are in relation to the primary monitor. So shouldn't I just be able to subtract the resolution of the above monitor from the primary one to move to the exact same location on the above?
I have tried both adding and subtracting, but I keep ending up in the bottom corner of the primary monitor.
INPUT input;
input.type = INPUT_MOUSE;
input.mi.dx = (2560 - 3840) * (65536.f / (float)GetSystemMetrics(SM_CXSCREEN));
input.mi.dy = (1440 - 2160) * (65536.f / (float)GetSystemMetrics(SM_CYSCREEN));
input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
input.mi.mouseData = 0;
input.mi.dwExtraInfo = NULL;
input.mi.time = 0;
SendInput(1, &input, sizeof(INPUT));
UPDATE: Here is one of my failed attempts using the RECT structure from GetMonitorInfo. I am probably making some sort of obvious mistake, but I can't figure it out.
DXGI_OUTPUT_DESC output_desc;
output->GetDesc(&output_desc);
MONITORINFOEX info;
info.cbSize = sizeof(info);
GetMonitorInfo(output_desc.Monitor, (LPMONITORINFO)&info);
INPUT input;
input.type = INPUT_MOUSE;
input.mi.dx = (info.rcMonitor.right) * (65536.f / (float)GetSystemMetrics(SM_CXVIRTUALSCREEN));
input.mi.dy = (info.rcMonitor.top) * (65536.f / (float)GetSystemMetrics(SM_CYVIRTUALSCREEN));
input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK| MOUSEEVENTF_MOVE;
input.mi.mouseData = 0;
input.mi.dwExtraInfo = NULL;
input.mi.time = 0;
SendInput(1, &input, sizeof(INPUT));

C++ How Do I Simulate a MouseClick On a BackGround Process?

As The Title Says I want to make a code or a app that runs in the background which clicks repeatedly so far I was only able to make a click code which is
void Click() {
INPUT iNPUTh = { 0 };
iNPUTh.type = INPUT_MOUSE;
iNPUTh.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
SendInput(1, &iNPUTh, sizeof(iNPUTh));
ZeroMemory(&iNPUTh, sizeof(iNPUTh));
iNPUTh.type = INPUT_MOUSE;
iNPUTh.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1, &iNPUTh, sizeof(iNPUTh));
}
int main() {
HWND hhProcess;
hhProcess = FindWindow(NULL, L"ARK: Survival Evolved");
if (hhProcess) {
AllocConsole();
cout << "Process Found!" << endl;
}
while (true) {
if (GetAsyncKeyState(VK_Numpad0) {
Click()
}
}
}
But my problem is that once I start to run it, it clicks on the surface what I want to happen is that it clicks on a background process
I have found myself an answer :) I tried testing some codes myself and tried to use Post Message
PostMessage(hhProcess, WM_LBUTTONDOWN, 0, 0);
Sleep(100);
PostMessage(hhProcess, WM_LBUTTONUP, 0, 0);
everytime i press numpad 6 while the window is not active it punches i thank you guys for helping me find ways even tho sometimes i dont understand it :)
Now My Problem is How do i make it click on a certain coords x,y in the background

Waking up Windows when in AwayMode

I am using the Windows AwayMode to turn off the monitor and audio instead of going into sleep mode. This is working fine. How do I "wake up" the system when an event I want occurs? I can detect the event, but I don't know how to get the monitor back on and the system to appear awake again.
I have tried GetCursorPos() and SetCursorPos() to try move the cursor but that did not work.
I also tried the CreateWaitableTimer() and SetWaitableTimer() but that didn't work either. I set the fResume option to TRUE.
I also tried to turn off AwayMode with the PowerSetRequest() handle and setting it NULL. That also did not work.
I also have tried the SetThreadExecutionState() call with no luck. There is an AwayMode defined here as well. I tried to set that and clear it, but the monitor doesn't come back on.
I found a way to do it using SendInput() with a mouse movement. I also had to use the SetThreadExecutionState() to let the system know that a user is present otherwise it will go back to AwayMode in 2 seconds. Here is the code I used.
// Get the current position to ensure we put it back at the end
POINT pt;
GetCursorPos(&pt);
// Make a mouse movement
// Go to upper left corner (0,0)
INPUT input;
input.type = INPUT_MOUSE;
input.mi.mouseData = 0;
input.mi.dx = 0;
input.mi.dy = 0;
input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
SendInput(1, &input, sizeof(input));
Sleep(5); // Just in case this is needed
// Go to lower right corner (65535,65535)
input.mi.dx = 65535;
input.mi.dy = 65535;
input.mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
SendInput(1, &input, sizeof(input));
Sleep(5); // Just in case this is needed
// Restore to original
SetCursorPos(pt.x, pt.y);
// Now let the system know a user is present
DWORD state = SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED);

Sending Mouse Click to DirectX Game Running as Admin

I have been building a gaming-related program that needs to send simulated input to the game (which is the top window on the screen and runs in fullscreen mode). After some struggling, I finally got mouse movements (cursor drag) and keyboard input working, but for some reason, the game will not respond to simulated mouse clicks.
I have tried the following:
#if TRUE // SendInput works for keyboard simulation and mouse drag, but not clicks:
INPUT mouse = {0};
mouse.type = INPUT_MOUSE;
mouse.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
SendInput(1, &mouse, sizeof(INPUT));
Sleep(100);
ZeroMemory(&mouse, sizeof INPUT);
mouse.type = INPUT_MOUSE;
mouse.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1, &mouse, sizeof(INPUT));
#else // tried this, but it did not work:
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
Sleep(75);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
#endif
The first dilemma I faced was sending the messages in general, but I realized this issue was caused by game process privileges > sending application privileges. After this, I encountered another problem with keypresses only registering on certain game windows/screens, but after some searching, I was able to use scancodes to overcome this. For example:
void SendSpacePress(bool bHardwareLevel){
INPUT space = {0};
space.type = INPUT_KEYBOARD;
space.ki.time = 0;
space.ki.dwExtraInfo = 0;
if(!bHardwareLevel){
space.ki.wVk = VK_SPACE;
}else{
space.ki.wScan = 0x39; // physical keyboard scan code
}
space.ki.dwFlags = bHardwareLevel ? KEYEVENTF_SCANCODE : 0;
SendInput(1, &space, sizeof(INPUT));
Sleep(rand()%25 + 25);
space.ki.dwFlags = bHardwareLevel ? KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP : KEYEVENTF_KEYUP;
SendInput(1, &space, sizeof(INPUT));
}
I have also been able to do mouse movement using INPUT like below:
void PanMouse(){
INPUT mouse = {0};
mouse.type = INPUT_MOUSE;
mouse.mi.time = 0;
mouse.mi.mouseData = 0;
mouse.mi.dwExtraInfo = 0;
mouse.mi.dwFlags = MOUSEEVENTF_MOVE;
mouse.mi.dx = rand()%10 -5;
mouse.mi.dy = rand()%10 -5;
SendInput(1, &mouse, sizeof(INPUT));
}
Now the big problem is the game refuses to register my simulated mouse clicks. I would preferably like a way to send the mouse inputs without having to dive into hooking. (The game has multiple client-side anti-cheat mechanisms, so I would venture to guess that any kind of foreign process hooking or DLL injection would trigger the protection.) From what I have read, I might need to write a custom driver for a simulated hardware mouse so the input comes at the kernel level. Not a preferable option, but if need be, sobeit. (And if need be, can anyone provide helpful information for this? I have never messed around with writing drivers, but there's a first time for everything I suppose.)
TL;DR: What do I need to do to get simulated mouse clicks to register in a game that seems to ignore non-hardware input? (I.e., how can I trick the game into thinking mouse clicks are legitimate similarly to using KEYEVENTF_SCANCODE when simulating keyboard input?)
Instead of sleeping between inputs, you need to inject a pair of mouse inputs together with the time member appropriately set to indicate "how long".
Here's something close to what you want. This will click the current cursor position with the left mouse simulated for 100ms.
INPUT inputs[2] = {};
inputs[0].type = INPUT_MOUSE;
inputs[0].mi.time = 0;
inputs[0].mi.dx = 0;
inputs[0].mi.dy = 0;
inputs[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
inputs[1].type = INPUT_MOUSE;
inputs[1].mi.time = 100;
inputs[1].mi.dx = 0;
inputs[1].mi.dy = 0;
inputs[1].mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(2, inputs, sizeof(INPUT));
The mouse event won't happen immediately. It gets "queued" to happen shortly afterwards.
You should use the same technique for your keyboard events. Don't call "Sleep".

Send "button pressed" message to UnityWndClass

I have 3D game and i need to press buttons in this game from another application. Spy++ says that window of the game is UnityWndClass. When i pressing buttons in game, window recives only mouse messages like WM_SETCURSOR, WM_LBUTTONDOWN etc, but when i try to send WM_LBUTTONDOWN and WM_LBUTTONUP with coordinates of the button from another window nothing happend. Why? Any ideas how to press buttons?
WM_SETCURSOR is for changing the cursor image of your own window. WM_LBUTTONDOWN and WM_LBUTTONUP are notification messages sent after mouse click. WM_LBUTTONXXX messages are probably not handled by the main Window procedure.
To fake mouse input, you can use mouse_event or SendInput. For example, this moves cursor to x=10 / y=10 and and clicks left mouse.
int x = 10 * 65536 / GetSystemMetrics(SM_CXSCREEN);
int y = 10 * 65536 / GetSystemMetrics(SM_CYSCREEN);
mouse_event(MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE, x, y, 0, 0);
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
Or use SendInput for multiple calls (see comments)
INPUT input[3];
for (int i = 0; i < 3; i++)
{
memset(&input[i], 0, sizeof(INPUT));
input[i].type = INPUT_MOUSE;
}
input[0].mi.dx = x;
input[0].mi.dy = y;
input[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE;
input[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
input[2].mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(3, input, sizeof(INPUT));
Window should be at least visible and preferably be active. You can use SetForegroundWindow. See this example to make sure window is visible and active.
Other alternatives:
Use Spy++ to get information about the button which you want to press.
For example, if this was Windows Calculator, you can spy on calculator's buttons, it shows calculator button 2 has ID set to 0x84. You can send WM_COMMAND with WPARAM set to 0x84 to simulate button press.
HWND hwnd = FindWindow(0, L"Calculator");
if (IsWindow(hwnd))
{
//this should put "234" in to calculator's edit box
SendMessage(hwnd, WM_COMMAND, 0x84, 0);
SendMessage(hwnd, WM_COMMAND, 0x85, 0);
SendMessage(hwnd, WM_COMMAND, 0x86, 0);
}