Initial checkin
This commit is contained in:
parent
8cebd67505
commit
4f0a2aeac8
301
events_received.go
Normal file
301
events_received.go
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
package streamdeck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
var receivedEventTypeMap = map[string]reflect.Type{}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
receivedEventTypeMap["keyUp"] = reflect.TypeOf(ERKeyUp{})
|
||||||
|
receivedEventTypeMap["didReceiveSettingsPayload"] = reflect.TypeOf(ERDidReceiveSettingsPayload{})
|
||||||
|
receivedEventTypeMap["didReceiveSettings"] = reflect.TypeOf(ERDidReceiveSettings{})
|
||||||
|
receivedEventTypeMap["globalSettings"] = reflect.TypeOf(ERGlobalSettings{})
|
||||||
|
receivedEventTypeMap["didReceiveDeepLink"] = reflect.TypeOf(ERDidReceiveDeepLink{})
|
||||||
|
receivedEventTypeMap["touchTap"] = reflect.TypeOf(ERTouchTap{})
|
||||||
|
receivedEventTypeMap["dialDown"] = reflect.TypeOf(ERDialDown{})
|
||||||
|
receivedEventTypeMap["dialUp"] = reflect.TypeOf(ERDialUp{})
|
||||||
|
receivedEventTypeMap["dialRotate"] = reflect.TypeOf(ERDialRotate{})
|
||||||
|
receivedEventTypeMap["keyDown"] = reflect.TypeOf(ERKeyDown{})
|
||||||
|
receivedEventTypeMap["willAppear"] = reflect.TypeOf(ERWillAppear{})
|
||||||
|
receivedEventTypeMap["willDisappear"] = reflect.TypeOf(ERWillDisappear{})
|
||||||
|
receivedEventTypeMap["titleParametersDidChange"] = reflect.TypeOf(ERTitleParametersDidChange{})
|
||||||
|
receivedEventTypeMap["deviceDidConnect"] = reflect.TypeOf(ERDeviceDidConnect{})
|
||||||
|
receivedEventTypeMap["deviceDidDisconnect"] = reflect.TypeOf(ERDeviceDidDisconnect{})
|
||||||
|
receivedEventTypeMap["applicationDidLaunch"] = reflect.TypeOf(ERApplicationDidLaunch{})
|
||||||
|
receivedEventTypeMap["applicationDidTerminate"] = reflect.TypeOf(ERApplicationDidTerminate{})
|
||||||
|
receivedEventTypeMap["applicationSystemDidWakeUp"] = reflect.TypeOf(ERApplicationSystemDidWakeUp{})
|
||||||
|
receivedEventTypeMap["applicationPropertyInspectorDidAppear"] = reflect.TypeOf(ERApplicationPropertyInspectorDidAppear{})
|
||||||
|
receivedEventTypeMap["applicationPropertyInspectorDidDisappear"] = reflect.TypeOf(ERApplicationPropertyInspectorDidDisappear{})
|
||||||
|
receivedEventTypeMap["applicationPropertySendToPlugin"] = reflect.TypeOf(ERApplicationPropertySendToPlugin{})
|
||||||
|
receivedEventTypeMap["applicationPropertySendToPropertyInspector"] = reflect.TypeOf(ERApplicationPropertySendToPropertyInspector{})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ERBase struct {
|
||||||
|
Event string `json:"event"`
|
||||||
|
}
|
||||||
|
|
||||||
|
//{Action: Event:deviceDidConnect Context: Device:A1DA463F033AD2616E05636CD16F064F Payload:[]}"}
|
||||||
|
|
||||||
|
type ERCommon struct {
|
||||||
|
Action string `json:"action"`
|
||||||
|
Event string `json:"event"`
|
||||||
|
Context string `json:"context"`
|
||||||
|
Device string `json:"device"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#didreceivesettings
|
||||||
|
|
||||||
|
type ERDidReceiveSettingsPayload struct {
|
||||||
|
Settings json.RawMessage `json:"settings"`
|
||||||
|
Coordinates struct {
|
||||||
|
Column int `json:"column"`
|
||||||
|
Row int `json:"row"`
|
||||||
|
} `json:"coordinates"`
|
||||||
|
IsInMultiAction bool `json:"isInMultiAction"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ERDidReceiveSettings struct {
|
||||||
|
ERCommon
|
||||||
|
Payload ERDidReceiveSettingsPayload `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#didreceiveglobalsettings
|
||||||
|
|
||||||
|
type ERGlobalSettings struct {
|
||||||
|
Event string `json:"event"`
|
||||||
|
Payload json.RawMessage `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#didreceivedeeplink
|
||||||
|
|
||||||
|
type ERDidReceiveDeepLink struct {
|
||||||
|
Event string `json:"event"`
|
||||||
|
Payload struct {
|
||||||
|
Url string `json:"url"`
|
||||||
|
} `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#touchtap-sd
|
||||||
|
|
||||||
|
type ERTouchTap struct {
|
||||||
|
ERCommon
|
||||||
|
Payload struct {
|
||||||
|
Settings json.RawMessage `json:"settings"`
|
||||||
|
Controller string `json:"controller"`
|
||||||
|
Coordinates struct {
|
||||||
|
Column int `json:"column"`
|
||||||
|
Row int `json:"row"`
|
||||||
|
} `json:"coordinates"`
|
||||||
|
TapPosition []int `json:"tapPos"`
|
||||||
|
Hold bool `json:"hold"`
|
||||||
|
} `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#dialdown-sd
|
||||||
|
|
||||||
|
type ERDialDown struct {
|
||||||
|
ERCommon
|
||||||
|
Payload struct {
|
||||||
|
Settings json.RawMessage `json:"settings"`
|
||||||
|
Controller string `json:"controller"`
|
||||||
|
Coordinates struct {
|
||||||
|
Column int `json:"column"`
|
||||||
|
Row int `json:"row"`
|
||||||
|
} `json:"coordinates"`
|
||||||
|
} `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#dialup-sd
|
||||||
|
|
||||||
|
type ERDialUp struct {
|
||||||
|
ERCommon
|
||||||
|
Payload struct {
|
||||||
|
Settings json.RawMessage `json:"settings"`
|
||||||
|
Controller string `json:"controller"`
|
||||||
|
Coordinates struct {
|
||||||
|
Column int `json:"column"`
|
||||||
|
Row int `json:"row"`
|
||||||
|
} `json:"coordinates"`
|
||||||
|
} `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#dialrotate-sd
|
||||||
|
|
||||||
|
type ERDialRotate struct {
|
||||||
|
ERCommon
|
||||||
|
Payload struct {
|
||||||
|
Settings json.RawMessage `json:"settings"`
|
||||||
|
Controller string `json:"controller"`
|
||||||
|
Coordinates struct {
|
||||||
|
Column int `json:"column"`
|
||||||
|
Row int `json:"row"`
|
||||||
|
} `json:"coordinates"`
|
||||||
|
Ticks int `json:"ticks"`
|
||||||
|
Pressed bool `json:"pressed"`
|
||||||
|
} `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#keydown
|
||||||
|
|
||||||
|
type ERKeyDown struct {
|
||||||
|
ERCommon
|
||||||
|
Payload struct {
|
||||||
|
Settings json.RawMessage `json:"settings"`
|
||||||
|
Coordinates struct {
|
||||||
|
Column int `json:"column"`
|
||||||
|
Row int `json:"row"`
|
||||||
|
} `json:"coordinates"`
|
||||||
|
State int `json:"state"`
|
||||||
|
UserDesiredState int `json:"userDesiredState"`
|
||||||
|
IsInMultiAction bool `json:"isInMultiAction"`
|
||||||
|
} `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#keyup
|
||||||
|
type ERKeyUp struct {
|
||||||
|
ERCommon
|
||||||
|
Payload struct {
|
||||||
|
Settings json.RawMessage `json:"settings"`
|
||||||
|
Coordinates struct {
|
||||||
|
Column int `json:"column"`
|
||||||
|
Row int `json:"row"`
|
||||||
|
} `json:"coordinates"`
|
||||||
|
State int `json:"state"`
|
||||||
|
UserDesiredState int `json:"userDesiredState"`
|
||||||
|
IsInMultiAction bool `json:"isInMultiAction"`
|
||||||
|
} `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#willappear
|
||||||
|
type ERWillAppear struct {
|
||||||
|
ERCommon
|
||||||
|
Payload struct {
|
||||||
|
Settings json.RawMessage `json:"settings"`
|
||||||
|
Coordinates struct {
|
||||||
|
Column int `json:"column"`
|
||||||
|
Row int `json:"row"`
|
||||||
|
} `json:"coordinates"`
|
||||||
|
Controller string `json:"controller"`
|
||||||
|
State int `json:"state"`
|
||||||
|
IsInMultiAction bool `json:"isInMultiAction"`
|
||||||
|
} `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#willdisappear
|
||||||
|
|
||||||
|
const ERWillDisappearAction = "willDisappear"
|
||||||
|
|
||||||
|
type ERWillDisappear struct {
|
||||||
|
ERCommon
|
||||||
|
Payload struct {
|
||||||
|
Settings json.RawMessage `json:"settings"`
|
||||||
|
Coordinates struct {
|
||||||
|
Column int `json:"column"`
|
||||||
|
Row int `json:"row"`
|
||||||
|
} `json:"coordinates"`
|
||||||
|
Controller string `json:"controller"`
|
||||||
|
State int `json:"state"`
|
||||||
|
IsInMultiAction bool `json:"isInMultiAction"`
|
||||||
|
} `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#titleparametersdidchange
|
||||||
|
|
||||||
|
type ERTitleParametersDidChange struct {
|
||||||
|
ERCommon
|
||||||
|
Payload struct {
|
||||||
|
Settings json.RawMessage `json:"settings"`
|
||||||
|
Coordinates struct {
|
||||||
|
Column int `json:"column"`
|
||||||
|
Row int `json:"row"`
|
||||||
|
} `json:"coordinates"`
|
||||||
|
State int `json:"state"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
TitleParameters struct {
|
||||||
|
FontFamily string `json:"fontFamily"`
|
||||||
|
FontSize int `json:"fontSize"`
|
||||||
|
FontStyle string `json:"fontStyle"`
|
||||||
|
FontUnderline bool `json:"fontUnderline"`
|
||||||
|
ShowTitle bool `json:"showTitle"`
|
||||||
|
TitleAlignment string `json:"titleAlignment"`
|
||||||
|
TitleColor string `json:"titleColor"`
|
||||||
|
} `json:"titleParameters"`
|
||||||
|
} `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#devicedidconnect
|
||||||
|
|
||||||
|
type ERDeviceDidConnect struct {
|
||||||
|
Event string `json:"event"`
|
||||||
|
|
||||||
|
Device string `json:"device"`
|
||||||
|
DeviceInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
DeviceType int `json:"type"`
|
||||||
|
Size struct {
|
||||||
|
Columns int `json:"columns"`
|
||||||
|
Rows int `json:"rows"`
|
||||||
|
} `json:"size"`
|
||||||
|
} `json:"deviceInfo"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#devicediddisconnect
|
||||||
|
|
||||||
|
type ERDeviceDidDisconnect struct {
|
||||||
|
Event string `json:"event"`
|
||||||
|
Device string `json:"device"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#applicationdidlaunch
|
||||||
|
|
||||||
|
type ERApplicationDidLaunch struct {
|
||||||
|
Event string `json:"event"`
|
||||||
|
Payload struct {
|
||||||
|
Application string `json:"application"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#applicationdidterminate
|
||||||
|
|
||||||
|
type ERApplicationDidTerminate struct {
|
||||||
|
Event string `json:"event"`
|
||||||
|
Payload struct {
|
||||||
|
Application string `json:"application"`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#systemdidwakeup
|
||||||
|
|
||||||
|
type ERApplicationSystemDidWakeUp struct {
|
||||||
|
Event string `json:"event"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#propertyinspectordidappear
|
||||||
|
type ERApplicationPropertyInspectorDidAppear struct {
|
||||||
|
ERCommon
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#propertyinspectordiddisappear
|
||||||
|
|
||||||
|
type ERApplicationPropertyInspectorDidDisappear struct {
|
||||||
|
ERCommon
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#sendtoplugin
|
||||||
|
|
||||||
|
type ERApplicationPropertySendToPlugin struct {
|
||||||
|
Action string `json:"action"`
|
||||||
|
Event string `json:"event"`
|
||||||
|
Context string `json:"context"`
|
||||||
|
Payload json.RawMessage `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-received#sendtopropertyinspector
|
||||||
|
type ERApplicationPropertySendToPropertyInspector struct {
|
||||||
|
Action string `json:"action"`
|
||||||
|
Event string `json:"event"`
|
||||||
|
Context string `json:"context"`
|
||||||
|
Payload json.RawMessage `json:"payload"`
|
||||||
|
}
|
385
events_send.go
Normal file
385
events_send.go
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
package streamdeck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"image"
|
||||||
|
"image/png"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EventTarget int
|
||||||
|
|
||||||
|
const EventTargetBoth = 0
|
||||||
|
const EventTargetHardware = 1
|
||||||
|
const EventTargetSoftware = 2
|
||||||
|
|
||||||
|
type ESCommon struct {
|
||||||
|
Event string `json:"event"`
|
||||||
|
Context string `json:"context"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESCommonNoContext struct {
|
||||||
|
Event string `json:"event"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESOpenMessage struct {
|
||||||
|
ESCommonNoContext
|
||||||
|
UUID string `json:"uuid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#setsettings
|
||||||
|
|
||||||
|
type ESSetSettings struct {
|
||||||
|
ESCommon
|
||||||
|
Payload json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESSetSettings(context string, payload json.RawMessage) ESSetSettings {
|
||||||
|
return ESSetSettings{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "setSettings",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
Payload: payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#getsettings
|
||||||
|
|
||||||
|
type ESGetSettings struct {
|
||||||
|
ESCommon
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESGetSettings(context string) ESGetSettings {
|
||||||
|
return ESGetSettings{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "getSettings",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#setglobalsettings
|
||||||
|
|
||||||
|
type ESSetGlobalSettings struct {
|
||||||
|
ESCommon
|
||||||
|
Payload json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESSetGlobalSettings(context string, payload json.RawMessage) ESSetGlobalSettings {
|
||||||
|
return ESSetGlobalSettings{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "setGlobalSettings",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
Payload: payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#getglobalsettings
|
||||||
|
|
||||||
|
type ESGetGlobalSettings struct {
|
||||||
|
ESCommon
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESGetGlobalSettings(context string) ESGetGlobalSettings {
|
||||||
|
return ESGetGlobalSettings{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "getGlobalSettings",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#openurl
|
||||||
|
|
||||||
|
type ESOpenURL struct {
|
||||||
|
ESCommonNoContext
|
||||||
|
Payload ESOpenURLPayload `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESOpenURLPayload struct {
|
||||||
|
URL string `json:"url"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESOpenURL(url string) ESOpenURL {
|
||||||
|
return ESOpenURL{
|
||||||
|
ESCommonNoContext: ESCommonNoContext{Event: "openUrl"},
|
||||||
|
Payload: ESOpenURLPayload{
|
||||||
|
URL: url,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#logmessage
|
||||||
|
type ESLogMessage struct {
|
||||||
|
ESCommonNoContext
|
||||||
|
Payload ESLogMessagePayload `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESLogMessagePayload struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESLogMessage(message string) ESLogMessage {
|
||||||
|
return ESLogMessage{
|
||||||
|
ESCommonNoContext: ESCommonNoContext{Event: "logMessage"},
|
||||||
|
Payload: ESLogMessagePayload{Message: message},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// setTitle https://docs.elgato.com/sdk/plugins/events-sent#settitle
|
||||||
|
type ESSetTitle struct {
|
||||||
|
ESCommon
|
||||||
|
Payload ESSetTitlePayload `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESSetTitlePayload struct {
|
||||||
|
Title string `json:"title"`
|
||||||
|
Target EventTarget `json:"target"`
|
||||||
|
State int `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESSetTitle(context string, title string, target EventTarget, state int) ESSetTitle {
|
||||||
|
return ESSetTitle{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "setTitle",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
Payload: ESSetTitlePayload{
|
||||||
|
Title: title,
|
||||||
|
Target: target,
|
||||||
|
State: state,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#setimage
|
||||||
|
type ESSetImage struct {
|
||||||
|
ESCommon
|
||||||
|
Payload ESSetImagePayload `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESSetImagePayload struct {
|
||||||
|
Image string `json:"title"`
|
||||||
|
Target EventTarget `json:"target"`
|
||||||
|
State int `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESSetImagePayload(context string, imageBase64 string, target EventTarget, state int) ESSetImage {
|
||||||
|
return ESSetImage{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "setImage",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
Payload: ESSetImagePayload{
|
||||||
|
Image: imageBase64,
|
||||||
|
Target: target,
|
||||||
|
State: state,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#setfeedback-sd
|
||||||
|
type ESSetFeedback struct {
|
||||||
|
ESCommon
|
||||||
|
Payload json.RawMessage `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESSetFeedback(context string, payload json.RawMessage) ESSetFeedback {
|
||||||
|
return ESSetFeedback{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "setFeedback",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
Payload: payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#setfeedbacklayout-sd
|
||||||
|
type ESSetFeedbackLayout struct {
|
||||||
|
ESCommon
|
||||||
|
Payload ESSetFeedbackLayoutPayload `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESSetFeedbackLayoutPayload struct {
|
||||||
|
Layout string `json:"layout"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESSetFeedbackLayout(context string, layout string) ESSetFeedbackLayout {
|
||||||
|
return ESSetFeedbackLayout{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "setFeedbackLayout",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
Payload: ESSetFeedbackLayoutPayload{
|
||||||
|
Layout: layout,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#settriggerdescription-sd
|
||||||
|
type ESSetTriggerDescription struct {
|
||||||
|
ESCommon
|
||||||
|
Payload ESSetTriggerDescriptionPayload `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESSetTriggerDescriptionPayload struct {
|
||||||
|
Rotate string `json:"rotate,omitempty"`
|
||||||
|
Push string `json:"push,omitempty"`
|
||||||
|
Touch string `json:"touch,omitempty"`
|
||||||
|
LongTouch string `json:"longTouch,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESSetTriggerDescription(context string, rotate, push, touch, longTouch string) ESSetTriggerDescription {
|
||||||
|
return ESSetTriggerDescription{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "setTriggerDescription",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
Payload: ESSetTriggerDescriptionPayload{
|
||||||
|
Rotate: rotate,
|
||||||
|
Push: push,
|
||||||
|
Touch: touch,
|
||||||
|
LongTouch: longTouch,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#showalert
|
||||||
|
type ESShowAlert struct {
|
||||||
|
ESCommon
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESShowAlert(context string) ESShowAlert {
|
||||||
|
return ESShowAlert{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "showAlert",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#showok
|
||||||
|
type ESShowOK struct {
|
||||||
|
ESCommon
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESShowOK(context string) ESShowOK {
|
||||||
|
return ESShowOK{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "showOk",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//https://docs.elgato.com/sdk/plugins/events-sent#setstate
|
||||||
|
|
||||||
|
type ESSetState struct {
|
||||||
|
ESCommon
|
||||||
|
Payload ESSetStatePayload `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESSetStatePayload struct {
|
||||||
|
State int `json:"state"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESSetState(context string, state int) ESSetImage {
|
||||||
|
return ESSetImage{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "setState",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
Payload: ESSetImagePayload{
|
||||||
|
State: state,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#switchtoprofile
|
||||||
|
|
||||||
|
type ESSwitchToProfile struct {
|
||||||
|
ESCommon
|
||||||
|
Device string `json:"device"`
|
||||||
|
Payload ESSwitchToProfilePayload `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ESSwitchToProfilePayload struct {
|
||||||
|
Profile string `json:"profile"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESSwitchToProfile(context string, device, profileName string, page int) ESSwitchToProfile {
|
||||||
|
return ESSwitchToProfile{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "switchToProfile",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
Device: device,
|
||||||
|
Payload: ESSwitchToProfilePayload{
|
||||||
|
Profile: profileName,
|
||||||
|
Page: page,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#sendtopropertyinspector
|
||||||
|
|
||||||
|
type ESSendToPropertyInspector struct {
|
||||||
|
ESCommon
|
||||||
|
Action string `json:"action"`
|
||||||
|
Payload json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESSendToPropertyInspector(context string, action string, payload json.RawMessage) ESSendToPropertyInspector {
|
||||||
|
return ESSendToPropertyInspector{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "sendToPropertyInspector",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
Action: action,
|
||||||
|
Payload: payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://docs.elgato.com/sdk/plugins/events-sent#sendtoplugin
|
||||||
|
|
||||||
|
type ESSendToPlugin struct {
|
||||||
|
ESCommon
|
||||||
|
Action string `json:"action"`
|
||||||
|
Payload json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewESSendToPlugin(context string, action string, payload json.RawMessage) ESSendToPlugin {
|
||||||
|
return ESSendToPlugin{
|
||||||
|
ESCommon: ESCommon{
|
||||||
|
Event: "sendToPlugin",
|
||||||
|
Context: context,
|
||||||
|
},
|
||||||
|
Action: action,
|
||||||
|
Payload: payload,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// --------- helpers ----------
|
||||||
|
|
||||||
|
// Turns an image.Image into a string suitable for delivering
|
||||||
|
// via a ESSetImage struct
|
||||||
|
func ImageToPayload(i image.Image) string {
|
||||||
|
|
||||||
|
out := bytes.Buffer{}
|
||||||
|
b64 := base64.NewEncoder(base64.RawStdEncoding, &out)
|
||||||
|
err := png.Encode(b64, i)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return "data:image/png;base64," + out.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turns an image.Image into a string suitable for delivering
|
||||||
|
// via a ESSetImage struct
|
||||||
|
func SVGToPayload(context string, svg string) string {
|
||||||
|
return "data:image/svg+xml;charset=utf8," + svg
|
||||||
|
}
|
5
go.mod
Normal file
5
go.mod
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
module github.com/tardisx/streamdeck-plugin
|
||||||
|
|
||||||
|
go 1.22.1
|
||||||
|
|
||||||
|
require github.com/gorilla/websocket v1.5.3
|
2
go.sum
Normal file
2
go.sum
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||||
|
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
202
streamdeck.go
Normal file
202
streamdeck.go
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
package streamdeck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
type logger interface {
|
||||||
|
Info(string, ...any)
|
||||||
|
Error(string, ...any)
|
||||||
|
Debug(string, ...any)
|
||||||
|
}
|
||||||
|
|
||||||
|
type nullLogger struct{}
|
||||||
|
|
||||||
|
func (nl nullLogger) Info(string, ...any) {}
|
||||||
|
func (nl nullLogger) Error(string, ...any) {}
|
||||||
|
func (nl nullLogger) Debug(string, ...any) {}
|
||||||
|
|
||||||
|
type EventHandler struct {
|
||||||
|
MsgType string
|
||||||
|
Handler func()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Connection struct {
|
||||||
|
ws *websocket.Conn
|
||||||
|
logger logger
|
||||||
|
handlers map[reflect.Type]reflect.Value
|
||||||
|
done chan (bool)
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() Connection {
|
||||||
|
return Connection{
|
||||||
|
handlers: make(map[reflect.Type]reflect.Value),
|
||||||
|
logger: nullLogger{},
|
||||||
|
done: make(chan bool),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewWithLogger(l logger) Connection {
|
||||||
|
c := New()
|
||||||
|
c.logger = l
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *Connection) Connect(port int, openEvent string, uuid string) error {
|
||||||
|
|
||||||
|
c, _, err := websocket.DefaultDialer.Dial(fmt.Sprintf("ws://localhost:%d", port), nil)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
conn.ws = c
|
||||||
|
msg := ESOpenMessage{
|
||||||
|
ESCommonNoContext: ESCommonNoContext{
|
||||||
|
Event: openEvent,
|
||||||
|
},
|
||||||
|
UUID: uuid,
|
||||||
|
}
|
||||||
|
conn.logger.Debug(fmt.Sprintf("writing openMessage: %+v", msg))
|
||||||
|
err = c.WriteJSON(msg)
|
||||||
|
if err != nil {
|
||||||
|
conn.logger.Error(err.Error())
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the reader forever
|
||||||
|
conn.logger.Info("starting reader")
|
||||||
|
go conn.reader()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Connection) WaitForPluginExit() {
|
||||||
|
<-c.done
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterHandler registers a function to be called for a particular event. The
|
||||||
|
// event to be handled is determined by the functions single parameter type.
|
||||||
|
// This should be called before Connect to be sure your application is ready to
|
||||||
|
// receive events. You can register as many handlers as you like, but only one
|
||||||
|
// function per event type. This function will panic if the wrong kind of
|
||||||
|
// function is passed in, or if you try to register more than one for a single
|
||||||
|
// event type.
|
||||||
|
func (r *Connection) RegisterHandler(handler any) {
|
||||||
|
hType := reflect.TypeOf(handler)
|
||||||
|
if hType.Kind() != reflect.Func {
|
||||||
|
panic("handler must be a function")
|
||||||
|
}
|
||||||
|
// Assuming the function takes exactly one argument
|
||||||
|
if hType.NumIn() != 1 {
|
||||||
|
panic("handler func must take exactly one argument")
|
||||||
|
}
|
||||||
|
|
||||||
|
argType := hType.In(0)
|
||||||
|
|
||||||
|
// check its a valid one (one that matches an event type)
|
||||||
|
valid := false
|
||||||
|
for i := range receivedEventTypeMap {
|
||||||
|
if receivedEventTypeMap[i] == argType {
|
||||||
|
valid = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !valid {
|
||||||
|
panic("you cannot register a handler with this argument type")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, alreadyExists := r.handlers[argType]
|
||||||
|
if alreadyExists {
|
||||||
|
panic("handler for " + argType.Name() + " already exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
r.handlers[argType] = reflect.ValueOf(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *Connection) Send(e any) error {
|
||||||
|
b, _ := json.Marshal(e)
|
||||||
|
conn.logger.Debug(fmt.Sprintf("sending: %s", string(b)))
|
||||||
|
|
||||||
|
return conn.ws.WriteJSON(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *Connection) handle(event any) {
|
||||||
|
conn.logger.Debug(fmt.Sprintf("handle: incoming a %T", event))
|
||||||
|
argType := reflect.TypeOf(event)
|
||||||
|
handler, ok := conn.handlers[argType]
|
||||||
|
if !ok {
|
||||||
|
conn.logger.Debug(fmt.Sprintf("handle: no handler registered for type %s", argType))
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
conn.logger.Debug(fmt.Sprintf("handle: found handler function for type %s", argType))
|
||||||
|
|
||||||
|
v := []reflect.Value{reflect.ValueOf(event)}
|
||||||
|
conn.logger.Debug(fmt.Sprintf("handle: handler func: %+v", handler))
|
||||||
|
conn.logger.Debug(fmt.Sprintf("handle: handler var: %+v", v))
|
||||||
|
|
||||||
|
conn.logger.Debug("handle: calling handler function")
|
||||||
|
|
||||||
|
handler.Call(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (conn *Connection) reader() {
|
||||||
|
|
||||||
|
for {
|
||||||
|
_, r, err := conn.ws.NextReader()
|
||||||
|
if err != nil {
|
||||||
|
conn.logger.Error(err.Error())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
b := bytes.Buffer{}
|
||||||
|
r = io.TeeReader(r, &b)
|
||||||
|
base := ERBase{}
|
||||||
|
err = json.NewDecoder(r).Decode(&base)
|
||||||
|
if err != nil {
|
||||||
|
conn.logger.Error("cannot decode: " + err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
t, ok := receivedEventTypeMap[base.Event]
|
||||||
|
if !ok {
|
||||||
|
conn.logger.Error(fmt.Sprintf("no type registered for event '%s'", base.Event))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
d, err := conn.unmarshalToConcrete(t, b.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
conn.logger.Error("cannot unmarshal: " + err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
conn.handle(d)
|
||||||
|
}
|
||||||
|
conn.logger.Info("websocket closed, shutting down reader")
|
||||||
|
conn.done <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
// unmarshalToConcrete takes a reflect.Type and a byte slice, creates a concrete
|
||||||
|
// instance of the type and unmarshals the JSON byte slice into it.
|
||||||
|
func (conn *Connection) unmarshalToConcrete(t reflect.Type, b []byte) (any, error) {
|
||||||
|
// t is a reflect.Type of the thing we need to decode into
|
||||||
|
d := reflect.New(t).Interface()
|
||||||
|
conn.logger.Info(fmt.Sprintf("instance is a %T", d))
|
||||||
|
|
||||||
|
err := json.Unmarshal(b, &d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not unmarshal this:\n%s\ninto a %v (%v)\nbecause: %s", string(b), d, t, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
// get concrete instance of d into v
|
||||||
|
v := reflect.ValueOf(d).Elem().Interface()
|
||||||
|
conn.logger.Info(fmt.Sprintf("NOW instance is a %T", v))
|
||||||
|
|
||||||
|
conn.logger.Debug(fmt.Sprintf("reader: unmarshalled to: %+v", v))
|
||||||
|
return v, nil
|
||||||
|
}
|
69
streamdesk_test.go
Normal file
69
streamdesk_test.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package streamdeck
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testLogger struct {
|
||||||
|
t *testing.T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tl testLogger) Info(s string, x ...any) { tl.t.Log(s, x) }
|
||||||
|
func (tl testLogger) Debug(s string, x ...any) { tl.t.Log(s, x) }
|
||||||
|
func (tl testLogger) Error(s string, x ...any) { tl.t.Log(s, x) }
|
||||||
|
|
||||||
|
func TestReflection(t *testing.T) {
|
||||||
|
|
||||||
|
c := NewWithLogger(testLogger{t: t})
|
||||||
|
// incoming
|
||||||
|
in := ERDidReceiveSettingsPayload{}
|
||||||
|
|
||||||
|
ranHandler := false
|
||||||
|
c.RegisterHandler(func(event ERDidReceiveSettingsPayload) {
|
||||||
|
ranHandler = true
|
||||||
|
})
|
||||||
|
|
||||||
|
c.handle(in)
|
||||||
|
|
||||||
|
if !ranHandler {
|
||||||
|
t.Error("did not run handler")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUmmarshal(t *testing.T) {
|
||||||
|
|
||||||
|
b := []byte(`
|
||||||
|
{
|
||||||
|
"action": "com.elgato.example.action1",
|
||||||
|
"event": "keyUp",
|
||||||
|
"context": "ABC123",
|
||||||
|
"device": "DEF456",
|
||||||
|
"payload": {
|
||||||
|
"settings": {},
|
||||||
|
"coordinates": {
|
||||||
|
"column": 3,
|
||||||
|
"row": 1
|
||||||
|
},
|
||||||
|
"state": 0,
|
||||||
|
"userDesiredState": 1,
|
||||||
|
"isInMultiAction": false
|
||||||
|
}
|
||||||
|
}`)
|
||||||
|
|
||||||
|
c := NewWithLogger(testLogger{t: t})
|
||||||
|
keyUp, err := c.unmarshalToConcrete(receivedEventTypeMap["keyUp"], b)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
realKeyUp, ok := keyUp.(ERKeyUp)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("wrong type (is %T)", keyUp)
|
||||||
|
}
|
||||||
|
if realKeyUp.Context != "ABC123" {
|
||||||
|
t.Error("wrong value")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user