//go:build windows
|
|
package hotkey
|
|
import (
|
"syscall"
|
"time"
|
"unsafe"
|
)
|
|
var (
|
user32 = syscall.NewLazyDLL("user32.dll")
|
procGetAsyncKeyState = user32.NewProc("GetAsyncKeyState")
|
)
|
|
type windowsListener struct{}
|
|
func newPlatformListener() Listener {
|
return &windowsListener{}
|
}
|
|
func getAsyncKeyState(vk int) uint16 {
|
ret, _, _ := procGetAsyncKeyState.Call(uintptr(vk))
|
return uint16(ret)
|
}
|
|
func (l *windowsListener) IsKeyDown(vk int) bool {
|
return getAsyncKeyState(vk)&0x8000 != 0
|
}
|
|
func (l *windowsListener) IsAnyOtherKeyPressed(excludeVK int) bool {
|
// Check meaningful keys: A-Z, 0-9, function keys, common keys
|
checkKeys := []int{
|
0x08, 0x09, 0x0D, 0x1B, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x2C, 0x2D, 0x2E,
|
}
|
// 0-9
|
for i := 0x30; i <= 0x39; i++ {
|
checkKeys = append(checkKeys, i)
|
}
|
// A-Z
|
for i := 0x41; i <= 0x5A; i++ {
|
checkKeys = append(checkKeys, i)
|
}
|
// F1-F12
|
for i := 0x70; i <= 0x7B; i++ {
|
checkKeys = append(checkKeys, i)
|
}
|
// OEM keys
|
checkKeys = append(checkKeys, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xDB, 0xDC, 0xDD, 0xDE)
|
|
for _, k := range checkKeys {
|
if k == excludeVK {
|
continue
|
}
|
if getAsyncKeyState(k)&0x8000 != 0 {
|
return true
|
}
|
}
|
|
// Check modifier keys not matching the exclude key
|
ctrlKeys := []int{0x11, 0xA2, 0xA3}
|
altKeys := []int{0x12, 0xA4, 0xA5}
|
shiftKeys := []int{0x10, 0xA0, 0xA1}
|
|
if !contains(ctrlKeys, excludeVK) {
|
for _, k := range ctrlKeys {
|
if getAsyncKeyState(k)&0x8000 != 0 {
|
return true
|
}
|
}
|
}
|
if !contains(altKeys, excludeVK) {
|
for _, k := range altKeys {
|
if getAsyncKeyState(k)&0x8000 != 0 {
|
return true
|
}
|
}
|
}
|
if !contains(shiftKeys, excludeVK) {
|
for _, k := range shiftKeys {
|
if getAsyncKeyState(k)&0x8000 != 0 {
|
return true
|
}
|
}
|
}
|
|
return false
|
}
|
|
func (l *windowsListener) IsAnyOtherKeyPressedSince(excludeVK int, since time.Time) bool {
|
return l.IsAnyOtherKeyPressed(excludeVK)
|
}
|
|
func contains(slice []int, val int) bool {
|
for _, v := range slice {
|
if v == val {
|
return true
|
}
|
}
|
return false
|
}
|
|
// Ensure unsafe is used (needed for syscall alignment)
|
var _ = unsafe.Sizeof(0)
|