streamdeck_rs/lib.rs
1#[cfg(feature = "logging")]
2pub mod logging;
3pub mod registration;
4pub mod socket;
5
6pub use crate::registration::RegistrationInfo;
7pub use crate::socket::StreamDeckSocket;
8
9use serde::{de, ser};
10use serde_derive::{Deserialize, Serialize};
11use serde_json::Value;
12use serde_repr::{Deserialize_repr, Serialize_repr};
13use std::fmt;
14
15/// A message received from the Stream Deck software.
16///
17/// - `G` represents the global settings that are persisted within the Stream Deck software.
18/// - `S` represents the settings that are persisted within the Stream Deck software.
19/// - `M` represents the messages that are received from the property inspector.
20///
21/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/)
22#[derive(Debug, Deserialize, Serialize)]
23#[serde(tag = "event", rename_all = "camelCase")]
24pub enum Message<G, S, M> {
25 /// A key has been pressed.
26 ///
27 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#keydown)
28 #[serde(rename_all = "camelCase")]
29 KeyDown {
30 /// The uuid of the action.
31 action: String,
32 /// The instance of the action (key or part of a multiaction).
33 context: String,
34 /// The device where the key was pressed.
35 device: String,
36 /// Additional information about the key press.
37 payload: KeyPayload<S>,
38 },
39 /// A key has been released.
40 ///
41 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#keyup)
42 #[serde(rename_all = "camelCase")]
43 KeyUp {
44 /// The uuid of the action.
45 action: String,
46 /// The instance of the action (key or part of a multiaction).
47 context: String,
48 /// The device where the key was pressed.
49 device: String,
50 /// Additional information about the key press.
51 payload: KeyPayload<S>,
52 },
53 /// An instance of the action has been added to the display.
54 ///
55 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#willappear)
56 #[serde(rename_all = "camelCase")]
57 WillAppear {
58 /// The uuid of the action.
59 action: String,
60 /// The instance of the action (key or part of a multiaction).
61 context: String,
62 /// The device where the action will appear, or None if it does not appear on a device.
63 device: Option<String>,
64 /// Additional information about the action's appearance.
65 payload: VisibilityPayload<S>,
66 },
67 /// An instance of the action has been removed from the display.
68 ///
69 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#willdisappear)
70 #[serde(rename_all = "camelCase")]
71 WillDisappear {
72 /// The uuid of the action.
73 action: String,
74 /// The instance of the action (key or part of a multiaction).
75 context: String,
76 /// The device where the action was visible, or None if it was not on a device.
77 device: Option<String>,
78 /// Additional information about the action's appearance.
79 payload: VisibilityPayload<S>,
80 },
81 /// The title has changed for an instance of an action.
82 ///
83 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#titleparametersdidchange)
84 #[serde(rename_all = "camelCase")]
85 TitleParametersDidChange {
86 /// The uuid of the action.
87 action: String,
88 /// The instance of the action (key or part of a multiaction).
89 context: String,
90 /// The device where the action is visible, or None if it is not on a device.
91 device: Option<String>,
92 /// Additional information about the new title.
93 payload: TitleParametersPayload<S>,
94 },
95 /// A device has connected.
96 ///
97 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#devicedidconnect)
98 #[serde(rename_all = "camelCase")]
99 DeviceDidConnect {
100 /// The ID of the device that has connected.
101 device: String,
102 /// Information about the device.
103 device_info: DeviceInfo,
104 },
105 /// A device has disconnected.
106 ///
107 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#devicediddisconnect)
108 #[serde(rename_all = "camelCase")]
109 DeviceDidDisconnect {
110 /// The ID of the device that has disconnected.
111 device: String,
112 },
113 /// An application monitored by the manifest file has launched.
114 ///
115 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#applicationdidlaunch)
116 #[serde(rename_all = "camelCase")]
117 ApplicationDidLaunch {
118 /// Information about the launched application.
119 payload: ApplicationPayload,
120 },
121 /// An application monitored by the manifest file has terminated.
122 ///
123 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#applicationdidterminate)
124 #[serde(rename_all = "camelCase")]
125 ApplicationDidTerminate {
126 /// Information about the terminated application.
127 payload: ApplicationPayload,
128 },
129 /// The property inspector has sent data.
130 ///
131 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#sendtoplugin)
132 #[serde(rename_all = "camelCase")]
133 SendToPlugin {
134 /// The uuid of the action.
135 action: String,
136 /// The instance of the action (key or part of a multiaction).
137 context: String,
138 /// Information sent from the property inspector.
139 payload: M,
140 },
141 /// The application has sent settings for an action.
142 ///
143 /// This message is sent in response to GetSettings, but also after the
144 /// property inspector changes the settings.
145 ///
146 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#didreceivesettings)
147 #[serde(rename_all = "camelCase")]
148 DidReceiveSettings {
149 /// The uuid of the action.
150 action: String,
151 /// The instance of the action (key or part of a multiaction).
152 context: String,
153 /// The device where the action exists.
154 device: String,
155 /// The current settings for the action.
156 payload: KeyPayload<S>,
157 },
158 /// The property inspector for an action has become visible.
159 ///
160 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#propertyinspectordidappear)
161 #[serde(rename_all = "camelCase")]
162 PropertyInspectorDidAppear {
163 /// The uuid of the action.
164 action: String,
165 /// The instance of the action (key or part of a multiaction).
166 context: String,
167 /// The device where the action exists.
168 device: String,
169 },
170 /// The property inspector for an action is no longer visible.
171 ///
172 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#propertyinspectordiddisappear)
173 #[serde(rename_all = "camelCase")]
174 PropertyInspectorDidDisappear {
175 /// The uuid of the action.
176 action: String,
177 /// The instance of the action (key or part of a multiaction).
178 context: String,
179 /// The device where the action exists.
180 device: String,
181 },
182 /// The application has sent settings for an action.
183 ///
184 /// This message is sent in response to GetGlobalSettings, but also after
185 /// the property inspector changes the settings.
186 ///
187 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#didreceiveglobalsettings)
188 #[serde(rename_all = "camelCase")]
189 DidReceiveGlobalSettings {
190 /// The current settings for the action.
191 payload: GlobalSettingsPayload<G>,
192 },
193 /// The computer has resumed from sleep.
194 ///
195 /// Added in Stream Deck software version 4.3.
196 ///
197 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#systemdidwakeup)
198 SystemDidWakeUp,
199
200 /// The touchscreen has been tapped.
201 ///
202 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received#touchtap-sd)
203 #[serde(rename_all = "camelCase")]
204 TouchTap {
205 /// The uuid of the action.
206 action: String,
207 /// The instance of the action (key or part of a multiaction).
208 context: String,
209 /// The device where the action exists.
210 device: String,
211 /// Additional information about the touch event.
212 payload: TouchTapPayload<S>,
213 },
214
215 /// An encoder has been pressed.
216 ///
217 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received#dialdown-sd)
218 #[serde(rename_all = "camelCase")]
219 DialDown {
220 /// The uuid of the action.
221 action: String,
222 /// The instance of the action (key or part of a multiaction).
223 context: String,
224 /// The device where the action exists.
225 device: String,
226 /// Additional information about the press event.
227 payload: DialDownPayload<S>,
228 },
229
230 /// An encoder has been released.
231 ///
232 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received#dialup-sd)
233 #[serde(rename_all = "camelCase")]
234 DialUp {
235 /// The uuid of the action.
236 action: String,
237 /// The instance of the action (key or part of a multiaction).
238 context: String,
239 /// The device where the action exists.
240 device: String,
241 /// Additional information about the release event.
242 payload: DialUpPayload<S>,
243 },
244
245 /// An encoder has been rotated.
246 ///
247 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received#dialrotate-sd)
248 #[serde(rename_all = "camelCase")]
249 DialRotate {
250 /// The uuid of the action.
251 action: String,
252 /// The instance of the action (key or part of a multiaction).
253 context: String,
254 /// The device where the action exists.
255 device: String,
256 /// Additional information about the rotate event.
257 payload: DialRotatePayload<S>,
258 },
259
260 /// An event from an unsupported version of the Stream Deck software.
261 ///
262 /// This occurs when the Stream Deck software sends an event that is not
263 /// understood. Usually this will be because the Stream Deck software is
264 /// newer than the plugin, and it should be safe to ignore these.
265 #[serde(other)]
266 Unknown,
267}
268
269/// A message to be sent to the Stream Deck software.
270///
271/// - `G` represents the global settings that are persisted within the Stream Deck software.
272/// - `S` represents the action settings that are persisted within the Stream Deck software.
273/// - `M` represents the messages that are sent to the property inspector.
274///
275/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/)
276#[derive(Debug, Deserialize, Serialize)]
277#[serde(tag = "event", rename_all = "camelCase")]
278pub enum MessageOut<G, S, M> {
279 /// Set the title of an action instance.
280 ///
281 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#settitle)
282 #[serde(rename_all = "camelCase")]
283 SetTitle {
284 /// The instance of the action (key or part of a multiaction).
285 context: String,
286 /// The title to set.
287 payload: TitlePayload,
288 },
289 /// Set the image of an action instance.
290 ///
291 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#setimage)
292 #[serde(rename_all = "camelCase")]
293 SetImage {
294 /// The instance of the action (key or part of a multiaction).
295 context: String,
296 /// The image to set.
297 payload: ImagePayload,
298 },
299 /// Temporarily overlay the key image with an alert icon.
300 ///
301 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#showalert)
302 #[serde(rename_all = "camelCase")]
303 ShowAlert {
304 /// The instance of the action (key or part of a multiaction).
305 context: String,
306 },
307 /// Temporarily overlay the key image with a checkmark.
308 ///
309 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#showok)
310 #[serde(rename_all = "camelCase")]
311 ShowOk {
312 /// The instance of the action (key or part of a multiaction).
313 context: String,
314 },
315 /// Retrieve settings for an instance of an action via DidReceiveSettings.
316 ///
317 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#getsettings)
318 #[serde(rename_all = "camelCase")]
319 GetSettings {
320 /// The instance of the action (key or part of a multiaction).
321 context: String,
322 },
323 /// Store settings for an instance of an action.
324 ///
325 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#setsettings)
326 #[serde(rename_all = "camelCase")]
327 SetSettings {
328 /// The instance of the action (key or part of a multiaction).
329 context: String,
330 /// The settings to save.
331 payload: S,
332 },
333 /// Set the state of an action.
334 ///
335 /// Normally, Stream Deck changes the state of an action automatically when the key is pressed.
336 ///
337 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#setstate)
338 #[serde(rename_all = "camelCase")]
339 SetState {
340 /// The instance of the action (key or part of a multiaction).
341 context: String,
342 /// The desired state.
343 payload: StatePayload,
344 },
345 /// Send data to the property inspector.
346 ///
347 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#sendtopropertyinspector)
348 #[serde(rename_all = "camelCase")]
349 SendToPropertyInspector {
350 /// The uuid of the action.
351 action: String,
352 /// The instance of the action (key or part of a multiaction).
353 context: String,
354 /// The message to send.
355 payload: M,
356 },
357 /// Select a new profile.
358 ///
359 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#switchtoprofile)
360 #[serde(rename_all = "camelCase")]
361 SwitchToProfile {
362 /// The instance of the action (key or part of a multiaction).
363 context: String,
364 /// The device to change the profile of.
365 device: String,
366 /// The profile to activate.
367 payload: ProfilePayload,
368 },
369 /// Open a URL in the default browser.
370 ///
371 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#openurl)
372 #[serde(rename_all = "camelCase")]
373 OpenUrl {
374 /// The url to open.
375 payload: UrlPayload,
376 },
377 /// Retrieve plugin settings for via DidReceiveGlobalSettings.
378 ///
379 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#getglobalsettings)
380 #[serde(rename_all = "camelCase")]
381 GetGlobalSettings {
382 /// The instance of the action (key or part of a multiaction).
383 context: String,
384 },
385 /// Store plugin settings.
386 ///
387 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#setglobalsettings)
388 #[serde(rename_all = "camelCase")]
389 SetGlobalSettings {
390 /// The instance of the action (key or part of a multiaction).
391 context: String,
392 /// The settings to save.
393 payload: G,
394 },
395 /// Write to the log.
396 ///
397 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#logmessage)
398 #[serde(rename_all = "camelCase")]
399 LogMessage {
400 /// The message to log.
401 payload: LogMessagePayload,
402 },
403 /// Set feedback.
404 ///
405 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#setfeedback-sd)
406 #[serde(rename_all = "camelCase")]
407 SetFeedback {
408 /// The instance of the action (key or part of a multiaction).
409 context: String,
410 /// The data to send to the display.
411 payload: Value,
412 },
413 /// Set feedback layout.
414 ///
415 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#setfeedbacklayout-sd)
416 #[serde(rename_all = "camelCase")]
417 SetFeedbackLayout {
418 /// The instance of the action (key or part of a multiaction).
419 context: String,
420 /// The data to send to the display.
421 payload: SetFeedbackLayoutPayload,
422 },
423 /// Set trigger description.
424 ///
425 /// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#settriggerdescription-sd)
426 #[serde(rename_all = "camelCase")]
427 SetTriggerDescription {
428 /// The instance of the action (key or part of a multiaction).
429 context: String,
430 /// The data to send to the display.
431 payload: SetTriggerDescriptionPayload,
432 },
433}
434
435/// The target of a command.
436#[derive(Debug, Deserialize_repr, Serialize_repr)]
437#[repr(u8)]
438pub enum Target {
439 /// Both the device and a the display within the Stream Deck software.
440 Both = 0,
441 /// Only the device.
442 Hardware = 1,
443 /// Only the display within the Stream Deck software.
444 Software = 2,
445}
446
447/// The title to set as part of a [SetTitle](enum.MessageOut.html#variant.SetTitle) message.
448///
449/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#settitle)
450#[derive(Debug, Deserialize, Serialize)]
451#[serde(rename_all = "camelCase")]
452pub struct TitlePayload {
453 /// The new title.
454 pub title: Option<String>,
455 /// The target displays.
456 pub target: Target,
457 /// The state to set the title for. If not set, it is set for all states.
458 #[serde(skip_serializing_if = "Option::is_none")]
459 pub state: Option<u8>,
460}
461
462/// The image to set as part of a [SetImage](enum.MessageOut.html#variant.SetImage) message.
463///
464/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#setimage)
465#[derive(Debug, Deserialize, Serialize)]
466#[serde(rename_all = "camelCase")]
467pub struct ImagePayload {
468 /// An image in the form of a data URI.
469 pub image: Option<String>,
470 /// The target displays.
471 pub target: Target,
472 /// The state to set the image for. If not set, it is set for all states.
473 #[serde(skip_serializing_if = "Option::is_none")]
474 pub state: Option<u8>,
475}
476
477/// The state to set as part of a [SetState](enum.MessageOut.html#variant.SetState) message.
478///
479/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#setstate)
480#[derive(Debug, Deserialize, Serialize)]
481#[serde(rename_all = "camelCase")]
482pub struct StatePayload {
483 /// The new state.
484 pub state: u8,
485}
486
487/// The profile to activate as part of a [SwitchToProfile](enum.MessageOut.html#variant.SwitchToProfile) message.
488///
489/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#SwitchToProfile)
490#[derive(Debug, Deserialize, Serialize)]
491#[serde(rename_all = "camelCase")]
492pub struct ProfilePayload {
493 /// The name of the profile to activate.
494 pub profile: String,
495}
496
497/// The URL to launch as part of a [OpenUrl](enum.MessageOut.html#variant.OpenUrl) message.
498///
499/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent/#openurl)
500#[derive(Debug, Deserialize, Serialize)]
501#[serde(rename_all = "camelCase")]
502pub struct UrlPayload {
503 /// The URL to launch.
504 pub url: String,
505}
506
507/// Additional information about the key pressed.
508#[derive(Debug, Deserialize, Serialize)]
509#[serde(rename_all = "camelCase")]
510pub struct KeyPayload<S> {
511 /// The stored settings for the action instance.
512 pub settings: S,
513 /// The location of the key that was pressed, or None if this action instance is part of a multi action.
514 pub coordinates: Option<Coordinates>,
515 /// The current state of the action instance.
516 pub state: Option<u8>,
517 /// The desired state of the action instance (if this instance is part of a multi action).
518 pub user_desired_state: Option<u8>,
519 //TODO: is_in_multi_action ignored. replace coordinates with enum Location { Coordinates, MultiAction }.
520}
521
522/// Additional information about a key's appearance.
523#[derive(Debug, Deserialize, Serialize)]
524#[serde(rename_all = "camelCase")]
525pub struct VisibilityPayload<S> {
526 /// The stored settings for the action instance.
527 pub settings: S,
528 /// The location of the key, or None if this action instance is part of a multi action.
529 pub coordinates: Option<Coordinates>,
530 /// The state of the action instance.
531 pub state: Option<u8>,
532 //TODO: is_in_multi_action ignored. replace coordinates with enum Location { Coordinates, MultiAction }.
533}
534
535/// The new title of a key.
536#[derive(Debug, Deserialize, Serialize)]
537#[serde(rename_all = "camelCase")]
538pub struct TitleParametersPayload<S> {
539 /// The stored settings for the action instance.
540 pub settings: S,
541 /// The location of the key, or None if this action instance is part of a multi action.
542 pub coordinates: Coordinates,
543 /// The state of the action instance.
544 pub state: Option<u8>,
545 /// The new title.
546 pub title: String,
547 /// Additional parameters for the display of the title.
548 pub title_parameters: TitleParameters,
549}
550
551/// The new global settings.
552#[derive(Debug, Deserialize, Serialize)]
553#[serde(rename_all = "camelCase")]
554pub struct GlobalSettingsPayload<G> {
555 /// The stored settings for the plugin.
556 pub settings: G,
557}
558
559/// A log message.
560#[derive(Debug, Deserialize, Serialize)]
561#[serde(rename_all = "camelCase")]
562pub struct LogMessagePayload {
563 /// The log message text.
564 pub message: String,
565}
566
567/// A layout update message.
568///
569/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent#setfeedbacklayout-sd)
570#[derive(Debug, Deserialize, Serialize)]
571#[serde(rename_all = "camelCase")]
572pub struct SetFeedbackLayoutPayload {
573 /// A predefined layout identifier or the relative path to a JSON file that contains a custom layout.
574 pub layout: String,
575}
576
577/// A trigger description update message.
578///
579/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-sent#settriggerdescription-sd)
580#[derive(Debug, Deserialize, Serialize)]
581#[serde(rename_all = "camelCase")]
582pub struct SetTriggerDescriptionPayload {
583 /// A value that describes the long-touch interaction with the touch display.
584 pub long_touch: Option<String>,
585 /// A value that describes the push interaction with the dial.
586 pub push: Option<String>,
587 /// A value that describes the rotate interaction with the dial.
588 pub rotate: Option<String>,
589 /// A value that describes the touch interaction with the touch display.
590 pub touch: Option<String>,
591}
592
593/// Additional information about a touch tap event.
594///
595/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received#touchtap-sd)
596#[derive(Debug, Deserialize, Serialize)]
597#[serde(rename_all = "camelCase")]
598pub struct TouchTapPayload<S> {
599 /// The stored settings for the action instance.
600 pub settings: S,
601 /// The location of the action triggered.
602 pub coordinates: Option<Coordinates>,
603 /// The coordinates of the touch event within the LCD slot associated with the action.
604 pub tap_pos: (u8, u8),
605 /// Whether the tap was long.
606 pub hold: bool,
607}
608
609/// Additional information about an encoder press event.
610///
611/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received#dialdown-sd)
612#[derive(Debug, Deserialize, Serialize)]
613#[serde(rename_all = "camelCase")]
614pub struct DialDownPayload<S> {
615 /// The stored settings for the action instance.
616 pub settings: S,
617 /// The location of the action triggered.
618 pub coordinates: Option<Coordinates>,
619}
620
621/// Additional information about an encoder release event.
622///
623/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received#dialup-sd)
624#[derive(Debug, Deserialize, Serialize)]
625#[serde(rename_all = "camelCase")]
626pub struct DialUpPayload<S> {
627 /// The stored settings for the action instance.
628 pub settings: S,
629 /// The location of the action triggered.
630 pub coordinates: Option<Coordinates>,
631}
632
633/// Additional information about an encoder rotate event.
634///
635/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received#dialrotate-sd)
636#[derive(Debug, Deserialize, Serialize)]
637#[serde(rename_all = "camelCase")]
638pub struct DialRotatePayload<S> {
639 /// The stored settings for the action instance.
640 pub settings: S,
641 /// The location of the action triggered.
642 pub coordinates: Option<Coordinates>,
643 /// The number of ticks of the rotation (positive values are clockwise).
644 pub ticks: i64,
645 /// Whether the encoder was being pressed down during the rotation.
646 pub pressed: bool,
647}
648
649/// Information about a hardware device.
650///
651/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#devicedidconnect)
652#[derive(Debug, Deserialize, Serialize)]
653#[serde(rename_all = "camelCase")]
654pub struct DeviceInfo {
655 /// The user-provided name of the device.
656 ///
657 /// Added in Stream Deck software version 4.3.
658 pub name: Option<String>,
659 /// The size of the device.
660 pub size: DeviceSize,
661 /// The type of the device, or None if the Stream Deck software is running with no device attached.
662 #[serde(rename = "type")]
663 pub _type: Option<DeviceType>,
664}
665
666/// Information about a monitored application that has launched or terminated.
667#[derive(Debug, Deserialize, Serialize)]
668#[serde(rename_all = "camelCase")]
669pub struct ApplicationPayload {
670 /// The name of the application.
671 pub application: String,
672}
673
674/// The location of a key on a device.
675///
676/// Locations are specified using zero-indexed values starting from the top left corner of the device.
677#[derive(Debug, Deserialize, Serialize)]
678#[serde(rename_all = "camelCase")]
679pub struct Coordinates {
680 /// The x coordinate of the key.
681 pub column: u8,
682 /// The y-coordinate of the key.
683 pub row: u8,
684}
685
686/// The vertical alignment of a title.
687///
688/// Titles are always centered horizontally.
689#[derive(Debug, Deserialize, Serialize)]
690#[serde(rename_all = "camelCase")]
691pub enum Alignment {
692 /// The title should appear at the top of the key.
693 Top,
694 /// The title should appear in the middle of the key.
695 Middle,
696 /// The title should appear at the bottom of the key.
697 Bottom,
698}
699
700/// Style information for a title.
701///
702/// [Official Documentation](https://docs.elgato.com/sdk/plugins/events-received/#titleparametersdidchange)
703#[derive(Debug, Deserialize, Serialize)]
704#[serde(rename_all = "camelCase")]
705pub struct TitleParameters {
706 /// The name of the font family.
707 pub font_family: String,
708 /// The font size.
709 pub font_size: u8,
710 /// Whether the font is bold and/or italic.
711 pub font_style: String,
712 /// Whether the font is underlined.
713 pub font_underline: bool,
714 /// Whether the title is displayed.
715 pub show_title: bool,
716 /// The vertical alignment of the title.
717 pub title_alignment: Alignment,
718 /// The color of the title.
719 pub title_color: String,
720}
721
722/// The size of a device in keys.
723#[derive(Debug, Deserialize, Serialize)]
724#[serde(rename_all = "camelCase")]
725pub struct DeviceSize {
726 /// The number of key columns on the device.
727 pub columns: u8,
728 /// The number of key rows on the device.
729 pub rows: u8,
730}
731
732/// The type of connected hardware device.
733///
734/// [Official Documentation](https://docs.elgato.com/sdk/plugins/manifest/#profiles)
735#[derive(Debug)]
736pub enum DeviceType {
737 /// The [Stream Deck](https://www.elgato.com/en/gaming/stream-deck).
738 StreamDeck, // 0
739 /// The [Stream Deck Mini](https://www.elgato.com/en/gaming/stream-deck-mini).
740 StreamDeckMini, // 1
741 /// The [Stream Deck XL](https://www.elgato.com/en/gaming/stream-deck-xl).
742 ///
743 /// Added in Stream Deck software version 4.3.
744 StreamDeckXl, // 2
745 /// The [Stream Deck Mobile](https://www.elgato.com/en/gaming/stream-deck-mobile) app.
746 ///
747 /// Added in Stream Deck software version 4.3.
748 StreamDeckMobile, // 3
749 /// The G-keys in Corsair keyboards
750 ///
751 /// Added in Stream Deck software version 4.7
752 CorsairGKeys, // 4
753 /// The [Stream Deck Pedal](https://www.elgato.com/en/stream-deck-pedal).
754 ///
755 /// Added in Stream Deck software version 5.2
756 StreamDeckPedal, // 5
757 /// The [Corsair Voyager Streaming Laptop](https://www.corsair.com/us/en/voyager-a1600-gaming-streaming-pc-laptop).
758 ///
759 /// Added in Stream Deck software version 5.3
760 CorsairVoyager, // 6
761 /// The [Stream Deck +](https://www.elgato.com/en/stream-deck-plus)
762 ///
763 /// Added in Stream Deck software version 6.0
764 StreamDeckPlus, // 7
765 /// A device not documented in the 6.0 SDK.
766 Unknown(u64),
767}
768
769impl ser::Serialize for DeviceType {
770 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
771 where
772 S: ser::Serializer,
773 {
774 serializer.serialize_u64(match self {
775 DeviceType::StreamDeck => 0,
776 DeviceType::StreamDeckMini => 1,
777 DeviceType::StreamDeckXl => 2,
778 DeviceType::StreamDeckMobile => 3,
779 DeviceType::CorsairGKeys => 4,
780 DeviceType::StreamDeckPedal => 5,
781 DeviceType::CorsairVoyager => 6,
782 DeviceType::StreamDeckPlus => 7,
783 DeviceType::Unknown(value) => *value,
784 })
785 }
786}
787
788impl<'de> de::Deserialize<'de> for DeviceType {
789 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
790 where
791 D: de::Deserializer<'de>,
792 {
793 struct Visitor;
794
795 impl<'de> de::Visitor<'de> for Visitor {
796 type Value = DeviceType;
797
798 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
799 formatter.write_str("an integer")
800 }
801
802 fn visit_u64<E>(self, value: u64) -> Result<DeviceType, E>
803 where
804 E: de::Error,
805 {
806 Ok(match value {
807 0 => DeviceType::StreamDeck,
808 1 => DeviceType::StreamDeckMini,
809 2 => DeviceType::StreamDeckXl,
810 3 => DeviceType::StreamDeckMobile,
811 4 => DeviceType::CorsairGKeys,
812 5 => DeviceType::StreamDeckPedal,
813 6 => DeviceType::CorsairVoyager,
814 7 => DeviceType::StreamDeckPlus,
815 value => DeviceType::Unknown(value),
816 })
817 }
818 }
819
820 deserializer.deserialize_u64(Visitor)
821 }
822}
823
824#[derive(Clone, Debug, Eq, PartialEq)]
825pub enum Color {
826 Rgb { r: u8, g: u8, b: u8 },
827 Rgba { r: u8, g: u8, b: u8, a: u8 },
828}
829
830impl ser::Serialize for Color {
831 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
832 where
833 S: ser::Serializer,
834 {
835 let html_color = match self {
836 Color::Rgb { r, g, b } => format!("#{:02x}{:02x}{:02x}", r, g, b),
837 Color::Rgba { r, g, b, a } => format!("#{:02x}{:02x}{:02x}{:02x}", r, g, b, a),
838 };
839 serializer.serialize_str(&html_color)
840 }
841}
842
843impl<'de> de::Deserialize<'de> for Color {
844 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
845 where
846 D: de::Deserializer<'de>,
847 {
848 struct Visitor;
849
850 impl<'de> de::Visitor<'de> for Visitor {
851 type Value = Color;
852
853 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
854 formatter.write_str("a hex color")
855 }
856
857 fn visit_str<E>(self, value: &str) -> Result<Color, E>
858 where
859 E: de::Error,
860 {
861 let parse_component = |value: &str| {
862 u8::from_str_radix(value, 16)
863 .map_err(|_| E::invalid_value(de::Unexpected::Str(value), &self))
864 };
865
866 let parse_rgb = |value: &str| {
867 if &value[0..1] != "#" {
868 return Err(E::custom("expected string to begin with '#'"));
869 }
870
871 let r = parse_component(&value[1..3])?;
872 let g = parse_component(&value[3..5])?;
873 let b = parse_component(&value[5..7])?;
874
875 Ok((r, g, b))
876 };
877
878 match value.len() {
879 7 => {
880 let (r, g, b) = parse_rgb(value)?;
881 Ok(Color::Rgb { r, g, b })
882 }
883 9 => {
884 let (r, g, b) = parse_rgb(value)?;
885 let a = parse_component(&value[7..9])?;
886 Ok(Color::Rgba { r, g, b, a })
887 }
888 _ => Err(E::invalid_length(value.len(), &self)),
889 }
890 }
891 }
892
893 deserializer.deserialize_str(Visitor)
894 }
895}
896
897#[cfg(test)]
898mod test {
899 use super::Color;
900
901 #[test]
902 fn color() {
903 let color_a = Color::Rgb {
904 r: 0x12,
905 g: 0x34,
906 b: 0x56,
907 };
908 let color_b = Color::Rgba {
909 r: 0x12,
910 g: 0x12,
911 b: 0x12,
912 a: 0x12,
913 };
914
915 let as_json = r##"["#123456","#12121212"]"##;
916 let colors: Vec<Color> = serde_json::from_str(as_json).expect("array of colors");
917
918 assert_eq!(2, colors.len());
919 assert_eq!(color_a, colors[0]);
920 assert_eq!(color_b, colors[1]);
921
922 let json_str: String = serde_json::to_string(&vec![color_a, color_b]).expect("JSON array");
923 assert_eq!(as_json, json_str);
924 }
925}