У меня возникли проблемы с написанием слушателя клавиш мыши.
Моя цель
Цель состоит в том, чтобы написать общесистемный слушатель кнопок / клавиш, который поддерживает ввод с клавиатуры и кнопок мыши.
Не волнуйтесь, эта тема только о частях кнопок мыши, слушатель клавиатуры работает отлично.
Я использую это для пу sh, чтобы говорить голосовые ворота для моего Приложение VoIP.
Мой текущий подход
В настоящее время я использую WH_MOUSE_LL
ловушку мыши для захвата событий мыши.
Для достижения максимальной производительности Чтобы избежать замедления работы мыши, я попытался минимизировать любые узкие места.
В настоящее время я использую этот код для метода обратного вызова:
thread_local KeyboardHook* thread_hook{nullptr};
void KeyboardHook::register_mouse_hook() {
this->mouse_hook_id = SetWindowsHookEx(WH_MOUSE_LL, _mouse_hook_callback, GetModuleHandle(nullptr), 0);
if(!this->keyboad_hook_id) {
UnhookWindowsHookEx(this->keyboad_hook_id);
cerr << "Failed to register mouse hook" << endl;
return;
}
MSG msg;
while(!GetMessage(&msg, nullptr, 0, 0) && this->active) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
LRESULT _mouse_hook_callback(int nCode, WPARAM event, LPARAM ptr_keyboard) {
assert(thread_hook);
auto consume = thread_hook->mouse_hook_callback(nCode, event, ptr_keyboard);
if(consume)
return 1;
return CallNextHookEx(nullptr, nCode, event, ptr_keyboard);
}
bool KeyboardHook::mouse_hook_callback(int nCode, WPARAM event, LPARAM ptr_mouse) {
MouseButtonEventEntry* mb_event;
switch (event) {
case WM_LBUTTONDOWN:
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::PRESS;
mb_event->key = "MOUSE1";
break;
case WM_LBUTTONUP:
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::RELEASE;
mb_event->key = "MOUSE1";
break;
case WM_RBUTTONDOWN:
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::PRESS;
mb_event->key = "MOUSE3";
break;
case WM_RBUTTONUP:
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::RELEASE;
mb_event->key = "MOUSE3";
break;
case WM_XBUTTONDOWN: {
auto mouse = (MouseHookStruct*) ptr_mouse;
auto x_index = GET_XBUTTON_WPARAM(mouse->mouseData);
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::PRESS;
mb_event->key = "MOUSEX" + std::to_string(x_index);
break;
}
case WM_XBUTTONUP: {
auto mouse = (MouseHookStruct*) ptr_mouse;
auto x_index = GET_XBUTTON_WPARAM(mouse->mouseData);
mb_event = allocate_mb_event();
mb_event->type = KeyEvent::RELEASE;
mb_event->key = "MOUSEX" + std::to_string(x_index);
break;
}
default:
return false;
}
mb_event->next = nullptr;
mb_event->hook = thread_hook;
EnterCriticalSection(&global_event_dispatcher->mutex);
*global_event_dispatcher->event_tail = mb_event;
global_event_dispatcher->event_tail = &mb_event->next;
/* notify other threads that some work needs to be done */
WakeAllConditionVariable(&global_event_dispatcher->cv_work);
LeaveCriticalSection(&global_event_dispatcher->mutex);
return false;
}
Обратите внимание, хотя allocate_mb_event
может указывать иначе, я не выделяю никакой памяти в этом методе вообще. Я просто использую список блоков без блокировок, чтобы получить следующую структуру MouseButtonEventEntry
.
Блокировка global_event_dispatcher->mutex
также не является проблемой, только один другой поток может заблокировать этот мьютекс. Он спит на условной переменной, а затем извлекает только следующие записи в очереди событий, когда получает уведомление через cv.
Моя проблема
В общем, этот код работает как задумано ... за исключением некоторых пользователей.
Некоторые пользователи, особенно те, которые играют в игры, испытывают значительное отставание / замедление работы мыши.
Как выясняется, это похоже на крючок WH_MOUSE_LL
сама проблема. Даже без какой-либо значительной обработки событий (например, пустой метод) они все еще испытывают это.
Один из моих подходов заключался в повышении класса приоритета диспетчерского потока до REALTIME_PRIORITY_CLASS
, но это не очень помогает. Я также измерил фактическое время, потраченное на обратный вызов, и оно постоянно было меньше 1us.
Так что я не думаю, что обратный вызов - это сама проблема.
Что я ищу
Я не уверен, просто ли я что-то пропускаю или использование обратного вызова WH_MOUSE_LL
вообще не очень хорошая идея.
Итак, что может быть альтернативой для захвата глобальных событий кнопок мыши или каким-то образом улучшить производительность обратного вызова?