I'm trying to figure out the proper use of the SendInput function so I can directly manipulate the cursor on the screen, so for a basic test to see how things work, I made this short snippet that should move the cursor 10 pixels to the right. In theory.
#include <windows.h>
#include <winable.h>
int main()
{
INPUT joyInput;
joyInput.type = INPUT_MOUSE;
joyInput.mi.dx = 10;
joyInput.mi.dwFlags = MOUSEEVENTF_MOVE;
SendInput(1, &joyInput, sizeof(INPUT));
return 0;
}
However, in practice, the SendInput function is either putting my computer to sleep, or at least shutting off my monitors, which is certainly an unwanted effect! Commenting out that line prevents the issue from happening, but obviously I need it to perform the task. What am I doing wrong?
The MOUSEINPUT structure has three members that you aren't initializing - dy, mouseData, and time. Since the documentation doesn't mention default values, I assume the program is free to initially fill those members with whatever junk it wants. You should explicitly set the values to avoid this.
#include <windows.h>
#include <winable.h>
int main()
{
INPUT joyInput;
joyInput.type = INPUT_MOUSE;
joyInput.mi.dx = 10;
joyInput.mi.dwFlags = MOUSEEVENTF_MOVE;
joyInput.mi.dy = 0;
joyInput.mi.mouseData = 0;
joyInput.mi.time = 0;
SendInput(1, &joyInput, sizeof(INPUT));
return 0;
}
Related
I'm trying to make an auto clicker with left and right mouse buttons but each with different delay, I'm quite familiar with lua so I'll try explain something similar in lua.
So in lua you could use a corontine and your function would look something like this...
coroutine.wrap(function()
while (true) do
--some code here
end
end)
But this means is that we could stack them and run 2 loops simultaneously, I want to know if there's a way to do something similar in c++ so I could run 2 loops with different delays
#include <iostream>
#include <Windows.h>
int main()
{
std::cout << "Hello World!\n";
while (true) {
if (GetAsyncKeyState(VK_LBUTTON)) {
Sleep(65); // IF BOTH BUTTONS ARE DOWN THEN DELAY WOULD BE HIGHER
INPUT iNPUT = { 0 };
iNPUT.type = INPUT_MOUSE;
iNPUT.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
SendInput(1, &iNPUT, sizeof(iNPUT));
ZeroMemory(&iNPUT, sizeof(iNPUT));
iNPUT.type = INPUT_MOUSE;;
iNPUT.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1, &iNPUT, sizeof(iNPUT));
}
if (GetAsyncKeyState(VK_RBUTTON)) {
Sleep(200); // IF BOTH BUTTONS ARE DOWN THEN DELAY WOULD BE HIGHER
INPUT iNPUT = { 0 };
iNPUT.type = INPUT_MOUSE;
iNPUT.mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
SendInput(1, &iNPUT, sizeof(iNPUT));
ZeroMemory(&iNPUT, sizeof(iNPUT));
iNPUT.type = INPUT_MOUSE;;
iNPUT.mi.dwFlags = MOUSEEVENTF_RIGHTUP;
SendInput(1, &iNPUT, sizeof(iNPUT));
}
}
}
There are many ways to do that. They fall in 3 categories.
Threads. They are like Lua coroutines but run in parallel instead of scheduled. That simplifies some things but requires extreme care in others. Since C++11 you can use its native threads, that’s easier than using Windows API directly.
Coroutines. As pointed in the comments C++ has those since C++20, but Windows had them since ever: fibers. They work much like Lua coroutines but need a bit more setup.
Action queue. Use a queue ordered on absolute time (not delay) the action should be executed. Instead of calling Sleep and doing stuff afterwards, enqueue the action; at beginning of an iteration, check which queued action should be executed first and sleep just the time remaining to it before executing it (or do some other work until it’s time to execute some queued action).
So I am trying to write a program in c++, which moves mouse cursor as if user moved mouse.
I have something a piece of code, which looks like this:
std::atomic<bool> exit_condition = false;
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> ud(-20, 20);
void move_mouse() {
while (!exit_condition) {
INPUT input;
input.type = INPUT_MOUSE;
input.mi.mouseData = 0;
input.mi.dwFlags = MOUSEEVENTF_MOVE;
input.mi.dx = ud(gen);
input.mi.dy = ud(gen);
SendInput(1, &input, sizeof(input));
std::this_thread::sleep_for(100ms);
}
}
The thing is, when the program reaches this loop, screen starts flickering.
I have second display connected to my laptop through HDMI cable and it gets completely turned off while laptop's display turns on/off every (what I believe) few cycles.
Mouse moves, tho. So the program does what I want, kind of...
Does anyone knows what is going on there? Can you, please, help me to understand the underlying problem?
One more thing, the following code has the same effect:
void move_mouse() {
INPUT input;
input.type = INPUT_MOUSE;
input.mi.mouseData = 0;
input.mi.dwFlags = MOUSEEVENTF_MOVE;
while (!exit_condition) {
input.mi.dx = ud(gen);
input.mi.dy = ud(gen);
SendInput(1, &input, sizeof(input));
std::this_thread::sleep_for(100ms);
}
}
I use MS Visual Studio 2019 on Windows 10 machine to build my "solution". Switching from x32 to x64 build config doesn't work.
_MSC_VER is 784. _MSC_FULL_VER is b78391c. I don't know if it is relevant.
// EDIT:
I fixed flickering by using mouse_event:
mouse_event(MOUSEEVENTF_MOVE, ud(gen), ud(gen), 0, NULL);
But the question remains: why?
When I add input.mi.dwExtraInfo = NULL; and use SendInput flickering still occurs.
What else am I missing?
As Jonathan Potter said that, windows uses the timestamp of events in the input queue to decide when it's time to turn the screensaver or low power mode on and off.
So the problem lies in the time stamp. The solution is to use the system's own time stamp.
The time stamp for the event, in milliseconds. If this parameter is 0,
the system will provide its own time stamp.
You can use memset to initialize SendInput.
memset(&input, 0, sizeof(input));
Or
Add input.mi.time = 0;
Hey I am trying to make my autoclicker only click when I hold left mouse button down.
void clikr()
{
INPUT Input ={0};
int sleepzZz = 1000 / times;
active = false;
system(“cls”);
while(1)
{
if((GetAsyncKeyState(VK_LBUTTON) & 0x8000) != 0)
{
Sleep(sleepzZz);
Input.type = INPUT_MOUSE
Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
::SendInput(1, &Input, sizeof(INPUT))
::ZeroMemory(&Input, sizeof(INPUT));
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
::SendInput(1, &Input, sizeof(INPUT));
}
}
(I typed this out on my phone I’m so sorry 😐 )
Basically the loop cancels it self because it send leftup.
I understand I can bind it to another key but how would I go about getting this to work when I hold leftdown
Please help
Using GetAsyncKeyState or GetKeyState is bad for this case. Here is a quote from MSDN stating that exactly what you are trying to do is not suited to be done with the two functions in combination with SendInput.
This function does not reset the keyboard's current state. Any keys that are already pressed when the function is called might interfere with the events that this function generates.
VERY IMPORTANT: What you should be aiming for is to distinguish between inputs that are not simulated by your program and those that are.
This does not mean you should complicate the heck out of this code and verify input to be legitimate with hooks (More info on this approach in the answers here). You just want to see if an input is generated in your loop or not in your loop.
I came up with this simmilar solution that sadly still uses the two functions because i do not know other ones that will test for input. It is not perfect but its the closest i could get with simple code.
VOID WINAPI ClickLoop()
{
/** wait for any LMB press. */
while ((GetAsyncKeyState(VK_LBUTTON)&0x8000) == 0)
Sleep(1);
INT nCurrKeyState = GetKeyState(VK_LBUTTON);
INT nPrevKeyState;
do
{
INPUT Input;
ZeroMemory(&Input, sizeof(INPUT));
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
SendInput(1, &Input, sizeof(INPUT));
Sleep(0); // how many miliseconds between the clicks.
Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
SendInput(1, &Input, sizeof(INPUT));
// !! Do not set this number too low
// !! Setting it too low might cause infinite loops
// and you cannot stop your clicks at first try.
Sleep(70); // how many miliseconds the click is held.
nPrevKeyState = nCurrKeyState;
nCurrKeyState = GetKeyState(VK_LBUTTON);
if ((GetAsyncKeyState(VK_LBUTTON)&0x8000) == 0)
break;
}while (nCurrKeyState != nPrevKeyState);
}
And in your main you can have something like:
int main()
{
while(TRUE)
{
printf("In click loop...\n");
ClickLoop();
}
return 0;
}
Still, this is not a proper solution but i do not know any other functions for testing keys on windows aside than GetAsyncKeyState and GetKeyState. It also has the downside that you cannot set the time between clicks less than 70~80 ms or you can break it.
I am trying to hold a arrow key down for an uncertain time and release it after this.
Pseudocode:
SendKey(VK_RIGHT, KEY_DOWN);
// Do something
SendKey(VK_RIGHT, KEY_UP)
I use Visual Studio 2012 and Windows 7- 64 Bit.
I already searched a lot of time and tried something like this:
#include <Windows.h>
#include <WinUser.h>
using namespace std;
[...]
INPUT Event = {0};
Event.type = INPUT_KEYBOARD;
Event.ki.dwFlags = 0;
Event.ki.wScan = ::MapVirtualKey(VK_RIGHT, MAPVK_VK_TO_VSC);
Event.ki.time = 2000; // hold 2 sek. ?
Event.ki.dwExtraInfo = 0;
Event.ki.wVk = VK_RIGHT; // (Right-Arrow)
SendInput(1, &Event, sizeof(Event)); // hold
Sleep(1000); // do something (waiting in this case)
Event.ki.dwFlags = KEYEVENTF_KEYUP; // release
SendInput(1, &Event, sizeof(Event));
But this didn't work how expected and I don't know what is wrong.
The key is pressed correctly, but not hold.
Thanks in advance.
According to the documentation, the time field is a timestamp not a duration (see here). The documentation doesn't actually say what format the timestamp is for some reason. I've always just used 0 for this value which lets the system choose the appropriate timestamp.
I also believe you will need to set:
Event.ki.dwFlags = KEYEVENTF_EXTENDEDKEY;
...
Event.ki.dwFlags = KEYEVENTF_KEYUP | KEYEVENTF_EXTENDEDKEY;
for the arrow key codes to work.
Also, like the Captain mentioned, use the appropriate VK_ macros (VK_LEFT). Note that 0x27 is actually defined as VK_RIGHT which may be another issue in your code.
This is probably one of the strangest things I've encountered so far in C++:
while(counter != stop_value)
{
//Part A starting
ip.ki.wVk = VK_RETURN;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.wVk = VK_RETURN;
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
//Part A ending
if (s == 2) counter++;
else counter--;
cout << counter; //for debugging
Sleep(i);
}
Whenever I comment the "Part A"-part away, it works properly; the program sleeps for i seconds, depending on user input. However, as soon as I add the easy way of triggering the return-key again, it makes my whole computer sleep instead (AKA, the screen goes entirely black for i seconds). I've tried googling, but I can't find anything about this.
And, this is only a small part of the code. I have added the INPUT class and everything further up. s is also a user-defined variable, that (in this case) can vary between 2 and 3. If equal to two, the counter's value will be set to 0, and it will increase until it has reached its max value (which is user-defined, and set to stop-value). While using this method, the sleep function works properly, and only the program "pauses" for i seconds. HOWEVER, as soon as a user set s to 3, it will start decreasing from the max value (user-defined) until it has reached its stop-value, which always is equal to zero. When this happens, the screen gets a blackout instead.
I've tried debugging for ages now, and I just can't seem to find the solution... Since the code is way more complex than this, and I'd need to use way more space (which I don't want to), I'll give you some inputs for the variables you can use instead:
Working input: counter = 0; stop_value = 21; s = 2; i = 1000;
Input leading to screen blackout: counter = 20; stop_value = 0; s = 3; i = 1000;
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms686298(v=vs.85).aspx
May as well stick it as an answer :)
Are you setting the type of ip to INPUT_KEYBOARD? and are you using ZeroMemory on the structure prior to use?