У меня есть приложение, которое должно отправлять нажатия клавиш другому процессу. У меня был ограниченный успех при использовании функции PostMessage, определенной в user32.dll. Я могу отправлять обычные нажатия клавиш, но не могу отправлять нажатия клавиш с модификаторами (например, ALT, CTRL).
Покажу, что у меня сейчас есть...
Константы:
public const ushort WM_KEYDOWN = 0x0100;
public const ushort WM_KEYUP = 0x0101;
public const ushort WM_SYSKEYDOWN = 0x0104;
public const ushort WM_SYSKEYUP = 0x0105;
public const ushort WM_SYSCHAR = 0x0106;
public const ushort VK_MENU = 0x12; // ALT key
Импорт DLL:
[DllImport("user32.dll")]
public static extern int PostMessage(IntPtr hWnd, int Msg, uint wParam, int lParam);
Способ отправки одного ключа:
public static void PostKey(ushort key, IntPtr hWnd)
{
SetActiveWindow(hWnd);
PostMessage(hWnd, WM_KEYDOWN, key, 0);
PostMessage(hWnd, WM_KEYUP, key, 0);
}
Метод отправки одной клавиши вместе с ALT (не работает):
public static void PostKeyWithAlt(ushort key, IntPtr hWnd)
{
SetActiveWindow(hWnd);
PostMessage(hWnd, WM_SYSKEYDOWN, VK_MENU, 0);
PostMessage(hWnd, WM_SYSKEYDOWN, key, 0);
PostMessage(hWnd, WM_SYSKEYUP, key, 0);
PostMessage(hWnd, WM_KEYUP, VK_MENU, 0);
}
PostKey работает безупречно. Я могу подключиться к другому процессу, получить дескриптор главного окна и отправить любое произвольное нажатие клавиши.
Проблема возникает, когда я пытаюсь использовать PostKeyWithAlt. Это просто не работает. (Ключ отправляется, но не ALT, поэтому он в основном такой же, как PostKey.) Я погуглил и перепробовал так много комбинаций вызовов методов, что, честно говоря, готов назвать это выходом. :П
Итак, в отчаянии я воспользовался инструментом Visual Studio Spy++, чтобы посмотреть, что происходит, когда я нажимаю ALT+F1 в целевом приложении. Вот результат захвата сообщения:
Журнал Шпиона++:
<00001> 00080228 P WM_SYSKEYDOWN nVirtKey:VK_MENU cRepeat:1 ScanCode:38 fExtended:0 fAltDown:1 fRepeat:0 fUp:0
<00002> 00080228 P WM_SYSKEYDOWN nVirtKey:VK_F1 cRepeat:1 ScanCode:3B fExtended:0 fAltDown:1 fRepeat:0 fUp:0
<00003> 00080228 P WM_SYSKEYUP nVirtKey:VK_F1 cRepeat:1 ScanCode:3B fExtended:0 fAltDown:1 fRepeat:1 fUp:1
<00004> 00080228 P WM_KEYUP nVirtKey:VK_MENU cRepeat:1 ScanCode:38 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
Как видите, последовательность точно такая же, как у моей функции PostKeyWithAlt. Так что я бы подумал, что это сработает, но это не так.
Здесь должно быть что-то еще. Единственное, что я могу придумать, это четвертый параметр функции PostMessage. Согласно документации Microsoft этот четвертый параметр определяется как LPARAM lParam (см. ниже полное определение функции PostMessage).
Возможно, мне нужно установить для параметра lParam значение, отличное от 0? Если да, то какие значения мне нужно установить? Могу ли я использовать журнал Spy++, чтобы выяснить это? Если это так, я не понимаю, как интерпретировать что-либо после _nVirtKey:VK_MENU_ в этих сообщениях журнала:
<00001>.... cRepeat:1 ScanCode:38 fExtended:0 fAltDown:1 fRepeat:0 fUp:0
<00002>.... cRepeat:1 ScanCode:3B fExtended:0 fAltDown:1 fRepeat:0 fUp:0
<00003>.... cRepeat:1 ScanCode:3B fExtended:0 fAltDown:1 fRepeat:1 fUp:1
<00004>.... cRepeat:1 ScanCode:38 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
Если бы я мог перевести приведенные выше сообщения журнала в правильный аргумент lParam, это могло бы сработать.
Любая помощь/предложения о том, как это сделать, будет принята с благодарностью.
В качестве альтернативы, есть ли другой более элегантный способ отправки нажатий клавиш процессу? Возможно, библиотека С#? Я знаю о классе SendKeys, но этот класс не отправляет нажатия клавиш другим приложениям.
Спасибо!
Определение функции PostMessage:
BOOL WINAPI PostMessage(
_In_opt_ HWND hWnd,
_In_ UINT Msg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);