We help IT Professionals succeed at work.

Check out our new AWS podcast with Certified Expert, Phil Phillips! Listen to "How to Execute a Seamless AWS Migration" on EE or on your favorite podcast platform. Listen Now

x

WM_KEYDOWN problem

Gadi031698
Gadi031698 asked
on
Medium Priority
3,357 Views
Last Modified: 2013-12-03
I have to write an application that sends some keystrokes to other applications. I have to send them by using
WM_KEYDOWN. Unfortunately, sometimes (too much...) the translation is wrong, and a wrong WM_CHAR message is generated.
For example, I tried sending "ctrl+v" to notepad, to paste some text, and I have written something like(bad code - just for demonstrating the problem):

HWND      hWnd = ::FindWindow(NULL, "Untitled - NotePad");
HWND      hChildWindow = ::GetWindow(hWnd, GW_CHILD);
if (hChildWindow)
{
      ::SendMessage(hChildWindow, WM_SETFOCUS, 0, 0);
      ::PostMessage(hChildWindow, WM_KEYDOWN, VK_CONTROL, 0x001d0001);
      ::PostMessage(hChildWindow, WM_KEYDOWN, 0x56, 0x002f0001);
}

The parameters were copied exactly from the output of SPY++, tracing the same action.
The problem is that only a "v" is sent to notepad and NOT "ctrl+v".
What is the problem?

Comment
Watch Question

Commented:
I tried that before even with the following code. But it doesn't work.

// set the CTRL key state before 'v'
BYTE pbKeyState[256];
::GetKeyboardState((LPBYTE)&pbKeyState);
pbKeyState[VK_CONTROL] |= 0x80;
::SetKeyboardState((LPBYTE)&pbKeyState);


The working code is here.

HWND hWnd = ::FindWindow(NULL, "Untitled - NotePad");

::SetForegroundWindow(hWnd);

::keybd_event(VK_CONTROL, 0, 0, 0);
::keybd_event('V', 0, 0, 0);
::keybd_event('V', 0, KEYEVENTF_KEYUP, 0);
::keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);

::SetForegroundWindow(hMyWnd);

Commented:
In addition, you may wish to look into the article "Sending Keystrokes under Win32" written by Robert Mashlan in Windows Developer's Journal March 1997 issue. In this article, he demonstrates how to use a journal playback hook in Windows NT and Windows 95 to send keystrokes to other applications. You can download the source code at http://www.wdj.com.

Author

Commented:
Sorry not mentioned it in the original question, but Journal Playback is not an alternative and keybd_event is a problem because I don' t want:
a. Windows to pop up in the middle of an application.
b. Between the SetForegroundWindow & the keybd_event - another message can sneak in an deastroy all the business.

Commented:
a. To solve this, use the following code instead.
if (::IsIconic(hWnd))
    ::ShowWindow(hWnd, SW_RESTORE);

::ShowWindow(hWnd, SW_HIDE);

::SetForegroundWindow(hWnd);

::keybd_event(VK_CONTROL, 0, 0, 0);
::keybd_event('V', 0, 0, 0);
::keybd_event('V', 0, KEYEVENTF_KEYUP, 0);
::keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);

::SetForegroundWindow(hMyWnd);

::ShowWindow(hWnd, SW_SHOWNOACTIVATE);

b. This problem also exists with the PostMessage method. But it is unlikely to happen.

Author

Commented:
But if I use WM_KEYDOWN - the messages are sent to a specific - predefined window,
and I don't matter if other messages are sent, whereas using keybd_event - may result in keystrokes to other windows than the desired one.

Commented:
If it is possible that other messages may come in between the SetForegroundWindow & the keybd_event, it is also possible that

::SendMessage(hChildWindow, WM_SETFOCUS, 0, 0);
// some actions cause hChildWindow to lose the focus.
::PostMessage(hChildWindow, WM_KEYDOWN, VK_CONTROL, 0x001d0001);
// other key messages come in.
::PostMessage(hChildWindow, WM_KEYDOWN, 0x56, 0x002f0001);

And the problem is that we cannot make the PostMessage method work and only that method is what you want.

Author

Commented:
But when I PostMessage, I know exactly what is the target window. That is not
guaranteed when using keybd_event

Author

Commented:
Adjusted points to 200
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION

Commented:
I tested it. It works.

Actually,

::PostMessage(hChildWindow, WM_CHAR, 0x16, 0x002F0001);

is enough.

Author

Commented:
Nice...
But what does the 0x16 in the WM_CHAR stands for?

Commented:
The ASCII code for CTRL-V.
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.