简体   繁体   English

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

[英]How to send Ctrl/Shift/Alt + Key combinations to an application window? (via SendMessage)

I can successfully send any single key message to an application, but I don't know how to send combinations of keys (like Ctrl + F12 , Shift + F1 , Ctrl + R , etc..) 我可以成功地将任何单个键消息发送到应用程序,但我不知道如何发送键的组合(如Ctrl + F12Shift + F1Ctrl + R等...)

Tried doing it this way: 试过这样做:

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

but this does not seems to work (application acts like only F12 is pressed, not Ctrl + F12 ). 但这似乎不起作用(应用程序只按下F12 ,而不是Ctrl + F12 )。

Any ideas how to make this work? 任何想法如何使这项工作?

You would probably find that using SendInput (documentation here) works a lot better. 您可能会发现使用SendInput (此处的文档)可以更好地工作。 You will need to P/Invoke it from C#, example here . 你需要从C#调用它, 例如这里 You can provide arrays of data with keys down and up and properly set the other message parameters, for example whether left or right Ctrl / Shift / Alt were pressed. 您可以使用向下和向上键提供数据数组,并正确设置其他消息参数,例如是否按下了向左或向右Ctrl / Shift / Alt

You can also use the SendKeys class ( documentation here ). 您也可以使用SendKeys类( 此处的文档 )。 This allows you to specify keys by name, eg, {^F12} for Ctrl + F12 . 这允许您按名称指定键,例如,对于Ctrl + F12{^F12}

Edit : The OP is now saying he needs to send input to minimized applications without activating them. 编辑 :OP现在说他需要将输入发送到最小化的应用程序而不激活它们。 This is not possible to do reliably in any way , including even with specialized hardware. 这是不可能以任何方式可靠地进行,包括使用专门的硬件。 I've worked in automation. 我从事自动化工作。 It just isn't possible. 这是不可能的。 The OP needs to use FindWindow / SetForegroundWindow to toggle the target app on, and then he can toggle back to his application. OP需要使用FindWindow / SetForegroundWindow来打开目标应用程序,然后他可以切换回他的应用程序。

The OP is now saying he needs to send input to minimized applications without activating them. OP现在说他需要在不激活它们的情况下向最小化的应用程序发送输入。 This is not possible to do reliably in any way, including even with specialized hardware. 这是不可能以任何方式可靠地进行,包括使用专门的硬件。 I've worked in automation. 我从事自动化工作。 It just isn't possible. 这是不可能的。

Sending input to minimized applications is, in fact, possible, not sure about mouse input, but keyboard input works just fine. 事实上,向最小化应用程序发送输入是可能的,不确定鼠标输入,但键盘输入工作正常。 Taking idea in a previous answer here's what I was able to accomplish (code is in Delphi, but it's pretty simple, so you can translate it to your required language): 在前面的回答中提出我的想法是什么(代码在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] must be the control to receive the input, not its parent form etc. [Key] is a key to be pressed; [Win]必须是接收输入的控件,而不是其父表单等。[Key]是要按下的键; [sKey] is an alternative key to be pressed while pressing [Key] such as CTRL/SHIFT (ALT is transferred through message itself, see MSDN WM_KEYDOWN reference for details). [sKey]是按下[Key]时按下的另一个键,例如CTRL / SHIFT(ALT通过消息本身传输,有关详细信息,请参阅MSDN WM_KEYDOWN参考)。

Sending a sole keystroke is fairly simple, you just do the sendmessage and it's done, but if you need to something like CTRL+SPACE here's where it gets complicated. 发送单击按键非常简单,只需执行sendmessage即可完成,但如果你需要像CTRL + SPACE这样的东西,那么它就变得复杂了。 Each thread has its own KeyboardState, altering KeyboardState in your own app will not affect another unless you join their thread inputs by AttachThreadInput function. 每个线程都有自己的KeyboardState,在您自己的应用程序中更改KeyboardState不会影响另一个,除非您通过AttachThreadInput函数加入其线程输入。 When application processes WM_KEYDOWN message it also tests current shift states (CTRL/SHIFT) by calling GetKeyboardState function (ALT key can be sent through the additional parameter of WM_KEYDOWN message) and that's when attached thread input comes into play. 当应用程序处理WM_KEYDOWN消息时,它还通过调用GetKeyboardState函数(ALT键可以通过WM_KEYDOWN消息的附加参数发送)测试当前的移位状态(CTRL / SHIFT),并且当附加的线程输入发挥作用时。

I already tried the method with GetKeyboardState and SetKeyboardState (preceded by attaching the window thread and ended with detaching from window thread). 我已经尝试了使用GetKeyboardState和SetKeyboardState的方法(先附加窗口线程,最后从窗口线程中分离)。 I doesn't work for combinations of keys like Ctrl+Something or combinations using Alt or Shift also. 我不能使用Ctrl + Something等键组合或使用Alt或Shift组合键。 Control, Alt and Shift keys are not seen as pressed. Control,Alt和Shift键不被视为按下。 It seems like the maximum you can get when the window is minimized is pressing individual keys using PostMessage with WM_KEYDOWN messages. 看起来当窗口最小化时可以获得的最大值是使用带有WM_KEYDOWN消息的PostMessage按下单个键。 Another thing I noticed is that if you Post WM_KEYDOWN and WM_KEYUP (for the same key) the key will be pressed twice. 我注意到的另一件事是,如果你发布WM_KEYDOWN和WM_KEYUP(对于相同的键),键将被按两次。 So only use WM_KEYDOWN one time. 所以一次只能使用WM_KEYDOWN。 This is not an 100% accurate method but when window is minimized there are some limitations. 这不是100%准确的方法,但是当窗口最小化时,存在一些限制。

The same situation happens when screen is locked. 屏幕锁定时会发生相同的情况。

Maybe you are looking something like that: 也许你看起来像这样:

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(Self); GoCursorUp(自拍);

Or something like this: 或类似的东西:

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

If you want to simulate keystrokes to minimized windows you can do something like this: 如果要模拟按键以最小化窗口,可以执行以下操作:

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

Next step is to use GetKeyboardState function to retrieve an array of all keys states of the window thread. 下一步是使用GetKeyboardState函数来检索窗口线程的所有键状态的数组。 Modify the state of SHIFT or CTRL or ALT keys to being pressed using their virtual key codes. 使用虚拟键代码修改SHIFT或CTRL或ALT键的状态。 Then call SetKeyboardState to apply these states. 然后调用SetKeyboardState以应用这些状态。 Press the F12 key: 按F12键:

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

Modify back the states of SHIFT, CTRL or ALT keys as being released. 将SHIFT,CTRL或ALT键的状态修改为已释放。 Call SetKeyboardState again. 再次调用SetKeyboardState。 Finally, detach from window thread: 最后,从窗口线程分离:

AttachThreadInput(myThreadId, windowThreadId, false);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM