├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── examples ├── keyboard │ ├── .envrc │ ├── .gitignore │ └── main.go ├── mouse │ ├── .envrc │ ├── .gitignore │ └── main.go └── swapkeys │ ├── .envrc │ └── main.go ├── go.mod └── pkg ├── keyboard ├── keyboard.go ├── keyboard_func.go └── keyboard_windows.go ├── mouse ├── mouse.go ├── mouse_func.go └── mouse_windows.go ├── types ├── VKCode_string.go ├── constant.go ├── event.go ├── hook_string.go ├── message_string.go └── win32.go └── win32 └── win32_windows.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # v0.1.0 2 | 3 | - Use standard Go project layout. 4 | - Change API sets. 5 | - Update mouse and keyboard examples. 6 | 7 | # v0.0.0 8 | 9 | Initial version. 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Yoshiyuki Koyanagi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | go-hook 2 | ======= 3 | 4 | [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)][license] 5 | 6 | [license]: https://github.com/moutend/go-wca/blob/master/LICENSE 7 | 8 | `go-hook`provides low level keyboard and mouse hook for Windows. This package is written in pure Go, `cgo` is not required. 9 | 10 | Note: The package is currently tested on Windows 10 64bit edition. Other versions of Windows are not guaranteed to work. 11 | 12 | ## Prerequisites 13 | 14 | Go 1.13 or later 15 | 16 | ## Usage 17 | 18 | Examples are stored in `examples` directory. 19 | 20 | - `mouse`: Capturing mouse events. 21 | - `keyboard`: Capturing keyboard events. 22 | - `swapkeys`: Swapping the keyboard input 'A' and 'B". 23 | 24 | ## Contributing 25 | 26 | 1. Fork ([https://github.com/moutend/go-hook/fork](https://github.com/moutend/go-hook/fork)) 27 | 1. Create a feature branch 28 | 1. Add changes 29 | 1. Run `go fmt` 30 | 1. Commit your changes 31 | 1. Open a new Pull Request 32 | 33 | ## Author 34 | 35 | [Yoshiyuki Koyanagi](https://github.com/moutend) 36 | 37 | ## LICENSE 38 | 39 | MIT 40 | -------------------------------------------------------------------------------- /examples/keyboard/.envrc: -------------------------------------------------------------------------------- 1 | export GOOS=windows 2 | -------------------------------------------------------------------------------- /examples/keyboard/.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | -------------------------------------------------------------------------------- /examples/keyboard/main.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "log" 8 | "os" 9 | "os/signal" 10 | "time" 11 | 12 | "github.com/moutend/go-hook/pkg/keyboard" 13 | "github.com/moutend/go-hook/pkg/types" 14 | ) 15 | 16 | func main() { 17 | log.SetFlags(0) 18 | log.SetPrefix("error: ") 19 | 20 | if err := run(); err != nil { 21 | log.Fatal(err) 22 | } 23 | } 24 | 25 | func run() error { 26 | // Buffer size is depends on your need. The 100 is placeholder value. 27 | keyboardChan := make(chan types.KeyboardEvent, 100) 28 | 29 | if err := keyboard.Install(nil, keyboardChan); err != nil { 30 | return err 31 | } 32 | 33 | defer keyboard.Uninstall() 34 | 35 | signalChan := make(chan os.Signal, 1) 36 | signal.Notify(signalChan, os.Interrupt) 37 | 38 | fmt.Println("start capturing keyboard input") 39 | 40 | for { 41 | select { 42 | case <-time.After(5 * time.Minute): 43 | fmt.Println("Received timeout signal") 44 | return nil 45 | case <-signalChan: 46 | fmt.Println("Received shutdown signal") 47 | return nil 48 | case k := <-keyboardChan: 49 | fmt.Printf("Received %v %v\n", k.Message, k.VKCode) 50 | continue 51 | } 52 | } 53 | 54 | // not reached 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /examples/mouse/.envrc: -------------------------------------------------------------------------------- 1 | export GOOS=windows 2 | -------------------------------------------------------------------------------- /examples/mouse/.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | -------------------------------------------------------------------------------- /examples/mouse/main.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "log" 8 | "os" 9 | "os/signal" 10 | "time" 11 | 12 | "github.com/moutend/go-hook/pkg/mouse" 13 | "github.com/moutend/go-hook/pkg/types" 14 | ) 15 | 16 | func main() { 17 | log.SetFlags(0) 18 | log.SetPrefix("error: ") 19 | 20 | if err := run(); err != nil { 21 | log.Fatal(err) 22 | } 23 | } 24 | 25 | func run() error { 26 | // Buffer size is depends on your need. The 100 is placeholder value. 27 | mouseChan := make(chan types.MouseEvent, 100) 28 | 29 | if err := mouse.Install(nil, mouseChan); err != nil { 30 | return err 31 | } 32 | 33 | defer mouse.Uninstall() 34 | 35 | signalChan := make(chan os.Signal, 1) 36 | signal.Notify(signalChan, os.Interrupt) 37 | 38 | fmt.Println("start capturing mouse input") 39 | 40 | for { 41 | select { 42 | case <-time.After(5 * time.Minute): 43 | fmt.Println("Received timeout signal") 44 | return nil 45 | case <-signalChan: 46 | fmt.Println("Received shutdown signal") 47 | return nil 48 | case m := <-mouseChan: 49 | fmt.Printf("Received %v {X:%v, Y:%v}\n", m.Message, m.X, m.Y) 50 | continue 51 | } 52 | } 53 | 54 | // not reached 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /examples/swapkeys/.envrc: -------------------------------------------------------------------------------- 1 | export GOOS=windows 2 | -------------------------------------------------------------------------------- /examples/swapkeys/main.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "log" 8 | "os" 9 | "os/signal" 10 | "time" 11 | "unsafe" 12 | 13 | "github.com/micmonay/keybd_event" 14 | "github.com/moutend/go-hook/pkg/keyboard" 15 | "github.com/moutend/go-hook/pkg/types" 16 | "github.com/moutend/go-hook/pkg/win32" 17 | ) 18 | 19 | var ( 20 | kbA, kbB keybd_event.KeyBonding 21 | ) 22 | 23 | func main() { 24 | log.SetFlags(0) 25 | log.SetPrefix("error: ") 26 | 27 | if err := run(); err != nil { 28 | log.Fatal(err) 29 | } 30 | } 31 | 32 | func run() (err error) { 33 | // Emulates pressing and releasing the 'A' key. 34 | kbA, err = keybd_event.NewKeyBonding() 35 | 36 | if err != nil { 37 | return err 38 | } 39 | 40 | kbA.SetKeys(keybd_event.VK_A) 41 | 42 | // Emulates pressing and releasing the 'B' key. 43 | kbB, err = keybd_event.NewKeyBonding() 44 | 45 | if err != nil { 46 | return err 47 | } 48 | 49 | kbB.SetKeys(keybd_event.VK_B) 50 | 51 | // Buffer size is depends on your need. The 100 is placeholder value. 52 | keyboardChan := make(chan types.KeyboardEvent, 100) 53 | 54 | if err := keyboard.Install(handler, keyboardChan); err != nil { 55 | return err 56 | } 57 | 58 | defer keyboard.Uninstall() 59 | 60 | signalChan := make(chan os.Signal, 1) 61 | signal.Notify(signalChan, os.Interrupt) 62 | 63 | fmt.Println("start capturing keyboard input") 64 | 65 | for { 66 | select { 67 | case <-time.After(5 * time.Minute): 68 | fmt.Println("Received timeout signal") 69 | return nil 70 | case <-signalChan: 71 | fmt.Println("Received shutdown signal") 72 | return nil 73 | case k := <-keyboardChan: 74 | fmt.Printf("Received %V %v\n", k.Message, k.VKCode) 75 | continue 76 | } 77 | } 78 | 79 | // not reached 80 | return nil 81 | } 82 | 83 | func handler(c chan<- types.KeyboardEvent) types.HOOKPROC { 84 | counter := 0 85 | 86 | return func(code int32, wParam, lParam uintptr) uintptr { 87 | if lParam == 0 { 88 | goto NEXT 89 | } 90 | 91 | c <- types.KeyboardEvent{ 92 | Message: types.Message(wParam), 93 | KBDLLHOOKSTRUCT: *(*types.KBDLLHOOKSTRUCT)(unsafe.Pointer(lParam)), 94 | } 95 | 96 | switch (*types.KBDLLHOOKSTRUCT)(unsafe.Pointer(lParam)).VKCode { 97 | case types.VK_A: 98 | if counter == 1 { 99 | counter = 0 100 | goto NEXT 101 | } 102 | switch types.Message(wParam) { 103 | case types.WM_KEYDOWN: 104 | go kbB.Press() 105 | case types.WM_KEYUP: 106 | go kbB.Release() 107 | } 108 | 109 | counter = 1 110 | 111 | return 1 112 | case types.VK_B: 113 | if counter == 1 { 114 | counter = 0 115 | goto NEXT 116 | } 117 | switch types.Message(wParam) { 118 | case types.WM_KEYDOWN: 119 | go kbA.Press() 120 | case types.WM_KEYUP: 121 | go kbA.Release() 122 | } 123 | 124 | counter = 1 125 | 126 | return 1 127 | default: 128 | } 129 | 130 | NEXT: 131 | 132 | return win32.CallNextHookEx(0, code, wParam, lParam) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/moutend/go-hook 2 | 3 | go 1.13 4 | -------------------------------------------------------------------------------- /pkg/keyboard/keyboard.go: -------------------------------------------------------------------------------- 1 | // Package keyboard provides low level hook for keyboard input. 2 | package keyboard 3 | 4 | import ( 5 | "github.com/moutend/go-hook/pkg/types" 6 | ) 7 | 8 | // HookHandler is a callback function which processes the incoming low level events. 9 | // 10 | // Note: You don't have to care about this function unless customize the default behavior. 11 | type HookHandler func(c chan<- types.KeyboardEvent) types.HOOKPROC 12 | 13 | // Install causes package signal to relay incoming keyboard events to c. 14 | func Install(fn HookHandler, c chan<- types.KeyboardEvent) error { 15 | return install(fn, c) 16 | } 17 | 18 | // Uninstall remove keyboard hook. 19 | func Uninstall() error { 20 | return uninstall() 21 | } 22 | -------------------------------------------------------------------------------- /pkg/keyboard/keyboard_func.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package keyboard 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/moutend/go-hook/pkg/types" 9 | ) 10 | 11 | func install(fn HookHandler, c chan<- types.KeyboardEvent) error { 12 | return fmt.Errorf("keyboard: not supported") 13 | } 14 | 15 | func uninstall() error { 16 | return fmt.Errorf("keyboard: not supported") 17 | } 18 | -------------------------------------------------------------------------------- /pkg/keyboard/keyboard_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package keyboard 4 | 5 | import ( 6 | "fmt" 7 | "sync" 8 | "syscall" 9 | "unsafe" 10 | 11 | "github.com/moutend/go-hook/pkg/types" 12 | "github.com/moutend/go-hook/pkg/win32" 13 | ) 14 | 15 | var hHook struct { 16 | sync.Mutex 17 | Pointer uintptr 18 | } 19 | 20 | // DefaultHookHandler used when calling keyboard.Register() without passing handler function. 21 | func DefaultHookHandler(c chan<- types.KeyboardEvent) types.HOOKPROC { 22 | return func(code int32, wParam, lParam uintptr) uintptr { 23 | if lParam != 0 { 24 | c <- types.KeyboardEvent{ 25 | Message: types.Message(wParam), 26 | KBDLLHOOKSTRUCT: *(*types.KBDLLHOOKSTRUCT)(unsafe.Pointer(lParam)), 27 | } 28 | } 29 | 30 | return win32.CallNextHookEx(0, code, wParam, lParam) 31 | } 32 | } 33 | 34 | func install(fn HookHandler, c chan<- types.KeyboardEvent) error { 35 | hHook.Lock() 36 | defer hHook.Unlock() 37 | 38 | if hHook.Pointer != 0 { 39 | return fmt.Errorf("keyboard: hook function is already installed") 40 | } 41 | if c == nil { 42 | return fmt.Errorf("keyboard: chan must not be nil") 43 | } 44 | if fn == nil { 45 | fn = DefaultHookHandler 46 | } 47 | 48 | go func() { 49 | hhk := win32.SetWindowsHookEx( 50 | types.WH_KEYBOARD_LL, 51 | syscall.NewCallback(fn(c)), 52 | 0, 53 | 0) 54 | 55 | if hhk == 0 { 56 | panic("keyboard: failed to install hook function") 57 | } 58 | 59 | hHook.Pointer = hhk 60 | 61 | var msg *types.MSG 62 | 63 | for { 64 | if hHook.Pointer == 0 { 65 | break 66 | } 67 | if result := win32.GetMessage(&msg, 0, 0, 0); result != 0 { 68 | if result < 0 { 69 | // We don't care what's went wrong, ignore the result value. 70 | continue 71 | } else { 72 | win32.TranslateMessage(&msg) 73 | win32.DispatchMessage(&msg) 74 | } 75 | } 76 | } 77 | }() 78 | 79 | return nil 80 | } 81 | 82 | func uninstall() error { 83 | hHook.Lock() 84 | defer hHook.Unlock() 85 | 86 | if !win32.UnhookWindowsHookEx(hHook.Pointer) { 87 | return fmt.Errorf("keyboard: failed to uninstall hook function") 88 | } 89 | 90 | hHook.Pointer = 0 91 | 92 | return nil 93 | } 94 | -------------------------------------------------------------------------------- /pkg/mouse/mouse.go: -------------------------------------------------------------------------------- 1 | // Package mouse provides low level hook for mouse input. 2 | package mouse 3 | 4 | import ( 5 | "github.com/moutend/go-hook/pkg/types" 6 | ) 7 | 8 | // HookHandler is a callback function which processes the incoming low level events. 9 | // 10 | // Note: You don't have to care about this function unless customize the default behavior. 11 | type HookHandler func(c chan<- types.MouseEvent) types.HOOKPROC 12 | 13 | // Install causes package signal to relay incoming mouse events to c. 14 | func Install(fn HookHandler, c chan<- types.MouseEvent) error { 15 | return install(fn, c) 16 | } 17 | 18 | // Uninstall remove mouse hook. 19 | func Uninstall() error { 20 | return uninstall() 21 | } 22 | -------------------------------------------------------------------------------- /pkg/mouse/mouse_func.go: -------------------------------------------------------------------------------- 1 | // +build !windows 2 | 3 | package mouse 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/moutend/go-hook/pkg/types" 9 | ) 10 | 11 | func install(fn HookHandler, c chan<- types.MouseEvent) error { 12 | return fmt.Errorf("mouse: not supported") 13 | } 14 | 15 | func uninstall() error { 16 | return fmt.Errorf("mouse: not supported") 17 | } 18 | -------------------------------------------------------------------------------- /pkg/mouse/mouse_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package mouse 4 | 5 | import ( 6 | "fmt" 7 | "sync" 8 | "syscall" 9 | "unsafe" 10 | 11 | "github.com/moutend/go-hook/pkg/types" 12 | "github.com/moutend/go-hook/pkg/win32" 13 | ) 14 | 15 | var hHook struct { 16 | sync.Mutex 17 | Pointer uintptr 18 | } 19 | 20 | // DefaultHookHandler used when calling keyboard.Register() without passing handler function. 21 | func DefaultHookHandler(c chan<- types.MouseEvent) types.HOOKPROC { 22 | return func(code int32, wParam, lParam uintptr) uintptr { 23 | if lParam != 0 { 24 | c <- types.MouseEvent{ 25 | Message: types.Message(wParam), 26 | MSLLHOOKSTRUCT: *(*types.MSLLHOOKSTRUCT)(unsafe.Pointer(lParam)), 27 | } 28 | } 29 | 30 | return win32.CallNextHookEx(0, code, wParam, lParam) 31 | } 32 | } 33 | 34 | func install(fn HookHandler, c chan<- types.MouseEvent) error { 35 | hHook.Lock() 36 | defer hHook.Unlock() 37 | 38 | if hHook.Pointer != 0 { 39 | return fmt.Errorf("mouse: hook function is already install") 40 | } 41 | if c == nil { 42 | return fmt.Errorf("mouse: chan must not be nil") 43 | } 44 | if fn == nil { 45 | fn = DefaultHookHandler 46 | } 47 | 48 | go func() { 49 | hhk := win32.SetWindowsHookEx( 50 | types.WH_MOUSE_LL, 51 | syscall.NewCallback(fn(c)), 52 | 0, 53 | 0) 54 | 55 | if hhk == 0 { 56 | panic("mouse: failed to install hook function") 57 | } 58 | 59 | hHook.Pointer = hhk 60 | 61 | var msg *types.MSG 62 | 63 | for { 64 | if hHook.Pointer == 0 { 65 | break 66 | } 67 | if result := win32.GetMessage(&msg, 0, 0, 0); result != 0 { 68 | if result < 0 { 69 | // We don't care what's went wrong, ignore the result value. 70 | continue 71 | } else { 72 | win32.TranslateMessage(&msg) 73 | win32.DispatchMessage(&msg) 74 | } 75 | } 76 | } 77 | }() 78 | 79 | return nil 80 | } 81 | 82 | func uninstall() error { 83 | hHook.Lock() 84 | defer hHook.Unlock() 85 | 86 | if !win32.UnhookWindowsHookEx(hHook.Pointer) { 87 | return fmt.Errorf("mouse: failed to uninstall hook function") 88 | } 89 | 90 | hHook.Pointer = 0 91 | 92 | return nil 93 | } 94 | -------------------------------------------------------------------------------- /pkg/types/VKCode_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=VKCode"; DO NOT EDIT. 2 | 3 | package types 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[VK_LBUTTON-1] 12 | _ = x[VK_RBUTTON-2] 13 | _ = x[VK_CANCEL-3] 14 | _ = x[VK_MBUTTON-4] 15 | _ = x[VK_XBUTTON1-5] 16 | _ = x[VK_XBUTTON2-6] 17 | _ = x[VK_BACK-8] 18 | _ = x[VK_TAB-9] 19 | _ = x[VK_CLEAR-12] 20 | _ = x[VK_RETURN-13] 21 | _ = x[VK_SHIFT-16] 22 | _ = x[VK_CONTROL-17] 23 | _ = x[VK_MENU-18] 24 | _ = x[VK_PAUSE-19] 25 | _ = x[VK_CAPITAL-20] 26 | _ = x[VK_KANA-21] 27 | _ = x[VK_HANGUEL-21] 28 | _ = x[VK_HANGUL-21] 29 | _ = x[VK_IME_ON-22] 30 | _ = x[VK_JUNJA-23] 31 | _ = x[VK_FINAL-24] 32 | _ = x[VK_HANJA-25] 33 | _ = x[VK_KANJI-25] 34 | _ = x[VK_IME_OFF-26] 35 | _ = x[VK_ESCAPE-27] 36 | _ = x[VK_CONVERT-28] 37 | _ = x[VK_NONCONVERT-29] 38 | _ = x[VK_ACCEPT-30] 39 | _ = x[VK_MODECHANGE-31] 40 | _ = x[VK_SPACE-32] 41 | _ = x[VK_PRIOR-33] 42 | _ = x[VK_NEXT-34] 43 | _ = x[VK_END-35] 44 | _ = x[VK_HOME-36] 45 | _ = x[VK_LEFT-37] 46 | _ = x[VK_UP-38] 47 | _ = x[VK_RIGHT-39] 48 | _ = x[VK_DOWN-40] 49 | _ = x[VK_SELECT-41] 50 | _ = x[VK_PRINT-42] 51 | _ = x[VK_EXECUTE-43] 52 | _ = x[VK_SNAPSHOT-44] 53 | _ = x[VK_INSERT-45] 54 | _ = x[VK_DELETE-46] 55 | _ = x[VK_HELP-47] 56 | _ = x[VK_0-48] 57 | _ = x[VK_1-49] 58 | _ = x[VK_2-50] 59 | _ = x[VK_3-51] 60 | _ = x[VK_4-52] 61 | _ = x[VK_5-53] 62 | _ = x[VK_6-54] 63 | _ = x[VK_7-55] 64 | _ = x[VK_8-56] 65 | _ = x[VK_9-57] 66 | _ = x[VK_A-65] 67 | _ = x[VK_B-66] 68 | _ = x[VK_C-67] 69 | _ = x[VK_D-68] 70 | _ = x[VK_E-69] 71 | _ = x[VK_F-70] 72 | _ = x[VK_G-71] 73 | _ = x[VK_H-72] 74 | _ = x[VK_I-73] 75 | _ = x[VK_J-74] 76 | _ = x[VK_K-75] 77 | _ = x[VK_L-76] 78 | _ = x[VK_M-77] 79 | _ = x[VK_N-78] 80 | _ = x[VK_O-79] 81 | _ = x[VK_P-80] 82 | _ = x[VK_Q-81] 83 | _ = x[VK_R-82] 84 | _ = x[VK_S-83] 85 | _ = x[VK_T-84] 86 | _ = x[VK_U-85] 87 | _ = x[VK_V-86] 88 | _ = x[VK_W-87] 89 | _ = x[VK_X-88] 90 | _ = x[VK_Y-89] 91 | _ = x[VK_Z-90] 92 | _ = x[VK_LWIN-91] 93 | _ = x[VK_RWIN-92] 94 | _ = x[VK_APPS-93] 95 | _ = x[VK_SLEEP-95] 96 | _ = x[VK_NUMPAD0-96] 97 | _ = x[VK_NUMPAD1-97] 98 | _ = x[VK_NUMPAD2-98] 99 | _ = x[VK_NUMPAD3-99] 100 | _ = x[VK_NUMPAD4-100] 101 | _ = x[VK_NUMPAD5-101] 102 | _ = x[VK_NUMPAD6-102] 103 | _ = x[VK_NUMPAD7-103] 104 | _ = x[VK_NUMPAD8-104] 105 | _ = x[VK_NUMPAD9-105] 106 | _ = x[VK_MULTIPLY-106] 107 | _ = x[VK_ADD-107] 108 | _ = x[VK_SEPARATOR-108] 109 | _ = x[VK_SUBTRACT-109] 110 | _ = x[VK_DECIMAL-110] 111 | _ = x[VK_DIVIDE-111] 112 | _ = x[VK_F1-112] 113 | _ = x[VK_F2-113] 114 | _ = x[VK_F3-114] 115 | _ = x[VK_F4-115] 116 | _ = x[VK_F5-116] 117 | _ = x[VK_F6-117] 118 | _ = x[VK_F7-118] 119 | _ = x[VK_F8-119] 120 | _ = x[VK_F9-120] 121 | _ = x[VK_F10-121] 122 | _ = x[VK_F11-122] 123 | _ = x[VK_F12-123] 124 | _ = x[VK_F13-124] 125 | _ = x[VK_F14-125] 126 | _ = x[VK_F15-126] 127 | _ = x[VK_F16-127] 128 | _ = x[VK_F17-128] 129 | _ = x[VK_F18-129] 130 | _ = x[VK_F19-130] 131 | _ = x[VK_F20-131] 132 | _ = x[VK_F21-132] 133 | _ = x[VK_F22-133] 134 | _ = x[VK_F23-134] 135 | _ = x[VK_F24-135] 136 | _ = x[VK_NUMLOCK-144] 137 | _ = x[VK_SCROLL-145] 138 | _ = x[VK_LSHIFT-160] 139 | _ = x[VK_RSHIFT-161] 140 | _ = x[VK_LCONTROL-162] 141 | _ = x[VK_RCONTROL-163] 142 | _ = x[VK_LMENU-164] 143 | _ = x[VK_RMENU-165] 144 | _ = x[VK_BROWSER_BACK-166] 145 | _ = x[VK_BROWSER_FORWARD-167] 146 | _ = x[VK_BROWSER_REFRESH-168] 147 | _ = x[VK_BROWSER_STOP-169] 148 | _ = x[VK_BROWSER_SEARCH-170] 149 | _ = x[VK_BROWSER_FAVORITES-171] 150 | _ = x[VK_BROWSER_HOME-172] 151 | _ = x[VK_VOLUME_MUTE-173] 152 | _ = x[VK_VOLUME_DOWN-174] 153 | _ = x[VK_VOLUME_UP-175] 154 | _ = x[VK_MEDIA_NEXT_TRACK-176] 155 | _ = x[VK_MEDIA_PREV_TRACK-177] 156 | _ = x[VK_MEDIA_STOP-178] 157 | _ = x[VK_MEDIA_PLAY_PAUSE-179] 158 | _ = x[VK_LAUNCH_MAIL-180] 159 | _ = x[VK_LAUNCH_MEDIA_SELECT-181] 160 | _ = x[VK_LAUNCH_APP1-182] 161 | _ = x[VK_LAUNCH_APP2-183] 162 | _ = x[VK_OEM_1-186] 163 | _ = x[VK_OEM_PLUS-187] 164 | _ = x[VK_OEM_COMMA-188] 165 | _ = x[VK_OEM_MINUS-189] 166 | _ = x[VK_OEM_PERIOD-190] 167 | _ = x[VK_OEM_2-191] 168 | _ = x[VK_OEM_3-192] 169 | _ = x[VK_OEM_4-219] 170 | _ = x[VK_OEM_5-220] 171 | _ = x[VK_OEM_6-221] 172 | _ = x[VK_OEM_7-222] 173 | _ = x[VK_OEM_8-223] 174 | _ = x[VK_OEM_102-226] 175 | _ = x[VK_PROCESSKEY-229] 176 | _ = x[VK_PACKET-231] 177 | _ = x[VK_ATTN-246] 178 | _ = x[VK_CRSEL-247] 179 | _ = x[VK_EXSEL-248] 180 | _ = x[VK_EREOF-249] 181 | _ = x[VK_PLAY-250] 182 | _ = x[VK_ZOOM-251] 183 | _ = x[VK_NONAME-252] 184 | _ = x[VK_PA1-253] 185 | _ = x[VK_OEM_CLEAR-254] 186 | } 187 | 188 | const _VKCode_name = "VK_LBUTTONVK_RBUTTONVK_CANCELVK_MBUTTONVK_XBUTTON1VK_XBUTTON2VK_BACKVK_TABVK_CLEARVK_RETURNVK_SHIFTVK_CONTROLVK_MENUVK_PAUSEVK_CAPITALVK_KANAVK_IME_ONVK_JUNJAVK_FINALVK_HANJAVK_IME_OFFVK_ESCAPEVK_CONVERTVK_NONCONVERTVK_ACCEPTVK_MODECHANGEVK_SPACEVK_PRIORVK_NEXTVK_ENDVK_HOMEVK_LEFTVK_UPVK_RIGHTVK_DOWNVK_SELECTVK_PRINTVK_EXECUTEVK_SNAPSHOTVK_INSERTVK_DELETEVK_HELPVK_0VK_1VK_2VK_3VK_4VK_5VK_6VK_7VK_8VK_9VK_AVK_BVK_CVK_DVK_EVK_FVK_GVK_HVK_IVK_JVK_KVK_LVK_MVK_NVK_OVK_PVK_QVK_RVK_SVK_TVK_UVK_VVK_WVK_XVK_YVK_ZVK_LWINVK_RWINVK_APPSVK_SLEEPVK_NUMPAD0VK_NUMPAD1VK_NUMPAD2VK_NUMPAD3VK_NUMPAD4VK_NUMPAD5VK_NUMPAD6VK_NUMPAD7VK_NUMPAD8VK_NUMPAD9VK_MULTIPLYVK_ADDVK_SEPARATORVK_SUBTRACTVK_DECIMALVK_DIVIDEVK_F1VK_F2VK_F3VK_F4VK_F5VK_F6VK_F7VK_F8VK_F9VK_F10VK_F11VK_F12VK_F13VK_F14VK_F15VK_F16VK_F17VK_F18VK_F19VK_F20VK_F21VK_F22VK_F23VK_F24VK_NUMLOCKVK_SCROLLVK_LSHIFTVK_RSHIFTVK_LCONTROLVK_RCONTROLVK_LMENUVK_RMENUVK_BROWSER_BACKVK_BROWSER_FORWARDVK_BROWSER_REFRESHVK_BROWSER_STOPVK_BROWSER_SEARCHVK_BROWSER_FAVORITESVK_BROWSER_HOMEVK_VOLUME_MUTEVK_VOLUME_DOWNVK_VOLUME_UPVK_MEDIA_NEXT_TRACKVK_MEDIA_PREV_TRACKVK_MEDIA_STOPVK_MEDIA_PLAY_PAUSEVK_LAUNCH_MAILVK_LAUNCH_MEDIA_SELECTVK_LAUNCH_APP1VK_LAUNCH_APP2VK_OEM_1VK_OEM_PLUSVK_OEM_COMMAVK_OEM_MINUSVK_OEM_PERIODVK_OEM_2VK_OEM_3VK_OEM_4VK_OEM_5VK_OEM_6VK_OEM_7VK_OEM_8VK_OEM_102VK_PROCESSKEYVK_PACKETVK_ATTNVK_CRSELVK_EXSELVK_EREOFVK_PLAYVK_ZOOMVK_NONAMEVK_PA1VK_OEM_CLEAR" 189 | 190 | var _VKCode_map = map[VKCode]string{ 191 | 1: _VKCode_name[0:10], 192 | 2: _VKCode_name[10:20], 193 | 3: _VKCode_name[20:29], 194 | 4: _VKCode_name[29:39], 195 | 5: _VKCode_name[39:50], 196 | 6: _VKCode_name[50:61], 197 | 8: _VKCode_name[61:68], 198 | 9: _VKCode_name[68:74], 199 | 12: _VKCode_name[74:82], 200 | 13: _VKCode_name[82:91], 201 | 16: _VKCode_name[91:99], 202 | 17: _VKCode_name[99:109], 203 | 18: _VKCode_name[109:116], 204 | 19: _VKCode_name[116:124], 205 | 20: _VKCode_name[124:134], 206 | 21: _VKCode_name[134:141], 207 | 22: _VKCode_name[141:150], 208 | 23: _VKCode_name[150:158], 209 | 24: _VKCode_name[158:166], 210 | 25: _VKCode_name[166:174], 211 | 26: _VKCode_name[174:184], 212 | 27: _VKCode_name[184:193], 213 | 28: _VKCode_name[193:203], 214 | 29: _VKCode_name[203:216], 215 | 30: _VKCode_name[216:225], 216 | 31: _VKCode_name[225:238], 217 | 32: _VKCode_name[238:246], 218 | 33: _VKCode_name[246:254], 219 | 34: _VKCode_name[254:261], 220 | 35: _VKCode_name[261:267], 221 | 36: _VKCode_name[267:274], 222 | 37: _VKCode_name[274:281], 223 | 38: _VKCode_name[281:286], 224 | 39: _VKCode_name[286:294], 225 | 40: _VKCode_name[294:301], 226 | 41: _VKCode_name[301:310], 227 | 42: _VKCode_name[310:318], 228 | 43: _VKCode_name[318:328], 229 | 44: _VKCode_name[328:339], 230 | 45: _VKCode_name[339:348], 231 | 46: _VKCode_name[348:357], 232 | 47: _VKCode_name[357:364], 233 | 48: _VKCode_name[364:368], 234 | 49: _VKCode_name[368:372], 235 | 50: _VKCode_name[372:376], 236 | 51: _VKCode_name[376:380], 237 | 52: _VKCode_name[380:384], 238 | 53: _VKCode_name[384:388], 239 | 54: _VKCode_name[388:392], 240 | 55: _VKCode_name[392:396], 241 | 56: _VKCode_name[396:400], 242 | 57: _VKCode_name[400:404], 243 | 65: _VKCode_name[404:408], 244 | 66: _VKCode_name[408:412], 245 | 67: _VKCode_name[412:416], 246 | 68: _VKCode_name[416:420], 247 | 69: _VKCode_name[420:424], 248 | 70: _VKCode_name[424:428], 249 | 71: _VKCode_name[428:432], 250 | 72: _VKCode_name[432:436], 251 | 73: _VKCode_name[436:440], 252 | 74: _VKCode_name[440:444], 253 | 75: _VKCode_name[444:448], 254 | 76: _VKCode_name[448:452], 255 | 77: _VKCode_name[452:456], 256 | 78: _VKCode_name[456:460], 257 | 79: _VKCode_name[460:464], 258 | 80: _VKCode_name[464:468], 259 | 81: _VKCode_name[468:472], 260 | 82: _VKCode_name[472:476], 261 | 83: _VKCode_name[476:480], 262 | 84: _VKCode_name[480:484], 263 | 85: _VKCode_name[484:488], 264 | 86: _VKCode_name[488:492], 265 | 87: _VKCode_name[492:496], 266 | 88: _VKCode_name[496:500], 267 | 89: _VKCode_name[500:504], 268 | 90: _VKCode_name[504:508], 269 | 91: _VKCode_name[508:515], 270 | 92: _VKCode_name[515:522], 271 | 93: _VKCode_name[522:529], 272 | 95: _VKCode_name[529:537], 273 | 96: _VKCode_name[537:547], 274 | 97: _VKCode_name[547:557], 275 | 98: _VKCode_name[557:567], 276 | 99: _VKCode_name[567:577], 277 | 100: _VKCode_name[577:587], 278 | 101: _VKCode_name[587:597], 279 | 102: _VKCode_name[597:607], 280 | 103: _VKCode_name[607:617], 281 | 104: _VKCode_name[617:627], 282 | 105: _VKCode_name[627:637], 283 | 106: _VKCode_name[637:648], 284 | 107: _VKCode_name[648:654], 285 | 108: _VKCode_name[654:666], 286 | 109: _VKCode_name[666:677], 287 | 110: _VKCode_name[677:687], 288 | 111: _VKCode_name[687:696], 289 | 112: _VKCode_name[696:701], 290 | 113: _VKCode_name[701:706], 291 | 114: _VKCode_name[706:711], 292 | 115: _VKCode_name[711:716], 293 | 116: _VKCode_name[716:721], 294 | 117: _VKCode_name[721:726], 295 | 118: _VKCode_name[726:731], 296 | 119: _VKCode_name[731:736], 297 | 120: _VKCode_name[736:741], 298 | 121: _VKCode_name[741:747], 299 | 122: _VKCode_name[747:753], 300 | 123: _VKCode_name[753:759], 301 | 124: _VKCode_name[759:765], 302 | 125: _VKCode_name[765:771], 303 | 126: _VKCode_name[771:777], 304 | 127: _VKCode_name[777:783], 305 | 128: _VKCode_name[783:789], 306 | 129: _VKCode_name[789:795], 307 | 130: _VKCode_name[795:801], 308 | 131: _VKCode_name[801:807], 309 | 132: _VKCode_name[807:813], 310 | 133: _VKCode_name[813:819], 311 | 134: _VKCode_name[819:825], 312 | 135: _VKCode_name[825:831], 313 | 144: _VKCode_name[831:841], 314 | 145: _VKCode_name[841:850], 315 | 160: _VKCode_name[850:859], 316 | 161: _VKCode_name[859:868], 317 | 162: _VKCode_name[868:879], 318 | 163: _VKCode_name[879:890], 319 | 164: _VKCode_name[890:898], 320 | 165: _VKCode_name[898:906], 321 | 166: _VKCode_name[906:921], 322 | 167: _VKCode_name[921:939], 323 | 168: _VKCode_name[939:957], 324 | 169: _VKCode_name[957:972], 325 | 170: _VKCode_name[972:989], 326 | 171: _VKCode_name[989:1009], 327 | 172: _VKCode_name[1009:1024], 328 | 173: _VKCode_name[1024:1038], 329 | 174: _VKCode_name[1038:1052], 330 | 175: _VKCode_name[1052:1064], 331 | 176: _VKCode_name[1064:1083], 332 | 177: _VKCode_name[1083:1102], 333 | 178: _VKCode_name[1102:1115], 334 | 179: _VKCode_name[1115:1134], 335 | 180: _VKCode_name[1134:1148], 336 | 181: _VKCode_name[1148:1170], 337 | 182: _VKCode_name[1170:1184], 338 | 183: _VKCode_name[1184:1198], 339 | 186: _VKCode_name[1198:1206], 340 | 187: _VKCode_name[1206:1217], 341 | 188: _VKCode_name[1217:1229], 342 | 189: _VKCode_name[1229:1241], 343 | 190: _VKCode_name[1241:1254], 344 | 191: _VKCode_name[1254:1262], 345 | 192: _VKCode_name[1262:1270], 346 | 219: _VKCode_name[1270:1278], 347 | 220: _VKCode_name[1278:1286], 348 | 221: _VKCode_name[1286:1294], 349 | 222: _VKCode_name[1294:1302], 350 | 223: _VKCode_name[1302:1310], 351 | 226: _VKCode_name[1310:1320], 352 | 229: _VKCode_name[1320:1333], 353 | 231: _VKCode_name[1333:1342], 354 | 246: _VKCode_name[1342:1349], 355 | 247: _VKCode_name[1349:1357], 356 | 248: _VKCode_name[1357:1365], 357 | 249: _VKCode_name[1365:1373], 358 | 250: _VKCode_name[1373:1380], 359 | 251: _VKCode_name[1380:1387], 360 | 252: _VKCode_name[1387:1396], 361 | 253: _VKCode_name[1396:1402], 362 | 254: _VKCode_name[1402:1414], 363 | } 364 | 365 | func (i VKCode) String() string { 366 | if str, ok := _VKCode_map[i]; ok { 367 | return str 368 | } 369 | return "VKCode(" + strconv.FormatInt(int64(i), 10) + ")" 370 | } 371 | -------------------------------------------------------------------------------- /pkg/types/constant.go: -------------------------------------------------------------------------------- 1 | //go:generate stringer -type=Hook 2 | //go:generate stringer -type=Message 3 | //go:generate stringer -type=VKCode 4 | 5 | package types 6 | 7 | // Hook represents Windows hook types. 8 | type Hook uintptr 9 | 10 | const ( 11 | WH_JOURNALRECORD Hook = 0 12 | WH_JOURNALPLAYBACK Hook = 1 13 | WH_KEYBOARD Hook = 2 14 | WH_GETMESSAGE Hook = 3 15 | WH_CALLWNDPROC Hook = 4 16 | WH_CBT Hook = 5 17 | WH_SYSMSGFILTER Hook = 6 18 | WH_MOUSE Hook = 7 19 | WH_DEBUG Hook = 9 20 | WH_SHELL Hook = 10 21 | WH_FOREGROUNDIDLE Hook = 11 22 | WH_CALLWNDPROCRET Hook = 12 23 | WH_KEYBOARD_LL Hook = 13 24 | WH_MOUSE_LL Hook = 14 25 | ) 26 | 27 | // Message represents Windows events. 28 | type Message uintptr 29 | 30 | const ( 31 | WM_LBUTTONDOWN Message = 0x0201 32 | WM_LBUTTONUP Message = 0x0202 33 | WM_MOUSEMOVE Message = 0x0200 34 | WM_MOUSEWHEEL Message = 0x020A 35 | WM_MOUSEHWHEEL Message = 0x020E 36 | WM_RBUTTONDOWN Message = 0x0204 37 | WM_RBUTTONUP Message = 0x0205 38 | WM_KEYDOWN Message = 0x0100 39 | WM_KEYUP Message = 0x0101 40 | WM_SYSKEYDOWN Message = 0x0104 41 | WM_SYSKEYUP Message = 0x0105 42 | ) 43 | 44 | // VKCode represents Microsoft defined virtual key codes. 45 | // 46 | // For more details, see the MSDN. 47 | // 48 | // https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes 49 | type VKCode uint32 50 | 51 | const ( 52 | VK_LBUTTON VKCode = 0x01 // Left mouse button 53 | VK_RBUTTON VKCode = 0x02 // Right mouse button 54 | VK_CANCEL VKCode = 0x03 // Control-break processing 55 | VK_MBUTTON VKCode = 0x04 // Middle mouse button (three-button mouse) 56 | VK_XBUTTON1 VKCode = 0x05 // X1 mouse button 57 | VK_XBUTTON2 VKCode = 0x06 // X2 mouse button 58 | VK_BACK VKCode = 0x08 // BACKSPACE key 59 | VK_TAB VKCode = 0x09 // TAB key 60 | VK_CLEAR VKCode = 0x0C // CLEAR key 61 | VK_RETURN VKCode = 0x0D // ENTER key 62 | VK_SHIFT VKCode = 0x10 // SHIFT key 63 | VK_CONTROL VKCode = 0x11 // CTRL key 64 | VK_MENU VKCode = 0x12 // ALT key 65 | VK_PAUSE VKCode = 0x13 // PAUSE key 66 | VK_CAPITAL VKCode = 0x14 // CAPS LOCK key 67 | VK_KANA VKCode = 0x15 // IME Kana mode 68 | VK_HANGUEL VKCode = 0x15 // IME Hanguel mode (maintained for compatibility; use VK_HANGUL) 69 | VK_HANGUL VKCode = 0x15 // IME Hangul mode 70 | VK_IME_ON VKCode = 0x16 // IME On 71 | VK_JUNJA VKCode = 0x17 // IME Junja mode 72 | VK_FINAL VKCode = 0x18 // IME final mode 73 | VK_HANJA VKCode = 0x19 // IME Hanja mode 74 | VK_KANJI VKCode = 0x19 // IME Kanji mode 75 | VK_IME_OFF VKCode = 0x1A // IME Off 76 | VK_ESCAPE VKCode = 0x1B // ESC key 77 | VK_CONVERT VKCode = 0x1C // IME convert 78 | VK_NONCONVERT VKCode = 0x1D // IME nonconvert 79 | VK_ACCEPT VKCode = 0x1E // IME accept 80 | VK_MODECHANGE VKCode = 0x1F // IME mode change request 81 | VK_SPACE VKCode = 0x20 // SPACEBAR 82 | VK_PRIOR VKCode = 0x21 // PAGE UP key 83 | VK_NEXT VKCode = 0x22 // PAGE DOWN key 84 | VK_END VKCode = 0x23 // END key 85 | VK_HOME VKCode = 0x24 // HOME key 86 | VK_LEFT VKCode = 0x25 // LEFT ARROW key 87 | VK_UP VKCode = 0x26 // UP ARROW key 88 | VK_RIGHT VKCode = 0x27 // RIGHT ARROW key 89 | VK_DOWN VKCode = 0x28 // DOWN ARROW key 90 | VK_SELECT VKCode = 0x29 // SELECT key 91 | VK_PRINT VKCode = 0x2A // PRINT key 92 | VK_EXECUTE VKCode = 0x2B // EXECUTE key 93 | VK_SNAPSHOT VKCode = 0x2C // PRINT SCREEN key 94 | VK_INSERT VKCode = 0x2D // INS key 95 | VK_DELETE VKCode = 0x2E // DEL key 96 | VK_HELP VKCode = 0x2F // HELP key 97 | VK_0 VKCode = 0x30 // 0 key 98 | VK_1 VKCode = 0x31 // 1 key 99 | VK_2 VKCode = 0x32 // 2 key 100 | VK_3 VKCode = 0x33 // 3 key 101 | VK_4 VKCode = 0x34 // 4 key 102 | VK_5 VKCode = 0x35 // 5 key 103 | VK_6 VKCode = 0x36 // 6 key 104 | VK_7 VKCode = 0x37 // 7 key 105 | VK_8 VKCode = 0x38 // 8 key 106 | VK_9 VKCode = 0x39 // 9 key 107 | VK_A VKCode = 0x41 // A key 108 | VK_B VKCode = 0x42 // B key 109 | VK_C VKCode = 0x43 // C key 110 | VK_D VKCode = 0x44 // D key 111 | VK_E VKCode = 0x45 // E key 112 | VK_F VKCode = 0x46 // F key 113 | VK_G VKCode = 0x47 // G key 114 | VK_H VKCode = 0x48 // H key 115 | VK_I VKCode = 0x49 // I key 116 | VK_J VKCode = 0x4A // J key 117 | VK_K VKCode = 0x4B // K key 118 | VK_L VKCode = 0x4C // L key 119 | VK_M VKCode = 0x4D // M key 120 | VK_N VKCode = 0x4E // N key 121 | VK_O VKCode = 0x4F // O key 122 | VK_P VKCode = 0x50 // P key 123 | VK_Q VKCode = 0x51 // Q key 124 | VK_R VKCode = 0x52 // R key 125 | VK_S VKCode = 0x53 // S key 126 | VK_T VKCode = 0x54 // T key 127 | VK_U VKCode = 0x55 // U key 128 | VK_V VKCode = 0x56 // V key 129 | VK_W VKCode = 0x57 // W key 130 | VK_X VKCode = 0x58 // X key 131 | VK_Y VKCode = 0x59 // Y key 132 | VK_Z VKCode = 0x5A // Z key 133 | VK_LWIN VKCode = 0x5B // Left Windows key (Natural keyboard) 134 | VK_RWIN VKCode = 0x5C // Right Windows key (Natural keyboard) 135 | VK_APPS VKCode = 0x5D // Applications key (Natural keyboard) 136 | VK_SLEEP VKCode = 0x5F // Computer Sleep key 137 | VK_NUMPAD0 VKCode = 0x60 // Numeric keypad 0 key 138 | VK_NUMPAD1 VKCode = 0x61 // Numeric keypad 1 key 139 | VK_NUMPAD2 VKCode = 0x62 // Numeric keypad 2 key 140 | VK_NUMPAD3 VKCode = 0x63 // Numeric keypad 3 key 141 | VK_NUMPAD4 VKCode = 0x64 // Numeric keypad 4 key 142 | VK_NUMPAD5 VKCode = 0x65 // Numeric keypad 5 key 143 | VK_NUMPAD6 VKCode = 0x66 // Numeric keypad 6 key 144 | VK_NUMPAD7 VKCode = 0x67 // Numeric keypad 7 key 145 | VK_NUMPAD8 VKCode = 0x68 // Numeric keypad 8 key 146 | VK_NUMPAD9 VKCode = 0x69 // Numeric keypad 9 key 147 | VK_MULTIPLY VKCode = 0x6A // Multiply key 148 | VK_ADD VKCode = 0x6B // Add key 149 | VK_SEPARATOR VKCode = 0x6C // Separator key 150 | VK_SUBTRACT VKCode = 0x6D // Subtract key 151 | VK_DECIMAL VKCode = 0x6E // Decimal key 152 | VK_DIVIDE VKCode = 0x6F // Divide key 153 | VK_F1 VKCode = 0x70 // F1 key 154 | VK_F2 VKCode = 0x71 // F2 key 155 | VK_F3 VKCode = 0x72 // F3 key 156 | VK_F4 VKCode = 0x73 // F4 key 157 | VK_F5 VKCode = 0x74 // F5 key 158 | VK_F6 VKCode = 0x75 // F6 key 159 | VK_F7 VKCode = 0x76 // F7 key 160 | VK_F8 VKCode = 0x77 // F8 key 161 | VK_F9 VKCode = 0x78 // F9 key 162 | VK_F10 VKCode = 0x79 // F10 key 163 | VK_F11 VKCode = 0x7A // F11 key 164 | VK_F12 VKCode = 0x7B // F12 key 165 | VK_F13 VKCode = 0x7C // F13 key 166 | VK_F14 VKCode = 0x7D // F14 key 167 | VK_F15 VKCode = 0x7E // F15 key 168 | VK_F16 VKCode = 0x7F // F16 key 169 | VK_F17 VKCode = 0x80 // F17 key 170 | VK_F18 VKCode = 0x81 // F18 key 171 | VK_F19 VKCode = 0x82 // F19 key 172 | VK_F20 VKCode = 0x83 // F20 key 173 | VK_F21 VKCode = 0x84 // F21 key 174 | VK_F22 VKCode = 0x85 // F22 key 175 | VK_F23 VKCode = 0x86 // F23 key 176 | VK_F24 VKCode = 0x87 // F24 key 177 | VK_NUMLOCK VKCode = 0x90 // NUM LOCK key 178 | VK_SCROLL VKCode = 0x91 // SCROLL LOCK key 179 | VK_LSHIFT VKCode = 0xA0 // Left SHIFT key 180 | VK_RSHIFT VKCode = 0xA1 // Right SHIFT key 181 | VK_LCONTROL VKCode = 0xA2 // Left CONTROL key 182 | VK_RCONTROL VKCode = 0xA3 // Right CONTROL key 183 | VK_LMENU VKCode = 0xA4 // Left MENU key 184 | VK_RMENU VKCode = 0xA5 // Right MENU key 185 | VK_BROWSER_BACK VKCode = 0xA6 // Browser Back key 186 | VK_BROWSER_FORWARD VKCode = 0xA7 // Browser Forward key 187 | VK_BROWSER_REFRESH VKCode = 0xA8 // Browser Refresh key 188 | VK_BROWSER_STOP VKCode = 0xA9 // Browser Stop key 189 | VK_BROWSER_SEARCH VKCode = 0xAA // Browser Search key 190 | VK_BROWSER_FAVORITES VKCode = 0xAB // Browser Favorites key 191 | VK_BROWSER_HOME VKCode = 0xAC // Browser Start and Home key 192 | VK_VOLUME_MUTE VKCode = 0xAD // Volume Mute key 193 | VK_VOLUME_DOWN VKCode = 0xAE // Volume Down key 194 | VK_VOLUME_UP VKCode = 0xAF // Volume Up key 195 | VK_MEDIA_NEXT_TRACK VKCode = 0xB0 // Next Track key 196 | VK_MEDIA_PREV_TRACK VKCode = 0xB1 // Previous Track key 197 | VK_MEDIA_STOP VKCode = 0xB2 // Stop Media key 198 | VK_MEDIA_PLAY_PAUSE VKCode = 0xB3 // Play/Pause Media key 199 | VK_LAUNCH_MAIL VKCode = 0xB4 // Start Mail key 200 | VK_LAUNCH_MEDIA_SELECT VKCode = 0xB5 // Select Media key 201 | VK_LAUNCH_APP1 VKCode = 0xB6 // Start Application 1 key 202 | VK_LAUNCH_APP2 VKCode = 0xB7 // Start Application 2 key 203 | VK_OEM_1 VKCode = 0xBA // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ';:' key 204 | VK_OEM_PLUS VKCode = 0xBB // For any country/region, the '+' key 205 | VK_OEM_COMMA VKCode = 0xBC // For any country/region, the ',' key 206 | VK_OEM_MINUS VKCode = 0xBD // For any country/region, the '-' key 207 | VK_OEM_PERIOD VKCode = 0xBE // For any country/region, the '.' key 208 | VK_OEM_2 VKCode = 0xBF // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '/?' key 209 | VK_OEM_3 VKCode = 0xC0 // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '`~' key 210 | VK_OEM_4 VKCode = 0xDB // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '[{' key 211 | VK_OEM_5 VKCode = 0xDC // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the '\|' key 212 | VK_OEM_6 VKCode = 0xDD // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the ']}' key 213 | VK_OEM_7 VKCode = 0xDE // Used for miscellaneous characters; it can vary by keyboard. For the US standard keyboard, the 'single-quote/double-quote' key 214 | VK_OEM_8 VKCode = 0xDF // Used for miscellaneous characters; it can vary by keyboard. 215 | VK_OEM_102 VKCode = 0xE2 // Either the angle bracket key or the backslash key on the RT 102-key keyboard 216 | VK_PROCESSKEY VKCode = 0xE5 // IME PROCESS key 217 | VK_PACKET VKCode = 0xE7 // Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP 218 | VK_ATTN VKCode = 0xF6 // Attn key 219 | VK_CRSEL VKCode = 0xF7 // CrSel key 220 | VK_EXSEL VKCode = 0xF8 // ExSel key 221 | VK_EREOF VKCode = 0xF9 // Erase EOF key 222 | VK_PLAY VKCode = 0xFA // Play key 223 | VK_ZOOM VKCode = 0xFB // Zoom key 224 | VK_NONAME VKCode = 0xFC // Reserved 225 | VK_PA1 VKCode = 0xFD // PA1 key 226 | VK_OEM_CLEAR VKCode = 0xFE // Clear key 227 | ) 228 | -------------------------------------------------------------------------------- /pkg/types/event.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // KeyboardEvent contains information about keyboard input event. 4 | type KeyboardEvent struct { 5 | Message Message 6 | KBDLLHOOKSTRUCT 7 | } 8 | 9 | // MouseEvent contains information about mouse input event. 10 | type MouseEvent struct { 11 | Message Message 12 | MSLLHOOKSTRUCT 13 | } 14 | -------------------------------------------------------------------------------- /pkg/types/hook_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Hook"; DO NOT EDIT. 2 | 3 | package types 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[WH_JOURNALRECORD-0] 12 | _ = x[WH_JOURNALPLAYBACK-1] 13 | _ = x[WH_KEYBOARD-2] 14 | _ = x[WH_GETMESSAGE-3] 15 | _ = x[WH_CALLWNDPROC-4] 16 | _ = x[WH_CBT-5] 17 | _ = x[WH_SYSMSGFILTER-6] 18 | _ = x[WH_MOUSE-7] 19 | _ = x[WH_DEBUG-9] 20 | _ = x[WH_SHELL-10] 21 | _ = x[WH_FOREGROUNDIDLE-11] 22 | _ = x[WH_CALLWNDPROCRET-12] 23 | _ = x[WH_KEYBOARD_LL-13] 24 | _ = x[WH_MOUSE_LL-14] 25 | } 26 | 27 | const ( 28 | _Hook_name_0 = "WH_JOURNALRECORDWH_JOURNALPLAYBACKWH_KEYBOARDWH_GETMESSAGEWH_CALLWNDPROCWH_CBTWH_SYSMSGFILTERWH_MOUSE" 29 | _Hook_name_1 = "WH_DEBUGWH_SHELLWH_FOREGROUNDIDLEWH_CALLWNDPROCRETWH_KEYBOARD_LLWH_MOUSE_LL" 30 | ) 31 | 32 | var ( 33 | _Hook_index_0 = [...]uint8{0, 16, 34, 45, 58, 72, 78, 93, 101} 34 | _Hook_index_1 = [...]uint8{0, 8, 16, 33, 50, 64, 75} 35 | ) 36 | 37 | func (i Hook) String() string { 38 | switch { 39 | case i <= 7: 40 | return _Hook_name_0[_Hook_index_0[i]:_Hook_index_0[i+1]] 41 | case 9 <= i && i <= 14: 42 | i -= 9 43 | return _Hook_name_1[_Hook_index_1[i]:_Hook_index_1[i+1]] 44 | default: 45 | return "Hook(" + strconv.FormatInt(int64(i), 10) + ")" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pkg/types/message_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -type=Message"; DO NOT EDIT. 2 | 3 | package types 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[WM_LBUTTONDOWN-513] 12 | _ = x[WM_LBUTTONUP-514] 13 | _ = x[WM_MOUSEMOVE-512] 14 | _ = x[WM_MOUSEWHEEL-522] 15 | _ = x[WM_MOUSEHWHEEL-526] 16 | _ = x[WM_RBUTTONDOWN-516] 17 | _ = x[WM_RBUTTONUP-517] 18 | _ = x[WM_KEYDOWN-256] 19 | _ = x[WM_KEYUP-257] 20 | _ = x[WM_SYSKEYDOWN-260] 21 | _ = x[WM_SYSKEYUP-261] 22 | } 23 | 24 | const ( 25 | _Message_name_0 = "WM_KEYDOWNWM_KEYUP" 26 | _Message_name_1 = "WM_SYSKEYDOWNWM_SYSKEYUP" 27 | _Message_name_2 = "WM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUP" 28 | _Message_name_3 = "WM_RBUTTONDOWNWM_RBUTTONUP" 29 | _Message_name_4 = "WM_MOUSEWHEEL" 30 | _Message_name_5 = "WM_MOUSEHWHEEL" 31 | ) 32 | 33 | var ( 34 | _Message_index_0 = [...]uint8{0, 10, 18} 35 | _Message_index_1 = [...]uint8{0, 13, 24} 36 | _Message_index_2 = [...]uint8{0, 12, 26, 38} 37 | _Message_index_3 = [...]uint8{0, 14, 26} 38 | ) 39 | 40 | func (i Message) String() string { 41 | switch { 42 | case 256 <= i && i <= 257: 43 | i -= 256 44 | return _Message_name_0[_Message_index_0[i]:_Message_index_0[i+1]] 45 | case 260 <= i && i <= 261: 46 | i -= 260 47 | return _Message_name_1[_Message_index_1[i]:_Message_index_1[i+1]] 48 | case 512 <= i && i <= 514: 49 | i -= 512 50 | return _Message_name_2[_Message_index_2[i]:_Message_index_2[i+1]] 51 | case 516 <= i && i <= 517: 52 | i -= 516 53 | return _Message_name_3[_Message_index_3[i]:_Message_index_3[i+1]] 54 | case i == 522: 55 | return _Message_name_4 56 | case i == 526: 57 | return _Message_name_5 58 | default: 59 | return "Message(" + strconv.FormatInt(int64(i), 10) + ")" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /pkg/types/win32.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | // KBDLLHOOKSTRUCT represents KBDLLHOOKSTRUCT structure. 4 | // 5 | // For more details, see the MSDN. 6 | // 7 | // https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-kbdllhookstruct 8 | type KBDLLHOOKSTRUCT struct { 9 | VKCode VKCode 10 | ScanCode uint32 11 | Flags uint32 12 | Time uint32 13 | DWExtraInfo uint32 14 | } 15 | 16 | // MSLLHOOKSTRUCT represents MSLLHOOKSTRUCT structure. 17 | // 18 | // For more details, see the MSDN. 19 | // 20 | // https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-msllhookstruct 21 | type MSLLHOOKSTRUCT struct { 22 | POINT 23 | MouseData uint32 24 | Flags uint32 25 | Time uint32 26 | DWExtraInfo uint32 27 | } 28 | 29 | // MSG represents MSG structure. 30 | // 31 | // For more details, refer to the MSDN. 32 | // 33 | // https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-msg 34 | type MSG struct { 35 | Hwnd uintptr 36 | Message uint32 37 | WParam uint32 38 | LParam uint32 39 | Time uint32 40 | POINT 41 | } 42 | 43 | // Point represents Point structure. 44 | // 45 | // For more details, refer to the MSDN. 46 | // 47 | // https://docs.microsoft.com/en-us/windows/win32/api/windef/ns-windef-point 48 | type POINT struct { 49 | X int32 50 | Y int32 51 | } 52 | 53 | // HOOKPROC represents HOOKPROC callback function type. 54 | // 55 | // For more details, see the MSDN. 56 | // 57 | // https://docs.microsoft.com/en-us/windows/win32/winmsg/using-hooks 58 | // 59 | // Note: you don't have to care about this function unless customize the default the mouse / keyboard hook behavior. 60 | type HOOKPROC func(code int32, wParam, lParam uintptr) uintptr 61 | -------------------------------------------------------------------------------- /pkg/win32/win32_windows.go: -------------------------------------------------------------------------------- 1 | // +build windows 2 | 3 | package win32 4 | 5 | import ( 6 | "syscall" 7 | "unsafe" 8 | 9 | "github.com/moutend/go-hook/pkg/types" 10 | ) 11 | 12 | var ( 13 | modUser32, _ = syscall.LoadDLL("user32.dll") 14 | 15 | procCallNextHookEx, _ = modUser32.FindProc("CallNextHookEx") 16 | procSetWindowsHookExW, _ = modUser32.FindProc("SetWindowsHookExW") 17 | procGetMessageW, _ = modUser32.FindProc("GetMessageW") 18 | procTranslateMessage, _ = modUser32.FindProc("TranslateMessage") 19 | procDispatchMessageW, _ = modUser32.FindProc("DispatchMessageW") 20 | procGetModuleHandleW, _ = modUser32.FindProc("GetModuleHandleW") 21 | procUnhookWindowsHookEx, _ = modUser32.FindProc("UnhookWindowsHookEx") 22 | ) 23 | 24 | func CallNextHookEx(hhk uintptr, code int32, wParam, lParam uintptr) uintptr { 25 | r, _, _ := procCallNextHookEx.Call(hhk, uintptr(code), wParam, lParam) 26 | 27 | return r 28 | } 29 | 30 | func SetWindowsHookEx(idHook types.Hook, lpfn, hmod uintptr, dwThreadId uint32) uintptr { 31 | r, _, _ := procSetWindowsHookExW.Call(uintptr(idHook), lpfn, hmod, uintptr(dwThreadId)) 32 | 33 | return r 34 | } 35 | 36 | func UnhookWindowsHookEx(hhk uintptr) bool { 37 | r, _, _ := procUnhookWindowsHookEx.Call(hhk) 38 | 39 | if r == 0 { 40 | return false 41 | } 42 | 43 | return true 44 | } 45 | 46 | func GetMessage(lpMsg **types.MSG, hWnd uintptr, wMsgFilterMin, wMsgFilterMax uint32) int32 { 47 | r, _, _ := procGetMessageW.Call( 48 | uintptr(unsafe.Pointer(lpMsg)), 49 | hWnd, 50 | uintptr(wMsgFilterMin), 51 | uintptr(wMsgFilterMin)) 52 | 53 | return int32(r) 54 | } 55 | 56 | func TranslateMessage(lpMsg **types.MSG) int32 { 57 | r, _, _ := procTranslateMessage.Call(uintptr(unsafe.Pointer(lpMsg))) 58 | 59 | return int32(r) 60 | } 61 | 62 | func DispatchMessage(lpMsg **types.MSG) int32 { 63 | r, _, _ := procDispatchMessageW.Call(uintptr(unsafe.Pointer(lpMsg))) 64 | 65 | return int32(r) 66 | } 67 | 68 | func GetModuleHandle(lpModuleName uintptr) uintptr { 69 | r, _, _ := procSetWindowsHookExW.Call(lpModuleName) 70 | 71 | return r 72 | } 73 | --------------------------------------------------------------------------------