diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..926b439 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +main.log diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..4a595f1 --- /dev/null +++ b/go.mod @@ -0,0 +1,14 @@ +module multiboxer + +go 1.23.2 + +require ( + fyne.io/systray v1.11.0 + github.com/robotn/gohook v0.41.0 +) + +require ( + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/vcaesar/keycode v0.10.1 // indirect + golang.org/x/sys v0.15.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..37f4a74 --- /dev/null +++ b/go.sum @@ -0,0 +1,12 @@ +fyne.io/systray v1.11.0 h1:D9HISlxSkx+jHSniMBR6fCFOUjk1x/OOOJLa9lJYAKg= +fyne.io/systray v1.11.0/go.mod h1:RVwqP9nYMo7h5zViCBHri2FgjXF7H2cub7MAq4NSoLs= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/robotn/gohook v0.41.0 h1:h1vK3w/UQpq0YkIiGnxm9Awv85W54esL0/NUYGueggo= +github.com/robotn/gohook v0.41.0/go.mod h1:FedpuAkVqzM5t67L5fcf3hSSCUDO9cM5YkWCw1U+nuc= +github.com/vcaesar/keycode v0.10.1 h1:0DesGmMAPWpYTCYddOFiCMKCDKgNnwiQa2QXindVUHw= +github.com/vcaesar/keycode v0.10.1/go.mod h1:JNlY7xbKsh+LAGfY2j4M3znVrGEm5W1R8s/Uv6BJcfQ= +github.com/vcaesar/tt v0.20.0 h1:9t2Ycb9RNHcP0WgQgIaRKJBB+FrRdejuaL6uWIHuoBA= +github.com/vcaesar/tt v0.20.0/go.mod h1:GHPxQYhn+7OgKakRusH7KJ0M5MhywoeLb8Fcffs/Gtg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= diff --git a/main.go b/main.go new file mode 100644 index 0000000..f49c930 --- /dev/null +++ b/main.go @@ -0,0 +1,102 @@ +package main + +import ( + "fmt" + "io" + "log" + "os" + "syscall" + + "fyne.io/systray" + hook "github.com/robotn/gohook" +) + +var ( + us32 = syscall.MustLoadDLL("user32.dll") + SetForegroundWindow = us32.MustFindProc("SetForegroundWindow") + GetForegroundWindow = us32.MustFindProc("GetForegroundWindow") +) + +var Error *log.Logger +var Warning *log.Logger + +func init() { + log.SetFlags(log.Lmicroseconds | log.Lshortfile) + logFile, err := os.Create("main.log") + if err != nil { + log.Printf("Error creating log file: %v", err) + os.Exit(1) + } + logger := io.MultiWriter(os.Stdout, logFile) + log.SetOutput(logger) + + Error = log.New(io.MultiWriter(logFile, os.Stderr, os.Stdout), + fmt.Sprintf("%sERROR:%s ", "\033[0;101m", "\033[0m"), + log.Lmicroseconds|log.Lshortfile) + Warning = log.New(io.MultiWriter(logFile, os.Stdout), + fmt.Sprintf("%sWarning:%s ", "\033[0;93m", "\033[0m"), + log.Lmicroseconds|log.Lshortfile) +} + +const ( + ALT = 0xa4 + TILDE = 0xc0 +) + +func main() { + systray.Run(onReady, onExit) + keyEvents := make(chan *hook.Event, 4096) + hook.Register(hook.KeyDown, []string{}, func(e hook.Event) { + keyEvents <- &e + }) + hook.Register(hook.KeyUp, []string{}, func(e hook.Event) { + keyEvents <- &e + }) + + processes := make(map[uintptr]bool) + keysDown := make(map[uint16]bool) + go func() { + for { + key, ok := <-keyEvents + if !ok { + Error.Printf("Error reading key events") + return + } + log.Printf("%#v", key) + if key.Kind == hook.KeyDown { + keysDown[key.Rawcode] = true + } else { + keysDown[key.Rawcode] = false + } + + if keysDown[ALT] && key.Rawcode == TILDE { + hwnd, _, _ := GetForegroundWindow.Call() + existing, ok := processes[hwnd] + if !ok { + processes[hwnd] = true + } else { + processes[hwnd] = !existing + } + } + + // if key.Kind == hook.KeyUp { + // StopSpam(key.Rawcode) + // } else if key.Kind == hook.KeyDown { + // DoSpam(key.Rawcode) + // } + } + }() + + s := hook.Start() + <-hook.Process(s) +} + +func onReady() { + systray.SetIcon(icon.Data) + systray.SetTitle("Awesome App") + systray.SetTooltip("Pretty awesome超级棒") + mQuit := systray.AddMenuItem("Quit", "Quit the whole app") + + // Sets the icon of a menu item. Only available on Mac and Windows. + mQuit.SetIcon(icon.Data) +}