Отправить Ctrl + до окна - PullRequest
       26

Отправить Ctrl + до окна

3 голосов
/ 30 апреля 2010

Я пытаюсь отправить сообщения в окно, в котором говорится, что были нажаты 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 ++.

Ответы [ 3 ]

4 голосов
/ 30 апреля 2010

У меня нет отличного способа проверить это, но сработал бы он, если бы порядок этих двух строк:

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);

так что нажатие клавиши управления по существу оборачивает нажатие другой клавиши?

2 голосов
/ 01 мая 2010

Теперь я нашел способ отправить 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);
2 голосов
/ 30 апреля 2010

Я нашел рабочее решение. Вы используете функцию 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...