[英]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.