2021-10-22 13:15:11 +00:00
|
|
|
package xinput_devnodes
|
|
|
|
|
|
|
|
// #cgo CFLAGS: -g --std=gnu99 -pedantic -Wall
|
|
|
|
// #cgo LDFLAGS: -lX11 -lXi
|
|
|
|
// #include "devnodes.h"
|
|
|
|
// #include <stdlib.h>
|
|
|
|
// #include <string.h>
|
|
|
|
import "C"
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"unsafe"
|
|
|
|
"regexp"
|
2021-10-24 12:09:00 +00:00
|
|
|
"errors"
|
|
|
|
"os"
|
2021-10-22 13:15:11 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
func FindKeyboardDevNode() string {
|
|
|
|
xslaveinfos, freeMethod := GetXSlaveInfo()
|
|
|
|
defer freeMethod()
|
|
|
|
|
|
|
|
re := regexp.MustCompile(`(?i).*keyboard.*`)
|
|
|
|
for _, xslaveinfo := range xslaveinfos {
|
|
|
|
name, devNode := C.GoString(xslaveinfo.name), C.GoString(xslaveinfo.dev_node)
|
|
|
|
if re.MatchString(name) {
|
|
|
|
return devNode
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func Print() {
|
|
|
|
xslaveinfos, freeMethod := GetXSlaveInfo()
|
|
|
|
defer freeMethod()
|
|
|
|
|
|
|
|
for _, xslaveinfo := range xslaveinfos {
|
|
|
|
fmt.Printf("%s = %s\n", C.GoString(xslaveinfo.name), C.GoString(xslaveinfo.dev_node))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func GetXSlaveInfo() ([]C.XSlaveInfo, func()) {
|
2021-10-24 12:09:00 +00:00
|
|
|
xDisplayName := C.CString(tryGetXDisplay())
|
|
|
|
defer C.free(unsafe.Pointer(xDisplayName))
|
|
|
|
|
|
|
|
var error C.int
|
|
|
|
xslaves := C.get_slave_info(xDisplayName, &error)
|
|
|
|
if (error != C.int(0)) {
|
|
|
|
panic(convertErrorIntToGoError(error))
|
|
|
|
}
|
|
|
|
|
2021-10-22 13:15:11 +00:00
|
|
|
arr := (*[1 << 30]C.XSlaveInfo)(unsafe.Pointer(xslaves.slaves))
|
|
|
|
slice := arr[:xslaves.length:xslaves.length]
|
|
|
|
freeMethod := func() {
|
|
|
|
C.free_xslaves(xslaves)
|
|
|
|
}
|
|
|
|
|
|
|
|
return slice, freeMethod
|
|
|
|
}
|
|
|
|
|
2021-10-24 12:09:00 +00:00
|
|
|
func tryGetXDisplay() string {
|
|
|
|
display := os.Getenv("DISPLAY")
|
|
|
|
if display == "" {
|
|
|
|
panic(errors.New("DISPLAY envvar not set"))
|
|
|
|
}
|
|
|
|
return display
|
|
|
|
}
|
|
|
|
|
|
|
|
func convertErrorIntToGoError(err C.int) error {
|
|
|
|
errorMsg := ""
|
|
|
|
switch err {
|
|
|
|
case C.MALLOCFAIL:
|
|
|
|
errorMsg = "Memory allocation failed"
|
|
|
|
case C.XSLAVESFULL:
|
|
|
|
errorMsg = "XSlaves full"
|
|
|
|
case C.BADDISPLAY:
|
|
|
|
errorMsg = "Failed to open X display"
|
|
|
|
case C.XINPUTEXTUNAVAIL:
|
|
|
|
errorMsg = "XInput extension unavailable"
|
|
|
|
case C.XINPUT20UNAVAIL:
|
|
|
|
errorMsg = "XInput extension is not 2.0"
|
|
|
|
case C.XINPUTQUERYVERSIONFAILED:
|
|
|
|
errorMsg = "Failed to query XInput extension version"
|
|
|
|
case C.XSLAVEINFOQUERYFAILED:
|
|
|
|
errorMsg = "Failed to query XInput slaves"
|
|
|
|
default:
|
|
|
|
errorMsg = fmt.Sprintf("Unknown error from devnodes.h: %v", err)
|
|
|
|
}
|
|
|
|
return errors.New(errorMsg)
|
|
|
|
}
|