2019-11-20 01:31:01 +00:00
|
|
|
package streamdeck
|
|
|
|
|
|
|
|
import (
|
|
|
|
"image"
|
|
|
|
"image/color"
|
|
|
|
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
hid "github.com/sstallion/go-hid"
|
|
|
|
)
|
|
|
|
|
|
|
|
const vendorElgato = 0x0fd9
|
|
|
|
|
|
|
|
const (
|
2019-11-20 01:38:04 +00:00
|
|
|
// Streamdeck Original V2 (0fd9:006d) 15 keys
|
2019-11-20 01:31:01 +00:00
|
|
|
StreamDeckOriginalV2 uint16 = 0x006d
|
|
|
|
)
|
|
|
|
|
2019-11-20 01:38:04 +00:00
|
|
|
// EventType represents the state of a button (Up / Down)
|
2019-11-20 01:31:01 +00:00
|
|
|
type EventType uint8
|
|
|
|
|
|
|
|
const (
|
|
|
|
EventTypeUp EventType = iota
|
|
|
|
EventTypeDown
|
|
|
|
)
|
|
|
|
|
2019-11-20 01:38:04 +00:00
|
|
|
// Event represents a state change on a button
|
2019-11-20 01:31:01 +00:00
|
|
|
type Event struct {
|
|
|
|
Key int
|
|
|
|
Type EventType
|
|
|
|
}
|
|
|
|
|
2019-11-20 01:38:04 +00:00
|
|
|
// Client manages the connection to the StreamDeck
|
2019-11-20 01:31:01 +00:00
|
|
|
type Client struct {
|
|
|
|
cfg deckConfig
|
|
|
|
dev *hid.Device
|
|
|
|
devType uint16
|
|
|
|
keyStates []EventType
|
|
|
|
|
|
|
|
evts chan Event
|
|
|
|
}
|
|
|
|
|
2019-11-20 01:38:04 +00:00
|
|
|
// New creates a new Client for the given device (see constants for supported types)
|
2019-11-20 01:31:01 +00:00
|
|
|
func New(devicePID uint16) (*Client, error) {
|
|
|
|
dev, err := hid.OpenFirst(vendorElgato, devicePID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "Unable to open device")
|
|
|
|
}
|
|
|
|
|
|
|
|
cfg := decks[devicePID]
|
|
|
|
cfg.SetDevice(dev)
|
|
|
|
|
|
|
|
client := &Client{
|
|
|
|
cfg: cfg,
|
|
|
|
dev: dev,
|
|
|
|
devType: devicePID,
|
|
|
|
keyStates: make([]EventType, cfg.NumKeys()),
|
|
|
|
|
|
|
|
evts: make(chan Event, 100),
|
|
|
|
}
|
|
|
|
|
|
|
|
go client.read()
|
|
|
|
|
|
|
|
return client, nil
|
|
|
|
}
|
|
|
|
|
2019-11-20 01:38:04 +00:00
|
|
|
// Close closes the underlying HID connection
|
|
|
|
func (c Client) Close() error { return c.dev.Close() }
|
|
|
|
|
|
|
|
// Serial returns the device serial
|
2019-11-20 01:31:01 +00:00
|
|
|
func (c Client) Serial() (string, error) { return c.dev.GetSerialNbr() }
|
|
|
|
|
2019-11-20 01:38:04 +00:00
|
|
|
// FillColor fills a key with a solid color
|
|
|
|
func (c Client) FillColor(keyIdx int, col color.RGBA) error { return c.cfg.FillColor(keyIdx, col) }
|
|
|
|
|
|
|
|
// FillImage fills a key with an image
|
2019-11-20 01:31:01 +00:00
|
|
|
func (c Client) FillImage(keyIdx int, img image.Image) error { return c.cfg.FillImage(keyIdx, img) }
|
|
|
|
|
2019-11-20 01:38:04 +00:00
|
|
|
// FillPanel slices a big image and fills the keys with the parts
|
|
|
|
func (c Client) FillPanel(img image.RGBA) error { return c.cfg.FillPanel(img) }
|
|
|
|
|
|
|
|
// ClearKey fills a key with solid black
|
2019-11-20 01:31:01 +00:00
|
|
|
func (c Client) ClearKey(keyIdx int) error { return c.cfg.ClearKey(keyIdx) }
|
|
|
|
|
2019-11-20 01:38:04 +00:00
|
|
|
// ClearAllKeys fills all keys with solid black
|
|
|
|
func (c Client) ClearAllKeys() error { return c.cfg.ClearAllKeys() }
|
|
|
|
|
|
|
|
// SetBrightness sets the brightness of the keys (0-100)
|
2019-11-20 01:31:01 +00:00
|
|
|
func (c Client) SetBrightness(pct int) error { return c.cfg.SetBrightness(pct) }
|
|
|
|
|
2019-11-20 01:38:04 +00:00
|
|
|
// ResetToLogo restores the original Elgato StreamDeck logo
|
2019-11-20 01:31:01 +00:00
|
|
|
func (c Client) ResetToLogo() error { return c.cfg.ResetToLogo() }
|
|
|
|
|
2019-11-20 01:38:04 +00:00
|
|
|
// GetFimwareVersion retrieves the firmware version
|
2019-11-20 01:31:01 +00:00
|
|
|
func (c Client) GetFimwareVersion() (string, error) { return c.cfg.GetFimwareVersion() }
|
|
|
|
|
2019-11-20 01:38:04 +00:00
|
|
|
// Subscribe returns a channel to listen for incoming events
|
|
|
|
func (c Client) Subscribe() <-chan Event { return c.evts }
|
|
|
|
|
2019-11-20 01:31:01 +00:00
|
|
|
func (c Client) emit(key int, t EventType) { c.evts <- Event{Key: key, Type: t} }
|
|
|
|
|
|
|
|
func (c *Client) read() {
|
|
|
|
for {
|
|
|
|
buf := make([]byte, 1024)
|
|
|
|
_, err := c.dev.Read(buf)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
for k := 0; k < c.cfg.NumKeys(); k++ {
|
|
|
|
newState := EventType(buf[k+c.cfg.KeyDataOffset()])
|
|
|
|
if c.keyStates[k] != newState {
|
|
|
|
c.emit(k, newState)
|
|
|
|
c.keyStates[k] = newState
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|