@@ -5,11 +5,13 @@ import (
55 "fmt"
66 "log"
77 "os"
8+ "path/filepath"
89 "sync"
910 "time"
1011
1112 "github.com/bendahl/uinput"
1213 "github.com/godbus/dbus"
14+ "github.com/mitchellh/go-homedir"
1315 "github.com/muesli/streamdeck"
1416)
1517
@@ -26,109 +28,25 @@ var (
2628 brightness = flag .Uint ("brightness" , 80 , "brightness in percent" )
2729)
2830
29- func handleActiveWindowChanged (dev streamdeck.Device , event ActiveWindowChangedEvent ) {
30- log .Printf ("Active window changed to %s (%d, %s)\n " ,
31- event .Window .Class , event .Window .ID , event .Window .Name )
32-
33- // remove dupes
34- i := 0
35- for _ , rw := range recentWindows {
36- if rw .ID == event .Window .ID {
37- continue
38- }
39-
40- recentWindows [i ] = rw
41- i ++
42- }
43- recentWindows = recentWindows [:i ]
44-
45- keys := int (dev .Rows * dev .Columns )
46- recentWindows = append ([]Window {event .Window }, recentWindows ... )
47- if len (recentWindows ) > keys {
48- recentWindows = recentWindows [0 :keys ]
49- }
50- deck .updateWidgets (& dev )
51- }
52-
53- func handleWindowClosed (dev streamdeck.Device , event WindowClosedEvent ) {
54- i := 0
55- for _ , rw := range recentWindows {
56- if rw .ID == event .Window .ID {
57- continue
58- }
59-
60- recentWindows [i ] = rw
61- i ++
62- }
63- recentWindows = recentWindows [:i ]
64- deck .updateWidgets (& dev )
65- }
66-
67- func main () {
68- flag .Parse ()
31+ const (
32+ longPressDuration = 350 * time .Millisecond
33+ )
6934
35+ func expandPath (base , path string ) (string , error ) {
7036 var err error
71-
72- dbusConn , err = dbus .SessionBus ()
37+ path , err = homedir .Expand (path )
7338 if err != nil {
74- log . Fatal ( err )
39+ return "" , err
7540 }
7641
77- tch := make (chan interface {})
78- xorg , err = Connect (os .Getenv ("DISPLAY" ))
79- if err == nil {
80- defer xorg .Close ()
81- xorg .TrackWindows (tch , time .Second )
42+ if ! filepath .IsAbs (path ) {
43+ path = filepath .Join (base , path )
8244 }
8345
84- d , err := streamdeck .Devices ()
85- if err != nil {
86- log .Fatal (err )
87- }
88- if len (d ) == 0 {
89- fmt .Println ("No Stream Deck devices found." )
90- return
91- }
92- dev := d [0 ]
93-
94- err = dev .Open ()
95- if err != nil {
96- log .Fatal (err )
97- }
98- ver , err := dev .FirmwareVersion ()
99- if err != nil {
100- log .Fatal (err )
101- }
102- log .Printf ("Found device with serial %s (firmware %s)\n " ,
103- dev .Serial , ver )
104-
105- deck , err = LoadDeck (& dev , "." , * deckFile )
106- if err != nil {
107- log .Fatal (err )
108- }
109-
110- err = dev .Reset ()
111- if err != nil {
112- log .Fatal (err )
113- }
114- deck .updateWidgets (& dev )
115-
116- if * brightness > 100 {
117- * brightness = 100
118- }
119- err = dev .SetBrightness (uint8 (* brightness ))
120- if err != nil {
121- log .Fatal (err )
122- }
123-
124- keyboard , err = uinput .CreateKeyboard ("/dev/uinput" , []byte ("Deckmaster" ))
125- if err != nil {
126- log .Printf ("Could not create virtual input device (/dev/uinput): %s" , err )
127- log .Println ("Emulating keyboard events will be disabled!" )
128- } else {
129- defer keyboard .Close () //nolint:errcheck
130- }
46+ return filepath .Abs (path )
47+ }
13148
49+ func eventLoop (dev * streamdeck.Device , tch chan interface {}) {
13250 var keyStates sync.Map
13351 keyTimestamps := make (map [uint8 ]time.Time )
13452
@@ -139,7 +57,7 @@ func main() {
13957 for {
14058 select {
14159 case <- time .After (100 * time .Millisecond ):
142- deck .updateWidgets (& dev )
60+ deck .updateWidgets (dev )
14361
14462 case k , ok := <- kch :
14563 if ! ok {
@@ -158,21 +76,21 @@ func main() {
15876
15977 if state && ! k .Pressed {
16078 // key was released
161- if time .Since (keyTimestamps [k .Index ]) < 200 * time . Millisecond {
79+ if time .Since (keyTimestamps [k .Index ]) < longPressDuration {
16280 // log.Println("Triggering short action")
163- deck .triggerAction (& dev , k .Index , false )
81+ deck .triggerAction (dev , k .Index , false )
16482 }
16583 }
16684 if ! state && k .Pressed {
16785 // key was pressed
16886 go func () {
16987 // launch timer to observe keystate
170- time .Sleep (200 * time . Millisecond )
88+ time .Sleep (longPressDuration )
17189
17290 if state , ok := keyStates .Load (k .Index ); ok && state .(bool ) {
17391 // key still pressed
17492 // log.Println("Triggering long action")
175- deck .triggerAction (& dev , k .Index , true )
93+ deck .triggerAction (dev , k .Index , true )
17694 }
17795 }()
17896 }
@@ -189,3 +107,79 @@ func main() {
189107 }
190108 }
191109}
110+
111+ func initDevice () (* streamdeck.Device , error ) {
112+ d , err := streamdeck .Devices ()
113+ if err != nil {
114+ log .Fatal (err )
115+ }
116+ if len (d ) == 0 {
117+ return nil , fmt .Errorf ("no Stream Deck devices found" )
118+ }
119+ dev := d [0 ]
120+
121+ if err := dev .Open (); err != nil {
122+ return nil , err
123+ }
124+ ver , err := dev .FirmwareVersion ()
125+ if err != nil {
126+ return nil , err
127+ }
128+ log .Printf ("Found device with serial %s (firmware %s)\n " ,
129+ dev .Serial , ver )
130+
131+ if err := dev .Reset (); err != nil {
132+ return nil , err
133+ }
134+
135+ if * brightness > 100 {
136+ * brightness = 100
137+ }
138+ if err = dev .SetBrightness (uint8 (* brightness )); err != nil {
139+ return nil , err
140+ }
141+
142+ return & dev , nil
143+ }
144+
145+ func main () {
146+ flag .Parse ()
147+
148+ // initialize device
149+ dev , err := initDevice ()
150+ if err != nil {
151+ log .Fatal (err )
152+ }
153+
154+ // initialize dbus connection
155+ dbusConn , err = dbus .SessionBus ()
156+ if err != nil {
157+ log .Fatal (err )
158+ }
159+
160+ // initialize xorg connection and track window focus
161+ tch := make (chan interface {})
162+ xorg , err = Connect (os .Getenv ("DISPLAY" ))
163+ if err == nil {
164+ defer xorg .Close ()
165+ xorg .TrackWindows (tch , time .Second )
166+ }
167+
168+ // initialize virtual keyboard
169+ keyboard , err = uinput .CreateKeyboard ("/dev/uinput" , []byte ("Deckmaster" ))
170+ if err != nil {
171+ log .Printf ("Could not create virtual input device (/dev/uinput): %s" , err )
172+ log .Println ("Emulating keyboard events will be disabled!" )
173+ } else {
174+ defer keyboard .Close () //nolint:errcheck
175+ }
176+
177+ // load deck
178+ deck , err = LoadDeck (dev , "." , * deckFile )
179+ if err != nil {
180+ log .Fatal (err )
181+ }
182+ deck .updateWidgets (dev )
183+
184+ eventLoop (dev , tch )
185+ }
0 commit comments