Понимание мыши низкого уровня и захвата клавиатуры (win32)

Я пытаюсь получить глобальную мышь и ввод с клавиатуры.

LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
  if (nCode >= 0) {
    if (wParam == WM_RBUTTONDOWN) printf("right mouse down\n");
    if (wParam == WM_RBUTTONUP) printf("right mouse up\n");
  }
  return CallNextHookEx(0, nCode, wParam, lParam);
}

HHOOK mousehook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0);
while(true) {
  MSG msg;
  if (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
    printf("msg recvd\n");
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
#ifdef TEST
  Sleep(50);
#endif
}

Таким образом, все работает здесь, кроме если я #define TEST вставить Sleep, мышь становится невероятно вялой, как мог бы ожидаться, если я внезапно только позволяю мыши обновлять 20 раз в секунду. И безо сна, я привязываю ЦП в 100%. Но это хорошо на данный момент (который уходит, если я использую GetMessage).

Теперь насколько я понимаю низкий уровень сцепляет работу контекстным переключением на процесс, который установил его, и затем отправка процесса некоторого сообщения, чтобы позволить ему выполнить обратный вызов рычага. Что смущает меня, немного, тем не менее, то, почему моя программа никогда не будет печатать "сообщение recvd", но это печатает "правильную мышь вниз /" каждый раз, когда я щелкаю правой кнопкой мыши. Это приводит меня приходить к заключению что мой MouseHookProc вызывается во время PeekMessage звонить. Это просто, оказывается, некоторое специальное сообщение и PeekMessage возвраты 0. Но я все еще должен звонить PeekMessage или некоторый эквивалент.

Так как моя программа должна сделать набор вещей, я ясно не могу пригнуть свое сообщение, качающее цикл (тот, который звонит PeekMessage) путем вызывания другой функции, которая берет, скажите 50 мс для возврата. Как я мог бы мультираспараллелить свою программу для поддержания скорости отклика мыши при одновременном выполнении небольшого тяжелого подъема? В многопоточной win32 программе существует все еще всего одна очередь сообщений, правильно?

Обновление: После чтения на документации MS я думаю, что знаю, какова правильная вещь для меня, чтобы сделать. Я должен просто породить поток в своем приложении, которое звонит SetWindowsHookEx зарегистрировать рычаг мыши и затем сидеть без дела в его собственном цикле сообщения и системе будут заботиться об отправке обновлений мыши этого потока. Это будет свободно сделать независимо от того, что это хочет в MouseHookProc, и остальная часть моего приложения будет работать независимо.

13
задан Steven Lu 28 June 2010 в 16:41
поделиться

4 ответа

Проблема в вашем цикле сообщений, он сжигает 100% циклов ЦП, потому что вы используете PeekMessage (). Windows знает, как поддерживать ловушку, даже если вы не запрашиваете сообщения, используйте GetMessage () для решения вашей проблемы. Использование Sleep (1) также решит вашу проблему, но в этом нет необходимости.

Почему необходимо использовать SetWindowsHookEx с очередью сообщений Windows

11
ответ дан 1 December 2019 в 22:06
поделиться

Вместо того, чтобы делать:

if (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
    printf("msg recvd\n");
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
Sleep(50);

Переключитесь на:

while (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
    // Add this potentially...
    if (msg.message == WM_QUIT)
        break;
    printf("msg recvd\n");
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}
Sleep(10);

Это позволит ваше приложение, чтобы продолжить обработку всех сообщений в очереди, пока она не станет пустой (например, без сна), затем откажитесь от некоторого процессорного времени, когда приложение находится в режиме ожидания.

3
ответ дан 1 December 2019 в 22:06
поделиться

MouseHookProc должен находиться в dll, иначе вы не сможете захватить «глобальный» ввод ( http://msdn.microsoft.com/en-us/library/ms997537. aspx )

О цикле - вы можете изменить его так:

while(true) {
  MSG msg;
  while (PeekMessage(&msg,0,0,0,PM_REMOVE)) {
    printf("msg recvd\n");
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
#ifdef TEST
  DoStuff();
  Sleep(50);
#endif
}
3
ответ дан 1 December 2019 в 22:06
поделиться

Я спросил вас, размещаете ли вы MouseHookProc в DLL, потому что при попытке разместить его внутри EXE возникает типичная ошибка. Я также делал ее много лет назад.

Прежде всего, как вы можете прочитать в http://msdn.microsoft.com/en-us/library/ms644990.aspx:

SetWindowsHookEx может быть использован для внедрения DLL в другой процесс. 32-битная DLL не может быть внедрена в 64-битный процесс, а 64-битная DLL не может быть внедрить в 32-битный процесс. Если приложение требует использования крючков в других процессах, необходимо чтобы 32-битное приложение вызвало SetWindowsHookEx для внедрения 32-битной DLL в 32-битные процессы, а 64-битное приложение вызывало SetWindowsHookEx для внедрения 64-битной DLL в 64-битные процессы. 32-битные и 64-битные библиотеки DLL должны иметь разные имена.

Поэтому вы должны поместить в DLL. Точнее, если вы хотите поддерживать как 32-битную, так и 64-битную платформы, вам придется реализовать две DLL: одну 32-битную и 64-битную DLL. Но зачем? И как работает SetWindowsHookEx?

Если вы выполните в EXE следующий код

HINSTANCE hinstDLL = LoadLibrary(TEXT("c:\\myapp\\syshook.dll"));
HOOKPROC hkprcMouse = (HOOKPROC)GetProcAddress(hinstDLL, "MouseHookProc");
HHOOK hhookMouse = SetWindowsHookEx( 
                    WH_MOUSE_LL,
                    hkprcMouse,
                    hinstDLL,
                    0); 

вы дадите user32.dll запрос на внедрение вашей syshook.dll во все остальные процессы на той же станции windows (dll не будет внедрена в службы и процессы других пользователей, залогиненных через быстрое переключение пользователей). Затем user32.dll вызывает LoadLibrary к syshook.dll в разных процессах. Затем, если будет вызвана функция MouseHookProc, то она будет вызвана в контексте процесса, который передал сообщение мыши. Если процесс не является консольным приложением, то код типа

printf("right mouse down\n");

не может работать.

Итак, надеюсь, теперь вы поняли, почему вы должны поместить MouseHookProc в DLL.

6
ответ дан 1 December 2019 в 22:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: