* docs: split usage and dev docs * # This is a combination of 2 commits. # This is the 1st commit message: docs: split usage and dev docs # The commit message #2 will be skipped: # fixup add docs * docs: add runner documentation and move hooks documentation to devdocs * docs: add stubs for modules technical description * docs: add paragraph about event thread-safety * docs: add 'Current modules' section header
3.9 KiB
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()
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)
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"win_hook_event"
- 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 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
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:
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<LowlevelKeyboardEvent*>(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. To subscribe to this event, add "win_hook_event"
to the table returned by the get_events()
method. See this MSDN doc for details.
The intptr_t data
event argument is a pointer to the WinHookEvent
struct.
The return value of the event handler is ignored.
Example usage, that detects a window being resized:
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<WinHookEvent*>(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.