This Tcl extension provides access to winapi function SetWindowsHookEx(). It allows to intercept events sent to various windows from OS.
Only a limited number of hooks are currently supported by this extension.
Hook | Thread | Thread revocable | Global |
---|---|---|---|
WH_CALLWNDPROC | 🔲 | 🔲 | 🔲 |
WH_CALLWNDPROCRET | 🔲 | 🔲 | 🔲 |
WH_CBT | 🔲 | 🔲 | 🔲 |
WH_DEBUG | 🔲 | 🔲 | 🔲 |
WH_FOREGROUNDIDLE | 🔲 | 🔲 | 🔲 |
WH_GETMESSAGE | 🔲 | 🔲 | 🔲 |
WH_JOURNALPLAYBACK | ⛔ | ⛔ | 🔲 |
WH_JOURNALRECORD | ⛔ | ⛔ | 🔲 |
WH_KEYBOARD | ✅ | ✅ | 🔲 |
WH_KEYBOARD_LL | ⛔ | ⛔ | 🔲 |
WH_MOUSE | 🔲 | 🔲 | 🔲 |
WH_MOUSE_LL | ⛔ | ⛔ | 🔲 |
WH_MSGFILTER | 🔲 | 🔲 | 🔲 |
WH_SHELL | 🔲 | 🔲 | 🔲 |
WH_SYSMSGFILTER | ⛔ | ⛔ | 🔲 |
This function is used to set hooks.
::winhooks::setHook ?-revocable? ?-threadId THREADID? hookType script
This procedure sets the specified hookType
using the callback script script
. On a successful call, it returns a hookId
, which can be used to release the hook by procedure releaseHook
. On error it returns an error code according to System Error Codes.
By default, a hook is set for its process. If the hook should be set for another process (or globaly), then parameter -threadId
must be used.
Optional parameters:
-revocable
- this option allows to revoke the event from callback script. If this option is specified, then the callback script must return boolean value. If the return value from the callback script is false, the event will be canceled and will not be processed by the target window.-threadId THREADID
- this option sets the scope of the hook. If it is not specified, then the hook will be set for the current process. If this option is set to0
then a global hook will be set. If a thread id is specified for this option, events from the specified thread will be hooked.
This function is used to release hooks.
::winhooks::releaseHook hookId
The hookId
parameter is the value that was previosly returned by procedure setHook
.
lappend auto_path ../release twapi
package require tclwinhooks
package require twapi
# Set keyboard hook for the our GUI window
::winhooks::setHook WH_KEYBOARD [list apply [list { hookNum wParam lParam } {
puts "Self key hook: $hookNum -> $wParam -> $lParam"
}]]
# Start 2 notepad processes
lassign [::twapi::create_process c:/Windows/notepad.exe] pid1 thread1
puts "PID1: $pid1 THREAD1: $thread1"
lassign [::twapi::create_process c:/Windows/notepad.exe] pid2 thread2
puts "PID1: $pid2 THREAD1: $thread2"
# Wait until notepad windows created
while {
[twapi::get_toplevel_windows -pids $pid1] eq "" &&
[twapi::get_toplevel_windows -pids $pid2] eq ""
} {
puts "Waiting for the notepad windows..."
after 10
}
# Set revocable keyboard hook for the first notepad windows
::winhooks::setHook -revocable -threadId $thread1 WH_KEYBOARD [list apply [list { hookNum wParam lParam } {
# block F1
if { [dict get $lParam vkCode] eq "VK_F1" } {
puts "NOTEPAD #1 key blocked: [dict get $lParam vkCode]"
return 1
}
# block "a" key
if { [dict get $lParam vkCode] eq "65" } {
puts "NOTEPAD #1 key blocked: [dict get $lParam vkCode]"
return 1
}
puts "NOTEPAD #1 key hook: $hookNum -> $wParam -> $lParam"
return 0
}]]
# Set keyboard hook for the first notepad windows
::winhooks::setHook -threadId $thread2 WH_KEYBOARD [list apply [list { hookNum wParam lParam } {
puts "NOTEPAD #2 key hook: $hookNum -> $wParam -> $lParam"
}]]