streamdeck-typescript
Version:
This library will help you build elgato stream deck plugins in typescript
273 lines (246 loc) • 8.08 kB
text/typescript
import { StreamDeckActionClass } from '../classes/stream-deck-action.class';
import { StateType, TargetType } from '../interfaces/enums';
import { PossibleEventsToReceive } from '../interfaces/types';
import { ActionManager } from '../manager/action.manager';
import { StreamDeckHandlerBase } from './stream-deck-handler-base';
/**
* This will help you create the stream deck action handler
* @author XeroxDev <help@xeroxdev.de>
* @copyright 2021
*/
export abstract class StreamDeckPluginHandler<
GlobalSettings = any
> extends StreamDeckHandlerBase<GlobalSettings> {
private readonly _actionManager: ActionManager;
protected constructor() {
super();
this._actionManager = new ActionManager(this);
}
public get actionManager(): ActionManager {
return this._actionManager;
}
/**
* Sets the action title
* @param {string} title The string the title should be
* @param {string} context The context which called it
* @param {TargetType} target [Optional] Show title only on hardware, software or both (default: Both)
* @param {StateType} state [Optional] Show title only on ON state or OFF state (default: Both)
*/
public setTitle(
title: string,
context: string,
target: TargetType = TargetType.BOTH,
state?: StateType
) {
if (state) {
this.send('setTitle', {
context,
payload: { title, target, state },
});
} else {
this.send('setTitle', {
context,
payload: { title, target },
});
}
}
/**
* Sets the action image
* @param {string} image Image as string
* @param {string} context The context which called it
* @param {TargetType} target [Optional] Show image only on hardware, software or both (default: Both)
* @param {StateType} state [Optional] Show image only on ON state or OFF state (default: Both)
*/
public setImage(
image: string,
context: string,
target: TargetType = TargetType.BOTH,
state?: StateType
) {
if (state) {
this.send('setImage', {
context,
payload: { image, target, state },
});
} else {
this.send('setImage', {
context,
payload: { image, target },
});
}
}
/**
* Sets the action image but instead from file, from URL
* @param {string} url
* @param {string} context
* @param {TargetType} target
* @param {StateType} state
* @returns {Promise<string>}
*/
public setImageFromUrl(
url: string,
context: string,
target: TargetType = TargetType.BOTH,
state?: StateType
): Promise<string> {
return new Promise((resolve, reject) => {
let image = new Image();
image.onload = () => {
let canvas = document.createElement('canvas');
canvas.width = image.naturalWidth;
canvas.height = image.naturalHeight;
let ctx = canvas.getContext('2d');
if (!ctx) {
reject(new Error('image failed to load'));
return;
}
ctx.drawImage(image, 0, 0);
image.onload = null;
image.onerror = null;
(image as any) = null;
const dataUrl = canvas.toDataURL('image/png');
this.setImage(dataUrl, context, target, state);
resolve(dataUrl);
};
image.onerror = () => {
image.onload = null;
image.onerror = null;
(image as any) = null;
reject(new Error('image failed to load'));
};
image.src = url;
});
}
/**
* Shows a alert icon on action
* @param {string} context
*/
public showAlert(context: string) {
this.send('showAlert', { context });
}
/**
* Shows a okay icon on action
* @param {string} context
*/
public showOk(context: string) {
this.send('showOk', { context });
}
/**
* Sets the state of the action (ON / OFF)
* @param {StateType} state
* @param {string} context The context which called it
*/
public setState(state: StateType, context: string) {
this.send('setState', {
context: context,
payload: { state },
});
}
/**
* Switch to a profile
* @param {string} profile
* @param {string} device
*/
public switchToProfile(profile: string, device?: string) {
this.send('switchToProfile', {
context: this.uuid,
device: device ? device : this.info.devices[0].id,
payload: { profile },
});
}
/**
* Send data to the property inspector
* @param {any} payload Data to send
* @param {string} action [Optional] Action context.
* @param {string} context The context which called it
*/
public sendToPropertyInspector(
payload: any,
action: string,
context: string
) {
this.send('sendToPropertyInspector', {
context,
action: action,
payload,
});
}
protected _eventHandler(ev: MessageEvent): void {
const eventData = JSON.parse(ev.data);
const event: PossibleEventsToReceive = eventData.event;
if (
event !== 'didReceiveGlobalSettings' &&
eventData.context &&
eventData.payload?.settings
)
this.settingsManager.cacheContextSettings(
eventData.context,
eventData.payload.settings
);
let settings,
column,
isInMultiAction,
row,
state,
userDesiredState,
action,
context,
device;
action = eventData?.action;
context = eventData?.context;
device = eventData?.device;
const payload = eventData?.payload;
settings = payload?.settings;
state = payload?.state;
userDesiredState = payload?.userDesiredState;
isInMultiAction = payload?.isInMultiAction;
column = payload?.coordinates?.column;
row = payload?.coordinates?.row;
const actionClass = this._actionManager.addOrGetAction(
context,
new StreamDeckActionClass(this)
);
if (actionClass) {
if (action !== undefined) actionClass.action = action;
if (context !== undefined) actionClass.context = context;
if (device !== undefined) actionClass.device = device;
if (settings !== undefined) actionClass.settings = settings;
if (column !== undefined) actionClass.column = column;
if (row !== undefined) actionClass.row = row;
if (state !== undefined) actionClass.state = state;
if (userDesiredState !== undefined)
actionClass.userDesiredState = userDesiredState;
if (isInMultiAction !== undefined)
actionClass.isInMultiAction = isInMultiAction;
}
super._eventHandler(ev);
}
/**
* Sets the action title
* @param {string} context The context which called it
* @param {any} json
*/
public setFeedback(
context: string,
payload: any
) {
this.send('setFeedback', {
context,
payload: payload,
});
}
/**
* Sets the action title
* @param {string} context The context which called it
* @param {string} layout
*/
public setFeedbackLayout(
context: string,
layout: string,
) {
this.send('setFeedbackLayout', {
context,
payload: { layout },
});
}
}