device.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package device
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "netdome.biz/paul/impact-80/internal/hid"
  8. )
  9. // Keyboard represents a keyboard definition from keyboards.json.
  10. type Keyboard struct {
  11. Name string `json:"name"`
  12. VendorID uint16 `json:"vendorId"`
  13. ProductID uint16 `json:"productId"`
  14. Protocol string `json:"protocol"`
  15. VIAVersion int `json:"viaVersion"`
  16. LEDLayout string `json:"ledLayout"`
  17. }
  18. // Device represents a connected keyboard device.
  19. type Device struct {
  20. Keyboard
  21. Path string
  22. }
  23. // LoadKeyboards reads keyboard definitions from keyboards.json.
  24. func LoadKeyboards() ([]Keyboard, error) {
  25. path, err := findKeyboardsJSON()
  26. if err != nil {
  27. return nil, fmt.Errorf("find keyboards.json: %w", err)
  28. }
  29. data, err := os.ReadFile(path)
  30. if err != nil {
  31. return nil, fmt.Errorf("read keyboards.json: %w", err)
  32. }
  33. var keyboards []Keyboard
  34. if err := json.Unmarshal(data, &keyboards); err != nil {
  35. return nil, fmt.Errorf("parse keyboards.json: %w", err)
  36. }
  37. return keyboards, nil
  38. }
  39. // findKeyboardsJSON searches for keyboards.json in common locations.
  40. var findKeyboardsJSON = func() (string, error) {
  41. exe, err := os.Executable()
  42. if err == nil {
  43. path := filepath.Join(filepath.Dir(exe), "keyboards.json")
  44. if _, err := os.Stat(path); err == nil {
  45. return path, nil
  46. }
  47. }
  48. path := "keyboards.json"
  49. if _, err := os.Stat(path); err == nil {
  50. return path, nil
  51. }
  52. cwd, err := os.Getwd()
  53. if err == nil {
  54. path := filepath.Join(cwd, "keyboards.json")
  55. if _, err := os.Stat(path); err == nil {
  56. return path, nil
  57. }
  58. }
  59. return "", fmt.Errorf("keyboards.json not found")
  60. }
  61. // UnknownDevice represents a QMK Raw HID keyboard not yet in keyboards.json.
  62. type UnknownDevice struct {
  63. VendorID uint16 `json:"vendorId"`
  64. ProductID uint16 `json:"productId"`
  65. Path string `json:"path"`
  66. Supported bool `json:"supported"`
  67. }
  68. // DiscoverAllQMK scans for all connected QMK keyboards (both known and unknown).
  69. func DiscoverAllQMK(keyboards []Keyboard) ([]UnknownDevice, error) {
  70. qmkDevices, err := hid.DiscoverAll()
  71. if err != nil {
  72. return nil, fmt.Errorf("discover qmk devices: %w", err)
  73. }
  74. known := make(map[string]bool)
  75. for _, kb := range keyboards {
  76. known[fmt.Sprintf("%04x:%04x", kb.VendorID, kb.ProductID)] = true
  77. }
  78. var results []UnknownDevice
  79. for _, q := range qmkDevices {
  80. key := fmt.Sprintf("%04x:%04x", q.VendorID, q.ProductID)
  81. results = append(results, UnknownDevice{
  82. VendorID: q.VendorID,
  83. ProductID: q.ProductID,
  84. Path: q.Path,
  85. Supported: known[key],
  86. })
  87. }
  88. return results, nil
  89. }
  90. func Discover(keyboards []Keyboard) ([]Device, error) {
  91. var found []Device
  92. for _, kb := range keyboards {
  93. err := hid.Enumerate(kb.VendorID, kb.ProductID, func(info *hid.DeviceInfo) error {
  94. found = append(found, Device{
  95. Keyboard: kb,
  96. Path: info.Path,
  97. })
  98. return nil
  99. })
  100. if err != nil {
  101. return nil, fmt.Errorf("enumerate VID=0x%04x PID=0x%04x: %w", kb.VendorID, kb.ProductID, err)
  102. }
  103. }
  104. if len(found) > 0 {
  105. fmt.Fprintf(os.Stderr, "Discovered %d keyboard(s):\n", len(found))
  106. for _, d := range found {
  107. fmt.Fprintf(os.Stderr, " - %s (VID=0x%04x PID=0x%04x) %s\n", d.Name, d.VendorID, d.ProductID, d.Path)
  108. }
  109. } else {
  110. fmt.Fprintln(os.Stderr, "No keyboards found.")
  111. }
  112. return found, nil
  113. }