diff --git a/NUGET.md b/NUGET.md index e064677..219f2bc 100644 --- a/NUGET.md +++ b/NUGET.md @@ -7,20 +7,10 @@ **Author's website and contact information:** [https://barraider.com](https://barraider.com) ** Samples of plugins using this framework: [Samples][1] -### Version 3.1 is out! -- Updated Logger class to include process name and thread id -- Updated [StreamDeck-Tools Template](https://github.com/BarRaider/streamdeck-tools/raw/master/utils/StreamDeck-Tools%20Template.vsix) for Visual Studio - -### Version 3.0 is out! -- Updated file handling in `Tools.AutoPopulateSettings` and `Tools.FilenameFromPayload` methods -- Removed obsolete MD5 functions, use SHA512 functions instead -- `Tools.CenterText` function now has optional out `textFitsImage` value to verify the text does not exceed the image width -- New `Tools.FormatBytes` function converts bytes to human-readable value -- New `Tools.FormatNumber()` function converts 54265 to 54.27k -- New `Graphics.GetFontSizeWhereTextFitsImage` function helps locate the best size for a text to fit an image on 1 line -- New ExtensionMethods for `Graphics` object: `DrawAndMeasureString` / `GetTextCenter` -- Updated dependency packages to latest versions -- Bug fix where FileNameProperty attribute +### Version 3.2 is out! +- Created new `ISDConnection` interface which is now implemented by SDConnection and used by PluginAction. +- GlobalSettingsManager now has a short delay before calling GetGlobalSettings(), to reduce spamming the Stream Deck SDK. +- Updated dependencies to latest version ## Features - Sample plugin now included in this project on Github diff --git a/README.md b/README.md index ea6491f..9860c7d 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,10 @@ * [StreamDeck-Tools Template](https://github.com/BarRaider/streamdeck-tools/raw/master/utils/StreamDeck-Tools%20Template.vsix) for Visual Studio - Automatically creates a project with all the files needed to compile a plugin * [Profiles](https://barraider.com/profiles) Downloadable empty profiles for the XL (32-key), Classic (15-key), Mini (6-key) and Mobile devices at https://barraider.com/profiles -### Version 3.1 is out! -- Updated Logger class to include process name and thread id -- Updated [StreamDeck-Tools Template](https://github.com/BarRaider/streamdeck-tools/raw/master/utils/StreamDeck-Tools%20Template.vsix) for Visual Studio - -### Version 3.0 is out! -- Updated file handling in `Tools.AutoPopulateSettings` and `Tools.FilenameFromPayload` methods -- Removed obsolete MD5 functions, use SHA512 functions instead -- `Tools.CenterText` function now has optional out `textFitsImage` value to verify the text does not exceed the image width -- New `Tools.FormatBytes` function converts bytes to human-readable value -- New `Graphics.GetFontSizeWhereTextFitsImage` function helps locate the best size for a text to fit an image on 1 line -- Updated dependency packages to latest versions -- Bug fix where FileNameProperty attribute +### Version 3.2 is out! +- Created new `ISDConnection` interface which is now implemented by SDConnection and used by PluginAction. +- GlobalSettingsManager now has a short delay before calling GetGlobalSettings(), to reduce spamming the Stream Deck SDK. +- Updated dependencies to latest version ## Features - Sample plugin now included in this project on Github @@ -317,6 +309,7 @@ private void SetGlobalSettings() ``` # Change Log + ### Version 3.1 is out! - Updated Logger class to include process name and thread id diff --git a/SamplePlugin/PluginAction.cs b/SamplePlugin/PluginAction.cs index 987477b..4782968 100644 --- a/SamplePlugin/PluginAction.cs +++ b/SamplePlugin/PluginAction.cs @@ -19,9 +19,11 @@ private class PluginSettings { public static PluginSettings CreateDefaultSettings() { - PluginSettings instance = new PluginSettings(); - instance.OutputFileName = String.Empty; - instance.InputString = String.Empty; + PluginSettings instance = new PluginSettings + { + OutputFileName = String.Empty, + InputString = String.Empty + }; return instance; } @@ -35,10 +37,10 @@ public static PluginSettings CreateDefaultSettings() #region Private Members - private PluginSettings settings; + private readonly PluginSettings settings; #endregion - public PluginAction(SDConnection connection, InitialPayload payload) : base(connection, payload) + public PluginAction(ISDConnection connection, InitialPayload payload) : base(connection, payload) { if (payload.Settings == null || payload.Settings.Count == 0) { diff --git a/barraider-sdtools/Backend/ISDConnection.cs b/barraider-sdtools/Backend/ISDConnection.cs new file mode 100644 index 0000000..448a28e --- /dev/null +++ b/barraider-sdtools/Backend/ISDConnection.cs @@ -0,0 +1,204 @@ +using BarRaider.SdTools.Events; +using BarRaider.SdTools.Wrappers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Text; +using System.Threading.Tasks; + +namespace BarRaider.SdTools +{ + /// + /// Interface for a Stream Deck connection + /// + public interface ISDConnection : IDisposable + { + #region Events + + /// + /// Event received by the plugin when the Property Inspector uses the sendToPlugin event. + /// + event EventHandler> OnSendToPlugin; + /// + /// Event received when the user changes the title or title parameters. + /// + event EventHandler> OnTitleParametersDidChange; + /// + /// Event received when a monitored application is terminated + /// + event EventHandler> OnApplicationDidTerminate; + /// + /// Event received when a monitored application is launched + /// + event EventHandler> OnApplicationDidLaunch; + /// + /// Event received when a device is unplugged from the computer + /// + event EventHandler> OnDeviceDidDisconnect; + /// + /// Event received when a device is plugged to the computer. + /// + event EventHandler> OnDeviceDidConnect; + /// + /// Event received when the Property Inspector appears in the Stream Deck software user interface, for example when selecting a new instance. + /// + event EventHandler> OnPropertyInspectorDidAppear; + /// + /// Event received when the Property Inspector for an instance is removed from the Stream Deck software user interface, for example when selecting a different instance. + /// + event EventHandler> OnPropertyInspectorDidDisappear; + + #endregion + + #region Methods + + /// + /// Send settings to the PropertyInspector + /// + /// + /// + Task SendToPropertyInspectorAsync(JObject settings); + + /// + /// Persists your plugin settings + /// + /// + /// + Task SetSettingsAsync(JObject settings); + + /// + /// Persists your global plugin settings + /// + /// Settings to save globally + /// Boolean whether to also trigger a didReceiveGlobalSettings event. Default is true + /// + Task SetGlobalSettingsAsync(JObject settings, bool triggerDidReceiveGlobalSettings = true); + + /// + /// Persists your global plugin settings + /// + /// + Task GetGlobalSettingsAsync(); + + /// + /// Sets an image on the StreamDeck key. + /// + /// Base64 encoded image + /// A 0-based integer value representing the state of an action with multiple states. This is an optional parameter. If not specified, the title is set to all states. + /// Should image be sent even if it is identical to the one sent previously. Default is false + /// + Task SetImageAsync(string base64Image, int? state = null, bool forceSendToStreamdeck = false); + + /// + /// Sets an image on the StreamDeck key + /// + /// Image object + /// A 0-based integer value representing the state of an action with multiple states. This is an optional parameter. If not specified, the title is set to all states. + /// Should image be sent even if it is identical to the one sent previously. Default is false + /// + Task SetImageAsync(Image image, int? state = null, bool forceSendToStreamdeck = false); + + /// + /// Sets the default image for this state, as configured in the manifest + /// + /// + Task SetDefaultImageAsync(); + + /// + /// Sets a title on the StreamDeck key + /// + /// + /// A 0-based integer value representing the state of an action with multiple states. This is an optional parameter. If not specified, the title is set to all states. + /// + Task SetTitleAsync(string title, int? state = null); + + /// + /// Switches to one of the plugin's built-in profiles + /// + /// + /// + Task SwitchProfileAsync(string profileName); + + /// + /// Switches to one of the plugin's built-in profiles. Allows to choose which device to switch it on. + /// + /// + /// + /// + Task SwitchProfileAsync(string profileName, string deviceId); + + /// + /// Shows the Alert (Yellow Triangle) on the StreamDeck key + /// + /// + Task ShowAlert(); + + /// + /// Shows the Success (Green checkmark) on the StreamDeck key + /// + /// + Task ShowOk(); + + /// + /// Add a message to the Stream Deck log. This is the log located at: %appdata%\Elgato\StreamDeck\logs\StreamDeck0.log + /// + /// + /// + Task LogSDMessage(string message); + + /// + /// Gets the Stream Deck device's info + /// + /// + StreamDeckDeviceInfo DeviceInfo(); + + /// + /// Tells Stream Deck to return the current plugin settings via the ReceivedSettings function + /// + /// + Task GetSettingsAsync(); + + /// + /// Opens a URI in the user's browser + /// + /// + /// + Task OpenUrlAsync(string uri); + + /// + /// Opens a URI in the user's browser + /// + /// + /// + Task OpenUrlAsync(Uri uri); + + /// + /// Sets the plugin to a specific state which is pre-configured in the manifest file + /// + /// + /// + Task SetStateAsync(uint state); + + #endregion + + /// + /// An opaque value identifying the plugin. This value is received during the Registration procedure + /// + [JsonIgnore] + String ContextId { get; } + + /// + /// An opaque value identifying the device the plugin is launched on. + /// + [JsonIgnore] + String DeviceId { get; } + + /// + /// StreamDeckConnection object, initialized based on the args received when launching the program + /// + [JsonIgnore] + streamdeck_client_csharp.StreamDeckConnection StreamDeckConnection { get; } + } +} diff --git a/barraider-sdtools/Backend/SDConnection.cs b/barraider-sdtools/Backend/SDConnection.cs index 38805b0..fb55a79 100644 --- a/barraider-sdtools/Backend/SDConnection.cs +++ b/barraider-sdtools/Backend/SDConnection.cs @@ -13,12 +13,27 @@ namespace BarRaider.SdTools /// /// Connection object which handles your communication with the Stream Deck app /// - public class SDConnection : IDisposable + public class SDConnection : ISDConnection { - #region Private Methods + #region Private Members private string previousImageHash = null; + [JsonIgnore] + private readonly string actionId; + + /// + /// An opaque value identifying the plugin. Received as an argument when the executable was launched. + /// + [JsonIgnore] + private readonly string pluginUUID; + + /// + /// Holds information about the devices connected to the computer + /// + [JsonIgnore] + private readonly StreamDeckInfo deviceInfo; + #endregion #region Public Events @@ -396,24 +411,5 @@ private void Connection_OnSendToPlugin(object sender, streamdeck_client_csharp.S } #endregion - - #region Private Members - - [JsonIgnore] - private readonly string actionId; - - /// - /// An opaque value identifying the plugin. Received as an argument when the executable was launched. - /// - [JsonIgnore] - private readonly string pluginUUID; - - /// - /// Holds information about the devices connected to the computer - /// - [JsonIgnore] - private readonly StreamDeckInfo deviceInfo; - - #endregion } } diff --git a/barraider-sdtools/Tools/GlobalSettingsManager.cs b/barraider-sdtools/Tools/GlobalSettingsManager.cs index 746facd..3177f8e 100644 --- a/barraider-sdtools/Tools/GlobalSettingsManager.cs +++ b/barraider-sdtools/Tools/GlobalSettingsManager.cs @@ -13,8 +13,19 @@ namespace BarRaider.SdTools public class GlobalSettingsManager { #region Private Static Members + private static GlobalSettingsManager instance = null; private static readonly object objLock = new object(); + + #endregion + + #region Private Members + + private const int GET_GLOBAL_SETTINGS_DELAY_MS = 300; + + private StreamDeckConnection connection; + private readonly System.Timers.Timer tmrGetGlobalSettings = new System.Timers.Timer(); + #endregion #region Constructor @@ -44,16 +55,13 @@ public static GlobalSettingsManager Instance private GlobalSettingsManager() { + tmrGetGlobalSettings.Interval = GET_GLOBAL_SETTINGS_DELAY_MS; + tmrGetGlobalSettings.Elapsed += TmrGetGlobalSettings_Elapsed; + tmrGetGlobalSettings.AutoReset = true; } #endregion - #region Private Members - - StreamDeckConnection connection; - - #endregion - #region Public Methods /// @@ -62,10 +70,13 @@ private GlobalSettingsManager() public event EventHandler OnReceivedGlobalSettings; - internal void Initialize(StreamDeckConnection connection) + internal void Initialize(StreamDeckConnection connection, int getGlobalSettingsDelayMs = GET_GLOBAL_SETTINGS_DELAY_MS) { this.connection = connection; this.connection.OnDidReceiveGlobalSettings += Connection_OnDidReceiveGlobalSettings; + + tmrGetGlobalSettings.Stop(); + tmrGetGlobalSettings.Interval = getGlobalSettingsDelayMs; Logger.Instance.LogMessage(TracingLevel.INFO, "GlobalSettingsManager initialized"); } @@ -73,16 +84,16 @@ internal void Initialize(StreamDeckConnection connection) /// Command to request the Global Settings. Use the OnDidReceiveGlobalSSettings callback function to receive the Global Settings. /// /// - public Task RequestGlobalSettings() + public void RequestGlobalSettings() { if (connection == null) { Logger.Instance.LogMessage(TracingLevel.ERROR, "GlobalSettingsManager::RequestGlobalSettings called while connection is null"); - return null; + return; } Logger.Instance.LogMessage(TracingLevel.INFO, "GlobalSettingsManager::RequestGlobalSettings called"); - return connection.GetGlobalSettingsAsync(); + tmrGetGlobalSettings.Start(); } /// @@ -104,7 +115,7 @@ public async Task SetGlobalSettings(JObject settings, bool triggerDidReceiveGlob if (triggerDidReceiveGlobalSettings) { - await connection.GetGlobalSettingsAsync(); + tmrGetGlobalSettings.Start(); } } @@ -118,6 +129,14 @@ private void Connection_OnDidReceiveGlobalSettings(object sender, StreamDeckEven OnReceivedGlobalSettings?.Invoke(this, JObject.FromObject(e.Event.Payload).ToObject()); } + private async void TmrGetGlobalSettings_Elapsed(object sender, System.Timers.ElapsedEventArgs e) + { + tmrGetGlobalSettings.Stop(); + + Logger.Instance.LogMessage(TracingLevel.INFO, "GlobalSettingsManager::GetGlobalSettingsAsync triggered"); + await connection.GetGlobalSettingsAsync(); + } + #endregion } } diff --git a/barraider-sdtools/Tools/PluginBase.cs b/barraider-sdtools/Tools/PluginBase.cs index 46c3586..26ba33d 100644 --- a/barraider-sdtools/Tools/PluginBase.cs +++ b/barraider-sdtools/Tools/PluginBase.cs @@ -63,7 +63,7 @@ public void Destroy() /// /// Connection object which handles your communication with the Stream Deck app /// - protected SDConnection Connection { get; private set; } + protected ISDConnection Connection { get; private set; } /// /// Constructor for PluginBase. Receives the communication and plugin settings @@ -83,7 +83,7 @@ public void Destroy() /// Communication module with Stream Deck /// Plugin settings - NOTE: Not used in base class, should be consumed by deriving class #pragma warning disable IDE0060 // Remove unused parameter - public PluginBase(SDConnection connection, InitialPayload payload) + public PluginBase(ISDConnection connection, InitialPayload payload) #pragma warning restore IDE0060 // Remove unused parameter { Connection = connection; diff --git a/barraider-sdtools/barraider-sdtools.csproj b/barraider-sdtools/barraider-sdtools.csproj index 923ef4b..d2733f3 100644 --- a/barraider-sdtools/barraider-sdtools.csproj +++ b/barraider-sdtools/barraider-sdtools.csproj @@ -9,18 +9,20 @@ This library encapsulates all the overhead of setting up the framework, so that [Samples for using the library are provided here: https://github.com/BarRaider/streamdeck-tools] Using this library, you only need to derive from the abstract PluginBase class and add one line of code in your program.cs to have a working plugin. More info and working samples here: https://github.com/BarRaider/streamdeck-tools . Feel free to contact me for more information: https://barraider.com - Copyright © BarRaider 2020 + Copyright © BarRaider 2021 https://github.com/BarRaider/streamdeck-tools/blob/master/LICENSE https://github.com/BarRaider/streamdeck-tools https://github.com/BarRaider/streamdeck-tools StreamDeck Elgato Library Plugin Stream Deck Toolkit StreamDeck-Tools - 3.1.0.0 - 3.1.0.0 - 3.1 - 3.1 - 1. Updated Logger class to include process name and thread id -2. Updated StreamDeck-Tools template for Visual Studio + 3.2.0.0 + 3.2.0.0 + 3.2 + 3.2 - 1. Created new ISDConnection interface which is now implemented by SDConnection and used by PluginAction. +2. GlobalSettingsManager now has a short delay before calling GetGlobalSettings, to reduce spamming the Stream Deck SDK. +3. Updated dependencies to latest version + BarRaider.SdTools StreamDeckTools BRLogo_460.png @@ -34,8 +36,8 @@ Feel free to contact me for more information: https://barraider.com - - + + diff --git a/streamdeck-tools.xml b/streamdeck-tools.xml index bbf16fd..57f7a0b 100644 --- a/streamdeck-tools.xml +++ b/streamdeck-tools.xml @@ -27,11 +27,208 @@ + + + Interface for a Stream Deck connection + + + + + Event received by the plugin when the Property Inspector uses the sendToPlugin event. + + + + + Event received when the user changes the title or title parameters. + + + + + Event received when a monitored application is terminated + + + + + Event received when a monitored application is launched + + + + + Event received when a device is unplugged from the computer + + + + + Event received when a device is plugged to the computer. + + + + + Event received when the Property Inspector appears in the Stream Deck software user interface, for example when selecting a new instance. + + + + + Event received when the Property Inspector for an instance is removed from the Stream Deck software user interface, for example when selecting a different instance. + + + + + Send settings to the PropertyInspector + + + + + + + Persists your plugin settings + + + + + + + Persists your global plugin settings + + Settings to save globally + Boolean whether to also trigger a didReceiveGlobalSettings event. Default is true + + + + + Persists your global plugin settings + + + + + + Sets an image on the StreamDeck key. + + Base64 encoded image + A 0-based integer value representing the state of an action with multiple states. This is an optional parameter. If not specified, the title is set to all states. + Should image be sent even if it is identical to the one sent previously. Default is false + + + + + Sets an image on the StreamDeck key + + Image object + A 0-based integer value representing the state of an action with multiple states. This is an optional parameter. If not specified, the title is set to all states. + Should image be sent even if it is identical to the one sent previously. Default is false + + + + + Sets the default image for this state, as configured in the manifest + + + + + + Sets a title on the StreamDeck key + + + A 0-based integer value representing the state of an action with multiple states. This is an optional parameter. If not specified, the title is set to all states. + + + + + Switches to one of the plugin's built-in profiles + + + + + + + Switches to one of the plugin's built-in profiles. Allows to choose which device to switch it on. + + + + + + + + Shows the Alert (Yellow Triangle) on the StreamDeck key + + + + + + Shows the Success (Green checkmark) on the StreamDeck key + + + + + + Add a message to the Stream Deck log. This is the log located at: %appdata%\Elgato\StreamDeck\logs\StreamDeck0.log + + + + + + + Gets the Stream Deck device's info + + + + + + Tells Stream Deck to return the current plugin settings via the ReceivedSettings function + + + + + + Opens a URI in the user's browser + + + + + + + Opens a URI in the user's browser + + + + + + + Sets the plugin to a specific state which is pre-configured in the manifest file + + + + + + + An opaque value identifying the plugin. This value is received during the Registration procedure + + + + + An opaque value identifying the device the plugin is launched on. + + + + + StreamDeckConnection object, initialized based on the args received when launching the program + + Connection object which handles your communication with the Stream Deck app + + + An opaque value identifying the plugin. Received as an argument when the executable was launched. + + + + + Holds information about the devices connected to the computer + + Event received by the plugin when the Property Inspector uses the sendToPlugin event. @@ -231,16 +428,6 @@ Dispose (Destructor) function - - - An opaque value identifying the plugin. Received as an argument when the executable was launched. - - - - - Holds information about the devices connected to the computer - - * Easy Configuration Instructions: @@ -1151,7 +1338,7 @@ Connection object which handles your communication with the Stream Deck app - + Constructor for PluginBase. Receives the communication and plugin settings Note that the settings object is not used by the base and should be consumed by the deriving class.