Add streamdeck-ctl JSON control CLI
streamdeck-ctl reports device/daemon/key status as JSON and edits the config (brightness, key set/clear/press, daemon control) so front-ends don't have to reimplement YAML handling or device probing. - internal/config/edit.go: comment-preserving, node-level YAML edits with atomic writes; key indices written as !!int so config.Load accepts them. - internal/device: add model names, Lookup() and Present() for probing without opening the HID handle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BjuZBBfzXqZgxRhxzJvkkC
This commit is contained in:
@@ -19,6 +19,7 @@ const VendorID = 0x0fd9
|
||||
|
||||
// ModelInfo describes hardware-specific constants for a Stream Deck model.
|
||||
type ModelInfo struct {
|
||||
Name string
|
||||
KeyCount int
|
||||
Cols int
|
||||
Rows int
|
||||
@@ -31,9 +32,35 @@ type ModelInfo struct {
|
||||
|
||||
// models maps USB product IDs to their hardware specs.
|
||||
var models = map[uint16]ModelInfo{
|
||||
0x00ba: {KeyCount: 32, Cols: 8, Rows: 4, ImageWidth: 96, ImageHeight: 96, FlipX: true, FlipY: true}, // XL v2
|
||||
0x006c: {KeyCount: 32, Cols: 8, Rows: 4, ImageWidth: 96, ImageHeight: 96, FlipX: true, FlipY: true}, // XL v1
|
||||
0x006d: {KeyCount: 15, Cols: 5, Rows: 3, ImageWidth: 72, ImageHeight: 72, FlipX: true, FlipY: true}, // MK.2
|
||||
0x00ba: {Name: "Stream Deck XL v2", KeyCount: 32, Cols: 8, Rows: 4, ImageWidth: 96, ImageHeight: 96, FlipX: true, FlipY: true},
|
||||
0x006c: {Name: "Stream Deck XL v1", KeyCount: 32, Cols: 8, Rows: 4, ImageWidth: 96, ImageHeight: 96, FlipX: true, FlipY: true},
|
||||
0x006d: {Name: "Stream Deck MK.2", KeyCount: 15, Cols: 5, Rows: 3, ImageWidth: 72, ImageHeight: 72, FlipX: true, FlipY: true},
|
||||
}
|
||||
|
||||
// Lookup returns the hardware spec for a product ID without opening the device.
|
||||
// Callers that only need geometry (key count, grid shape) can use this while the
|
||||
// daemon holds the HID handle.
|
||||
func Lookup(productID uint16) (ModelInfo, bool) {
|
||||
m, ok := models[productID]
|
||||
return m, ok
|
||||
}
|
||||
|
||||
// Present reports whether a Stream Deck with the given USB IDs is currently
|
||||
// enumerated. It does not open the device, so it is safe to call while the
|
||||
// daemon has it open.
|
||||
func Present(vendorID, productID uint16) (bool, error) {
|
||||
if err := hid.Init(); err != nil {
|
||||
return false, fmt.Errorf("hid init: %w", err)
|
||||
}
|
||||
found := false
|
||||
err := hid.Enumerate(vendorID, productID, func(*hid.DeviceInfo) error {
|
||||
found = true
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("hid enumerate: %w", err)
|
||||
}
|
||||
return found, nil
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
Reference in New Issue
Block a user