Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

WM_KEYDOWN problem

Posted on 1998-07-22
12
Medium Priority
?
3,280 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?

0
Comment
Question by:Gadi031698
  • 6
  • 5
12 Comments
 
LVL 23

Expert Comment

by:chensu
ID: 1410783
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);

0
 
LVL 23

Expert Comment

by:chensu
ID: 1410784
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.
0
 

Author Comment

by:Gadi031698
ID: 1410785
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.
0
Veeam Disaster Recovery in Microsoft Azure

Veeam PN for Microsoft Azure is a FREE solution designed to simplify and automate the setup of a DR site in Microsoft Azure using lightweight software-defined networking. It reduces the complexity of VPN deployments and is designed for businesses of ALL sizes.

 
LVL 23

Expert Comment

by:chensu
ID: 1410786
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.

0
 

Author Comment

by:Gadi031698
ID: 1410787
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.

0
 
LVL 23

Expert Comment

by:chensu
ID: 1410788
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.
0
 

Author Comment

by:Gadi031698
ID: 1410789
But when I PostMessage, I know exactly what is the target window. That is not
guaranteed when using keybd_event
0
 

Author Comment

by:Gadi031698
ID: 1410790
Adjusted points to 200
0
 
LVL 1

Accepted Solution

by:
vladimir_12345 earned 600 total points
ID: 1410791
1.It is impossible set the CTRL key by ::SetKeyboardState()
  for other thread.
 
2.Problem is that thread has 2 queues:
  1 - for kbd, mou messages and 2 - for others messages.
  Queue 1 has more lower priority from queue 2.
  PostMessage() puts messages to queue 2.
  For example:
  if PostMessage() 'A'-down, 'A'-up, target window gets
  WM_KEYDOWN-'A', WM_KEYUP-'A', WM_CHAR-'A'.
  For true kbd messages WM_CHAR has more higher priority from
  WM_KEYUP.
 
3. From 2 queues in your source translation from WM_KEYDOWN-Ctrl
   + WM_KEYDOWN-'V' to WM_CHAR-'CtrlV' is not correct.
   You got WM_CHAR-'V' instead of WM_CHAR-CtrlV.

4. If to use PostMessage() you have to change your source:

HWND hWnd         = ::FindWindow(NULL, "Untitled - NotePad");
HWND hChildWindow = ::GetWindow(hWnd, GW_CHILD);
if(hWnd && hChildWindow)
{
SetForegroundWindow(hWnd);
while(GetForegroundWindow() != hWnd);
{
::PostMessage(hChildWindow, WM_KEYDOWN, VK_CONTROL, 0x001d0001);
::PostMessage(hChildWindow, WM_CHAR,    0x16,       0x002F0001);
::PostMessage(hChildWindow, WM_KEYDOWN, VK_CONTROL, 0xC01D0001);
}

// if you need there restore focus for your application
// by SetForegroundWindow().
   
0
 
LVL 23

Expert Comment

by:chensu
ID: 1410792
I tested it. It works.

Actually,

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

is enough.
0
 

Author Comment

by:Gadi031698
ID: 1410793
Nice...
But what does the 0x16 in the WM_CHAR stands for?
0
 
LVL 23

Expert Comment

by:chensu
ID: 1410794
The ASCII code for CTRL-V.
0

Featured Post

Veeam Task Manager for Hyper-V

Task Manager for Hyper-V provides critical information that allows you to monitor Hyper-V performance by displaying real-time views of CPU and memory at the individual VM-level, so you can quickly identify which VMs are using host resources.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

As more and more people are shifting to the latest .Net frameworks, the windows presentation framework is gaining importance by the day. Many people are now turning to WPF controls to provide a rich user experience. I have been using WPF controls fo…
For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Look below the covers at a subform control , and the form that is inside it. Explore properties and see how easy it is to aggregate, get statistics, and synchronize results for your data. A Microsoft Access subform is used to show relevant calcul…

916 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question