I want to make a program that can catch keyboard events even if it's not active on any moment. Hooks were too complicated with all the things I have to do to make it to work (making a DLL, reading it, etcetera) so I decided to go on using hotkeys.
But now I have a problem. Registering the hotkey disables the key on the keyboard, thus I can only send the key to the program, while I can't type on any other program (e.g. Notepad).
This is my code:
#include <iostream>
#include <windows.h>
using namespace std;
int main(int argc, char* argv[]) {
RegisterHotKey(NULL, 1, NULL, 0x41); //Register A
MSG msg = {0};
while (GetMessageA(&msg, NULL, 0, 0) != 0) {
if (msg.message == WM_HOTKEY) {
cout << "A"; //Print A if I pressed it
}
}
UnregisterHotKey(NULL, 1);
return 0;
}
// and now I can't type A's
Is there any simple solution to this problem?
Thank you
I would let your program simulate a keypress which equals the one you actually performed. That means:
You press 'A'.
The program catches the 'A'.
The program simulates the keypress.
It's quite simple. The only problem would be that your program would also catch the simulated keypress. To avoid it, you can do the following:
You press 'A'.
The program catches the 'A'.
The program unregisters the hotkey.
The program simulates the keypress.
(The program does not (!) catch the 'A'.)
The program registers the hotkey again.
That's the whole loop.
Now, to simulate the keypress, you need to add some additional code. Have a look at this:
#include <iostream>
#include <windows.h>
using namespace std;
int main(int argc, char* argv[]) {
RegisterHotKey(NULL, 1, 0, 0x41); //Register A; Third argument should also be "0" instead of "NULL", so it is not seen as pointer argument
MSG msg = {0};
INPUT ip;
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0;
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
ip.ki.wVk = 0x41; //The key to be pressed is A.
while (GetMessage(&msg, NULL, 0, 0) != 0) {
if (msg.message == WM_HOTKEY) {
UnregisterHotKey(NULL, 1); //Prevents the loop from caring about the following
ip.ki.dwFlags = 0; //Prepares key down
SendInput(1, &ip, sizeof(INPUT)); //Key down
ip.ki.dwFlags = KEYEVENTF_KEYUP; //Prepares key up
SendInput(1, &ip, sizeof(INPUT)); //Key up
cout << "A"; //Print A if I pressed it
RegisterHotKey(NULL, 1, 0, 0x41); //you know...
}
}
UnregisterHotKey(NULL, 1);
return 0;
}
I tried it and it works fine, I guess.
Hope I could help ;)
Related
so I am trying to make an auto clicker that runs run you hold down the mouse button My current loop looks like However when I run this it just clicks for ever and ever and does not stop when I release the mouse button. Thanks in advance. ps pressed is defaulted as false.
while(GetAsyncKeyState(VK_LBUTTON)&&!pressed)
{
pressed = true;
INPUT Input = { 0 };
// left down
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
::SendInput(1, &Input, sizeof(INPUT
// left up
::ZeroMemory(&Input, sizeof(INPUT));
Input.type = INPUT_MOUSE;
Input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
::SendInput(1, &Input, sizeof(INPUT
cout << "pressed"
sleep_for(milliseconds(100));
pressed = false;
}
First of all, the return value of GetAsyncKeyState has two bits, we only need its highest bit, so we use GetAsyncKeyState(VK_LBUTTON)&0x8000.
Secondly, the signal sent at the end of the loop simulates the operation of the mouse release, so the return value of GetAsyncKeyState() is 0, and you cannot continue to enter the loop to simulate the click operation of the mouse. Therefore, we should first simulate the mouse release operation, and then simulate the mouse click operation, so that the function can be realized normally.
Finally, SendInput() supports multiple operations at a time, we can build an array of INPUT, and then send the required signals at once, so that you can more easily achieve your needs.
Here is the code you can refer:
#include <windows.h>
#include <iostream>
using namespace std;
#define INPUT_COUNT 2
int main(int argc, char* argv[])
{
int pressed = false;
while (true)
{
while (GetAsyncKeyState(VK_LBUTTON) & 0x8000)
{
pressed = true;
INPUT Input[INPUT_COUNT] = { 0,0 };
Input[0].type = INPUT_MOUSE;
Input[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;
Input[1].type = INPUT_MOUSE;
Input[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
::SendInput(INPUT_COUNT, Input, sizeof(INPUT));
cout << "pressed" << endl;
pressed = false;
Sleep(100);
}
}
return 0;
}
I am trying to make a program that when you type "Alt+A" it will write type out a line like "Hello" for example. This is the closest I've gotten:
if (GetAsyncKeyState(65))
{
cout << "worked" << std::endl;
string bind = "Hello";
INPUT Input = { 0 };
Input.type = INPUT_KEYBOARD;
for (int i = 0; i < bind.length(); i++)
{
Input.ki.wVk = VkKeyScanA(bind[i]);
SendInput(1, &Input, sizeof(Input));
}
Sleep(500);
}
It works similar to how I want, but there are some problems that I encountered:
I can't get the Alt key to work. When I use GetAsyncKeyState(18), it runs the "worked" output but it doesn't type out any of the word.
Whenever I press the key bind (for example "A"), it will type that letter as well. Is there any way I can cancel out that key press? I was thinking that I could just make it so that it types the backspace button before the word, but I'm assuming there is a better to go about this.
I also have a problem that the program doesn't type exactly what is put in. It doesn't type capital letters, and it only types one letter if there are two in a row. In the code that I put, it will say "helo" instead of "Hello."
I have made some simple changes to your code, which can basically meet your needs.
But if you need higher functionality, you may need to use RegisterHotKey, and create your window to handle the WM_HOTKEY message.
#include <windows.h>
#include <iostream>
using namespace std;
int main()
{
HWND hwnd = (HWND)0x001E0BF2; //notepad window
SetForegroundWindow(hwnd);
while (1)
{
if (GetAsyncKeyState(18)&0x8000)
{
if (GetAsyncKeyState(65)&0x8000)
{
INPUT keyup_ALT = { 0 };
keyup_ALT.type = INPUT_KEYBOARD;
keyup_ALT.ki.wVk = 18;
keyup_ALT.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &keyup_ALT, sizeof(INPUT));
cout << "worked" << std::endl;
string bind = "Hello";
INPUT Input[2] = { 0 };
Input[0].type = Input[1].type = INPUT_KEYBOARD;
Input[1].ki.dwFlags = KEYEVENTF_KEYUP;
for (int i = 0; i < bind.length(); i++)
{
short ch = VkKeyScanA(bind[i]);
Input[0].ki.wVk = Input[1].ki.wVk = ch;
if (((ch & 0xff00) >> 8) & 0x1)
{
INPUT shift = { 0 };
shift.type = INPUT_KEYBOARD;
shift.ki.wVk = VK_SHIFT;
SendInput(1, &shift, sizeof(INPUT));
}
SendInput(2, Input, sizeof(INPUT));
if (((ch & 0xff00) >> 8) & 0x1)
{
INPUT shift = { 0 };
shift.type = INPUT_KEYBOARD;
shift.ki.wVk = VK_SHIFT;
shift.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &shift, sizeof(INPUT));
}
}
Sleep(500);
}
}
}
}
CHANGES:
Add status check of ALT key;
Make the return value of the GetAsyncKeyState and (&) 0x8000;
Make the ALT key up, to resolve "it runs the "worked" output but it
doesn't type out any of the word."
Check the return value of VkKeyScanA, the high-order byte contains
the shift state, which control the capital letters, then determine whether to send shift key.
As written before, I would like to know how parallel keyboard input works.
This is my code so far:
cout << "Enter time for Key A: ";
cin >> timeA;
cout << "Enter time for Key B: ";
cin >> timeB;
while (1)
{
Sleep(timeA);
INPUT ip;
ip.type = INPUT_KEYBOARD;
ip.ki.time = 0;
ip.ki.dwFlags = KEYEVENTF_UNICODE; // Specify the key as a unicode character
ip.ki.wScan = 'A'; // Which keypress to simulate
ip.ki.wVk = 0;
ip.ki.dwExtraInfo = 0;
SendInput(1, &ip, sizeof(INPUT));
Sleep(timeB);
ip.type = INPUT_KEYBOARD;
ip.ki.time = 0;
ip.ki.dwFlags = KEYEVENTF_UNICODE; // Specify the key as a unicode character
ip.ki.wScan = 'B'; // Which keypress to simulate
ip.ki.wVk = 0;
ip.ki.dwExtraInfo = 0;
SendInput(1, &ip, sizeof(INPUT));
}
It works, but I would like to reach, that e.g. the Letter A is being pressed every 500ms and the Letter B is pressed every 1s. How would I do that?
This is a timer class. You can create an object and call it like:
timer timer_1(time_in_milliseconds, true_if_async, &function_name, argument_1, arg_2, ...);
This way you can run your functions after a certain amount of time has passed, you can run multiple functions together with async as well or just use sync and queue them. Your choice.
Threads is the best solution for your problem.
class timer
{
public:
template <class Callable, class... Arguments>
timer(int after, const bool async, Callable&& f, Arguments&&... args)
{
std::function<typename std::result_of<Callable(Arguments...)>::type()> task(bind(forward<Callable>(f), forward<Arguments>(args)...));
if (async)
{
thread([after, task]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(after));
task();
}).detach();
}
else
{
std::this_thread::sleep_for(std::chrono::milliseconds(after));
task();
}
}
};
Here's a small example usage:
void say(const string& word)
{
cout << "Hello, " << word << "!\n";
}
int main(int argc, char* argv[])
{
while (true)
{
timer timer1(500, false, &say, "pyreN - A");
timer timer2(1000, false, &say, "pyreN - B");
}
}
The following program didn't do anything, athough had been expected to simulate pressing "a" and "b" for each second. Why it doesn't work?
#include <Windows.h>
#include <iostream>
using namespace std;
const int INPUTS = 4;
int main()
{
INPUT inputArray[INPUTS];
INPUT input;
input.type = INPUT_KEYBOARD;
//Press 'a' key
input.ki.wVk = 0x41;
input.ki.wScan = MapVirtualKey(0x41,MAPVK_VK_TO_VSC);
inputArray[0] = input;
//Release 'a' key
input.ki.dwFlags = KEYEVENTF_KEYUP;
inputArray[1] = input;
//Press 'b' key
input.ki.dwFlags = 0;
input.ki.wVk = 0x42;
input.ki.wScan = MapVirtualKey(0x42,MAPVK_VK_TO_VSC);
inputArray[2] = input;
//Release 'b' key
input.ki.dwFlags = KEYEVENTF_KEYUP;
inputArray[3] = input;
Sleep(5000);
std::cout<<"GO!!!\n";
for(int i=0; i<100; i++)
{
SendInput(sizeof(inputArray),inputArray,sizeof(INPUT));
Sleep(1000); //Don't remove!
}
std::cout<<GetLastError()<<std::endl;
system("Pause");
return 0;
}
The last error is
ERROR_NOACCESS
998 (0x3E6)
Invalid access to memory location.
but I don't know what caused it.
Try
SendInput(INPUTS, inputArray, sizeof(INPUT));
and check that the return value is non-zero. In fact, it should equal to the number of inputs sent, in this case 4.
The function may fail if it is blocked by another thread or UIPI (User Interface Privilege Isolation)
To avoid other problems you may want to check the current keyboard state as well as SendInput adds to the input stream and other keys being pressed while this is running could interfere with it.
Out of curiosity what action are you trying to simulate? It's generally not a very graceful practice to "fake" user input to any application.
I am trying to get my application to convert a character array to uppercase letter so I can pass them as key presses. I know I am close to getting this code working but I just cant see the problem.
int a, b, c, d;
char text[25];
char upper[25];
for (a = 0, b = sizeof(login); a < b; a++)
{
if (isalpha(login[a])){
l[a] = toupper(login[a]);
Sleep(1000);
GenerateKey(l[a], FALSE);}
else{
GenerateKey(l[a], FALSE);
Sleep(1000);
l[a] = login[a];}
}
login[a]='\0';
GenerateKey(0x09, FALSE);
for (c = 0, d = sizeof(pass); c < d; c++)
{
if (isalpha(pass[c])){
p[c] = toupper(pass[c]);
GenerateKey(p[c], FALSE);
Sleep(1000);}
else{
GenerateKey(p[c], FALSE);
p[c] = pass[c];
Sleep(1000);}
}
pass[a]='\0';
GenerateKey(0x09, FALSE);
Sleep(1000);
GenerateKey(0x09, FALSE);
Sleep(1000);
GenerateKey(0x0D, FALSE);
And here is the GenerateKey function:
void GenerateKey(int vk, BOOL bExtended) {
KEYBDINPUT kb = {0};
INPUT Input = {0};
/* Generate a "key down" */
if (bExtended) { kb.dwFlags = KEYEVENTF_EXTENDEDKEY; }
kb.wVk = vk;
Input.type = INPUT_KEYBOARD;
Input.ki = kb;
SendInput(1, &Input, sizeof(Input));
/* Generate a "key up" */
ZeroMemory(&kb, sizeof(KEYBDINPUT));
ZeroMemory(&Input, sizeof(INPUT));
kb.dwFlags = KEYEVENTF_KEYUP;
if (bExtended) { kb.dwFlags |= KEYEVENTF_EXTENDEDKEY; }
kb.wVk = vk;
Input.type = INPUT_KEYBOARD;
Input.ki = kb;
SendInput(1, &Input, sizeof(Input));
return;
}
Any help would be great!
EDIT:
This appplication is trying to open a webpage and then enter login information and press submit(using tab to select the username, password fields, etc). To answer #Rup, l[] and p[] are initialised above this block of code.
char l[180];
char p[180];
l is the users login name and p is their password. I am trying to convert these to uppercase to pass them in GenerateKey. eg GenerateKey('A', FALSE);
At the moment the code does not seem to pass any keypresses at all but the application freezes so I believe it is getting stuck in a for loop somewhere.
EDIT 2:
Thanks to #William for providing the helpful code.
Using the toUpper function I am very close to solving this issue. The only issue I am having now is that the login and password being passed contain extra characters. For example if I pass login as username, then rerun the program and pass login as user I get the output userame.
This is the code I have now with the GenerateKey and toUpper functions:
// Convert to uppercase to be passed as keypresses
toUpper(login, sizeof(login));
toUpper(pass, sizeof(pass));
int a;
for(a=0; a<sizeof(login);a++){
GenerateKey(login[a], FALSE);}
login[a]='\0';
GenerateKey(0x09, FALSE);
a=0;
for(a=0; a<sizeof(pass);a++){
GenerateKey(pass[a], FALSE);}
pass[a]='\0';
GenerateKey(0x09, FALSE);
Sleep(1000);
GenerateKey(0x09, FALSE);
Sleep(1000);
GenerateKey(0x0D, FALSE);
SOLUTION:
Using strlen(login); in the above code cleared up all hte issues I was having.
void toUpper(char* pArray, int arrayLength)
{
for(int i = 0; i < arrayLength; i++)
{
if(pArray[i] >= 'a' && pArray[i] <= 'z')
pArray[i] -= ' ';
}
}
I have solved the Issue with the following code:
The code is explained in the comments.
// Convert to uppercase to be passed as keypresses
toUpper(login, sizeof(login));
toUpper(pass, sizeof(pass));
int a;
// Loop through the character array and send the key presses
for(a=0; a<strlen(login);a++){
GenerateKey(login[a], FALSE);}
GenerateKey(0x09, FALSE);
for(a=0; a<strlen(pass);a++){
GenerateKey(pass[a], FALSE);}
// Additional keypresses
GenerateKey(0x09, FALSE);
Sleep(1000);
GenerateKey(0x09, FALSE);
Sleep(1000);
GenerateKey(0x0D, FALSE);
The GenerateKey function and toUpper functions provided are also needed in order for this code to function correctly.
Thank you for all your help on this Issue.