使用 User32.dll SendMessage 发送带有 ALT 修饰符的键 [重复]

Posted

技术标签:

【中文标题】使用 User32.dll SendMessage 发送带有 ALT 修饰符的键 [重复]【英文标题】:Using User32.dll SendMessage To Send Keys With ALT Modifier [duplicate] 【发布时间】:2012-11-19 23:01:53 【问题描述】:

可能重复:C# and SendMessage (keys) is not working

我正在编写一个应用程序,它使用 user32.dll 中定义的 SendMessage 函数将击键发送到另一个应用程序。我已经想出了如何发送单次击键,但我很难将击键与 ALT 键一起发送。

就我的问题而言,我将重点关注发送 F1 和 ALT + F1。

如上所述,我可以发送 F1 键没有问题。这是我发送 F1 键的代码的 sn-p:

// 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);

一个有趣的旁注是,尽管上面的代码在将 F1 键发送到目标应用程序时有效,但它与我使用 Spy++ 看到的不同。这是我在监视目标应用程序时按 F1 键时 Spy++ 日志的输出:

<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

请注意,发送了两条消息,WM_KEYDOWN 和 WM_KEYUP。

我的第一个问题是,当 Spy++ 告诉我 WM_KEYDOWN + WM_KEYUP 是正确的消息序列时,为什么我使用 WM_SYSKEYDOWN 成功发送 F1?

继续我的下一个挑战,尝试发送 ALT + F1。

我使用 Spy++ 来监控在我的键盘上按 ALT + F1 时传递的消息,这就是我所看到的:

<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

鉴于上述 Spy++ 消息捕获,我尝试使用以下代码(简化)发送确切的消息序列:

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);

这不起作用。

所以这就引出了我的下一个问题。 还有什么我可以尝试的,或者我在这里做错了什么?

每当我使用 Spy++ 捕获程序的输出时,都会记录以下内容:

<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

请注意,在第 2、4、6 和 8 行发送了额外消息。这可能是事情不工作的原因吗?

关于从实际键盘输入捕获的消息与使用我的应用程序捕获的消息之间的差异,我还有最后一个问题。注意 cRepeatScanCodefExtended参数。它们在之前的消息中是非零的 使用我的键盘作为输入捕获,它们在我的应用程序发送的消息中都为零。 这可能是我的代码不起作用的原因吗? 如果是这样,我该如何修改这些值?(我假设它们来自 SendMessage 的第四个参数 函数,我在所有情况下都设置为零。)

谢谢,

一月

【问题讨论】:

重复,也许。但我的问题比你提到的问题要复杂得多,我相信这可以证明它不被删除。 SendMessage 为此目的不可靠。也许你可以让它在受控条件下工作。 (对不起,我不能提供更多细节——我很久以前就研究过这个。) 【参考方案1】:

另一种解决方案。您似乎没有为 WM_SYSKEYDOWN 的 lparam 传递任何内容。然而the docs,明确建议需要设置 lparam 的第 29 位以指示按下了 ALT 键。

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

【讨论】:

非常漂亮的自拍!我又近了一步。现在,在 Spy++ 中设置 lParam 并捕获消息表明我正确设置了 fAltDown 参数。另请注意,我从使用 SendMessage 更改为 PostMessage,这消除了我帖子中提到的 extra 消息。 事情越来越近了,但仍然无法正常工作。我感觉我还需要设置其他参数(cRepeat、ScanCode 等)。 很有可能。您可以使用 spy++(Visual Studio 附带)来计算您需要发送的大部分内容。【参考方案2】:

我不认为 SendMessage 和 WM_SYSKEYDOWN 是您想要使用的。相反,请使用 SendInput 函数。如果我记得,您可能会为要模拟的每个击键传递四个输入。一个用于 alt 键的“向下”事件。对应键的另一个向下事件。然后每个都有两个 up 事件。

自从我不得不编写这样的代码以来已经有一段时间了,但我相信文档建议 VK_MENU 是“alt”键的代码。

【讨论】:

SendInput 不是一个完全不同的库吗?如果我没记错的话,SendInput 要求目标应用程序处于活动状态并且 到前面,这是我的应用程序不能排除的。 (我必须能够向最小化的应用程序发送消息。) 对。新答案即将发布。

以上是关于使用 User32.dll SendMessage 发送带有 ALT 修饰符的键 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

user32.dll SendMessage:以大写字符发送的字符串...但区分大小写的字符串

是否有从 USER32.DLL 导入所有内容的 C# 即用型类? [关闭]

SendMessage 不适用于 InternetExplorer 对象

使用 PostMessage() 或 SendMessage() 发送大写字母

Windows SendMessage()消息代码[关闭]

SendMessage 到 .NET 控制台应用程序