Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

WM_KEYDOWN problem

Posted on 1998-07-22
12
Medium Priority
?
3,273 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
NFR key for Veeam Backup for Microsoft Office 365

Veeam is happy to provide a free NFR license (for 1 year, up to 10 users). This license allows for the non‑production use of Veeam Backup for Microsoft Office 365 in your home lab without any feature limitations.

 
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

Efficient way to get backups off site to Azure

This user guide provides instructions on how to deploy and configure both a StoneFly Scale Out NAS Enterprise Cloud Drive virtual machine and Veeam Cloud Connect in the Microsoft Azure Cloud.

Question has a verified solution.

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

This tutorial is about how to put some of your C++ program's functionality into a standard DLL, and how to make working with the EXE and the DLL simple and seamless.   We'll be using Microsoft Visual Studio 2008 and we will cut out the noise; that i…
What my article will show is if you ever had to do processing to a listbox without being able to just select all the items in it. My software Visual Studio 2008 crystal report v11 My issue was I wanted to add crystal report to a form and show…
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…
In this video, Percona Solution Engineer Dimitri Vanoverbeke discusses why you want to use at least three nodes in a database cluster. To discuss how Percona Consulting can help with your design and architecture needs for your database and infras…

661 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