Why Am I getting extra messages when sending keystroke to an application? - c++

I am sending CTRL+A and CTRL+C to an application ( in order to copy the content obviously ).
For this I wrote some C++ code which seems to be ok.
Indeed I see on spy++ that the messages produced and sent to the application by my code are exactly the same ( expect frepeat value ) than the messages received by the application when CTRL+A and CTRL+C are inputed ,manually on the keyboard... except that with my code, the application receive at the end two extra WM_CHAR messages for 'A' and 'B'.
since I do not send these WM_CHAR messages but only WM_KEYDOWN and WM_KEYUP I am slightly puzzled. Incidentally nothing is selected and nothing is copied ( even if selected before )
here is my C++ code:
HWND hTargetWindow=(HWND) 0x280908;
LPARAM lparam1 = 0x00000001 | (LPARAM)(0x1D << 16);
LPARAM lparam2 = 0x00000001 | (LPARAM)(0x1E << 16);
LPARAM lparam3 = 0x00000001 | (LPARAM)(0x2E << 16);
LPARAM lparam1_ = lparam1 | (LPARAM)(0x1 << 31);
LPARAM lparam2_ = lparam2 | (LPARAM)(0x1 << 31);
LPARAM lparam3_ = lparam3 | (LPARAM)(0x1 << 31);
PostMessage(hTargetWindow, WM_KEYDOWN, VK_CONTROL, lparam1);
PostMessage(hTargetWindow, WM_KEYDOWN, VK_A, lparam2);
PostMessage(hTargetWindow, WM_KEYUP, VK_CONTROL, lparam1_);
PostMessage(hTargetWindow, WM_KEYUP, VK_A, lparam2_);
PostMessage(hTargetWindow, WM_KEYDOWN, VK_CONTROL, lparam1);
PostMessage(hTargetWindow, WM_KEYDOWN, VK_C, lparam3);
PostMessage(hTargetWindow, WM_KEYUP, VK_C, lparam3_);
PostMessage(hTargetWindow, WM_KEYUP, VK_CONTROL, lparam1_);
and here respectively
a) the messages received when CTRL+A CTRL+C are inputed manually
b) here the messages received when when CTRL+A CTRL+C are sent by my C+ code
I will put frepeat to 1 for KEYUP events but I doubt this will change anything so I post the question anyway.
so why are these two extra messages sent by my code ?
thanks in advance for any hint.
added 7:09:05 p.m.(GMT + 2:00):
the KEYUP and KEYDOWN for CTRL+A are reversed ( CTRL+C sequence is the same ) but this is because I have also tried this to solve the problem. I have also tried many times the right combination.
this is spy++ when the keydown and keyup dequence is exactly the same , that does not change anything:

You're doing things in the wrong order, doing the WM_KEYUP on VK_A before you do the WM_KEYUP on VK_CONTROL. Same for the C. Reverse those and it should be fine.

// Send [CTRL-A] to select the entire text in a Notepad window, even if Notepad is out of focus,
// without bringing the Notepad window into focus.
// Works with Notepad, but not with Command Prompt window.
BYTE gucKeybStateCur [256] = {'\0'};
// hwN = Find Notepad HWND
AttachThreadInput (GetWindowThreadProcessId (hwN, NULL), GetCurrentThreadId (), TRUE);
GetKeyboardState ((PBYTE) &gucKeybStateCur);
gucKeybStateCur [VK_CONTROL] |= 0x80;
SetKeyboardState ((LPBYTE) &gucKeybStateCur);
PostMessage (hwN, WM_KEYDOWN, (WPARAM) 0x00000041, (LPARAM) 0x001E0001);
PostMessage (hwN, WM_KEYUP, (WPARAM) 0x00000041, (LPARAM) 0xC01E0001);
GetKeyboardState ((PBYTE) &gucKeybStateCur);
gucKeybStateCur [VK_CONTROL] &= 0x0F;
SetKeyboardState ((LPBYTE) &gucKeybStateCur);
AttachThreadInput (GetWindowThreadProcessId (hwN, NULL), GetCurrentThreadId (), FALSE);
// Send [CTRL-C] to interrupt a batch file running in a Command Prompt window, even if the Command Prompt window is not visible,
// without bringing the Command Prompt window into focus.
// [CTRL-C] will have an effect on the batch file, but not on the Command Prompt window itself -- in other words,
// [CTRL-C] will not have the same visible effect on a Command Prompt window that isn't running a batch file at the moment
// as bringing a Command Prompt window that isn't running a batch file into focus and pressing [CTRL-C] on the keyboard.
ulong ulProcessId = 0UL;
// hwC = Find Command Prompt window HWND
GetWindowThreadProcessId (hwC, (LPDWORD) &ulProcessId);
AttachConsole ((DWORD) ulProcessId);
SetConsoleCtrlHandler (NULL, TRUE);
GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0UL);
SetConsoleCtrlHandler (NULL, FALSE);
FreeConsole ();

