Solved

WM_KEYDOWN problem

Posted on 1998-07-22
12
3,251 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Salesforce Has Never Been Easier

Improve and reinforce salesforce training & adoption using WalkMe's digital adoption platform. Start saving on costly employee training by creating fast intuitive Walk-Thrus for Salesforce. Claim your Free Account Now

 
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

Free Tool: Postgres Monitoring System

A PHP and Perl based system to collect and display usage statistics from PostgreSQL databases.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Event ID 10010 3 77
Run Program using VBScript 3 80
Enable Clear Text in Win 8.1 7 47
Changing the installation path of this MSI 5 114
With most software applications trying to cater to multiple user needs nowadays, the focus is to make them as configurable as possible. For e.g., when creating Silverlight applications which will connect to WCF services, the service end point usuall…
After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
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…
Attackers love to prey on accounts that have privileges. Reducing privileged accounts and protecting privileged accounts therefore is paramount. Users, groups, and service accounts need to be protected to help protect the entire Active Directory …

726 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