Co-authored-by: Alexis Campailla <alexis@janeasystems.com> Co-authored-by: Bret Anderson <bretan@microsoft.com> Co-authored-by: Enrico Giordani <enrico.giordani@gmail.com> Co-authored-by: Jaime Bernardo <jaime@janeasystems.com> Co-authored-by: Jeff Bogdan <jeffbog@microsoft.com> Co-authored-by: March Rogers <marchr@microsoft.com> Co-authored-by: Mike Harsh <mharsh@microsoft.com> Co-authored-by: Nachum Bundak <Nachum.Bundak@microsoft.com> Co-authored-by: Oliver Jones <ojones@microsoft.com> Co-authored-by: Patrick Little <plittle@microsoft.com>
4.0 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.