Skip to content

Instantly share code, notes, and snippets.

@yohanes
Created November 24, 2022 09:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yohanes/5f85a3435f113a2215c4e6c7ffef2951 to your computer and use it in GitHub Desktop.
Save yohanes/5f85a3435f113a2215c4e6c7ffef2951 to your computer and use it in GitHub Desktop.
package main
//To avoid opening a console at application startup, use these compile flags:
//go build -ldflags -H=windowsgui
import (
"github.com/0xcafed00d/joystick"
"github.com/getlantern/systray"
"github.com/getlantern/systray/example/icon"
"log"
"os"
"os/exec"
"strconv"
"strings"
"time"
)
//from winddcutil.exe capaboilities 0: 60( 11 12 0F)
var displayList = [...]int64{0xf, 0x11, 0x12}
func switchToDisplay(display int64) {
//convert display to hex string
displayHex := strconv.FormatInt(display, 16)
cmd := exec.Command("c:\\apps\\winddcutil\\winddcutil.exe", "setvcp", "0", "60", displayHex)
cmd.Run()
}
func getCurrentDisplay() int64 {
cmd := exec.Command("c:\\apps\\winddcutil\\winddcutil.exe", "getvcp", "0", "60")
out, _ := cmd.Output()
//fmt.Printf("getvcp output: %s\n", out)
//err is always not nill, we just ignore it
//format is VCP <ID> <output>
//split the output to get the last part
split := strings.Split(string(out), " ")
//convert the last part to an int (from hex)
last := split[len(split)-1]
//remove the newline
last = strings.TrimSuffix(last, "\r\n")
display, _ := strconv.ParseInt(last, 16, 32)
return display
}
func handleButtonEvent(button int, pressed bool) {
if pressed {
log.Printf("Button %d pressed", button)
} else {
log.Printf("Button %d released", button)
//fmt.Printf("get current display")
currentDisplay := getCurrentDisplay()
//fmt.Printf("current display is %d", currentDisplay)
currentDisplayIndex := 0
for i, display := range displayList {
if display == currentDisplay {
currentDisplayIndex = i
}
}
if button%2 == 1 {
currentDisplayIndex = (currentDisplayIndex + 1) % len(displayList)
} else {
currentDisplayIndex = (currentDisplayIndex - 1 + len(displayList)) % len(displayList)
}
switchToDisplay(displayList[currentDisplayIndex])
}
}
func handleJoyStick() {
log.Println("Opening joystick")
jsid := 0
js, err := joystick.Open(jsid)
if err != nil {
panic(err)
}
log.Printf("Joystick Name: %s", js.Name())
log.Printf(" Axis Count: %d", js.AxisCount())
log.Printf(" Button Count: %d", js.ButtonCount())
buttons_state := make([]bool, js.ButtonCount())
buttons_tmp := make([]bool, js.ButtonCount())
state, err := js.Read()
if err != nil {
panic(err)
}
log.Printf("Axis Data: %v", state.AxisData)
ticker := time.NewTicker(time.Millisecond * 40)
for doQuit := false; !doQuit; {
<-ticker.C
state, err := js.Read()
if err != nil {
panic(err)
}
//fmt.Printf("Axis Data: %v", state.AxisData)
copy(buttons_tmp, buttons_state)
for button := 0; button < js.ButtonCount(); button++ {
if state.Buttons&(1<<uint32(button)) != 0 {
//fmt.Printf("Button %d pressed", button)
buttons_state[button] = true
} else {
buttons_state[button] = false
}
}
for button := 0; button < js.ButtonCount(); button++ {
if buttons_state[button] != buttons_tmp[button] {
handleButtonEvent(button, buttons_state[button])
}
}
}
js.Close()
}
func main() {
f, err := os.OpenFile("c:\\apps\\winddcutil\\joystick.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
log.Fatalf("error opening file: %v", err)
}
defer f.Close()
log.SetOutput(f)
log.Println("This is a test log entry")
systray.Run(onReady, onExit)
}
func onReady() {
go handleJoyStick()
log.Println("on Ready")
systray.SetIcon(icon.Data)
systray.SetTitle("Joystick display switcher")
systray.SetTooltip("Switch display using joystick")
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)
go func() {
for {
select {
case <-mQuit.ClickedCh:
systray.Quit()
}
}
}()
}
func onExit() {
// clean up here
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment