# Shared hooks To minimize the performance impact on the machine only `runner` installs global hooks, passing the events to registered callbacks in each PowerToy module. When a PowerToy module is loaded, the `runner` calls the [`get_events()`](/src/modules/interface/powertoy_module_interface.h#L40) method to get a NULL-terminated array of NULL-terminated strings with the names of the events that the PowerToy wants to subscribe to. A `const wchar_t*` string is provided for each of the event names. Events are signalled by the `runner` calling the [`signal_event(name, data)`](/src/modules/interface/powertoy_module_interface.h#L53) method of the PowerToy module. The `name` parameter contains the NULL-terminated name of the event. The `data` parameter and the method return value are specific for each event. Currently supported hooks: * `"ll_keyboard"` - [Low Level Keyboard Hook](#low-level-keyboard-hook) * `"win_hook_event"` - [Windows Event Hook](#windows-event-hook) ## Low Level Keyboard Hook This event is signaled whenever the user presses or releases a key on the keyboard. To subscribe to this event, add `"ll_keyboard"` to the table returned by the `get_events()` method. The PowerToys runner installs low-level keyboard hook using `SetWindowsHookEx(WH_KEYBOARD_LL, ...)`. See [this MSDN page](https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms644985(v%3Dvs.85)) for details. When a keyboard event is signaled and `ncCode` equals `HC_ACTION`, the `wParam` and `lParam` event parameters are passed to all subscribed clients in the [`LowlevelKeyboardEvent`](/src/modules/interface/lowlevel_keyboard_event_data.h#L38-L41) struct. The `intptr_t data` event argument is a pointer to the `LowlevelKeyboardEvent` struct. A non-zero return value from any of the subscribed PowerToys will cause the runner hook proc to return 1, thus swallowing the keyboard event. Example usage, that makes Windows ignore the L key: ```c++ virtual const wchar_t** get_events() override { static const wchar_t* events[2] = { ll_keyboard, nullptr }; return events; } virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override { if (wcscmp(name, ll_keyboard) == 0) { auto& event = *(reinterpret_cast(data)); // The L key has vkCode of 0x4C, see: // https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes if (event.wParam == WM_KEYDOWN && event.lParam->vkCode == 0x4C) { return 1; } else { return 0; } } else { return 0; } } ``` ## Windows Event Hook This event is signaled for [a range of events](https://docs.microsoft.com/pl-pl/windows/win32/winauto/event-constants). To subscribe to this event, add `"win_hook_event"` to the table returned by the `get_events()` method. See [this MSDN doc](https://docs.microsoft.com/pl-pl/windows/win32/api/winuser/nf-winuser-setwineventhook) for details. The `intptr_t data` event argument is a pointer to the [`WinHookEvent`](/src/modules/interface/win_hook_event_data.h#L43-L50) struct. The return value of the event handler is ignored. Example usage, that detects a window being resized: ```c++ virtual const wchar_t** get_events() override { static const wchar_t* events[2] = { win_hook_event, nullptr }; return events; } virtual intptr_t signal_event(const wchar_t* name, intptr_t data) override { if (wcscmp(name, win_hook_event) == 0) { auto& event = *(reinterpret_cast(data)); switch (event.event) { case EVENT_SYSTEM_MOVESIZESTART: size_start(event.hwnd); break; case EVENT_SYSTEM_MOVESIZEEND: size_end(event.hwnd); break; default: break; } } return 0; } ``` Taking too long to process the events has negative impact on the whole system performance. To address this, the events are signaled from a different thread, not from the event hook callback itself.