| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130 |
- package device
- import (
- "encoding/json"
- "fmt"
- "os"
- "path/filepath"
- "netdome.biz/paul/impact-80/internal/hid"
- )
- // Keyboard represents a keyboard definition from keyboards.json.
- type Keyboard struct {
- Name string `json:"name"`
- VendorID uint16 `json:"vendorId"`
- ProductID uint16 `json:"productId"`
- Protocol string `json:"protocol"`
- VIAVersion int `json:"viaVersion"`
- LEDLayout string `json:"ledLayout"`
- }
- // Device represents a connected keyboard device.
- type Device struct {
- Keyboard
- Path string
- }
- // LoadKeyboards reads keyboard definitions from keyboards.json.
- func LoadKeyboards() ([]Keyboard, error) {
- path, err := findKeyboardsJSON()
- if err != nil {
- return nil, fmt.Errorf("find keyboards.json: %w", err)
- }
- data, err := os.ReadFile(path)
- if err != nil {
- return nil, fmt.Errorf("read keyboards.json: %w", err)
- }
- var keyboards []Keyboard
- if err := json.Unmarshal(data, &keyboards); err != nil {
- return nil, fmt.Errorf("parse keyboards.json: %w", err)
- }
- return keyboards, nil
- }
- // findKeyboardsJSON searches for keyboards.json in common locations.
- var findKeyboardsJSON = func() (string, error) {
- exe, err := os.Executable()
- if err == nil {
- path := filepath.Join(filepath.Dir(exe), "keyboards.json")
- if _, err := os.Stat(path); err == nil {
- return path, nil
- }
- }
- path := "keyboards.json"
- if _, err := os.Stat(path); err == nil {
- return path, nil
- }
- cwd, err := os.Getwd()
- if err == nil {
- path := filepath.Join(cwd, "keyboards.json")
- if _, err := os.Stat(path); err == nil {
- return path, nil
- }
- }
- return "", fmt.Errorf("keyboards.json not found")
- }
- // UnknownDevice represents a QMK Raw HID keyboard not yet in keyboards.json.
- type UnknownDevice struct {
- VendorID uint16 `json:"vendorId"`
- ProductID uint16 `json:"productId"`
- Path string `json:"path"`
- Supported bool `json:"supported"`
- }
- // DiscoverAllQMK scans for all connected QMK keyboards (both known and unknown).
- func DiscoverAllQMK(keyboards []Keyboard) ([]UnknownDevice, error) {
- qmkDevices, err := hid.DiscoverAll()
- if err != nil {
- return nil, fmt.Errorf("discover qmk devices: %w", err)
- }
- known := make(map[string]bool)
- for _, kb := range keyboards {
- known[fmt.Sprintf("%04x:%04x", kb.VendorID, kb.ProductID)] = true
- }
- var results []UnknownDevice
- for _, q := range qmkDevices {
- key := fmt.Sprintf("%04x:%04x", q.VendorID, q.ProductID)
- results = append(results, UnknownDevice{
- VendorID: q.VendorID,
- ProductID: q.ProductID,
- Path: q.Path,
- Supported: known[key],
- })
- }
- return results, nil
- }
- func Discover(keyboards []Keyboard) ([]Device, error) {
- var found []Device
- for _, kb := range keyboards {
- err := hid.Enumerate(kb.VendorID, kb.ProductID, func(info *hid.DeviceInfo) error {
- found = append(found, Device{
- Keyboard: kb,
- Path: info.Path,
- })
- return nil
- })
- if err != nil {
- return nil, fmt.Errorf("enumerate VID=0x%04x PID=0x%04x: %w", kb.VendorID, kb.ProductID, err)
- }
- }
- if len(found) > 0 {
- fmt.Fprintf(os.Stderr, "Discovered %d keyboard(s):\n", len(found))
- for _, d := range found {
- fmt.Fprintf(os.Stderr, " - %s (VID=0x%04x PID=0x%04x) %s\n", d.Name, d.VendorID, d.ProductID, d.Path)
- }
- } else {
- fmt.Fprintln(os.Stderr, "No keyboards found.")
- }
- return found, nil
- }
|