I'm trying to send messages to a window that says Ctrl and Up-arrow has been pressed. I've got the basics down, I can send presses of the space key that registeres fine. But I can't seem to get the ctrl+ ↑ working. chosen code snippets:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
Now this works fine for sending Space:
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);
}
But this doesn't work for sending Ctrl+↑ to VLC to increase the sound volume:
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 lParamCtrlDown开发者_运维百科Ptr = 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);
}
What am I missing?
Edit3: The Messages are exactly the same and there are no extra messages since I switched to PostMessage but VLC still won't increase or decrease the volume.
It's not just VLC either, Spotify won't accept the same command even though the messagess look exactly alike in Spy++.
I don't have a great way to test it, but would it work if the order of these two lines:
SendMessage(handle, (int) WMessages.WM_KEYDOWN, (int) key, 0);
SendMessage(handle, (int) WMessages.WM_KEYDOWN, (int)VKeys.VK_CONTROL, 0);
was changed to:
SendMessage(handle, (int) WMessages.WM_KEYDOWN, (int)VKeys.VK_CONTROL, 0);
SendMessage(handle, (int) WMessages.WM_KEYDOWN, (int) key, 0);
so that the control key being down essentially wraps the press of the other key?
I found a working solution. You use the SetKeyboardState function to depress the control key, and then you can send any key you want. This Delphi code sends Ctrl+Right to a Memo component.
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;
I now found a method to send Ctrl+Right (for example) to a window of another process. If hEdit
is the handle of the window, then the following code works.
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"
Update
The drawback of this method is that the focus is changed for a small duration of time. In fact, the best solution, I believe, is a combination of my previous and this post:
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);
精彩评论