PowerToys/src/runner/win_hook_event.cpp

83 lines
2.5 KiB
C++
Raw Normal View History

#include "pch.h"
#include "win_hook_event.h"
#include "powertoy_module.h"
#include <mutex>
#include <deque>
#include <thread>
static std::mutex mutex;
static std::deque<WinHookEvent> hook_events;
static std::condition_variable dispatch_cv;
void intercept_system_menu_action(intptr_t);
static void CALLBACK win_hook_event_proc(HWINEVENTHOOK winEventHook,
DWORD event,
HWND window,
LONG object,
LONG child,
DWORD eventThread,
DWORD eventTime) {
std::unique_lock lock(mutex);
hook_events.push_back({ event,
window,
object,
child,
eventThread,
eventTime });
lock.unlock();
dispatch_cv.notify_one();
}
static bool running = false;
static std::thread dispatch_thread;
static void dispatch_thread_proc() {
std::unique_lock lock(mutex);
while (running) {
dispatch_cv.wait(lock, []{ return !running || !hook_events.empty(); });
if (!running)
return;
while (!hook_events.empty()) {
auto event = hook_events.front();
hook_events.pop_front();
lock.unlock();
intptr_t data = reinterpret_cast<intptr_t>(&event);
intercept_system_menu_action(data);
powertoys_events().signal_event(win_hook_event, data);
lock.lock();
}
}
}
static HWINEVENTHOOK hook_handle;
void start_win_hook_event() {
std::lock_guard lock(mutex);
if (running)
return;
running = true;
dispatch_thread = std::thread(dispatch_thread_proc);
hook_handle = SetWinEventHook(EVENT_MIN, EVENT_MAX, nullptr, win_hook_event_proc, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
}
void stop_win_hook_event() {
std::unique_lock lock(mutex);
if (!running)
return;
running = false;
UnhookWinEvent(hook_handle);
lock.unlock();
dispatch_cv.notify_one();
dispatch_thread.join();
lock.lock();
hook_events.clear();
hook_events.shrink_to_fit();
}
void intercept_system_menu_action(intptr_t data) {
WinHookEvent* evt = reinterpret_cast<WinHookEvent*>(data);
if (evt->event == EVENT_SYSTEM_MENUSTART || evt->event == EVENT_OBJECT_INVOKED) {
powertoys_events().handle_system_menu_action(*evt);
}
}