Solved

WM_KEYDOWN problem

Posted on 1998-07-22
12
3,242 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
3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

 
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 200 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

Optimizing Cloud Backup for Low Bandwidth

With cloud storage prices going down a growing number of SMBs start to use it for backup storage. Unfortunately, business data volume rarely fits the average Internet speed. This article provides an overview of main Internet speed challenges and reveals backup best practices.

Question has a verified solution.

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

If you have ever found yourself doing a repetitive action with the mouse and keyboard, and if you have even a little programming experience, there is a good chance that you can use a text editor to whip together a sort of macro to automate the proce…
Entering time in Microsoft Access can be difficult. An input mask often bothers users more than helping them and won't catch all typing errors. This article shows how to create a textbox for 24-hour time input with full validation politely catching …
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…
The Email Laundry PDF encryption service allows companies to send confidential encrypted  emails to anybody. The PDF document can also contain attachments that are embedded in the encrypted PDF. The password is randomly generated by The Email Laundr…

770 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