Skip to content

Commit

Permalink
feat: first release
Browse files Browse the repository at this point in the history
  • Loading branch information
syrm committed Jan 28, 2021
1 parent e9cc976 commit 32b5714
Show file tree
Hide file tree
Showing 15 changed files with 424 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
plugin
simulator
.idea
133 changes: 133 additions & 0 deletions Config/Json.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package Config

import (
"encoding/json"
"fmt"
"github.com/blackprism/goxlr-routing/GOXLR"
"io/ioutil"
)

type Keybinding struct {
Id int16
Name string
Triggers []Trigger
}

type Trigger struct {
Type string
Actions []Action
}

type Action struct {
Name GOXLR.ActionType
Input GOXLR.Input
Output GOXLR.Output
}

func Json(file string) []Keybinding {
type Root []struct {
Keybinding string `json:"keybinding"`
Triggers []struct {
Type string `json:"type"`
Actions []struct {
Name string `json:"name"`
Targets []struct {
Inputs []string `json:"inputs"`
Outputs []string `json:"outputs"`
} `json:"targets"`
} `json:"actions,omitempty"`
Name string `json:"name,omitempty"`
} `json:"triggers"`
}

jsonConfig, err := ioutil.ReadFile(file)

if err != nil {
panic(fmt.Sprintf("File %s can't be opened", file))
}

var root Root
json.Unmarshal(jsonConfig, &root)

keybindings := []Keybinding{}

for index, keybindingSetup := range root {
var tmpTriggers []Trigger
for _, trigger := range keybindingSetup.Triggers {
if trigger.Type == "routing" {
var tmpActions []Action
for _, action := range trigger.Actions {
for _, target := range action.Targets {
for _, input := range target.Inputs {
for _, output := range target.Outputs {
tmpActions = append(tmpActions, Action{
actionToGoXLR(action.Name),
inputToGoXLR(input),
outputToGoXLR(output),
})
}
}
}
}
tmpTriggers = append(tmpTriggers, Trigger{
trigger.Type,
tmpActions,
})
}
}
keybindings = append(keybindings, Keybinding{
Id: int16(index) + 1,
Name: keybindingSetup.Keybinding,
Triggers: tmpTriggers,
})
}

return keybindings
}

func actionToGoXLR(action string) GOXLR.ActionType {
switch action {
case "toggle":
return GOXLR.Toggle
}

panic(fmt.Sprintf("Action %s can't be converted to GOXLR format", action))
}

func inputToGoXLR(input string) GOXLR.Input {
switch input {
case "Mic":
return GOXLR.Mic
case "Chat":
return GOXLR.Chat
case "Music":
return GOXLR.Music
case "Game":
return GOXLR.Game
case "Console":
return GOXLR.Console
case "Line In":
return GOXLR.LineIn
case "System":
return GOXLR.System
case "Samples":
return GOXLR.Samples
}

panic(fmt.Sprintf("Input %s can't be converted to GOXLR format", input))
}

func outputToGoXLR(output string) GOXLR.Output {
switch output {
case "Headphones":
return GOXLR.Headphones
case "Broadcast Stream Mix":
return GOXLR.BroadcastMix
case "Line Out":
return GOXLR.LineOut
case "Chat Mic":
return GOXLR.ChatMic
}

panic(fmt.Sprintf("Output %s can't be converted to GOXLR format", output))
}
13 changes: 13 additions & 0 deletions GOXLR/ActionType.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package GOXLR

type ActionType string

const (
Toggle ActionType = "Toggle"
)
const (
TurnOn ActionType = "Turn On"
)
const (
TurnOff ActionType = "Turn Off"
)
28 changes: 28 additions & 0 deletions GOXLR/Input.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package GOXLR

type Input string

const (
Mic Input = "Mic"
)
const (
Chat Input = "Chat"
)
const (
Music Input = "Music"
)
const (
Game Input = "Game"
)
const (
Console Input = "Console"
)
const (
LineIn Input = "Line In"
)
const (
System Input = "System"
)
const (
Samples Input = "Samples"
)
16 changes: 16 additions & 0 deletions GOXLR/Output.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package GOXLR

type Output string

const (
Headphones Output = "Headphones"
)
const (
BroadcastMix Output = "Broadcast Mix"
)
const (
LineOut Output = "Line Out"
)
const (
ChatMic Output = "Chat Mic"
)
18 changes: 18 additions & 0 deletions GOXLR/Payload.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package GOXLR

type Payload struct {
}

func (p Payload) Routing(action ActionType, input Input, output Output) []byte {
return []byte(`{
"action": "com.tchelicon.goxlr.routingtable",
"event": "keyUp",
"payload": {
"settings":{
"RoutingAction": "` + string(action) + `",
"RoutingInput": "` + string(input) + `",
"RoutingOutput": "` + string(output) + `"
}
}
}`)
}
103 changes: 103 additions & 0 deletions Key/Listener.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package Key

