Fix image headers, add Stream Deck+ color mixer with coarse/fine encoders
This commit is contained in:
118
cmd/deckcolor/main.go
Normal file
118
cmd/deckcolor/main.go
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"image/draw"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"qrun/lib/streamdeck"
|
||||||
|
)
|
||||||
|
|
||||||
|
func clamp(v int) int {
|
||||||
|
if v < 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if v > 255 {
|
||||||
|
return 255
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
dev, err := streamdeck.OpenModel(&streamdeck.ModelPlus)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
defer dev.Close()
|
||||||
|
|
||||||
|
dev.SetBrightness(80)
|
||||||
|
|
||||||
|
rgb := [3]int{0, 0, 0}
|
||||||
|
fine := [3]bool{false, false, false}
|
||||||
|
labels := [3]string{"R", "G", "B"}
|
||||||
|
labelColors := [3]color.RGBA{
|
||||||
|
{255, 0, 0, 255},
|
||||||
|
{0, 255, 0, 255},
|
||||||
|
{0, 100, 255, 255},
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLCD := func() {
|
||||||
|
c := color.RGBA{uint8(rgb[0]), uint8(rgb[1]), uint8(rgb[2]), 255}
|
||||||
|
dev.SetLCDColor(0, 0, dev.Model().LCDWidth, dev.Model().LCDHeight, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
updateKey := func(i int) {
|
||||||
|
bg := color.RGBA{labelColors[i].R / 4, labelColors[i].G / 4, labelColors[i].B / 4, 255}
|
||||||
|
sz := dev.Model().KeySize
|
||||||
|
txt := streamdeck.TextImageWithFaceSized(streamdeck.MonoBoldSmall, sz, bg, labelColors[i], labels[i], fmt.Sprintf("%d", rgb[i]))
|
||||||
|
if fine[i] {
|
||||||
|
img := image.NewRGBA(image.Rect(0, 0, sz, sz))
|
||||||
|
draw.Draw(img, img.Bounds(), txt, image.Point{}, draw.Src)
|
||||||
|
border := labelColors[i]
|
||||||
|
b := 4
|
||||||
|
for y := 0; y < sz; y++ {
|
||||||
|
for x := 0; x < sz; x++ {
|
||||||
|
if x < b || x >= sz-b || y < b || y >= sz-b {
|
||||||
|
img.Set(x, y, border)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dev.SetKeyImage(i, img)
|
||||||
|
} else {
|
||||||
|
dev.SetKeyImage(i, txt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAllKeys := func() {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
updateKey(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLCD()
|
||||||
|
updateAllKeys()
|
||||||
|
|
||||||
|
for i := 3; i < dev.Model().Keys; i++ {
|
||||||
|
dev.ClearKey(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
input := make(chan streamdeck.InputEvent, 64)
|
||||||
|
go func() {
|
||||||
|
if err := dev.ReadInput(input); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Read error: %v\n", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
sig := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case ev := <-input:
|
||||||
|
if ev.Encoder != nil && ev.Encoder.Encoder < 3 {
|
||||||
|
i := ev.Encoder.Encoder
|
||||||
|
if ev.Encoder.Delta != 0 {
|
||||||
|
delta := ev.Encoder.Delta
|
||||||
|
if !fine[i] {
|
||||||
|
delta *= 10
|
||||||
|
}
|
||||||
|
rgb[i] = clamp(rgb[i] + delta)
|
||||||
|
updateLCD()
|
||||||
|
updateKey(i)
|
||||||
|
fmt.Printf("R=%d G=%d B=%d\n", rgb[0], rgb[1], rgb[2])
|
||||||
|
} else if ev.Encoder.Pressed {
|
||||||
|
fine[i] = !fine[i]
|
||||||
|
updateKey(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-sig:
|
||||||
|
fmt.Println()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -181,10 +181,10 @@ func (d *Device) ClearAllKeys() error {
|
|||||||
|
|
||||||
func (d *Device) sendKeyImage(key byte, imgData []byte) error {
|
func (d *Device) sendKeyImage(key byte, imgData []byte) error {
|
||||||
reportLen := d.dev.GetOutputReportLength()
|
reportLen := d.dev.GetOutputReportLength()
|
||||||
hdrLen := uint16(8)
|
hdrLen := uint16(7)
|
||||||
payloadLen := reportLen - hdrLen
|
payloadLen := reportLen - hdrLen
|
||||||
|
|
||||||
var page uint16
|
var page byte
|
||||||
for start := uint16(0); start < uint16(len(imgData)); page++ {
|
for start := uint16(0); start < uint16(len(imgData)); page++ {
|
||||||
end := start + payloadLen
|
end := start + payloadLen
|
||||||
last := byte(0)
|
last := byte(0)
|
||||||
@@ -195,14 +195,13 @@ func (d *Device) sendKeyImage(key byte, imgData []byte) error {
|
|||||||
|
|
||||||
chunk := imgData[start:end]
|
chunk := imgData[start:end]
|
||||||
hdr := []byte{
|
hdr := []byte{
|
||||||
0x02,
|
|
||||||
0x07,
|
0x07,
|
||||||
key,
|
key,
|
||||||
last,
|
last,
|
||||||
byte(len(chunk)),
|
byte(len(chunk)),
|
||||||
byte(len(chunk) >> 8),
|
byte(len(chunk) >> 8),
|
||||||
byte(page),
|
page,
|
||||||
byte(page >> 8),
|
0,
|
||||||
}
|
}
|
||||||
|
|
||||||
payload := append(hdr, chunk...)
|
payload := append(hdr, chunk...)
|
||||||
@@ -241,10 +240,10 @@ func (d *Device) SetLCDColor(x, y, w, h int, c color.Color) error {
|
|||||||
|
|
||||||
func (d *Device) sendLCDImage(x, y, w, h uint16, imgData []byte) error {
|
func (d *Device) sendLCDImage(x, y, w, h uint16, imgData []byte) error {
|
||||||
reportLen := d.dev.GetOutputReportLength()
|
reportLen := d.dev.GetOutputReportLength()
|
||||||
hdrLen := uint16(16)
|
hdrLen := uint16(15)
|
||||||
payloadLen := reportLen - hdrLen
|
payloadLen := reportLen - hdrLen
|
||||||
|
|
||||||
var page uint16
|
var page byte
|
||||||
for start := uint16(0); start < uint16(len(imgData)); page++ {
|
for start := uint16(0); start < uint16(len(imgData)); page++ {
|
||||||
end := start + payloadLen
|
end := start + payloadLen
|
||||||
last := byte(0)
|
last := byte(0)
|
||||||
@@ -254,17 +253,22 @@ func (d *Device) sendLCDImage(x, y, w, h uint16, imgData []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
chunk := imgData[start:end]
|
chunk := imgData[start:end]
|
||||||
hdr := make([]byte, 16)
|
hdr := make([]byte, 15)
|
||||||
hdr[0] = 0x02
|
hdr[0] = 0x0C
|
||||||
hdr[1] = 0x0C
|
hdr[1] = byte(x)
|
||||||
binary.LittleEndian.PutUint16(hdr[2:], x)
|
hdr[2] = byte(x >> 8)
|
||||||
binary.LittleEndian.PutUint16(hdr[4:], y)
|
hdr[3] = byte(y)
|
||||||
binary.LittleEndian.PutUint16(hdr[6:], w)
|
hdr[4] = byte(y >> 8)
|
||||||
binary.LittleEndian.PutUint16(hdr[8:], h)
|
hdr[5] = byte(w)
|
||||||
hdr[10] = last
|
hdr[6] = byte(w >> 8)
|
||||||
binary.LittleEndian.PutUint16(hdr[11:], page)
|
hdr[7] = byte(h)
|
||||||
binary.LittleEndian.PutUint16(hdr[13:], uint16(len(chunk)))
|
hdr[8] = byte(h >> 8)
|
||||||
hdr[15] = 0
|
hdr[9] = last
|
||||||
|
hdr[10] = page
|
||||||
|
hdr[11] = 0
|
||||||
|
hdr[12] = byte(len(chunk))
|
||||||
|
hdr[13] = byte(len(chunk) >> 8)
|
||||||
|
hdr[14] = 0
|
||||||
|
|
||||||
payload := append(hdr, chunk...)
|
payload := append(hdr, chunk...)
|
||||||
padding := make([]byte, reportLen-uint16(len(payload)))
|
padding := make([]byte, reportLen-uint16(len(payload)))
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ var (
|
|||||||
MonoRegular font.Face
|
MonoRegular font.Face
|
||||||
MonoMedium font.Face
|
MonoMedium font.Face
|
||||||
MonoBold font.Face
|
MonoBold font.Face
|
||||||
|
MonoRegularSmall font.Face
|
||||||
|
MonoMediumSmall font.Face
|
||||||
|
MonoBoldSmall font.Face
|
||||||
Regular font.Face
|
Regular font.Face
|
||||||
Bold font.Face
|
Bold font.Face
|
||||||
)
|
)
|
||||||
@@ -28,6 +31,9 @@ func init() {
|
|||||||
MonoRegular = loadFace("fonts/AtkinsonHyperlegibleMono-Regular.ttf", 72)
|
MonoRegular = loadFace("fonts/AtkinsonHyperlegibleMono-Regular.ttf", 72)
|
||||||
MonoMedium = loadFace("fonts/AtkinsonHyperlegibleMono-Medium.ttf", 72)
|
MonoMedium = loadFace("fonts/AtkinsonHyperlegibleMono-Medium.ttf", 72)
|
||||||
MonoBold = loadFace("fonts/AtkinsonHyperlegibleMono-Bold.ttf", 72)
|
MonoBold = loadFace("fonts/AtkinsonHyperlegibleMono-Bold.ttf", 72)
|
||||||
|
MonoRegularSmall = loadFace("fonts/AtkinsonHyperlegibleMono-Regular.ttf", 40)
|
||||||
|
MonoMediumSmall = loadFace("fonts/AtkinsonHyperlegibleMono-Medium.ttf", 40)
|
||||||
|
MonoBoldSmall = loadFace("fonts/AtkinsonHyperlegibleMono-Bold.ttf", 40)
|
||||||
Regular = loadFace("fonts/AtkinsonHyperlegible-Regular.ttf", 16)
|
Regular = loadFace("fonts/AtkinsonHyperlegible-Regular.ttf", 16)
|
||||||
Bold = loadFace("fonts/AtkinsonHyperlegible-Bold.ttf", 16)
|
Bold = loadFace("fonts/AtkinsonHyperlegible-Bold.ttf", 16)
|
||||||
}
|
}
|
||||||
@@ -93,6 +99,11 @@ func (d *Device) SetKeyText(key int, bg color.Color, fg color.Color, text string
|
|||||||
return d.SetKeyImage(key, TextImageSized(d.model.KeySize, bg, fg, lines...))
|
return d.SetKeyImage(key, TextImageSized(d.model.KeySize, bg, fg, lines...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Device) SetKeyTextWithFace(key int, face font.Face, bg color.Color, fg color.Color, text string) error {
|
||||||
|
lines := strings.Split(text, "\n")
|
||||||
|
return d.SetKeyImage(key, TextImageWithFaceSized(face, d.model.KeySize, bg, fg, lines...))
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Device) SetKeyBoldText(key int, bg color.Color, fg color.Color, text string) error {
|
func (d *Device) SetKeyBoldText(key int, bg color.Color, fg color.Color, text string) error {
|
||||||
lines := strings.Split(text, "\n")
|
lines := strings.Split(text, "\n")
|
||||||
return d.SetKeyImage(key, TextImageWithFaceSized(MonoBold, d.model.KeySize, bg, fg, lines...))
|
return d.SetKeyImage(key, TextImageWithFaceSized(MonoBold, d.model.KeySize, bg, fg, lines...))
|
||||||
|
|||||||
Reference in New Issue
Block a user