簡體   English   中英

發送 Ctrl+Up 到一個窗口

[英]Send Ctrl+Up to a window

我正在嘗試向一個窗口發送消息,該窗口顯示已按下 Ctrl 和向上箭頭。 我已經掌握了基礎知識,我可以發送可以正常注冊的空格鍵。 但我似乎無法讓ctrl + 工作。 選擇的代碼片段:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

現在這適用於發送空間:

public static void SendKeyPress(IntPtr handle, VKeys key)
{
    SendMessage(handle, (int) WMessages.WM_KEYDOWN, (int) key, 0);
    SendMessage(handle, (int)WMessages.WM_KEYUP, (int)key, 0);
}

但這不適用於將Ctrl + 發送到 VLC 以增加音量:

public static void SendKeyPress(IntPtr handle, VKeys key, bool control)
{
    int lParamKeyDown = 0;
    lParamKeyDown |= 1;
    lParamKeyDown |= 1 << 24;

    int lParamKeyUp = lParamKeyDown;
    lParamKeyUp |= 1 << 30;
    lParamKeyUp |= 1 << 31; //it was down before

    int lParamCtrlDown = lParamKeyDown;
    int lParamCtrlUp = lParamKeyUp;

    lParamKeyDown |= (int)MapVirtualKey((uint)key, 0) << 16;
    lParamKeyUp |= (int)MapVirtualKey((uint)key, 0) << 16;
    lParamCtrlDown |= (int)MapVirtualKey((uint)VKeys.VK_CONTROL, 0) << 16;
    lParamCtrlUp |= (int)MapVirtualKey((uint)VKeys.VK_CONTROL, 0) << 16;

    IntPtr controlPtr = new IntPtr((int)VKeys.VK_CONTROL);
    IntPtr lParamCtrlDownPtr = new IntPtr(lParamCtrlDown);
    IntPtr lParamCtrlUpPtr = new IntPtr(lParamCtrlUp);
    IntPtr lParamKeyDownPtr = new IntPtr(lParamKeyDown);
    IntPtr lParamKeyUpPtr = new IntPtr(lParamKeyUp);
    IntPtr keyPtr = new IntPtr((int)key);
    object o = new object();
    HandleRef wndRef = new HandleRef(o, handle);
    PostMessage(wndRef, (uint)WMessages.WM_KEYDOWN, controlPtr, lParamCtrlDownPtr);
    PostMessage(wndRef, (uint) WMessages.WM_KEYDOWN, keyPtr, lParamKeyDownPtr);

    PostMessage(wndRef, (uint) WMessages.WM_KEYUP, controlPtr, lParamCtrlUpPtr);
    PostMessage(wndRef, (uint) WMessages.WM_KEYUP, keyPtr, lParamKeyUpPtr);
 }

我錯過了什么?

Edit3:消息完全相同,自從我切換到 PostMessage 后沒有額外的消息,但 VLC 仍然不會增加或減少音量。

不僅是 VLC,Spotify 也不會接受相同的命令,即使 Spy++ 中的消息看起來完全相同。

我沒有一個很好的方法來測試它,但是如果這兩行的順序是否可行:

SendMessage(handle, (int) WMessages.WM_KEYDOWN, (int) key, 0);
SendMessage(handle, (int) WMessages.WM_KEYDOWN, (int)VKeys.VK_CONTROL, 0);

改為:

SendMessage(handle, (int) WMessages.WM_KEYDOWN, (int)VKeys.VK_CONTROL, 0);
SendMessage(handle, (int) WMessages.WM_KEYDOWN, (int) key, 0);

以便按下的控制鍵基本上包裹了另一個鍵的按下?

我找到了一個可行的解決方案。 您使用SetKeyboardState函數按下控制鍵,然后您可以發送任何您想要的鍵。 此 Delphi 代碼將 Ctrl+Right 發送到 Memo 組件。

var
  s: TKeyboardState;
  PrevState: byte;
begin
  GetKeyboardState(s);
  PrevState := s[VK_CONTROL];
  s[VK_CONTROL] := 128;
  SetKeyboardState(s);
  SendMessage(Memo1.Handle, WM_KEYDOWN, VK_RIGHT, 0);
  s[VK_CONTROL] := PrevState;
  SetKeyboardState(s)
end;

我現在找到了一種將Ctrl + Right (例如)發送到另一個進程的窗口的方法。 如果hEdit是窗口的句柄,則以下代碼有效。

AttachThreadInput(GetCurrentThreadID, GetWindowThreadProcessId(hEdit, 0), true);
hEdit := SetFocus(hEdit);

keybd_event(VK_CONTROL, 0, 0, 0);
keybd_event(VK_RIGHT, 0, 0, 0);
keybd_event(VK_RIGHT, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);

SetFocus(hEdit); // restore focus
AttachThreadInput(GetCurrentThreadID, GetWindowThreadProcessId(hEdit, 0), false); // "Disconnect"

更新

這種方法的缺點是焦點會在很短的時間內發生變化。 事實上,我相信最好的解決方案是結合我之前和這篇文章:

var
  s: TKeyboardState;
  PrevState: byte;

AttachThreadInput(GetCurrentThreadID, GetWindowThreadProcessId(hEdit, 0), true);

GetKeyboardState(s);
PrevState := s[VK_CONTROL];
s[VK_CONTROL] := 128;
SetKeyboardState(s);
SendMessage(hEdit, WM_KEYDOWN, VK_RIGHT, 0);
s[VK_CONTROL] := PrevState;
SetKeyboardState(s);

AttachThreadInput(GetCurrentThreadID, GetWindowThreadProcessId(hEdit, 0), false);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM