Skip to content

Instantly share code, notes, and snippets.

@kyoh86
Last active November 22, 2022 15:02
Show Gist options
  • Save kyoh86/43827afc4e9a7032e844c4d5fcf86476 to your computer and use it in GitHub Desktop.
Save kyoh86/43827afc4e9a7032e844c4d5fcf86476 to your computer and use it in GitHub Desktop.
WindowsのHotkey一覧を取得したい人生だった

常駐系アプリにCTRL+某を奪われがちなのがつらい。ATOKとか、Gyazoとか、まあいろいろ。設定もそれぞれバラバラに持ってるし。

Macなら大体CMD+で持って行くので、そこはまあ好きにしてくれ、と明け渡すことができるが、CTRL系だと自分が設定したいキーと衝突するので、これだけはなんとかならんか、と思って試行錯誤。

WindowにWM_GETHOTKEYメッセージを飛ばせば戻り値のUPPER WORDがMOD、LOWER WORDが実キーで返るよ、という記述を見つけて喜び勇んでやってみたものの、 どうやら今はWM_SETHOTKEYを使ったホットキー設定は使われていないらしい。 (RegisterHotKey関数を使っているぽい) そして、RegisterHotKeyを使って登録されたホットキーはWM_GETHOTKEYではどうにもならない。

夢は破れたのでここに供養。

module github.com/kyoh86/twinkle
go 1.19
package main
import (
"fmt"
"log"
"syscall"
"unsafe"
)
var (
user32 = syscall.MustLoadDLL("user32.dll")
procEnumWindows = user32.MustFindProc("EnumWindows")
procGetWindowTextW = user32.MustFindProc("GetWindowTextW")
procSendMessage = user32.MustFindProc("SendMessageW")
)
const (
WM_GETHOTKEY = 0x0033
)
func EnumWindows(enumFunc uintptr, lparam uintptr) error {
r1, _, eno := procEnumWindows.Call(uintptr(enumFunc), uintptr(lparam), 0)
if errno, ok := eno.(syscall.Errno); ok {
if errno != 0 {
return eno
}
} else {
return eno
}
if r1 == 0 {
return syscall.EINVAL
}
return nil
}
func GetWindowText(hwnd syscall.Handle, str *uint16, maxCount int32) (len int32, _ error) {
r0, _, eno := procGetWindowTextW.Call(uintptr(hwnd), uintptr(unsafe.Pointer(str)), uintptr(maxCount))
if errno, ok := eno.(syscall.Errno); ok {
if errno != 0 {
return 0, eno
}
} else {
return 0, eno
}
return int32(r0), nil
}
func SendMessage(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) (uintptr, error) {
ret, _, eno := procSendMessage.Call(uintptr(hwnd), uintptr(msg), wParam, lParam)
if errno, ok := eno.(syscall.Errno); ok {
if errno != 0 {
return 0, eno
}
} else {
return 0, eno
}
return ret, nil
}
type WindowHotkey struct {
WindowTitle string
WindowHandle syscall.Handle
Key uintptr
}
func EnumHotkeys() (hotkeys []WindowHotkey, retErr error) {
cb := syscall.NewCallback(func(hwnd syscall.Handle, p uintptr) uintptr {
key, err := SendMessage(hwnd, WM_GETHOTKEY, 0, 0)
if err != nil {
if retErr == nil {
retErr = fmt.Errorf("send message: %s", err)
}
return 0 // break enumeration
}
if key == 0 {
return 1 // continue enumeration
}
b := make([]uint16, 200)
if _, err := GetWindowText(hwnd, &b[0], int32(len(b))); err != nil {
if retErr == nil {
retErr = fmt.Errorf("get window test: %w", err)
}
return 0 // break enumeration
}
title := syscall.UTF16ToString(b)
hotkeys = append(hotkeys, WindowHotkey{
WindowTitle: title,
WindowHandle: hwnd,
Key: key,
})
return 1 // continue enumeration
})
if err := EnumWindows(cb, 0); err != nil {
return nil, err
}
return
}
func main() {
keys, err := EnumHotkeys()
if err != nil {
log.Fatalf("failed to process (%[1]T): %[1]v", err)
}
fmt.Println(keys)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment