c# передать Комбинацию клавиш в неактивное окно

Нужно передать Ctrl+Shift+M в неактивное окно браузера Firefox

SetForegroundWindow(HandleWnd);
SendKeys.SendWait("^+(m)");

Так работает, но окно активным становится при этом

[DllImport("user32.dll")] 
public static extern int FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")] 
public static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam);

public static void Go()
{
    HandleWnd = FindWindow(null, "Mozilla Firefox");
    const uint WM_KEYDOWN = 0x0100;
    const uint WM_KEYUP = 0x0101;
    PostMessage(HandleWnd, WM_KEYDOWN, (int)(System.Windows.Forms.Keys.Control), 0);
    PostMessage(HandleWnd, WM_KEYDOWN, (int)(System.Windows.Forms.Keys.Shift), 0);
    PostMessage(HandleWnd, WM_KEYDOWN, (int)(System.Windows.Forms.Keys.M), 0);
    PostMessage(HandleWnd, WM_KEYUP, (int)(System.Windows.Forms.Keys.M), 0);
    PostMessage(HandleWnd, WM_KEYUP, (int)(System.Windows.Forms.Keys.Shift), 0);
    PostMessage(HandleWnd, WM_KEYUP, (int)(System.Windows.Forms.Keys.Control), 0);
}

Это ближе к правильному, но не работает почему то


Ответы (1 шт):

Автор решения: aepot

Долгая история, но вот все необходимое для нажатия CTRL+SHIFT+M в Firefox, работает на свернутом окне. Дело в том что FF проверяет состояние клавиш Crtl и Shift через прямой ввод, а не через WM. Поэтому через WM достаточно отправить только букву.

[DllImport("user32.dll")]
internal static extern uint MapVirtualKey(Keys uCode, uint uMapType);

[DllImport("user32.dll", CharSet = CharSet.Unicode)]
internal static extern IntPtr FindWindow(IntPtr className, string windowName);

[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint msg, uint wParam, uint lParam);

[DllImport("user32.dll")]
internal static extern void keybd_event(Keys bVk, byte bScan, uint dwFlags, uint dwExtraInfo);

const uint WM_KEYDOWN = 0x100;
const uint WM_KEYUP = 0x0101;

// https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keydown
// https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keyup
public static void WindowsMessageSendKey(IntPtr hwnd, Keys keyCode, bool isDown)
{
    uint scanCode = MapVirtualKey(keyCode, 0);
    uint lParam = 0x00000001 | (scanCode << 16);
    if (!isDown)
        lParam |= 0xC0000000;
    PostMessage(hwnd, isDown ? WM_KEYDOWN : WM_KEYUP, (uint)keyCode, lParam);
}

private void CtrlShiftM_Firefox()
{
    IntPtr hwnd = FindWindow("MozillaWindowClass", null);
    if (hwnd == IntPtr.Zero)
        throw new NullReferenceException("Firefox window wasn't found. hwnd is null");
    byte VK_CONTROL = (byte)MapVirtualKey(Keys.ControlKey, 0);
    byte VK_SHIFT = (byte)MapVirtualKey(Keys.ShiftKey, 0);
    keybd_event(Keys.ControlKey, VK_CONTROL, 0, 0);
    keybd_event(Keys.ShiftKey, VK_SHIFT, 0, 0);
    WindowsMessageSendKey(hwnd, Keys.M, true);
    Thread.Sleep(20); // этот костыль обязателен, иначе FF не успеет отреагировать на WM, пока клавиши нажаты
    WindowsMessageSendKey(hwnd, Keys.M, false);
    keybd_event(Keys.ShiftKey, VK_SHIFT, 0x02, 0);
    keybd_event(Keys.ControlKey, VK_CONTROL, 0x02, 0);
}

Устаревший keybd_event грамотнее заменить на более современный SendInput. Или использовать NuGet пакет InputSimulator. Но и так вроде работает.

→ Ссылка