github.com/stampzilla/stampzilla-go@v2.0.0-rc9+incompatible/nodes/stampzilla-streamdeck/streamdeck/streamdeck.go (about) 1 package streamdeck 2 3 import ( 4 "image" 5 "log" 6 7 "github.com/davecgh/go-spew/spew" 8 "github.com/stamp/hid" 9 ) 10 11 var NUM_KEYS = 15 12 var ICON_SIZE = 72 13 14 var NUM_FIRST_PAGE_PIXELS = 2583 15 var NUM_SECOND_PAGE_PIXELS = 2601 16 17 var reset = []byte{0x0B, 0x63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 18 19 var brightnessBytes = []byte{0x05, 0x55, 0xAA, 0xD1, 0x01, 0, 0x00, 20 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} 21 22 var streamDeck *hid.Device 23 24 type StreamDeck struct { 25 DeviceInfo hid.DeviceInfo 26 Device *hid.Device 27 28 callbacks map[string][]func(button int, state bool) 29 } 30 31 func FindDecks() []*StreamDeck { 32 devices := hid.Enumerate(4057, 96) 33 34 decks := []*StreamDeck{} 35 for _, deviceInfo := range devices { 36 decks = append(decks, &StreamDeck{ 37 DeviceInfo: deviceInfo, 38 callbacks: make(map[string][]func(button int, state bool)), 39 }) 40 } 41 42 spew.Dump(decks) 43 44 return decks 45 } 46 47 func (deck *StreamDeck) Open() error { 48 var err error 49 deck.Device, err = deck.DeviceInfo.Open() 50 if err != nil { 51 return err 52 } 53 go deck.readLoop() 54 55 return nil 56 } 57 58 func (deck *StreamDeck) Close() { 59 deck.Device.Close() 60 } 61 62 func (deck *StreamDeck) Reset() error { 63 _, err := deck.Device.SendFeatureReport(reset) 64 return err 65 } 66 67 func (deck *StreamDeck) SetBrightness(brightness int) error { 68 brightnessBytes[5] = byte(brightness) 69 70 _, err := deck.Device.SendFeatureReport(brightnessBytes) 71 return err 72 } 73 74 func (deck *StreamDeck) WriteImageToKey(image *image.RGBA, key int) { 75 pixels := make([]byte, ICON_SIZE*ICON_SIZE*3) 76 77 for r := 0; r < ICON_SIZE; r++ { 78 rowStartImage := r * ICON_SIZE * 4 79 rowStartPixels := r * ICON_SIZE * 3 80 for c := 0; c < ICON_SIZE; c++ { 81 colPosImage := (c * 4) + rowStartImage 82 colPosPixels := (ICON_SIZE * 3) + rowStartPixels - (c * 3) - 1 83 84 pixels[colPosPixels-2] = image.Pix[colPosImage+2] 85 pixels[colPosPixels-1] = image.Pix[colPosImage+1] 86 pixels[colPosPixels] = image.Pix[colPosImage] 87 } 88 } 89 90 writePage1(deck.Device, key, pixels[0:NUM_FIRST_PAGE_PIXELS*3]) 91 writePage2(deck.Device, key, pixels[NUM_FIRST_PAGE_PIXELS*3:]) 92 } 93 94 func (deck *StreamDeck) OnKeyDown(callback func(button int, state bool)) { 95 deck.on("down", callback) 96 } 97 func (deck *StreamDeck) OnKeyUp(callback func(button int, state bool)) { 98 deck.on("up", callback) 99 } 100 func (deck *StreamDeck) OnKeyChange(callback func(button int, state bool)) { 101 deck.on("change", callback) 102 } 103 func (deck *StreamDeck) on(event string, callback func(button int, state bool)) { 104 deck.callbacks[event] = append(deck.callbacks[event], callback) 105 } 106 107 func writePage1(sd *hid.Device, key int, pixels []byte) error { 108 header := []byte{ 109 0x02, 0x01, 0x01, 0x00, 0x00, (byte)(key + 1), 0x00, 0x00, 110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 111 0x42, 0x4d, 0xf6, 0x3c, 0x00, 0x00, 0x00, 0x00, 112 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00, 113 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x48, 0x00, 114 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00, 115 0x00, 0x00, 0xc0, 0x3c, 0x00, 0x00, 0xc4, 0x0e, 116 0x00, 0x00, 0xc4, 0x0e, 0x00, 0x00, 0x00, 0x00, 117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 118 } 119 120 header = append(header, pixels...) 121 122 data := make([]byte, 8191) 123 124 copy(data, header) 125 126 _, err := sd.Write(data) 127 if err != nil { 128 return err 129 } 130 131 return nil 132 } 133 134 func writePage2(sd *hid.Device, key int, pixels []byte) error { 135 header := []byte{ 136 0x02, 0x01, 0x02, 0x00, 0x01, (byte)(key + 1), 137 } 138 139 padding := make([]byte, 10) 140 141 header = append(header, padding...) 142 header = append(header, pixels...) 143 144 data := make([]byte, 8191) 145 146 copy(data, header) 147 148 _, err := sd.Write(data) 149 if err != nil { 150 return err 151 } 152 153 return nil 154 } 155 156 func (deck *StreamDeck) readLoop() { 157 data := make([]byte, 255) 158 159 var keyState [15]bool 160 161 for { 162 size, err := deck.Device.Read(data) 163 if err != nil { 164 log.Println("Failed to read from streamdeck: ", err) 165 return 166 } 167 168 for k, v := range data[1 : size-1] { 169 state := v > 0 170 if keyState[k] != state { 171 keyState[k] = state 172 173 for _, callback := range deck.callbacks["change"] { 174 callback(k, state) 175 } 176 if state { 177 for _, callback := range deck.callbacks["down"] { 178 callback(k, state) 179 } 180 } else { 181 for _, callback := range deck.callbacks["up"] { 182 callback(k, state) 183 } 184 } 185 } 186 } 187 } 188 }