import (
"fmt"
"github.com/blackprism/goxlr-routing/Config"
"github.com/blackprism/goxlr-routing/GOXLR"
"github.com/gorilla/websocket"
"log"
"strings"
"syscall"
"time"
"unsafe"
)

type MSG struct {
HWND uintptr
UINT uintptr
WPARAM int16
LPARAM int64
DWORD int32
POINT struct{ X, Y int64 }
}

const (
ModAlt = 1 << iota
ModCtrl
ModShift
)

type Listener struct {
user32 *syscall.DLL
keybindings []Config.Keybinding
payload GOXLR.Payload
}

func NewListener(actions []Config.Keybinding, payload GOXLR.Payload) Listener {
return Listener{
user32: syscall.MustLoadDLL("user32"),
keybindings: actions,
payload: payload,
}
}

func (l *Listener) Register() {
l.user32 = syscall.MustLoadDLL("user32")

reghotkey := l.user32.MustFindProc("RegisterHotKey")
for _, keybinding := range l.keybindings {
keys := strings.Split(keybinding.Name, "+")
mods := keys[:len(keys)-1]
key := keys[len(keys)-1]

modSum := 0
for _, mod := range mods {
switch mod {
case "Ctrl":
modSum += ModCtrl
case "Alt":
modSum += ModAlt
case "Shift":
modSum += ModShift
}
}

// Register hotkeys:
r1, _, err := reghotkey.Call(0, uintptr(keybinding.Id), uintptr(modSum), uintptr(key[0]))
if r1 != 1 {
fmt.Println("Failed to register", keybinding.Name, ", error:", err)
}
}
}

func (l Listener) Listen(c *websocket.Conn) {
peekmsg := l.user32.MustFindProc("PeekMessageW")

for {
var msg = &MSG{}
peekmsg.Call(uintptr(unsafe.Pointer(msg)), 0, 0, 0, 1)

// Registered id is in the WPARAM field:
if id := msg.WPARAM; id != 0 {
for _, keybinding := range l.keybindings {
if keybinding.Id != id {
continue
}

log.Println("Hotkey pressed:", keybinding.Name)

for _, trigger := range keybinding.Triggers {
if trigger.Type == "routing" {
for _, action := range trigger.Actions {
w, _ := c.NextWriter(websocket.TextMessage)
w.Write(l.payload.Routing(action.Name, action.Input, action.Output))
w.Close()
}
}
}
}
}

time.Sleep(time.Millisecond * 5)
}
}
9 changes: 9 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
BIN = goxlr-routing
BUILDOS ?= windows
BUILDARCH ?= 386
BUILDENVS ?= CGO_ENABLED=0 GOOS=$(BUILDOS) GOARCH=$(BUILDARCH)
BUILDFLAGS ?= -a -installsuffix cgo --ldflags '-X main.Version=$(VERSION) -extldflags "-lm -lstdc++ -static"'

build:
@echo "==> Building binary ($(BUILDOS)/$(BUILDARCH)/$(BIN))"
@$(BUILDENVS) go build -v $(BUILDFLAGS) -o bin/$(BIN).exe
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
GO XLR Application to change routing via keybinding
===================================================

This tiny application allows you to change the routing via keybinding
You can look the file config.json to see how configure it.

How to use
----------

1. You need GO XLR StreamDeck plugin enabled.
2. Configure config.json
3. Launch goxlr-routing.exe
4. Click on "Global Settings > Connect/Reconnect to Streamdeck App"
5. Enjoy

42 changes: 42 additions & 0 deletions Websocket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package main

import (
"github.com/blackprism/goxlr-routing/Key"
gwebsocket "github.com/gorilla/websocket"
"log"
"net/http"
)

type Websocket struct {
listener Key.Listener
upgrader gwebsocket.Upgrader
}

func NewWebsocket(listener Key.Listener) Websocket {
var upgrader = gwebsocket.Upgrader{}

return Websocket{
listener,
upgrader,
}
}

func (w Websocket) Listen(addr string) {
http.HandleFunc("/", w.handler)

log.Println("Start websocket server")
log.Fatal(http.ListenAndServe(addr, nil))
}

func (w Websocket) handler(writer http.ResponseWriter, request *http.Request) {
connection, err := w.upgrader.Upgrade(writer, request, nil)
if err != nil {
log.Print("Can't convert Http request to websocket:", err)
return
}
defer connection.Close()

log.Println("Connection from", connection.RemoteAddr())

w.listener.Listen(connection)
}
Loading

0 comments on commit 32b5714

Please sign in to comment.