13

我可以成功地将任何单个键消息发送到应用程序,但我不知道如何发送键组合(如Ctrl+ F12Shift+ F1Ctrl+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)。

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

4

5 回答 5

4

您可能会发现使用 SendInput (此处的文档)效果更好。您将需要从 C# 中 P/Invoke 它,例如此处。您可以提供带有向下和向上键的数据数组,并正确设置其他消息参数,例如是否按下了左键或Ctrl右键。ShiftAlt

您还可以使用SendKeys该类(此处的文档)。这允许您按名称指定键,例如{^F12}for Ctrl+ F12

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

于 2012-11-02T17:45:41.033 回答
4

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] 必须是接收输入的控件,而不是其父窗体等。 [Key] 是要按下的键;[sKey] 是在按下 [Key] 时按下的替代键,例如 CTRL/SHIFT(ALT 通过消息本身传输,有关详细信息,请参阅 MSDN WM_KEYDOWN 参考)。

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

于 2013-05-29T15:50:05.450 回答
3

I already tried the method with GetKeyboardState and SetKeyboardState (preceded by attaching the window thread and ended with detaching from window thread). I doesn't work for combinations of keys like Ctrl+Something or combinations using Alt or Shift also. Control, Alt and Shift keys are not seen as pressed. It seems like the maximum you can get when the window is minimized is pressing individual keys using PostMessage with WM_KEYDOWN messages. Another thing I noticed is that if you Post WM_KEYDOWN and WM_KEYUP (for the same key) the key will be pressed twice. So only use WM_KEYDOWN one time. This is not an 100% accurate method but when window is minimized there are some limitations.

The same situation happens when screen is locked.

于 2015-03-31T11:30:21.963 回答
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);
于 2013-02-26T20:59:38.637 回答
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);
于 2015-03-18T09:10:26.480 回答