Related

Chrome Automation with C/C++ ,PostMessage() can send Message even to a minimized window but it sends extra WM_CHAR message after WM_KEYDOWN message

I am writing a code in C/C++ with Win32API which Automates Chrome(I know there is Selenium and I used that but there is BOT detection available. Just forget about slenium).In my code There are extra features too ie.-If you have multiple Chrome Profile you can chose to run how many Profiles to Run at Once. To change the Tabs in Google Chrome they have the Shortcut Key Ctrl+TAB. I want to Simulate that.
The Problems --->
1.To Run Multiple Profiles at Once.
2.Detecting The Window Handles of Every Profile.
3.Automating Certain Keyboard Events.
I have solved Problem 1 and 2.
Even Problem 3 is easy.To automate Chrome Tab changes I have done something like this ----
void clicktabs()
{
SetForegroundWindow(hwnd);
INPUT ip[4];
ip[0] = ip[1] = ip[2] = ip[3] = { 0 };
ip[0].type = ip[1].type = ip[2].type = ip[3].type = INPUT_KEYBOARD;
ip[0].ki.wVk = ip[3].ki.wVk = VK_CONTROL;
ip[0].ki.wScan = ip[3].ki.wScan = 0x1D; //scancode of CTRL for my Keyboard
ip[1].ki.wScan = ip[2].ki.wScan = 0x0F;//scancode of TAB for my Keyboard
//You can also check for yours by observing the lParam Parameter of WndProc().bit 16 to 23 of lParam is your scan code for that particular key.Though it does not matter.
ip[3].ki.dwFlags = ip[2].ki.dwFlags = KEYEVENTF_KEYUP;
ip[1].ki.wVk = ip[2].ki.wVk = VK_TAB;
for(int count = 1;;count++)
{
if (count == //number of tabs you want to open)
{count = 0;}
SendInput(4, ip, sizeof(INPUT));
Sleep(2000);
}
}
It is working just fine to press Ctrl+TAB at once.And I am successful to automate TAB changes in Chrome.
Main Problem ---->
SendInput() work on the Focused window. If i change my Focus to other window or if i minimize the window, the chrome TAB change automation stops. To solve it I used PostMessage().Because I have used PostMessage to send mouse clicks on the tabs which it had done succesfully even in minimized window(I dont want to send mouse clicks because after a certain number of tabs the tab size changes.).But postMessage failed to send ctrl+tab message.
I inspect Chrome Window by Spy++ while pressing ctrl+tab by Myself on My Keyboard. And it generates-----
1.P WM_KEYDOWN nVirtkey:VK_CONTROL cRepeat: 1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:0 fUP:0
2.P WM_KEYDOWN nVirtkey:VK_TAB cRepeat: 1 ScanCode:0F fExtended:0 fAltDown:0 fRepeat:0 fUP:0
3.P WM_KEYUP nVirtkey:VK_TAB cRepeat: 1 ScanCode:0F fExtended:0 fAltDown:0 fRepeat:1 fUP:1
4.P WM_KEYUP nVirtkey:VK_CONTROL cRepeat: 1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:1 fUP:1
Image of messages send by Real Keyboard Input in Spy++
(Here all the preceeding 'P' means the message is Posted by PostMessage() Note-For normal keydown messages OS PostsMessage not SendMessage().You can see it here - Message Codes -https://learn.microsoft.com/en-us/visualstudio/debugger/message-codes?view=vs-2019)
When I am using SendInput() function and checking browser window with Spy++ it exactly generates the same sequence of Messages as the real keyboard press do.
Image of messages send by SendInput() in Spy++
But when I am using PostMessage() like this -
\\\In the below code section i am sure about setting the lParam correctly.Because the values of lParam reflects on the cRepeat, ScanCode, fExtended, fAltDown, fRepeat, fUP section of Spy++
void clicktabs()
{
SetForegroundWindow(hwnd);
for(int count = 1;;count++)
{
if (count == //number of tabs you want to open)
{count = 0;}
LPARAM lparam_ctrlkey, lparam_tabkey;
lparam_ctrlkey = 1 | (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20);
PostMessage(hwnd, WM_KEYDOWN, VK_CONTROL, lparam_ctrlkey);
lparam_tabkey = 1| (1 << 16) | (1 << 17) | (1 << 18) | (1 << 19);
PostMessage(hwnd, WM_KEYDOWN, VK_TAB, lparam_tabkey);
lparam_tabkey = lparam_tabkey|(1<<30)|(1<<31); \\stteing up the lparams.
PostMessage(hwnd, WM_KEYUP, VK_TAB, lparam_tabkey);
lparam_ctrlkey = lparam_ctrlkey | (1 << 30) | (1 << 31);
PostMessage(hwnd, WM_KEYUP, VK_CONTROL, lparam_ctrlkey);
Sleep(2000);
}
}
and Checking with Spy++.It generates one extra message(see line 3)-----
1.P WM_KEYDOWN nVirtkey:VK_CONTROL cRepeat: 1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:0 fUP:0
2.P WM_KEYDOWN nVirtkey:VK_TAB cRepeat: 1 ScanCode:0F fExtended:0 fAltDown:0 fRepeat:0 fUP:0
3.P WM_CHAR chCharCode:'9' cRepeat:1 ScanCode:0F fExtended:0 fAltDown:0 fRepeat:0 fUp:0
4.P WM_KEYUP nVirtkey:VK_TAB cRepeat: 1 ScanCode:0F fExtended:0 fAltDown:0 fRepeat:1 fUP:1
5.P WM_KEYUP nVirtkey:VK_CONTROL cRepeat: 1 ScanCode:1D fExtended:0 fAltDown:0 fRepeat:1 fUP:1
At line 3 it's Generating WM_CHAR for TAB key.ASCII code for TAB key is 0x09 or 9(decimal).And Here PostMessage() fails.
Image of messages send by PostMessage() in Spy++
Please help me to solve this.I have seen similar problem on StackOverflow where someone suggested to use SetKeyboardState() . I also tried that but failed.The link is- Why Am I getting extra messages when sending keystroke to an application?
I also tried SendMessage but it also generates extra WM_KEYDOWN message. You can see it here-Trouble Simulating Keystrokes
Image of Messages send by SendMessage() in Spy++

How to make Windows Hot Keys work in Direct X environments?

I am programming a really simple MFC C++ Application which is working with HotKeys. To set a HotKey I use the following method from the WinAPI for my application:
BOOL RegisterHotKey(
HWND hWnd, // window to receive hot-key notification
int id, // identifier of hot key
UINT fsModifiers, // key-modifier flags
UINT vk // virtual-key code
);
To catch any HotKey Message I use: ON_MESSAGE(WM_HOTKEY,OnHotKey) in the message map and this Callback Method to test it's functionality:
LRESULT OnHotKey(WPARAM wParam, LPARAM lParam)
{
if (wParam == MY_HOTKEY_KEY_CODE)
{
MessageBox(L"HotKey was pressed!");
return TRUE;
}
return FALSE;
}
When a HotKey is pressed it enters the OnHotKey Method and does not process the key normally. For example if I write some text in Notepad and press "O" as HotKey, the "O" wont append to my text but the Message "HotKey was pressed!" appears, which is nice.
But when I am in any Direct X Game and press my HotKey, it is not sent to my application. Also when typing something in a Direct X environment the HotKey just works as normal key.
Is Direct X binding all key inputs somehow? Is there a way to make Windows HotKeys work with Direct X environments?

C++ simulate left mouse click on minimized program

I have been searching for a bit about this particular problem I am having, I want to be able to simulate a left mouse click on a program that I am currently attached to.
Right now, I create a thread that checks a database for certain values, and when those values come back (the ones I am looking for), I want to be able to then send a left mouse click in any x,y coord of the program (while minimized).
How can this be done for Windows 7? Thanks!
EDIT: Here is how I am calling the thread ...
HWND child = GetActiveWindow();
if ( child == NULL )
MessageBox(0,"Couldn't get the child hwnd!","",0);
DWORD ID;
HANDLE thread_check_game = CreateThread ( NULL , 0 , (LPTHREAD_START_ROUTINE) game_check_thread , (LPVOID)child, 0 , &ID ); CloseHandle ( game_check_thread );
and then ...
DWORD WINAPI game_check_thread(LPVOID lpParam) {
HWND Window;
Window = (HWND)lpParam;
// ... some other code ...
// ...
WORD mouseX = 398;
WORD mouseY = 398;
SendMessage(Window,WM_LBUTTONDOWN,MK_LBUTTON,MAKELPARAM(mouseX,mouseY));
SendMessage(Window, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM(mouseX, mouseY));
Write("Sent Left Click\n");
ExitThread(0);
return 0;
}
If you want to fire a mouse event in your application, use the SendMessage function, and your message will appear in the window with handle hWnd's message pump.
SendMessage(hWnd, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM(mousePosX, mousePosY));
You may need to notify for WM_LBUTTONUP, depending on the way you application handles it's mouse events.

C++ ToUnicodeEx() not recognizing shift key unless i have a messgaebox()

im having a bit of trouble writing a keyboard hook in C++.
I can read keystrokes but im trying to using ToUnicodeEx() to convert keystrokes when shift key is pressed.
In the code i have so far i have
i = ToUnicodeEx(keyboard.vkCode, keyboard.scanCode, (PBYTE)&keyState, (LPWSTR)&keybuff, sizeof(keybuff) / 16, 0,keyboardlayout);
MessageBox(MainnhWnd,keybuff, L"message", MB_OK | MB_ICONEXCLAMATION);
with this 'MessageBox' line when I press Shift+2 i get two message boxes pops up, the first is blank for the shift key, the second shows a '#' character. This is expected.
But if i remove this messagebox, the ToUnicodeEx() function converts the keystroke as if the shift key had not been used. I can see this by either setting a breakpoint, with a hit counter, or outputting the character to an edit box in my program windows.
Also when i include the MsgBox line and use the CapLock, my letters change accordingly but after i remove the msgbox line it only uses the state of the cap lock at the time my program starts (cap locks is on when programm starts, all letters are capital, vice verse, caps off when programm starts all letters are small,, even if i change the cap lock state)
Anyone know why my hook just remembers the keyboard state at start, unless i include the msgbox?
My hook is set like:
theHook = SetWindowsHookEx ( WH_KEYBOARD_LL, (HOOKPROC) KeyEvent, exe, 0);
and my hook callback function is:
DLLEXPORT LRESULT CALLBACK KeyEvent(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode>=0) {
int i = 0;
KBDLLHOOKSTRUCT keyboard;
WCHAR keybuff[256]= {0};
if ((wParam == WM_KEYDOWN)|| (wParam == WM_SYSKEYDOWN)||(wParam == WM_SYSKEYUP)) {
keyboard = *((KBDLLHOOKSTRUCT*)lParam);
if (keyboard.vkCode == VK_RETURN) {
i += wsprintf (((LPWSTR)keybuff + i),L"[Return]\r\n");
}
else {
HKL keyboardlayout = GetKeyboardLayout(0);
GetKeyboardState((PBYTE)&keyState);
i = ToUnicodeEx(keyboard.vkCode, keyboard.scanCode, (PBYTE)&keyState, (LPWSTR)&keybuff, sizeof(keybuff) / 16, 0,keyboardlayout);
MessageBox(MainnhWnd,keybuff, L"message", MB_OK | MB_ICONEXCLAMATION);
}
if (keybuff>0) {
addToEditBox(keybuff);
}
}
}
return CallNextHookEx(theHook, nCode, wParam, lParam);
}
According to documentation of ToUnicodeEx function, you should provide a pointer to a 256-byte array that contains the current keyboard state (const BYTE *lpKeyState). Each element (byte) in the array contains the state of one key. If the high-order bit of a byte is set, the key is down.
Before you call ToUnicodeEx, you should set this array like this (pseudocode):
enum Keys
{
ShiftKey = 16, // shift
ControlKey = 17, // ctrl
Menu = 18, // alt
Capital = 20, // caps lock
};
BYTE keyState[256]= {0};
if (Control key down)
keyState[Keys::ControlKey] = 0x80;
if (Shift key down)
keyState[Keys::ShiftKey] = 0x80;
if (Alt key down)
keyState[Keys::Menu] = 0x80;
if (Caps lock ON)
keyState[Keys::Capital] = 0x01;
And when keyState array is set, then you can call:
ToUnicodeEx(keyboard.vkCode, keyboard.scanCode, (PBYTE)&keyState, (LPWSTR)&keybuff, sizeof(keybuff) / 16, 0,keyboardlayout);
I have been working with ToUnicodeEx function just like this and it worked fine.
Hope this will help you ;)

How to check if a window button is pressed C++

How can I test if a button is being pressed ?
I am using EnumChildWindows() to enumerate the child windows of a given window, and one of the child window is a button, I want to test if that specific button is being pressed.
My code until know is:
BOOL CALLBACK MyEnumProc(HWND hwnd, LPARAM lParam)
{
char buffer[256];
GetWindowText(hwnd, buffer, sizeof(buffer));
cout << buffer << endl;
return true;
}
int main()
{
HWND hwnd = FindWindow(0, "Window to find");
EnumChildWindows(hwnd, MyEnumProc, 0);
return 0;
}
You can send the BM_GETSTATE message to the button control, if it is pressed the result will be
BST_PUSHED.
You need to inject a DLL into the process space, hook the window message loop (like you used to hand code a subclassed window in native Win32 API C code, Window Proc) (google-able) and listen to the actual messages.
All of this is ancient stuff for me, and I'm afraid that recent Windows versions (hopefully) made this a little bit more difficult to do.
That said, if you can get the application trusted with the right level of permissions, you should still be able to do this