-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
207 lines (181 loc) · 5.58 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package main
import (
_ "embed"
"fmt"
"io"
"log"
"os"
"os/signal"
"sync"
"syscall"
"telewindow/lumberjack"
"telewindow/window"
"time"
"github.com/getlantern/systray"
"github.com/moutend/go-hook/pkg/keyboard"
"github.com/moutend/go-hook/pkg/types"
)
//go:embed assets/dock-window-light.ico
var iconData []byte
var signalChan chan os.Signal = make(chan os.Signal, 1)
// Direction constants
const (
LeftDirection = -1
RightDirection = 1
UpDirection = -2
DownDirection = 2
)
// Constants for Windows API
const (
WM_KEYDOWN = "WM_KEYDOWN"
WM_KEYUP = "WM_KEYUP"
WM_SYSKEYDOWN = "WM_SYSKEYDOWN"
)
func main() {
// Create a multi-writer that writes to both file and stdout
multiWriter := io.MultiWriter(os.Stdout, &lumberjack.Logger{
Filename: "./telewindow.log",
MaxSize: 1, // megabytes
MaxBackups: 5,
MaxAge: 28, //days
Compress: false, // disabled by default
})
// Set the output of the default logger to the multi-writer
log.SetOutput(multiWriter)
config, err := window.LoadConfig()
if err != nil {
log.Println("Error loading config:", err)
os.Exit(1)
}
// Set the global SizeByPixel variable
window.SizeByPixel = config.SizeByPixel
// Detect if we are running as admininstrator
if !window.IsRunningAsAdmin() {
if !config.AllowNonAdmin {
fmt.Println("This application needs to run as administrator.")
err := window.RelaunchAsAdmin()
if err != nil {
fmt.Println("Failed to restart as administrator:", err)
os.Exit(1)
}
os.Exit(0) // Exit current instance
} else {
log.Println("WARNING: Not running as administrator. Some features may not work correctly. Such as keyboard hooking in administrative windows.")
}
}
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)
systray.Run(func() {
// Pass in the config to the onReady function
onReady(config)
}, onExit)
}
func onReady(config *window.Config) {
// Set the icon (optional)
systray.SetIcon(iconData)
systray.SetTooltip("TeleWindow Service")
mQuit := systray.AddMenuItem("Quit", "Quit the application")
go func() {
select {
case <-mQuit.ClickedCh:
log.Println("Quit menu item clicked.")
signalChan <- syscall.SIGTERM
case <-signalChan:
log.Println("Interrupt signal received.")
}
log.Println("Quitting TeleWindow.")
systray.Quit()
os.Exit(0)
}()
log.Println("Window manager is running. Press Ctrl+C to exit.")
go keyboardHook(signalChan, config)
}
func onExit() {
// Cleanup tasks
log.Println("TeleWindow exited.")
}
func keyboardHook(signalChan chan os.Signal, config *window.Config) error {
// Buffer size is depends on your need. The 100 is placeholder value.
keyboardChan := make(chan types.KeyboardEvent, 100)
if err := keyboard.Install(nil, keyboardChan); err != nil {
return err
}
defer keyboard.Uninstall()
keyDownMap := make(map[string]bool)
var keyDownMapMutex sync.Mutex
var lastMove time.Time = time.Now()
for {
select {
case <-signalChan:
log.Println("Received shutdown signal")
return nil
case k := <-keyboardChan:
// log.Printf("Received %v %v\n", k.Message, k.VKCode)
msg := fmt.Sprint(k.Message)
key := fmt.Sprint(k.VKCode)
down := msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN
up := msg == WM_KEYUP
keyDownMapMutex.Lock()
if down && !keyDownMap[key] {
// log.Printf("Down %v\n", k.VKCode)
keyDownMap[key] = true
// fmt.Println(keyDownMap)
// If control and right arrow are pressed
if time.Since(lastMove) > 50*time.Millisecond {
if config.KeyBindings.MoveRight.Down(keyDownMap) {
log.Println("Hotkey Move Right Pressed")
window.MoveActiveWindow(RightDirection)
lastMove = time.Now()
} else if config.KeyBindings.MoveLeft.Down(keyDownMap) {
log.Println("Hotkey Move Left Pressed")
window.MoveActiveWindow(LeftDirection)
lastMove = time.Now()
} else if config.KeyBindings.MoveUp.Down(keyDownMap) {
log.Println("Hotkey Move Up Pressed")
window.MoveActiveWindow(UpDirection)
lastMove = time.Now()
} else if config.KeyBindings.MoveDown.Down(keyDownMap) {
log.Println("Hotkey Move Down Pressed")
window.MoveActiveWindow(DownDirection)
lastMove = time.Now()
} else if config.KeyBindings.ToggleMaximize.Down(keyDownMap) {
log.Println("Hotkey Toggle Maximize Pressed")
maximized, err := window.IsActiveWindowMaximized(nil)
if err != nil {
log.Println("Error checking if window is maximized:", err)
continue
}
if maximized {
log.Println("Window is maximized, restoring window.")
window.RestoreActiveWindow(nil)
} else {
log.Println("Window is not maximized, maximizing window.")
window.MaximizeActiveWindow(nil)
}
lastMove = time.Now()
} else if config.KeyBindings.SplitLeft.Down(keyDownMap) {
log.Println("Hotkey Split Left Pressed")
window.SplitActiveWindow(LeftDirection)
lastMove = time.Now()
} else if config.KeyBindings.SplitRight.Down(keyDownMap) {
log.Println("Hotkey Split Right Pressed")
window.SplitActiveWindow(RightDirection)
lastMove = time.Now()
} else if config.KeyBindings.SplitUp.Down(keyDownMap) {
log.Println("Hotkey Split Up Pressed")
window.SplitActiveWindow(UpDirection)
lastMove = time.Now()
} else if config.KeyBindings.SplitDown.Down(keyDownMap) {
log.Println("Hotkey Split Down Pressed")
window.SplitActiveWindow(DownDirection)
lastMove = time.Now()
}
}
} else if up && keyDownMap[key] {
// log.Printf("Up %v\n", k.VKCode)
keyDownMap[key] = false
}
keyDownMapMutex.Unlock()
continue
}
}
}