#include "pch.h" #include "win_hook_event.h" #include "powertoy_module.h" #include #include #include static std::mutex mutex; static std::deque 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(&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(data); if (evt->event == EVENT_SYSTEM_MENUSTART || evt->event == EVENT_OBJECT_INVOKED) { powertoys_events().handle_system_menu_action(*evt); } }