如何将Ctrl / Shift / Alt +组合键发送到应用程序窗口? (通过SendMessage)

时间:2012-11-02 17:36:46

标签: c# sendmessage

我可以成功地将任何单个密钥消息发送到应用程序,但我不知道如何发送密钥组合(例如 Ctrl + F12 Shift + F1 Ctrl + R 等。)

尝试这样做:

SendMessage(handle, WM_KEYDOWN, Keys.Control, 0);
SendMessage(handle, WM_KEYDOWN, Keys.F12, 0);
SendMessage(handle, WM_KEYUP, Keys.F12, 0);
SendMessage(handle, WM_KEYUP, Keys.Control, 0);

但这似乎不起作用(应用程序仅按 F12 ,而不是 Ctrl + F12 )。

任何想法如何使这项工作?

5 个答案:

答案 0 :(得分:5)

您可能会发现使用SendInput (documentation here)效果更好。您需要从C#,example here进行P / Invoke。您可以使用向下和向上键提供数据数组并正确设置其他消息参数,例如是左还是右 Ctrl / Shift / Alt 被压了。

您还可以使用SendKeys班级(documentation here)。这允许您按名称指定键,例如,{kbd> Ctrl + F12 {^F12}

编辑:OP现在说他需要将输入发送到最小化的应用程序而不激活它们。这不可能以任何方式可靠地执行,包括使用专门的硬件。我从事自动化工作。这是不可能的。 OP需要使用FindWindow / SetForegroundWindow来切换目标应用,然后他可以切换回他的应用。

答案 1 :(得分:3)

  

OP现在说他需要向最小化的应用程序发送输入   没有激活它们。任何情况都不可能做到这一点   方式,甚至包括专门的硬件。我曾经参与过   自动化。这是不可能的。

事实上,向最小化应用程序发送输入是可能的,不确定鼠标输入,但键盘输入工作正常。 在前面的回答中提出我的想法是什么(代码在Delphi中,但它非常简单,所以你可以将它翻译成你需要的语言):

procedure SendKeys(const Win : HWND; const Key,sKey: Cardinal);
var
  thrID : Cardinal;
  KB : TKeyBoardState;
begin
  if sKey <> 0 then
  begin
    thrID := GetWindowThreadProcessId(win,nil);
    GetKeyboardState(KB);
    AttachThreadInput(GetCurrentThreadID, thrID, True);
    KB[sKey] := KB[sKey] or $80;
    SetKeyboardState(KB);
  end;
  SendMessage(Win,WM_KEYDOWN,Key,0);
  SendMessage(Win,WM_KEYUP,Key,0);
  if sKey <> 0 then
  begin
    KB[sKey] := 0;
    SetKeyBoardState(KB);
    AttachThreadInput(GetCurrentThreadId, thrID, False);
  end;
end;

[Win]必须是接收输入的控件,而不是其父表单等。 [键]是一个被按下的关键; [sKey]是按下[Key]时按下的另一个键,例如CTRL / SHIFT(ALT通过消息本身传输,详见MSDN WM_KEYDOWN参考)。

发送单击按键非常简单,只需执行sendmessage即可完成,但如果你需要像CTRL + SPACE这样的东西,那么它就变得复杂了。每个线程都有自己的KeyboardState,在您自己的应用程序中更改KeyboardState不会影响另一个,除非您通过AttachThreadInput函数加入其线程输入。当应用程序处理WM_KEYDOWN消息时,它还通过调用GetKeyboardState函数来测试当前的移位状态(CTRL / SHIFT)(ALT键可以通过WM_KEYDOWN消息的附加参数发送),并且当附加的线程输入发挥作用时。

答案 2 :(得分:3)

我已经尝试了使用GetKeyboardState和SetKeyboardState的方法(先附加窗口线程,最后从窗口线程中分离)。我不能使用Ctrl + Something等键组合或使用Alt或Shift组合键。 Control,Alt和Shift键不被视为按下。看起来当窗口最小化时可以获得的最大值是使用带有WM_KEYDOWN消息的PostMessage按下单个键。我注意到的另一件事是,如果你发布WM_KEYDOWN和WM_KEYUP(对于相同的键),键将被按两次。所以一次只能使用WM_KEYDOWN。这不是100%准确的方法,但是当窗口最小化时,存在一些限制。

屏幕锁定时会发生同样的情况。

答案 3 :(得分:0)

也许你看起来像这样:

procedure GoCursorUp(Obj: TControl);
var   KeyState : TKeyboardState;
begin
  GetKeyboardState(KeyState);
  KeyState[VK_CONTROL] := KeyState[VK_CONTROL] or $80;
  SetKeyboardState(KeyState);// control down
  Obj.Perform(WM_KEYDOWN,VK_HOME,0); //ex. with HOME key
  KeyState[VK_CONTROL] := $0;
  SetKeyboardState(KeyState);// control up
end;

...

GoCursorUp(自拍);

或类似的东西:

  //for example: SHIFT + TAB
  keybd_event(VK_SHIFT, 0, 0, 0);
  keybd_event(VK_TAB, 0, 0, 0);
  keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);

答案 4 :(得分:0)

如果您想模拟按键以最小化窗口,您可以执行以下操作:

uint windowThreadId = GetWindowThreadProcessId(hwnd, IntPtr.Zero);
uint myThreadId = GetCurrentThreadId();
AttachThreadInput(myThreadId, windowThreadId, true);

下一步是使用GetKeyboardState函数来检索窗口线程的所有键状态的数组。 使用虚拟键代码修改SHIFT或CTRL或ALT键的状态。然后调用SetKeyboardState以应用这些状态。按F12键:

SendMessage(hwnd, WM_KEYDOWN, Keys.F12, 0);
SendMessage(hwnd, WM_KEYUP, Keys.F12, 0);

将SHIFT,CTRL或ALT键的状态修改为已释放。再次调用SetKeyboardState。最后,从窗口线程分离:

AttachThreadInput(myThreadId, windowThreadId, false);