Using User32.dll SendMessage To Send Keys With ALT

2019-01-20 07:12发布

问题:

Possible Duplicate:
C# and SendMessage (keys) is not working

I am writing an application that sends keystrokes to another application using the SendMessage function defined in user32.dll. I have figured out how to send a single keystroke but I am stumped trying to send the keystroke along with the ALT key.

For the purposes of my question I will focus on sending F1, and ALT + F1.

As stated above, I am able to send the F1 key no problem. Here is a snippet of my code that sends the F1 key:

// DLL Imports

//Set the active window
[DllImport("user32.dll")]
public static extern IntPtr SetActiveWindow(IntPtr hWnd);

//sends a windows message to the specified window
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);

// ...

// Some constants
#define WM_SYSKEYDOWN 260
#define WM_SYSKEYUP 261
#define WM_CHAR 258
#define WM_KEYDOWN 256
#define WM_KEYUP 257

// ...

// activate the window and send F1
SetActiveWindow(hWnd);
ushort action = (ushort)WM_SYSKEYDOWN;
ushort key = (ushort)System.Windows.Forms.Keys.F1;
SendMessage(hWnd, action, key, 0);

One interesting side note is that even though the above code works in sending the F1 key to the target application it is not the same as what I see using Spy++. Here is the output of the Spy++ log whenever I hit the F1 key while monitoring the target application:

<00001> 00050412 P WM_KEYDOWN nVirtKey:VK_F1 cRepeat:1 ScanCode:3B fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00002> 00050412 P WM_KEYUP nVirtKey:VK_F1 cRepeat:1 ScanCode:3B fExtended:0 fAltDown:0 fRepeat:1 fUp:1

Note that there are two messages sent, WM_KEYDOWN and WM_KEYUP.

My first question would be, why am I succesful sending F1 using WM_SYSKEYDOWN when Spy++ tells me that WM_KEYDOWN + WM_KEYUP is the proper message sequence?

Moving on to my next challenge of trying to send ALT + F1.

I have used Spy++ to monitor the messages passed when pressing ALT + F1 on my keyboard and this is what I see:

<00001> 00050412 P WM_SYSKEYDOWN nVirtKey:VK_MENU cRepeat:1 ScanCode:38 fExtended:1 fAltDown:1 fRepeat:0 fUp:0
<00002> 00050412 P WM_SYSKEYDOWN nVirtKey:VK_F1 cRepeat:1 ScanCode:3B fExtended:0 fAltDown:1 fRepeat:0 fUp:0
<00003> 00050412 P WM_SYSKEYUP nVirtKey:VK_F1 cRepeat:1 ScanCode:3B fExtended:0 fAltDown:1 fRepeat:1 fUp:1
<00004> 00050412 P WM_KEYUP nVirtKey:VK_MENU cRepeat:1 ScanCode:38 fExtended:1 fAltDown:0 fRepeat:1 fUp:1

Given the above Spy++ message capture I tried to send the exact message sequence using the following code (simplified):

SetActiveWindow(hWnd);    
SendMessage(hWnd, (ushort)WM_SYSKEYDOWN, (ushort)System.Windows.Forms.Keys.Menu, 0);
SendMessage(hWnd, (ushort)WM_SYSKEYDOWN, (ushort)System.Windows.Forms.Keys.F1, 0);
SendMessage(hWnd, (ushort)WM_SYSKEYUP, (ushort)System.Windows.Forms.Keys.F1, 0);
SendMessage(hWnd, (ushort)WM_KEYUP, (ushort)System.Windows.Forms.Keys.Menu, 0);

This did not work.

And so this leads to my next question. Is there anything else I can try or is there something that I am doing wrong here?

Whenever I captured the output of my program using Spy++ here is what was logged:

<00001> 00050412 S WM_SYSKEYDOWN nVirtKey:VK_MENU cRepeat:0 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00002> 00050412 R WM_SYSKEYDOWN
<00003> 00050412 S WM_SYSKEYDOWN nVirtKey:VK_F1 cRepeat:0 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00004> 00050412 R WM_SYSKEYDOWN
<00005> 00050412 S WM_SYSKEYUP nVirtKey:VK_F1 cRepeat:0 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00006> 00050412 R WM_SYSKEYUP
<00007> 00050412 S WM_KEYUP nVirtKey:VK_MENU cRepeat:0 ScanCode:00 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00008> 00050412 R WM_KEYUP

Notice that there are extra messages being sent at lines 2, 4, 6, and 8. Could this be the reason why things are not working?

I have one final question regarding the difference between the messages captured from actual keyboard input and those captured using my application. Notice the cRepeat, ScanCode, fExtended, etc. arguments. They are non-zero in the messages that were captured using my keyboard as the input and they are all zero in the messages sent by my application. Could this be the reason why my code is not working? If so, how do I modify these values? (I am assuming they come from the 4th argument to the SendMessage function, which I have set to zero in all cases.)

Thank you,

Jan

回答1:

Another solution. It doesn't appear you are passing anything for the lparam of the WM_SYSKEYDOWN. Yet the docs, clearly suggest that bit 29 of the lparam needs to be set to indicate the ALT key was pressed.

ushort action = (ushort)WM_SYSKEYDOWN;
ushort key = (ushort)System.Windows.Forms.Keys.F1;
uint lparam = (0x01 << 28);
SendMessage(hWnd, action, key, lparam);


回答2:

I don't think SendMessage and WM_SYSKEYDOWN is what you want to use. Instead, use the SendInput function. If I recall, you'll likely pass four inputs for every keystroke you want to simulate. One for the "down" event of the alt key. Another down event for the corresponding key. Then two up events for each.

It's been a while since I've had to write code like this, but I believe the docs suggest that VK_MENU is the code for the "alt" key.