@@ -7,8 +7,10 @@ import (
7
7
"os/exec"
8
8
"path/filepath"
9
9
"strconv"
10
+ "strings"
10
11
"time"
11
12
13
+ "github.com/go-toast/toast"
12
14
"github.com/go-vgo/robotgo"
13
15
"github.com/manifoldco/promptui"
14
16
"golang.design/x/hotkey"
@@ -18,8 +20,6 @@ type RecordingOptions struct {
18
20
FPS int `json:"fps"`
19
21
CaptureMouse bool `json:"capture_mouse"`
20
22
AudioDevice string `json:"audio_device"`
21
- Width int `json:"width"`
22
- Height int `json:"height"`
23
23
}
24
24
25
25
var defaultOpts = map [string ]any {
@@ -28,6 +28,47 @@ var defaultOpts = map[string]any{
28
28
"audio_device" : "" ,
29
29
}
30
30
31
+ var (
32
+ keys = map [string ]hotkey.Key {
33
+ "a" : hotkey .KeyA ,
34
+ "b" : hotkey .KeyB ,
35
+ "c" : hotkey .KeyC ,
36
+ "d" : hotkey .KeyD ,
37
+ "e" : hotkey .KeyE ,
38
+ "f" : hotkey .KeyF ,
39
+ "g" : hotkey .KeyG ,
40
+ "h" : hotkey .KeyH ,
41
+ "i" : hotkey .KeyI ,
42
+ "j" : hotkey .KeyJ ,
43
+ "k" : hotkey .KeyK ,
44
+ "l" : hotkey .KeyL ,
45
+ "m" : hotkey .KeyM ,
46
+ "n" : hotkey .KeyN ,
47
+ "o" : hotkey .KeyO ,
48
+ "p" : hotkey .KeyP ,
49
+ "q" : hotkey .KeyQ ,
50
+ "r" : hotkey .KeyR ,
51
+ "s" : hotkey .KeyS ,
52
+ "t" : hotkey .KeyT ,
53
+ "u" : hotkey .KeyU ,
54
+ "v" : hotkey .KeyV ,
55
+ "w" : hotkey .KeyW ,
56
+ "x" : hotkey .KeyX ,
57
+ "y" : hotkey .KeyY ,
58
+ "z" : hotkey .KeyZ ,
59
+ "0" : hotkey .Key0 ,
60
+ "1" : hotkey .Key1 ,
61
+ "2" : hotkey .Key2 ,
62
+ "3" : hotkey .Key3 ,
63
+ "4" : hotkey .Key4 ,
64
+ "5" : hotkey .Key5 ,
65
+ "6" : hotkey .Key6 ,
66
+ "7" : hotkey .Key7 ,
67
+ "8" : hotkey .Key8 ,
68
+ "9" : hotkey .Key9 ,
69
+ }
70
+ )
71
+
31
72
func mergeRecordingDefaults () {
32
73
data , err := os .ReadFile (configFilePath )
33
74
if err != nil {
@@ -70,14 +111,11 @@ func mergeRecordingDefaults() {
70
111
os .WriteFile (configFilePath , out , 0644 )
71
112
}
72
113
73
- func ternary (cond bool , a , b any ) any {
74
- if cond {
75
- return a
76
- }
77
- return b
78
- }
79
-
80
114
func RecordDisplay () {
115
+ if config .HotkeyConfig != nil && (len (config .HotkeyConfig .Modkeys ) == 0 || config .HotkeyConfig .Finalkey == "" ) {
116
+ fmt .Println ("Invalid hotkey configured. Please reset Captr." )
117
+ os .Exit (1 )
118
+ }
81
119
active_displays := robotgo .DisplaysNum ()
82
120
displays := []string {"Display 1 (Primary)" }
83
121
for i := 2 ; i < active_displays ; i ++ {
@@ -102,10 +140,15 @@ func RecordDisplay() {
102
140
"-offset_x" , strconv .Itoa (x ),
103
141
"-offset_y" , strconv .Itoa (y ),
104
142
"-video_size" , fmt .Sprintf ("%dx%d" , w , h ),
105
- "-draw_mouse" , ternary (config .RecordingOpts .CaptureMouse , "1" , "0" ).( string ) ,
143
+ "-draw_mouse" , ternary (config .RecordingOpts .CaptureMouse , "1" , "0" ),
106
144
"-i" , "desktop" ,
107
145
"-c:v" , "libx264" ,
108
146
"-preset" , "ultrafast" ,
147
+ "-profile:v" , "main" ,
148
+ "-level" , "4.0" ,
149
+ "-pix_fmt" , "yuv420p" ,
150
+ "-c:a" , "aac" ,
151
+ "-movflags" , "+faststart" ,
109
152
"-y" , filename ,
110
153
}
111
154
@@ -117,20 +160,46 @@ func RecordDisplay() {
117
160
return
118
161
}
119
162
120
- fmt .Println ("Recording started. Press ctrl+shift+3 to stop" )
163
+ var modkeys []hotkey.Modifier
164
+ func () {
165
+ if config .HotkeyConfig == nil {
166
+ modkeys = []hotkey.Modifier {hotkey .ModCtrl , hotkey .ModAlt }
167
+ } else {
168
+ pressedKeys := map [string ]bool {}
169
+ for _ , key := range config .HotkeyConfig .Modkeys {
170
+ pressedKeys [key ] = true
171
+ }
172
+ for _ , mod := range []string {"ctrl" , "alt" , "shift" } {
173
+ if pressedKeys [mod ] {
174
+ switch mod {
175
+ case "ctrl" :
176
+ modkeys = append (modkeys , hotkey .ModCtrl )
177
+ case "alt" :
178
+ modkeys = append (modkeys , hotkey .ModAlt )
179
+ case "shift" :
180
+ modkeys = append (modkeys , hotkey .ModShift )
181
+ }
182
+ }
183
+ }
184
+ }
185
+ }()
186
+ fmt .Printf ("Recording started. Press %s to stop\n " , ternary (config .HotkeyConfig == nil , strings .Join ([]string {"ctrl" , "alt" , "3" }, "+" ), strings .Join (append (config .HotkeyConfig .Modkeys , config .HotkeyConfig .Finalkey ), "+" )))
187
+ tickStop := make (chan struct {})
121
188
ticker := time .NewTicker (time .Second )
122
- go func () {
123
- defer ticker .Stop ()
124
- for range ticker .C {
189
+ defer ticker .Stop ()
190
+ i := 0
191
+ last := []string {"🔴" , "⚫" }
192
+ func () {
193
+ for {
125
194
select {
126
195
case <- ticker .C :
127
- fmt .Printf ("\r Recording time elapsed: %02d:%02d" , int (time .Since (start ).Minutes ()), int (time .Since (start ).Seconds ())% 60 )
128
- default :
196
+ fmt .Printf ("\r %s Recording time elapsed: %02d:%02d" , last [i ], int (time .Since (start ).Minutes ()), int (time .Since (start ).Seconds ())% 60 )
197
+ i = (i + 1 ) % 2
198
+ case <- tickStop :
129
199
}
130
200
}
131
- fmt .Println ()
132
201
}()
133
- hk := hotkey .New ([]hotkey. Modifier { hotkey . ModCtrl , hotkey . ModShift } , hotkey .Key3 )
202
+ hk := hotkey .New (modkeys , ternary ( config . HotkeyConfig == nil , hotkey .Key3 , keys [ config . HotkeyConfig . Finalkey ]) )
134
203
err = hk .Register ()
135
204
if err != nil {
136
205
fmt .Println ("Error registering hotkey:" , err )
@@ -142,7 +211,19 @@ func RecordDisplay() {
142
211
fmt .Println ("\n Stopping recording..." )
143
212
stdin .Write ([]byte ("q" ))
144
213
stdin .Close ()
145
- ticker .Stop ()
214
+ tickStop <- struct {}{}
215
+ notification := toast.Notification {
216
+ AppID : "Captr" ,
217
+ Title : "Recording Stopped" ,
218
+ Message : fmt .Sprintf ("Recording saved at %s" , filename ),
219
+ Icon : filename ,
220
+ ActivationArguments : filename ,
221
+ Audio : toast .IM ,
222
+ Actions : []toast.Action {
223
+ {Type : "protocol" , Label : "Open" , Arguments : filename },
224
+ },
225
+ }
226
+ notification .Push ()
146
227
break
147
228
}
148
229
0 commit comments