Stream Deck Provider
Provider for integrating HTML widgets with Stream Deck: connects to Stream Deck devices, manages virtual device layout, and sends key events.
Note: Stream Deck Provider is available only on Windows.
Revision History
- Rev 1.1
- Added documentation for Stream Deck signals:
virtualDeviceCreated,buttonIconUpdated,streamdeckUnreachable,authenticationRequired,authenticationRejected. - Documented
reconnectStreamDeck(widgetId)behavior, including when a new virtual device is created vs. reusing an existing one. - Added
disconnectStreamDeck(widgetId)method description and QML example wiring for all error-related signals.
- Added documentation for Stream Deck signals:
- Rev 1.2
- Updated
connectStreamDeckbehavior: it no longer creates a new virtual device when an emptydeviceIdis provided. To create a virtual device, use thestream-deck-virtual-devicecontrol manually. - When a widget is deleted, its virtual device is no longer deleted. To delete a virtual device, navigate to the Stream Deck application and delete it there.
- Added documentation for Stream Deck signal
streamdeckAuthenticated.
- Updated
Overview
- Module name:
widgetbuilder.streamdeck - Plugin name:
StreamDeck - Version:
1.2
Manifest entry:
"required_plugins": [
"widgetbuilder.streamdeck:StreamDeck:1.2"
]Runtime objects:
- Initialization flag:
pluginStreamdeck_initialized - Initialization callback map:
pluginStreamdeckEvents = { "onInitialized": onStreamdeckInitialized } - Plugin access:
window.plugins.Streamdeck
All methods are synchronous from JavaScript perspective but operate on an asynchronous RPC connection to the Stream Deck provider. Device creation, icon updates, and error conditions are delivered via signals.
Methods
connectStreamDeck(widgetId, deviceId, columns, rows)
Connects the widget to an existing virtual Stream Deck device with the specified grid size.
| Parameter | Type | Description |
|---|---|---|
widgetId | string | Unique widget identifier provided by iCUE |
deviceId | string | Target Stream Deck device identifier |
columns | int | Number of columns in the virtual key matrix |
rows | int | Number of rows in the virtual key matrix |
On success, virtualDeviceCreated(widgetId, deviceId) is emitted once the virtual device is ready.
On connection or authentication errors, one or more of the following signals may be emitted (see the Signals section below):
streamdeckAuthenticated(widgetId)– when authentication succeeds.streamdeckUnreachable(widgetId)– when the Stream Deck provider cannot be reached or the connection drops.authenticationRequired(widgetId)– when the user must authenticate before the widget can interact with Stream Deck.authenticationRejected(widgetId)– when authentication fails or is rejected.
reconnectStreamDeck(widgetId)
Requests reconnection for a previously connected widget. The method is asynchronous and
restarts the underlying connection logic for the given widgetId, attempting to reuse
the existing virtual device when possible. If the original virtual device no longer
exists on the Stream Deck side, a new one is created during reconnection (see signal
behavior below).
| Parameter | Type | Description |
|---|---|---|
widgetId | string | Widget identifier used during connect |
Use this when the Stream Deck process was restarted or the connection was lost and
re-established. Calling reconnectStreamDeck multiple times for the same widgetId
is safe; as long as the original virtual device still exists, no extra devices are
created.
Signal behavior:
-
If the existing virtual device for
widgetIdis still present on the Stream Deck side,virtualDeviceCreated(widgetId, deviceId)is not emitted again. The originaldeviceIdremains valid. When the device is opened after reconnection, the plugin will re-emitbuttonIconUpdated(widgetId, buttonIndex, iconDataUrl)for all known buttons. -
If the stored virtual device no longer exists (for example, the Stream Deck app lost its state), a new virtual device is created and
virtualDeviceCreated(widgetId, deviceId)is emitted again with the newdeviceId. -
In case of connection problems or authentication issues, no special "reconnect failed" signal is emitted; instead, the regular error signals are used:
-
streamdeckAuthenticated(widgetId)when the connection transitions to the Authenticated state; -
streamdeckUnreachable(widgetId)when the connection transitions to the Disconnected state; -
authenticationRequired(widgetId)when user authentication is needed; -
authenticationRejected(widgetId)if authentication fails.
-
disconnectStreamDeck(widgetId)
Disconnects the widget from its Stream Deck session. If this is the last subscriber
for the given widgetId, the underlying client session and WebSocket connection are
closed.
| Parameter | Type | Description |
|---|---|---|
widgetId | string | Widget identifier used during connect |
Typical usage:
- Call
disconnectStreamDeck(widgetId)when the widget is removed or its QML/HTML component is destroyed. - When multiple views share the same
widgetId(for example, dashboard + mimic), the Stream Deck session remains active until the last view disconnects.
updateVirtualDeviceSize(widgetId, columns, rows)
Updates the size of the virtual device grid without reconnecting.
| Parameter | Type | Description |
|---|---|---|
widgetId | string | Widget identifier |
columns | int | New number of columns |
rows | int | New number of rows |
The provider keeps existing connection and only resizes the virtual device.
sendKeyPress(widgetId, buttonIndex, pressed)
Sends a key press or release event for a virtual button.
| Parameter | Type | Description |
|---|---|---|
widgetId | string | Widget identifier |
buttonIndex | int | Zero-based button index in the virtual key grid |
pressed | bool | true for press, false for release |
The grid is traversed in row-major order:
-
Rows are numbered from top to bottom starting at
0. -
Columns are numbered from left to right starting at
0. -
The index is computed as:
buttonIndex = row * columns + column
For example, for a 5 × 3 grid (columns = 5, rows = 3):
buttonIndex = 0→ row0, column0(top-left)buttonIndex = 4→ row0, column4(top-right)buttonIndex = 5→ row1, column0(first button of the second row)buttonIndex = 14→ row2, column4(bottom-right)
Use this from an interactive widget when the user taps or releases a virtual key.
Properties
connectionStatus
Current state of the connection to the Stream Deck application, reported as a string.
The value belongs to the widget passed to connectStreamDeck(widgetId, ...), statuses of
other widgets are ignored. The value is updated automatically and the
connectionStatusChanged() notify signal is emitted on every change. The signal carries
no arguments, read the property to get the current value.
| Value | Description |
|---|---|
"Disconnected" | No connection to the Stream Deck application |
"Connecting" | Connection is being established |
"AuthRequested" | Waiting for the user to approve the iCUE connection |
"Authenticated" | Connection is approved |
"DeviceOpened" | Virtual device is opened and ready |
"AuthenticationRejected" | The iCUE connection was not approved |
const plugin = window.plugins.Streamdeck;
plugin.connectionStatusChanged.connect(function () {
// Update the widget UI according to plugin.connectionStatus
});Signals
virtualDeviceCreated(widgetId, deviceId)
Emitted when a virtual Stream Deck device has been created and is ready.
| Parameter | Type | Description |
|---|---|---|
widgetId | string | Widget identifier |
deviceId | string | Connected Stream Deck device id |
buttonIconUpdated(widgetId, buttonIndex, iconDataUrl)
Emitted when an icon for a specific virtual button changes.
| Parameter | Type | Description |
|---|---|---|
widgetId | string | Widget identifier |
buttonIndex | int | Button index whose icon was updated |
iconDataUrl | string | Icon image as a data: URL (PNG, etc) |
streamdeckAuthenticated(widgetId)
Emitted when a connection with the Stream Deck application is established.
| Parameter | Type | Description |
|---|---|---|
widgetId | string | Widget identifier |
streamdeckUnreachable(widgetId)
Emitted when the Stream Deck provider cannot be reached or the connection is lost.
| Parameter | Type | Description |
|---|---|---|
widgetId | string | Widget identifier |
authenticationRequired(widgetId)
Emitted when authentication is required before the widget can interact with Stream Deck.
| Parameter | Type | Description |
|---|---|---|
widgetId | string | Widget identifier |
authenticationRejected(widgetId)
Emitted when authentication fails or is rejected.
| Parameter | Type | Description |
|---|---|---|
widgetId | string | Widget identifier |
Example
manifest.json
"required_plugins": [
"widgetbuilder.streamdeck:StreamDeck:1.2"
]index.html
Add the stream-deck-virtual-device control to the HTML <head> so the user can select a virtual device:
<meta
name="x-icue-property"
content="virtualDevice"
data-label="tr('Virtual Device')"
data-type="stream-deck-virtual-device"
>Then use the selected virtualDevice value in your script:
// Initialize plugin events for async signals (recommended)
pluginStreamdeckEvents = {
"onInitialized": function onStreamdeckInitialized() {
if (!window.plugins || !window.plugins.Streamdeck) {
return;
}
const plugin = window.plugins.Streamdeck;
// Handle successful virtual device creation
plugin.virtualDeviceCreated.connect(function (widgetId, deviceId) {
// Example: hide an error overlay and cache deviceId if needed
});
// Handle connection loss
plugin.streamdeckUnreachable.connect(function (widgetId) {
// Example: show an error overlay in the widget
});
// Plugin is ready; you can safely call methods here
connectStreamDeckPlugin();
}
};
function connectStreamDeckPlugin() {
if (window.plugins && window.plugins.Streamdeck && pluginStreamdeck_initialized) {
const widgetId = iCUE.widgetId; // Provided by iCUE global object
const deviceId = virtualDevice; // Provided by the stream-deck-virtual-device control
const columns = 5;
const rows = 3;
window.plugins.Streamdeck.connectStreamDeck(widgetId, deviceId, columns, rows);
}
}
// Called by your UI when a virtual button is pressed or released
function onVirtualButtonPressed(buttonIndex, pressed) {
if (window.plugins && window.plugins.Streamdeck && pluginStreamdeck_initialized) {
window.plugins.Streamdeck.sendKeyPress(iCUE.widgetId, buttonIndex, pressed);
}
}
// Example: bind UI events to virtual button presses
const button = document.getElementById("streamdeck-button-0");
if (button) {
button.addEventListener("pointerdown", () => onVirtualButtonPressed(0, true));
button.addEventListener("pointerup", () => onVirtualButtonPressed(0, false));
}Note: The iCUE widget runtime provides
iCUE.widgetId. The selected device ID comes from thevirtualDeviceproperty defined by the stream-deck-virtual-device control, not from theiCUEglobal object.
StreamDeck QML Wrapper
The StreamDeck QML wrapper provides a thin, declarative layer over the HTML plugin API so that QML components can control Stream Deck devices without writing JavaScript glue code.
The wrapper is implemented in the widgetbuilder.streamdeck module as StreamDeck.qml and
internally forwards all calls to the same backend that powers the HTML plugin.
Initialization
To use the QML wrapper, import the module and keep a single StreamDeck object in the QML
scope that needs to interact with Stream Deck. The wrapper exposes the same methods and
signals as the HTML plugin:
connectStreamDeck(widgetId, deviceId, columns, rows)reconnectStreamDeck(widgetId)disconnectStreamDeck(widgetId)updateVirtualDeviceSize(widgetId, columns, rows)sendKeyPress(widgetId, buttonIndex, pressed)
Properties:
connectionStatus
Signals:
virtualDeviceCreated(widgetId, deviceId)buttonIconUpdated(widgetId, buttonIndex, iconDataUrl)streamdeckAuthenticated(widgetId)streamdeckUnreachable(widgetId)authenticationRequired(widgetId)authenticationRejected(widgetId)
QML Example
import QtQuick
import widgetbuilder.streamdeck
Item {
id: root
// These values are typically provided by the host QML environment,
// for example via context properties or a view model.
property string widgetId: "{widget-id-from-environment}"
property string deviceId: "{streamdeck-device-id-from-environment}"
StreamDeck {
id: streamDeck
onVirtualDeviceCreated: function(widgetId, deviceId) {
// Handle initial virtual device creation
}
onButtonIconUpdated: function(widgetId, buttonIndex, iconDataUrl) {
// Update button visuals in QML if needed
}
onStreamdeckAuthenticated: function(widgetId) {
// Handle Stream Deck authentication
}
onStreamdeckUnreachable: function(widgetId) {
// Handle connection loss, e.g. show an error overlay in QML
}
onAuthenticationRequired: function(widgetId) {
// Prompt the user to authenticate before using Stream Deck
}
onAuthenticationRejected: function(widgetId) {
// Inform the user that authentication failed
}
}
Component.onCompleted: {
streamDeck.connectStreamDeck(widgetId, deviceId, 5, 3);
}
}