migrate
This commit is contained in:
106
app/pkg/device/device.go
Normal file
106
app/pkg/device/device.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package device
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
|
||||
"github.com/microjelly/hid"
|
||||
"microjelly.com/beeon/app/pkg/device/report3"
|
||||
)
|
||||
|
||||
var (
|
||||
_devices []Info
|
||||
_logLevel LogLevel = LogNone
|
||||
)
|
||||
|
||||
// Version - returns the version of this module
|
||||
func Version() string {
|
||||
return "v1.0.1"
|
||||
}
|
||||
|
||||
// UsbSupported - returns true if usb is supported on this platform
|
||||
func UsbSupported() bool {
|
||||
return hid.Supported()
|
||||
}
|
||||
|
||||
// SetLogLevel - sets the logging level
|
||||
func SetLogLevel(level LogLevel) {
|
||||
_logLevel = level
|
||||
}
|
||||
|
||||
// Enumerate - gets connected devices
|
||||
func Enumerate(vendorID uint16, productID uint16) ([]Info, error) {
|
||||
|
||||
var (
|
||||
_devices []Info = nil
|
||||
pSN string = ""
|
||||
)
|
||||
|
||||
for _, dev := range hid.Enumerate(vendorID, productID) {
|
||||
if dev.Serial != pSN {
|
||||
_devices = append(_devices, Info{
|
||||
Serial: dev.Serial,
|
||||
Version: dev.Release,
|
||||
Manufacturer: dev.Manufacturer,
|
||||
Product: dev.Product,
|
||||
})
|
||||
pSN = dev.Serial
|
||||
}
|
||||
}
|
||||
|
||||
return _devices, nil
|
||||
}
|
||||
|
||||
func open(vendorID uint16, productID uint16, serial string) (*hid.Device, error) {
|
||||
|
||||
devices := hid.Enumerate(vendorID, productID)
|
||||
for _, dev := range devices {
|
||||
if (serial != "" && dev.Serial == serial) || serial == "" {
|
||||
_log(LogInfo, "opening device [%s]", dev.Serial)
|
||||
return dev.Open()
|
||||
}
|
||||
}
|
||||
return nil, errors.New("device not found")
|
||||
}
|
||||
|
||||
// ReadReport3 - get device configuration
|
||||
func ReadReport3(vendorID uint16, productID uint16, serial string) (*report3.Report, error) {
|
||||
|
||||
report := []byte{0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
|
||||
dev, err := open(vendorID, productID, serial)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer dev.Close()
|
||||
_, err = dev.GetFeatureReport(report)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := report3.New(report)
|
||||
_log(LogDebug, "read %v > %v", report, r)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// WriteReport3 - get device configuration
|
||||
func WriteReport3(vendorID uint16, productID uint16, serial string, report []byte) error {
|
||||
|
||||
dev, err := open(vendorID, productID, serial)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dev.Close()
|
||||
|
||||
_log(LogDebug, "write %v > %v", report, report3.New(report))
|
||||
_, err = dev.SendFeatureReport(report)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func _log(level LogLevel, format string, v ...interface{}) {
|
||||
if level >= _logLevel {
|
||||
log.Printf(format, v...)
|
||||
}
|
||||
}
|
||||
175
app/pkg/device/keycodes/keycodes.go
Normal file
175
app/pkg/device/keycodes/keycodes.go
Normal file
@@ -0,0 +1,175 @@
|
||||
// The contents of this file is free and unencumbered software released into
|
||||
// the public domain. Refer to <http://unlicense.org/> for more information.
|
||||
// Src: https://github.com/yakshaveinc/go-keycodes/blob/master/keycodes.go
|
||||
|
||||
package keycodes
|
||||
|
||||
import "fmt"
|
||||
|
||||
type KeyCode uint8
|
||||
|
||||
func (k KeyCode) String() string {
|
||||
if k == KeyUnset {
|
||||
return "unset"
|
||||
}
|
||||
return fmt.Sprintf("Key(%d)", k)
|
||||
}
|
||||
|
||||
// note: similar keys have different key codes, like Enter and
|
||||
// Keypad Enter
|
||||
|
||||
// cross-platform key codes, compatible with SDL 2 and USB HID speccy
|
||||
// https://hg.libsdl.org/SDL/file/default/include/SDL_scancode.h
|
||||
// http://www.usb.org/developers/hidpage/Hut1_12v2.pdf (page 53)
|
||||
|
||||
// key for codes 0 - 3 are not present on keyboards, they are:
|
||||
// 0 - Reserved (no event)
|
||||
// 1 - ErrorRollOver
|
||||
// 2 - POSTFail
|
||||
// 3 - ErrorUndefined
|
||||
|
||||
const (
|
||||
KeyA KeyCode = 4 + iota
|
||||
KeyB
|
||||
KeyC
|
||||
KeyD
|
||||
KeyE
|
||||
KeyF
|
||||
KeyG
|
||||
KeyH
|
||||
KeyI
|
||||
KeyJ
|
||||
KeyK
|
||||
KeyL
|
||||
KeyM
|
||||
KeyN
|
||||
KeyO
|
||||
KeyP
|
||||
KeyQ
|
||||
KeyR
|
||||
KeyS
|
||||
KeyT
|
||||
KeyU
|
||||
KeyV
|
||||
KeyW
|
||||
KeyX
|
||||
KeyY
|
||||
KeyZ
|
||||
)
|
||||
const (
|
||||
Key1 KeyCode = 30 + iota
|
||||
Key2
|
||||
Key3
|
||||
Key4
|
||||
Key5
|
||||
Key6
|
||||
Key7
|
||||
Key8
|
||||
Key9
|
||||
Key0
|
||||
)
|
||||
const (
|
||||
// choice is to use Enter name instead of Return
|
||||
// and the key code is different from Keypad Enter
|
||||
KeyEnter KeyCode = 40 + iota
|
||||
KeyEscape
|
||||
KeyBackspace
|
||||
KeyTab
|
||||
KeySpace
|
||||
// keypad minus has different key code
|
||||
KeyMinus
|
||||
KeyEquals
|
||||
KeyLeftBracket
|
||||
KeyRightBracket
|
||||
KeyBackslash
|
||||
)
|
||||
|
||||
// key code number 50 is skipped, because it is unclear
|
||||
// where is the key, and what is its name and function
|
||||
|
||||
const (
|
||||
// different name from SDL2 for brevity
|
||||
KeyColon KeyCode = 51 + iota
|
||||
KeyApostrophe
|
||||
// KeyTilde is an alias
|
||||
KeyGrave
|
||||
KeyCommad
|
||||
// KeyDot is an alias, keypad period is a different
|
||||
KeyPeriod
|
||||
Slash
|
||||
CapsLock
|
||||
)
|
||||
const KeyTilde = KeyGrave
|
||||
const KeyDot = KeyPeriod
|
||||
|
||||
const (
|
||||
KeyF1 KeyCode = 58 + iota
|
||||
KeyF2
|
||||
KeyF3
|
||||
KeyF4
|
||||
KeyF5
|
||||
KeyF6
|
||||
KeyF7
|
||||
KeyF8
|
||||
KeyF9
|
||||
KeyF10
|
||||
KeyF11
|
||||
KeyF12
|
||||
)
|
||||
const (
|
||||
KeyPrintScreen KeyCode = 70 + iota
|
||||
KeyScrollLock
|
||||
KeyPause
|
||||
KeyInsert
|
||||
KeyHome
|
||||
KeyPageUp
|
||||
KeyDelete
|
||||
KeyEnd
|
||||
KeyPageDown
|
||||
KeyRight
|
||||
KeyLeft
|
||||
KeyDown
|
||||
KeyUp
|
||||
)
|
||||
const (
|
||||
KeyNumLock KeyCode = 83 + iota
|
||||
KeyKpDivide
|
||||
KeyKpMultiply
|
||||
KeyKpMinus
|
||||
KeyKpPlus
|
||||
KeyKpEnter
|
||||
KeyKp1
|
||||
KeyKp2
|
||||
KeyKp3
|
||||
KeyKp4
|
||||
KeyKp5
|
||||
KeyKp6
|
||||
KeyKp7
|
||||
KeyKp8
|
||||
KeyKp9
|
||||
KeyKp0
|
||||
// KeyKpDot is an alias
|
||||
KeyKpPeriod
|
||||
)
|
||||
const KeyKpDot = KeyKpPeriod
|
||||
|
||||
// key code 100 is skipped, because I can not find the key
|
||||
// key code 101 is not present on Mac
|
||||
// key codes 102-223 are not present on PC
|
||||
|
||||
const (
|
||||
KeyLCtrl KeyCode = 224 + iota
|
||||
KeyLShift
|
||||
KeyLAlt
|
||||
// KeyLWin is an alias
|
||||
KeyLGUI
|
||||
KeyRCtrl
|
||||
KeyRShift
|
||||
KeyRAlt
|
||||
// KeyRWin is an alias
|
||||
KeyRGUI
|
||||
)
|
||||
const KeyLWin = KeyLGUI
|
||||
const KeyRWin = KeyRGUI
|
||||
|
||||
const KeyUnset = 255
|
||||
139
app/pkg/device/report3/report3.go
Normal file
139
app/pkg/device/report3/report3.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package report3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"microjelly.com/beeon/app/pkg/device/keycodes"
|
||||
)
|
||||
|
||||
type State uint8
|
||||
|
||||
const (
|
||||
StateIdle = State(10)
|
||||
StateActive = State(20)
|
||||
StateUnset = State(255)
|
||||
)
|
||||
|
||||
func (r State) String() string {
|
||||
switch r {
|
||||
case StateActive:
|
||||
return "active"
|
||||
case StateIdle:
|
||||
return "idle"
|
||||
case StateUnset:
|
||||
return "unset"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
type Mode uint8
|
||||
|
||||
const (
|
||||
ModeMouse = Mode(10)
|
||||
ModeKeyboard = Mode(20)
|
||||
ModeUnset = Mode(255)
|
||||
)
|
||||
|
||||
func (r Mode) String() string {
|
||||
switch r {
|
||||
case ModeMouse:
|
||||
return "mouse"
|
||||
case ModeKeyboard:
|
||||
return "keyboard"
|
||||
case ModeUnset:
|
||||
return "unset"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
type Rate uint8
|
||||
|
||||
const (
|
||||
RateFast = Rate(1)
|
||||
RateNormal = Rate(8)
|
||||
RateSlow = Rate(16)
|
||||
RateExtraSlow = Rate(32)
|
||||
RateUnset = Rate(255)
|
||||
)
|
||||
|
||||
func (r Rate) String() string {
|
||||
switch r {
|
||||
case RateFast:
|
||||
return "fast"
|
||||
case RateNormal:
|
||||
return "normal"
|
||||
case RateSlow:
|
||||
return "slow"
|
||||
case RateExtraSlow:
|
||||
return "extra-slow"
|
||||
case RateUnset:
|
||||
return "unset"
|
||||
default:
|
||||
return fmt.Sprintf("custom (%d)", r)
|
||||
}
|
||||
}
|
||||
|
||||
type MouseMode uint8
|
||||
|
||||
const (
|
||||
MouseModeCircle = MouseMode(10)
|
||||
MouseModeRandom = MouseMode(20)
|
||||
MouseModeUnset = MouseMode(255)
|
||||
)
|
||||
|
||||
func (r MouseMode) String() string {
|
||||
switch r {
|
||||
case MouseModeCircle:
|
||||
return "circle"
|
||||
case MouseModeRandom:
|
||||
return "random"
|
||||
case MouseModeUnset:
|
||||
return "unset"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
type Report struct {
|
||||
State State
|
||||
Mode Mode
|
||||
Rate Rate
|
||||
KeyCode keycodes.KeyCode
|
||||
MouseMode MouseMode
|
||||
}
|
||||
|
||||
func (r Report) String() string {
|
||||
switch r.Mode {
|
||||
case ModeMouse:
|
||||
return fmt.Sprintf("{Mode: %s, MouseMode: %s, Rate: %s, State: %s}", r.Mode, r.MouseMode, r.Rate, r.State)
|
||||
case ModeKeyboard:
|
||||
return fmt.Sprintf("{Mode: %s, KeyCode: %s, Rate: %s, State: %s}", r.Mode, r.KeyCode, r.Rate, r.State)
|
||||
case ModeUnset:
|
||||
return fmt.Sprintf("{Mode: %s, MouseMode: %s, KeyCode: %s, Rate: %s, State: %s}", r.Mode, r.MouseMode, r.KeyCode, r.Rate, r.State)
|
||||
default:
|
||||
return "{invalid}"
|
||||
}
|
||||
}
|
||||
|
||||
func New(b []byte) *Report {
|
||||
r := new(Report)
|
||||
r.State = State(b[1])
|
||||
r.Mode = Mode(b[2])
|
||||
r.Rate = Rate(b[3])
|
||||
r.KeyCode = keycodes.KeyCode(b[4])
|
||||
r.MouseMode = MouseMode(b[5])
|
||||
return r
|
||||
}
|
||||
|
||||
func (r Report) Bytes() []byte {
|
||||
b := make([]byte, 6)
|
||||
b[0] = 3
|
||||
b[1] = uint8(r.State)
|
||||
b[2] = uint8(r.Mode)
|
||||
b[3] = uint8(r.Rate)
|
||||
b[4] = uint8(r.KeyCode)
|
||||
b[5] = uint8(r.MouseMode)
|
||||
return b
|
||||
}
|
||||
21
app/pkg/device/types.go
Normal file
21
app/pkg/device/types.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package device
|
||||
|
||||
// Info - short list of details
|
||||
type Info struct {
|
||||
Serial string
|
||||
Manufacturer string
|
||||
Version uint16
|
||||
Product string
|
||||
}
|
||||
|
||||
// LogLevel - something
|
||||
type LogLevel uint
|
||||
|
||||
// LogNone - disabled logging
|
||||
// LogInfo - basic logging
|
||||
// LogDebug - even more
|
||||
const (
|
||||
LogDebug LogLevel = iota
|
||||
LogInfo
|
||||
LogNone
|
||||
)
|
||||
Reference in New Issue
Block a user