Solved

WM_KEYDOWN problem

Posted on 1998-07-22
12
3,223 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 23

Expert Comment

by:chensu
Comment Utility
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
Comment Utility
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
Comment Utility
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
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 

Author Comment

by:Gadi031698
Comment Utility
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
Comment Utility
Adjusted points to 200
0
 
LVL 1

Accepted Solution

by:
vladimir_12345 earned 200 total points
Comment Utility
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
Comment Utility
I tested it. It works.

Actually,

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

is enough.
0
 

Author Comment

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

Expert Comment

by:chensu
Comment Utility
The ASCII code for CTRL-V.
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
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…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…

728 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

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now