Last active
February 21, 2024 10:13
-
-
Save obonyojimmy/52d836a1b31e2fc914d19a81bd2e0a1b to your computer and use it in GitHub Desktop.
go lang keyboard capture
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"syscall" | |
//~ "time" | |
"unsafe" | |
"golang.org/x/sys/windows" | |
) | |
// String returns a human-friendly display name of the hotkey | |
// such as "Hotkey[Id: 1, Alt+Ctrl+O]" | |
var ( | |
user32 = windows.NewLazySystemDLL("user32.dll") | |
procSetWindowsHookEx = user32.NewProc("SetWindowsHookEx") | |
procLowLevelKeyboard = user32.NewProc("LowLevelKeyboardProc") | |
procCallNextHookEx = user32.NewProc("CallNextHookEx") | |
procUnhookWindowsHookEx = user32.NewProc("UnhookWindowsHookEx") | |
procGetMessage = user32.NewProc("GetMessageW") | |
procTranslateMessage = user32.NewProc("TranslateMessage") | |
procDispatchMessage = user32.NewProc("DispatchMessageW") | |
keyboardHook HHOOK | |
) | |
const ( | |
WH_KEYBOARD_LL = 13 | |
WH_KEYBOARD = 2 | |
WM_KEYDOWN = 256 | |
WM_SYSKEYDOWN = 260 | |
WM_KEYUP = 257 | |
WM_SYSKEYUP = 261 | |
WM_KEYFIRST = 256 | |
WM_KEYLAST = 264 | |
PM_NOREMOVE = 0x000 | |
PM_REMOVE = 0x001 | |
PM_NOYIELD = 0x002 | |
WM_LBUTTONDOWN = 513 | |
WM_RBUTTONDOWN = 516 | |
NULL = 0 | |
) | |
type ( | |
DWORD uint32 | |
WPARAM uintptr | |
LPARAM uintptr | |
LRESULT uintptr | |
HANDLE uintptr | |
HINSTANCE HANDLE | |
HHOOK HANDLE | |
HWND HANDLE | |
) | |
type HOOKPROC func(int, WPARAM, LPARAM) LRESULT | |
type KBDLLHOOKSTRUCT struct { | |
VkCode DWORD | |
ScanCode DWORD | |
Flags DWORD | |
Time DWORD | |
DwExtraInfo uintptr | |
} | |
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd162805.aspx | |
type POINT struct { | |
X, Y int32 | |
} | |
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms644958.aspx | |
type MSG struct { | |
Hwnd HWND | |
Message uint32 | |
WParam uintptr | |
LParam uintptr | |
Time uint32 | |
Pt POINT | |
} | |
func SetWindowsHookEx(idHook int, lpfn HOOKPROC, hMod HINSTANCE, dwThreadId DWORD) HHOOK { | |
ret, _, _ := procSetWindowsHookEx.Call( | |
uintptr(idHook), | |
uintptr(syscall.NewCallback(lpfn)), | |
uintptr(hMod), | |
uintptr(dwThreadId), | |
) | |
return HHOOK(ret) | |
} | |
func CallNextHookEx(hhk HHOOK, nCode int, wParam WPARAM, lParam LPARAM) LRESULT { | |
ret, _, _ := procCallNextHookEx.Call( | |
uintptr(hhk), | |
uintptr(nCode), | |
uintptr(wParam), | |
uintptr(lParam), | |
) | |
return LRESULT(ret) | |
} | |
func UnhookWindowsHookEx(hhk HHOOK) bool { | |
ret, _, _ := procUnhookWindowsHookEx.Call( | |
uintptr(hhk), | |
) | |
return ret != 0 | |
} | |
func GetMessage(msg *MSG, hwnd HWND, msgFilterMin uint32, msgFilterMax uint32) int { | |
ret, _, _ := procGetMessage.Call( | |
uintptr(unsafe.Pointer(msg)), | |
uintptr(hwnd), | |
uintptr(msgFilterMin), | |
uintptr(msgFilterMax)) | |
return int(ret) | |
} | |
func TranslateMessage(msg *MSG) bool { | |
ret, _, _ := procTranslateMessage.Call( | |
uintptr(unsafe.Pointer(msg))) | |
return ret != 0 | |
} | |
func DispatchMessage(msg *MSG) uintptr { | |
ret, _, _ := procDispatchMessage.Call( | |
uintptr(unsafe.Pointer(msg))) | |
return ret | |
} | |
func LowLevelKeyboardProc (nCode int, wParam WPARAM, lParam LPARAM) LRESULT { | |
ret, _, _ := procLowLevelKeyboard.Call( | |
uintptr(nCode), | |
uintptr(wParam), | |
uintptr(lParam), | |
) | |
return LRESULT(ret) | |
} | |
func Start() { | |
// defer user32.Release() | |
keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, | |
(HOOKPROC)(func(nCode int, wparam WPARAM, lparam LPARAM) LRESULT { | |
if nCode == 0 && wparam == WM_KEYDOWN { | |
fmt.Println("key pressed:") | |
kbdstruct := (*KBDLLHOOKSTRUCT)(unsafe.Pointer(lparam)) | |
code := byte(kbdstruct.VkCode) | |
fmt.Sprintf("%q", code) | |
} | |
return CallNextHookEx(keyboardHook, nCode, wparam, lparam) | |
}), 0, 0) | |
var msg MSG | |
for GetMessage(&msg, 0, 0, 0) != 0 { | |
} | |
//~ for { | |
//~ | |
//~ GetMessage(uintptr(unsafe.Pointer(msg)), 0, 0, 0) | |
//~ TranslateMessage(msg) | |
//~ DispatchMessage(msg) | |
//~ // fmt.Println("key pressed:") | |
//~ | |
//~ } | |
UnhookWindowsHookEx(keyboardHook) | |
keyboardHook = 0 | |
} | |
func main() { | |
go Start() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey! Thank you for sharing this.
I had to make two small modifications to make this work for me under Go 1.9 on Windows 10:
panic: Failed to find SetWindowsHookEx procedure in user32.dll: The specified procedure could not be found.
Printf
instead ofSprintf