162 lines
2.8 KiB
Go
162 lines
2.8 KiB
Go
package hid
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
|
|
log "github.com/sirupsen/logrus"
|
|
)
|
|
|
|
type Hid struct {
|
|
g0 *os.File
|
|
g1 *os.File
|
|
g2 *os.File
|
|
kbMutex sync.Mutex
|
|
mouseMutex sync.Mutex
|
|
}
|
|
|
|
const (
|
|
HID0 = "/dev/hidg0"
|
|
HID1 = "/dev/hidg1"
|
|
HID2 = "/dev/hidg2"
|
|
)
|
|
|
|
var (
|
|
hid *Hid
|
|
hidOnce sync.Once
|
|
)
|
|
|
|
func GetHid() *Hid {
|
|
hidOnce.Do(func() {
|
|
hid = &Hid{}
|
|
})
|
|
return hid
|
|
}
|
|
|
|
func (h *Hid) Lock() {
|
|
h.kbMutex.Lock()
|
|
h.mouseMutex.Lock()
|
|
}
|
|
|
|
func (h *Hid) Unlock() {
|
|
h.kbMutex.Unlock()
|
|
h.mouseMutex.Unlock()
|
|
}
|
|
|
|
func (h *Hid) OpenNoLock() {
|
|
var err error
|
|
h.CloseNoLock()
|
|
|
|
h.g0, err = os.OpenFile(HID0, os.O_WRONLY, 0o666)
|
|
if err != nil {
|
|
log.Errorf("open %s failed: %s", HID0, err)
|
|
}
|
|
|
|
h.g1, err = os.OpenFile(HID1, os.O_WRONLY, 0o666)
|
|
if err != nil {
|
|
log.Errorf("open %s failed: %s", HID1, err)
|
|
}
|
|
|
|
h.g2, err = os.OpenFile(HID2, os.O_WRONLY, 0o666)
|
|
if err != nil {
|
|
log.Errorf("open %s failed: %s", HID2, err)
|
|
}
|
|
}
|
|
|
|
func (h *Hid) CloseNoLock() {
|
|
for _, file := range []*os.File{h.g0, h.g1, h.g2} {
|
|
if file != nil {
|
|
_ = file.Sync()
|
|
_ = file.Close()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (h *Hid) Open() {
|
|
h.kbMutex.Lock()
|
|
defer h.kbMutex.Unlock()
|
|
h.mouseMutex.Lock()
|
|
defer h.mouseMutex.Unlock()
|
|
|
|
h.CloseNoLock()
|
|
|
|
h.OpenNoLock()
|
|
}
|
|
|
|
func (h *Hid) Close() {
|
|
h.kbMutex.Lock()
|
|
defer h.kbMutex.Unlock()
|
|
h.mouseMutex.Lock()
|
|
defer h.mouseMutex.Unlock()
|
|
|
|
h.CloseNoLock()
|
|
}
|
|
|
|
func (h *Hid) WriteHid0(data []byte) {
|
|
h.kbMutex.Lock()
|
|
_, err := h.g0.Write(data)
|
|
h.kbMutex.Unlock()
|
|
|
|
if err != nil {
|
|
if errors.Is(err, os.ErrClosed) {
|
|
log.Errorf("hid already closed, reopen it...")
|
|
h.OpenNoLock()
|
|
} else {
|
|
log.Debugf("write to %s failed: %s", HID0, err)
|
|
}
|
|
return
|
|
}
|
|
|
|
log.Debugf("write to %s: %v", HID0, data)
|
|
}
|
|
|
|
func (h *Hid) WriteHid1(data []byte) {
|
|
deadline := time.Now().Add(8 * time.Millisecond)
|
|
|
|
h.mouseMutex.Lock()
|
|
_ = h.g1.SetWriteDeadline(deadline)
|
|
_, err := h.g1.Write(data)
|
|
h.mouseMutex.Unlock()
|
|
|
|
if err != nil {
|
|
switch {
|
|
case errors.Is(err, os.ErrClosed):
|
|
log.Errorf("hid already closed, reopen it...")
|
|
h.OpenNoLock()
|
|
case errors.Is(err, os.ErrDeadlineExceeded):
|
|
log.Debugf("write to %s timeout", HID1)
|
|
default:
|
|
log.Errorf("write to %s failed: %s", HID1, err)
|
|
}
|
|
return
|
|
}
|
|
|
|
log.Debugf("write to %s: %v", HID1, data)
|
|
}
|
|
|
|
func (h *Hid) WriteHid2(data []byte) {
|
|
deadline := time.Now().Add(8 * time.Millisecond)
|
|
|
|
h.mouseMutex.Lock()
|
|
_ = h.g2.SetWriteDeadline(deadline)
|
|
_, err := h.g2.Write(data)
|
|
h.mouseMutex.Unlock()
|
|
|
|
if err != nil {
|
|
switch {
|
|
case errors.Is(err, os.ErrClosed):
|
|
log.Errorf("hid already closed, reopen it...")
|
|
h.OpenNoLock()
|
|
case errors.Is(err, os.ErrDeadlineExceeded):
|
|
log.Debugf("write to %s timeout", HID2)
|
|
default:
|
|
log.Errorf("write to %s failed: %s", HID2, err)
|
|
}
|
|
return
|
|
}
|
|
|
|
log.Debugf("write to %s: %v", HID2, data)
|
|
}
|