device.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. package device
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "github.com/wobkey/rgb/internal/hid"
  8. )
  9. // Keyboard represents a VIA-compatible keyboard 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. // Discover scans for connected VIA-compatible keyboards.
  62. func Discover(keyboards []Keyboard) ([]Device, error) {
  63. var found []Device
  64. for _, kb := range keyboards {
  65. err := hid.Enumerate(kb.VendorID, kb.ProductID, func(info *hid.DeviceInfo) error {
  66. found = append(found, Device{
  67. Keyboard: kb,
  68. Path: info.Path,
  69. })
  70. return nil
  71. })
  72. if err != nil {
  73. return nil, fmt.Errorf("enumerate VID=0x%04x PID=0x%04x: %w", kb.VendorID, kb.ProductID, err)
  74. }
  75. }
  76. fmt.Fprintf(os.Stderr, "DEBUG discover: found %d keyboard(s)\n", len(found))
  77. for _, d := range found {
  78. fmt.Fprintf(os.Stderr, "DEBUG discover: %s path=%s VID=0x%04x PID=0x%04x\n", d.Name, d.Path, d.VendorID, d.ProductID)
  79. }
  80. return found, nil
  81. }