### Example: Get or Create User ID Setting Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/managing-plugin-settings This example demonstrates how to retrieve a user ID setting, generating and saving a new one if it doesn't exist. It uses `TryGetPluginSetting` to check for an existing setting and `SetPluginSetting` to save a new one if necessary. Settings are accessed directly using `this` when in plugin-level code. ```csharp private String GetUserId() { const String SettingName = "UserId"; // first try to get existing user ID if (this.TryGetPluginSetting(SettingName, out var existingUserId)) { return existingUserId; } // if it does not exist, generate a new one and save it var newUserId = Guid.NewGuid().ToString("N"); this.SetPluginSetting(SettingName, newUserId, false); return newUserId; } ``` -------------------------------- ### Install Plugin Dependencies Source: https://logitech.github.io/actions-sdk-docs/nodejs/introduction Navigate to your plugin's directory and run this command to install all necessary project dependencies. ```bash npm install ``` -------------------------------- ### Setting Plugin Status Examples Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/plugin-status Examples demonstrating how to use the `OnPluginStatusChanged` method to set different plugin states. ```APIDOC ## Setting Plugin Status Examples ### To set "normal" state: ```csharp this.OnPluginStatusChanged(PluginStatus.Normal, null); ``` ### To set "warning" state: ```csharp this.OnPluginStatusChanged(PluginStatus.Warning, "Open the application."); ``` ### To set "error" state: ```csharp this.OnPluginStatusChanged(PluginStatus.Error, "Cannot connect to the application.", "https://support.loupedeck.com", "Details"); ``` ### Example Usage within `RunCommand`: ```csharp protected override void RunCommand(String actionParameter) { if (actionParameter.TryGetEnumValue(out var pluginStatus)) { this.Plugin.OnPluginStatusChanged(pluginStatus, $"Plugin status changed to {pluginStatus}."); } } ``` ``` -------------------------------- ### Example LoupedeckPackage.yaml for Spotify Premium Plugin Source: https://logitech.github.io/actions-sdk-docs/csharp/tutorial/plugin-structure An example of a complete LoupedeckPackage.yaml file for a Spotify Premium plugin, demonstrating support for both Windows and Mac. ```yaml type: plugin4 name: SpotifyPremium displayName: Spotify Premium version: 1.0 author: Logitech copyright: Logitech backgroundColor: 4278869247 foregroundColor: 4294967295 textColor: 4294967295 supportedDevices: - LoupedeckCt - LoupedeckLive pluginFileName: SpotifyPremiumPlugin.dll pluginFolderWin: bin/win/ pluginFolderMac: bin/mac/ license: MIT licenseUrl: https://opensource.org/licenses/MIT homePageUrl: https://logitech.com supportPageUrl: https://support.logitech.com/f-a-q-support ``` -------------------------------- ### Plugin Account Preference Setup and Event Handling Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/external-service-login This C# code demonstrates how to create and configure a PluginPreferenceAccount, subscribe to login and logout events, and handle the reporting of authentication status to the external service. It includes setup in the constructor and event subscription/unsubscription in Load/Unload methods. ```csharp public class MyPlugin : Plugin { private readonly PluginPreferenceAccount _myAccount; public MyPlugin() { // Create an account preference this._myAccount = new PluginPreferenceAccount("my-account") { DisplayName = "My account", IsRequired = true, LoginUrlTitle = "Sign in", LogoutUrlTitle = "Sign out" }; // Add the preference to the list this.PluginPreferences.Add(this._myAccount); } public override void Load() { // Subscribe to login/logout requests this._myAccount.LoginRequested += this.OnMyAccountLoginRequested; this._myAccount.LogoutRequested += this.OnMyAccountLogoutRequested; } public override void Unload() { // Unsubscribe from login/logout requests this._myAccount.LoginRequested -= this.OnMyAccountLoginRequested; this._myAccount.LogoutRequested -= this.OnMyAccountLogoutRequested; } private void OnMyAccountLoginRequested(Object sender, EventArgs e) { // Login to external service to get access token and refresh token (if it exists) // ... // Set user name, access token and refresh token this._myAccount.ReportLogin("ExternalServiceUserName", "ExternalServiceAccessToken", "ExternalServiceRefreshToken"); } private void OnMyAccountLogoutRequested(Object sender, EventArgs e) { // Logout from external service // ... // Clear user name, access token and refresh token this._myAccount.ReportLogout(); } } ``` -------------------------------- ### Minimal Example: Toggle Multistate Dynamic Command Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/multistate-plugin-actions This example demonstrates a simple multistate command that toggles between 'On' and 'Off' states using `ToggleCurrentState()`. ```csharp namespace Loupedeck.Test4Plugin { using System; public class ToggleMultistateDynamicCommand : PluginMultistateDynamicCommand { public ToggleMultistateDynamicCommand() : base("Toggle Multistate", null, "Test") { this.AddState("On", "Turn me on"); this.AddState("Off", "Turn me off"); } protected override void RunCommand(String actionParameter) => this.ToggleCurrentState(); } } ``` -------------------------------- ### Minimal Example: ToggleMultistateDynamicCommand Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/multistate-plugin-actions A basic example demonstrating the creation of a multistate dynamic command that toggles between 'On' and 'Off' states. ```APIDOC ## Minimal Example ### Description This example shows a simple implementation of a multistate dynamic command that toggles between two states: 'On' and 'Off'. ### Class Definition ```csharp namespace Loupedeck.Test4Plugin { using System; public class ToggleMultistateDynamicCommand : PluginMultistateDynamicCommand { public ToggleMultistateDynamicCommand() : base("Toggle Multistate", null, "Test") { this.AddState("On", "Turn me on"); this.AddState("Off", "Turn me off"); } protected override void RunCommand(String actionParameter) => this.ToggleCurrentState(); } } ``` ``` -------------------------------- ### Define Plugin Installation Capabilities Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/plugin-capabilities Use the `pluginCapabilities` field in `LoupedeckPackage.yaml` to specify special installation and runtime requirements for your plugin. ```yaml pluginCapabilities: - RequiresAdminInstallation - RequiresAdminUninstallation - RequireApplicationCloseOnInstallWin - RequireApplicationCloseOnInstallMac ``` -------------------------------- ### Install a Plugin using Logi Plugin Tool Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/install-and-uninstall Use this command to install a plugin package (.lplug4) with the Logi Plugin Tool. ```bash logiplugintool install Example.lplug4 ``` -------------------------------- ### Check Logi Plugin Tool Installation Source: https://logitech.github.io/actions-sdk-docs/csharp/haptics/haptics-tutorial Verifies that the Logi Plugin Tool has been installed correctly by displaying its available commands. ```bash LogiPluginTool --help ``` -------------------------------- ### Install node-notifier Package Source: https://logitech.github.io/actions-sdk-docs/nodejs/working-with-external-packages Install the node-notifier package as a dependency for your plugin. ```bash npm install --save node-notifier ``` -------------------------------- ### Install Logi Plugin Tool Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-development/introduction Installs the LogiPluginTool package globally as a .NET tool. This tool is used for creating, packaging, and verifying C# plugin projects. ```bash dotnet tool install --global LogiPluginTool ``` -------------------------------- ### Start Hot Reloading (Windows) Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-development/introduction Navigates to the plugin's src directory and starts the .NET watch command to enable hot reloading. This automatically rebuilds and reloads the plugin when source files change. ```bash cd ExamplePlugin\src\ dotnet watch build ``` -------------------------------- ### Start Hot Reloading (macOS) Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-development/introduction Navigates to the plugin's src directory and starts the .NET watch command to enable hot reloading. This automatically rebuilds and reloads the plugin when source files change. ```bash cd ExamplePlugin/src/ dotnet watch build ``` -------------------------------- ### Generate a C# Plugin Project Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-development/introduction Creates a new C# plugin project using the Logi Plugin Tool. Replace 'Example' with your desired plugin name. ```bash logiplugintool generate Example ``` -------------------------------- ### Get and Read Image Resources Source: https://logitech.github.io/actions-sdk-docs/csharp/tutorial/change-a-button-image Use PluginResources.FindFile to get the resource name and PluginResources.ReadImage to load the image. Ensure 'MyImage.png' is present in your plugin resources. ```csharp String resourceName = PluginResources.FindFile("MyImage.png"); BitmapImage myImage = PluginResources.ReadImage(resourceName); ``` -------------------------------- ### Example: Changing Plugin Status Dynamically Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/plugin-status This example demonstrates how to dynamically change the plugin status based on an action parameter. It attempts to parse the parameter as a PluginStatus enum value. ```csharp protected override void RunCommand(String actionParameter) { if (actionParameter.TryGetEnumValue(out var pluginStatus)) { this.Plugin.OnPluginStatusChanged(pluginStatus, $"Plugin status changed to {pluginStatus}."); } } ``` -------------------------------- ### ActionEditorKeyboardKey Example Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/action-editor-actions Adds a keyboard shortcut capture control for defining hotkeys. ```csharp this.ActionEditor.AddControlEx( new ActionEditorKeyboardKey(name: "KeyControl", labelText: "Shortcut:") .SetBehavior(ActionEditorKeyboardKeyBehavior.KeyboardKey)); ``` -------------------------------- ### List All Plugin Setting Names Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/managing-plugin-settings Use `ListPluginSettings` to get an array of all available plugin setting names. ```csharp protected String[] ListPluginSettings(); ``` -------------------------------- ### Build and Package Distributable Plugin Source: https://logitech.github.io/actions-sdk-docs/nodejs/introduction This command creates a minified build of the plugin and packages it into a `.lplug4` format, suitable for installation on devices running the Logi Plugin Service. ```bash npm run build:pack ``` -------------------------------- ### ActionEditorDirectorySelector Example Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/action-editor-actions Adds a directory browser control for selecting folders. ```csharp this.ActionEditor.AddControlEx( new ActionEditorDirectorySelector(name: "DirectoryControl", labelText: "Select directory:")); ``` -------------------------------- ### ActionEditorFileSelector Example Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/action-editor-actions Adds a file browser control for selecting files, with an option to set the initial directory. ```csharp this.ActionEditor.AddControlEx( new ActionEditorFileSelector(name: "FileControl", labelText: "Select file:") .SetInitialDirectory(Environment.GetFolderPath(Environment.SpecialFolder.Desktop))); ``` -------------------------------- ### Get Plugin Data Directory and Ensure Existence Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/storing-plugin-data Use Plugin.GetPluginDataDirectory() to retrieve the plugin's data folder path. Call IoHelpers.EnsureDirectoryExists() to create the directory if it doesn't exist, then proceed to write data to a file within it. ```csharp var pluginDataDirectory = this.GetPluginDataDirectory(); if (IoHelpers.EnsureDirectoryExists(pluginDataDirectory)) { var filePath = Path.Combine(pluginDataDirectory, "MyData.bin"); using (var streamWriter = new StreamWriter(filePath)) { // Write data } } ``` -------------------------------- ### Link Plugin to Logi Plugin Service Source: https://logitech.github.io/actions-sdk-docs/nodejs/introduction If you used the `build` script, run this command to create a symlink for the plugin from the `dist` folder to the Logi Plugin Service's installed plugins directory. ```bash npm run link ``` -------------------------------- ### Define Application Patterns for Installation Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/plugin-capabilities The `applicationPatterns` field is required when using application close capabilities. It defines regex expressions to identify supported applications. ```yaml applicationPatterns: processNamePattern: ^lightroom$ bundleNamePattern: ^com.adobe.LightroomClassicCC7$ displayNamePattern: ^Adobe Lightroom Classic$ executablePathPattern: Adobe Lightroom Classic\\lightroom.exe$ ``` -------------------------------- ### Getting All Action States Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/multistate-plugin-actions Retrieve a read-only list of all defined states for a multistate dynamic command. ```APIDOC ## States ### Description Gets a read-only list of all available states for the multistate dynamic command. ### Property ```csharp public IReadOnlyList States { get; } ``` ### Remarks This property is null by default and is initialized upon the first call to `AddState()`. ``` -------------------------------- ### Inherit from PluginDynamicAdjustment Source: https://logitech.github.io/actions-sdk-docs/csharp/tutorial/add-a-simple-adjustment Start by creating a new class that inherits from the PluginDynamicAdjustment class to define a new adjustment. ```csharp public class CounterAdjustment : PluginDynamicAdjustment ``` -------------------------------- ### Execute Command Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/implementing-dynamic-folders Override RunCommand to execute a command when it is triggered. This example shows parsing an actionParameter as a process ID. ```csharp public override void RunCommand(String actionParameter) { if (Int32.TryParse(actionParameter, out var processId)) { // Implement process activation logic with the given processId } } ``` -------------------------------- ### Implement Command Execution Source: https://logitech.github.io/actions-sdk-docs/csharp/tutorial/add-a-simple-command Override the RunCommand method to define the action performed when the command is triggered. This example sends a virtual key code to toggle mute. ```csharp protected override void RunCommand(String actionParameter) { this.Plugin.ClientApplication.SendKeyboardShortcut(VirtualKeyCode.VolumeMute); } ``` -------------------------------- ### Initialize PluginSDK with Options Source: https://logitech.github.io/actions-sdk-docs/nodejs/api/html/types/PluginSDKOptions.html Demonstrates how to instantiate the PluginSDK, either with a custom log level or using default options. The logLevel property controls the verbosity of SDK output. ```javascript import { PluginSDK, LoggerLevel } from '@logitech/plugin-sdk'; // With custom log level const sdk = new PluginSDK({ logLevel: LoggerLevel.DEBUG }); // Using default options const sdk = new PluginSDK(); ``` -------------------------------- ### Generate Plugin Project Source: https://logitech.github.io/actions-sdk-docs/csharp/haptics/haptics-tutorial Creates a new plugin project skeleton named 'Tutorial' using the Logi Plugin Tool. This command generates the necessary file structure for a new plugin. ```bash LogiPluginTool generate Tutorial ``` -------------------------------- ### Initialize and Connect PluginSDK Source: https://logitech.github.io/actions-sdk-docs/nodejs/api/html/classes/PluginSDK.html Instantiate the PluginSDK, register custom actions, and then establish a connection to the Logi Plugin Service. Ensure all actions are registered prior to calling connect. ```typescript import { PluginSDK } from '@logitech/plugin-sdk'; import { MyCustomAction } from './actions/my-custom-action'; const sdk = new PluginSDK(); // Register your custom actions const myAction = new MyCustomAction(); sdk.registerAction(myAction); // Connect to the Logi Plugin Service await sdk.connect(); ``` -------------------------------- ### Build a C# Plugin Project Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-development/introduction Navigates to the generated plugin project directory and builds the solution. This command compiles your plugin code. ```bash cd ExamplePlugin dotnet build ``` -------------------------------- ### Create PluginSDK Instance with Options Source: https://logitech.github.io/actions-sdk-docs/nodejs/api/html/classes/PluginSDK.html Instantiate the PluginSDK with various configuration options, including setting the logger level. Defaults to WARN if no options are provided. ```typescript import { PluginSDK, LoggerLevel } from '@logitech/plugin-sdk'; // Create SDK with default options (WARN log level) const sdk = new PluginSDK(); // Create SDK with custom log level const debugSdk = new PluginSDK({ logLevel: LoggerLevel.DEBUG }); // Create SDK with minimal logging const quietSdk = new PluginSDK({ logLevel: LoggerLevel.ERROR }); ``` -------------------------------- ### Action Editor Lifecycle Event Handling Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/action-editor-actions Handles Action Editor start and finish lifecycle events by subscribing to the Started and Finished events for initialization and cleanup tasks. ```csharp // ... public MyActionEditorCommand() { // ... // Subscribe to Action Editor lifecycle events this.ActionEditor.Started += this.OnActionEditorStarted; this.ActionEditor.Finished += this.OnActionEditorFinished; } private void OnActionEditorStarted(Object sender, ActionEditorStartedEventArgs e) { // Called when user opens the Action Editor // Initialize any resources, start monitoring external data, etc. } private void OnActionEditorFinished(Object sender, ActionEditorFinishedEventArgs e) { // Called when user closes the Action Editor // Clean up resources, stop monitoring external data, save temporary data, etc. } ``` -------------------------------- ### Create PluginSDK Instance Source: https://logitech.github.io/actions-sdk-docs/nodejs/using-sdk Instantiate the PluginSDK class to create a new SDK instance. ```javascript const pluginSDK = new PluginSDK(); ``` -------------------------------- ### Create a New Plugin with Node.js SDK Source: https://logitech.github.io/actions-sdk-docs/nodejs/introduction Use this command to create a new plugin project. Specify your desired plugin name. Add the `--javascript` flag if you prefer JavaScript over TypeScript. ```bash npx @logitech/plugin-toolkit create ``` -------------------------------- ### ActionEditorButton Example Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/action-editor-actions Adds an interactive button control for triggering actions within the editor. ```csharp this.ActionEditor.AddControlEx( new ActionEditorButton(name: "ButtonControl", labelText: "Click me")); ``` -------------------------------- ### ActionEditorCheckbox Example Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/action-editor-actions Adds a boolean toggle control for true/false options to the Action Editor. ```csharp this.ActionEditor.AddControlEx( new ActionEditorCheckbox(name: "CheckboxControl", labelText: "Enable feature:") .SetDefaultValue(false)); ``` -------------------------------- ### Write Plugin Setting Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/managing-plugin-settings Use `SetPluginSetting` to save a plugin setting. Set `backupOnline` to `true` to back up the setting in the cloud, or `false` to keep it only locally. ```csharp protected void SetPluginSetting(String settingName, String settingValue, Boolean backupOnline); ``` -------------------------------- ### Verify Plugin Build Output (Windows) Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-development/introduction Shows the expected path for the .link file on Windows after a successful build. This file is used by the Logi Plugin Service to locate the plugin. ```text C:\Users\USERNAME\AppData\Local\Logi\LogiPluginService\Plugins\ExamplePlugin.link ``` -------------------------------- ### Get Adjustment Value Source: https://logitech.github.io/actions-sdk-docs/csharp/tutorial/add-a-simple-adjustment Implement the GetAdjustmentValue method to return the current counter value as a string for display. ```csharp protected override String GetAdjustmentValue(String actionParameter) => this._counter.ToString(); ``` -------------------------------- ### List All Settings Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/managing-plugin-settings Retrieves an array of all available plugin setting names. ```APIDOC ## List All Settings ### Description Returns a list of all plugin setting names. ### Method Signature ```csharp protected String[] ListPluginSettings() ``` ### Returns - **String[]** - An array of strings, where each string is a setting name. ``` -------------------------------- ### Register Multiple Actions and Connect Source: https://logitech.github.io/actions-sdk-docs/nodejs/using-sdk Register multiple actions and then connect to the Logi Plugin Service. All actions must be registered prior to calling connect. ```javascript pluginSDK.registerAction(new MyTestAction()); pluginSDK.registerAction(new MyTestAction2()); await pluginSDK.connect(); ``` -------------------------------- ### Pack Plugin to .lplug4 File Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-development/distributing-the-plugin Use the Logi Plugin Tool with the 'pack' command to create a .lplug4 distribution file. Specify the output directory and the desired package name. ```bash logiplugintool pack ./bin/Release/ ./Example.lplug4 ``` -------------------------------- ### ActionEditorSlider Example Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/action-editor-actions Adds a numeric slider control for value selection within a defined range, with custom formatting. ```csharp this.ActionEditor.AddControlEx( new ActionEditorSlider(name: "SliderControl", labelText: "Volume:", description: "Adjust volume level") .SetValues(minimumValue: 0, maximumValue: 100, defaultValue: 50, step: 5) .SetFormatString("{0}%")); ``` -------------------------------- ### Get Adjustment Value Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/implementing-dynamic-folders Override GetAdjustmentValue to return the current value of an adjustment. Returns null if the value is not available. ```csharp public override String GetAdjustmentValue(String actionParameter) => this.TryGetVolume(actionParameter, out var volume) ? volume.ToString("D") : null; ``` -------------------------------- ### connect Source: https://logitech.github.io/actions-sdk-docs/nodejs/api/html/classes/PluginSDK.html Establishes a connection to the Logi Plugin Service. This method must be called after registering all actions. ```APIDOC ## connect * connect(): Promise ### Description Establishes connection to the Logi Plugin Service. This method connects the plugin to the Logi Plugin Service via WebSocket, enables communication, and sets up graceful shutdown handling. Must be called after registering all actions. ### Returns Promise Promise that resolves when connection is established ### Throws Will log errors if connection fails ### Example ```javascript const sdk = new PluginSDK(); // Register actions first sdk.registerAction(new MyAction()); // Then connect try { await sdk.connect(); console.log('Plugin connected successfully'); } catch (error) { console.error('Failed to connect:', error); } ``` ``` -------------------------------- ### Get Command Image Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/implementing-dynamic-folders Override GetCommandImage to provide a custom image for a command. Returns null if no image is available. ```csharp public override BitmapImage GetCommandImage(String actionParameter, PluginImageSize imageSize) => this.TryGetNativeApplication(actionParameter, out var app) ? app.Icon?.ToImage() : null; ``` -------------------------------- ### Get Command Display Name Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/implementing-dynamic-folders Override GetCommandDisplayName to provide a custom display name for a command. Returns null if not available. ```csharp public override String GetCommandDisplayName(String actionParameter, PluginImageSize imageSize) => this.TryGetNativeApplication(actionParameter, out var app) ? app.DisplayName : "Unknown"; ``` -------------------------------- ### Getting the State Image Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/multistate-plugin-actions Retrieve the image for a specific state of a multistate dynamic command, considering the device state and image size. ```APIDOC ## GetCommandImage ### Description Gets the image for a specific state of the command, used for actions with multiple states. ### Method Signature ```csharp protected virtual BitmapImage GetCommandImage(String actionParameter, Int32 deviceState, PluginImageSize imageSize); ``` ### Parameters * **actionParameter** (String) - The parameter associated with the action. * **deviceState** (Int32) - The index of the device state. * **imageSize** (PluginImageSize) - The desired size of the image associated with the state. ### Return Value A `BitmapImage` representing the state's image. ``` -------------------------------- ### Verify Plugin Build Output (macOS) Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-development/introduction Shows the expected path for the .link file on macOS after a successful build. This file is used by the Logi Plugin Service to locate the plugin. ```text /Users/USERNAME/Library/Application Support/Logi/LogiPluginService/Plugins/ExamplePlugin.link ``` -------------------------------- ### Get Current Action State Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/multistate-plugin-actions Use `TryGetCurrentState()` to retrieve the current state index, with an optional overload for specific action parameters. ```csharp public Boolean TryGetCurrentState(out Int32 currentState); public Boolean TryGetCurrentState(String actionParameter, out Int32 currentState); ``` -------------------------------- ### Create Profile Action (list) Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/profile-actions Implement a profile action of type 'list' where the user selects an item from a combo box. The selected item is then used to change the plugin status. ```csharp public class DynamicListProfileAction : PluginDynamicCommand { public DynamicListProfileAction() { this.DisplayName = "Dynamic List"; this.GroupName = "Profile Actions"; for (var i = 0; i < 5; i++) { this.AddParameter($"item{i}", $"Item {i}", this.GroupName); } } } ``` ```csharp this.MakeProfileAction("list;Select parameter:"); ``` ```csharp protected override void RunCommand(String actionParameter) => this.Plugin.OnPluginStatusChanged(PluginStatus.Warning, actionParameter); ``` -------------------------------- ### Getting the State Display Name Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/multistate-plugin-actions Retrieve the display name for a specific state of a multistate dynamic command, considering the device state and image size. ```APIDOC ## GetCommandDisplayName ### Description Gets the display name for a specific state of the command, used for actions with multiple states. ### Method Signature ```csharp protected virtual String GetCommandDisplayName(String actionParameter, Int32 deviceState, PluginImageSize imageSize); ``` ### Parameters * **actionParameter** (String) - The parameter associated with the action. * **deviceState** (Int32) - The index of the device state. * **imageSize** (PluginImageSize) - The desired size of the image associated with the state. ``` -------------------------------- ### Initialize Image Resource Paths Source: https://logitech.github.io/actions-sdk-docs/csharp/tutorial/change-a-button-image Initializes string members with the paths to image resources using `PluginResources.FindFile()`. Ensure images are embedded resources in the plugin project. ```csharp private readonly String _imageResourcePathThumbUp; private readonly String _imageResourcePathThumbDown; public ThumbUpDownCommand() : base(displayName: "Thumb up/down", description: null, groupName: "Switches") { this._imageResourcePathThumbUp = PluginResources.FindFile("ThumbUp.png"); this._imageResourcePathThumbDown = PluginResources.FindFile("ThumbDown.png"); } ``` -------------------------------- ### Getting the Current Action State Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/multistate-plugin-actions Safely retrieve the current state index of a multistate dynamic command, with an optional overload to specify an action parameter. ```APIDOC ## TryGetCurrentState ### Description Attempts to retrieve the current state index of the multistate dynamic command. ### Overloads 1. **Without actionParameter**: ```csharp public Boolean TryGetCurrentState(out Int32 currentState); ``` 2. **With actionParameter**: ```csharp public Boolean TryGetCurrentState(String actionParameter, out Int32 currentState); ``` ### Parameters * **actionParameter** (String, Optional) - The parameter associated with the action. * **currentState** (out Int32) - When this method returns, contains the index of the current state, if successful. ### Return Value `true` if the current state was successfully retrieved; otherwise, `false`. ``` -------------------------------- ### Create Profile Action (tree) Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/profile-actions Implement a profile action of type 'tree' to allow multi-level selection, such as choosing a Windows Settings application. Override GetProfileActionData to provide the tree structure. ```csharp this.MakeProfileAction("tree"); ``` ```csharp protected override PluginProfileActionData GetProfileActionData() { // create tree data var tree = new PluginProfileActionTree("Select Windows Settings Application"); // describe levels tree.AddLevel("Category"); tree.AddLevel("Application"); // add data tree var categoryNames = this._applications.Values.Select(a => a.CategoryName).Distinct(); foreach (var categoryName in categoryNames) { var node = tree.Root.AddNode(categoryName); var items = this._applications.Values.Where(a => a.CategoryName.EqualsNoCase(categoryName)); foreach (var item in items) { node.AddItem(item.ApplicationUri, item.ApplicationName, null); } } // return tree data return tree; } ``` ```csharp protected override String GetCommandDisplayName(String actionParameter, PluginImageSize imageSize) => this._applications.TryGetValue(actionParameter, out var application) ? application.ApplicationName : null; ``` ```csharp protected override void RunCommand(String actionParameter) => Process.Start(actionParameter); ``` -------------------------------- ### Enable Haptic Capability Source: https://logitech.github.io/actions-sdk-docs/csharp/haptics/haptics-tutorial Configures the plugin to support haptic feedback by adding the 'HasHapticMapping' capability in the plugin's metadata file. ```yaml pluginCapabilities: - HasHapticMapping ``` -------------------------------- ### Mouse Scroll Action Editor Adjustment Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/action-editor-actions An example of an ActionEditorAdjustment for mouse scrolling. It includes a checkbox to invert direction and implements ApplyAdjustment to handle scroll differences. ```csharp public class MouseScrollAdjustment : ActionEditorAdjustment { private const String IsInvertedControlName = "IsInverted"; public MouseScrollAdjustment() : base(false) { this.Name = "MouseScroll"; this.DisplayName = "Mouse Scroll"; this.GroupName = "Action Editor"; this.Description = "Control mouse scroll wheel"; this.ActionEditor.AddControlEx(new ActionEditorCheckbox(IsInvertedControlName, "Invert Direction")); } protected override Boolean ApplyAdjustment(ActionEditorActionParameters actionParameters, Int32 diff) { if (actionParameters.TryGetBoolean(IsInvertedControlName, out var isInverted)) { if (isInverted) { diff = -diff; } // Implement mouse wheel scrolling functionality return true; } return false; } } ``` -------------------------------- ### Enable Haptic Capability in Plugin Configuration Source: https://logitech.github.io/actions-sdk-docs/csharp/haptics/haptics-getting-started Declare the `HasHapticMapping` capability in your `LoupedeckPackage.yaml` file to enable haptic functionality for your plugin. ```yaml # ... other configuration fields pluginCapabilities: - HasHapticMapping # Enables haptics # ... other configuration fields ``` -------------------------------- ### Set Command Properties in Constructor Source: https://logitech.github.io/actions-sdk-docs/csharp/tutorial/add-a-simple-command Initialize the command's display name, description, and group name by calling the base class constructor. ```csharp public ToggleMuteCommand() : base(displayName: "Toggle Mute", description: "Toggles audio mute state", groupName: "Audio") { } ``` -------------------------------- ### Dynamically Get Button Display Name Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/implementing-dynamic-folders Override GetButtonDisplayName to provide a dynamic text label for the button that opens the dynamic folder, based on runtime conditions. ```csharp public override String GetButtonDisplayName(PluginImageSize imageSize) => $"{this.ChannelCount} Channels"; ``` -------------------------------- ### Initialize PluginLog in Constructor Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/logging Initialize the PluginLog class in your plugin's constructor by passing the plugin's log method. Replace 'DemoPlugin' with your actual plugin class name. ```csharp public DemoPlugin() => PluginLog.Init(this.Log); ``` -------------------------------- ### Send Text Action Editor Command Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/action-editor-actions An example of an ActionEditorCommand for sending text. It includes a textbox control for user input and implements the RunCommand method to process the text. ```csharp public class SendTextCommand : ActionEditorCommand { private const String TextControlName = "Text"; public SendTextCommand() { this.Name = "SendText"; this.DisplayName = "Send Text"; this.GroupName = "Action Editor"; this.Description = "Place text into an active text field"; this.ActionEditor.AddControlEx(new ActionEditorTextbox(TextControlName, "Text:")); } protected override Boolean RunCommand(ActionEditorActionParameters actionParameters) { if (actionParameters.TryGetString(TextControlName, out var text)) { // Implement text sending functionality return true; } return false; } } ``` -------------------------------- ### Get Button Image for Dynamic Folder Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/implementing-dynamic-folders Override GetButtonImage to display an image on the button that opens the dynamic folder, instead of text. Ensure the image is accessible via PluginResources. ```csharp protected override BitmapImage GetButtonImage(PluginImageSize imageSize) { var bitmapImage = PluginResources.ReadImage("Loupedeck.DemoPlugin.Images.ButtonImage.png"); return bitmapImage; } ``` -------------------------------- ### PluginSDK Constructor Source: https://logitech.github.io/actions-sdk-docs/nodejs/api/html/classes/PluginSDK.html Creates a new PluginSDK instance with optional configuration options. Initializes the WebSocket client, message dispatcher, logger, and connection event handlers. ```APIDOC ## constructor * new PluginSDK(options?: PluginSDKOptions): PluginSDK ### Description Creates a new PluginSDK instance with the specified configuration options. Initializes the WebSocket client for communication with the Logi Plugin Service, sets up the message dispatcher for handling incoming messages, configures the logger with the specified log level, and establishes connection event handlers. ### Parameters #### options: PluginSDKOptions Configuration options for the SDK. If not provided, defaults to WARN log level. ### Returns PluginSDK ### Example ```javascript import { PluginSDK, LoggerLevel } from '@logitech/plugin-sdk'; // Create SDK with default options (WARN log level) const sdk = new PluginSDK(); // Create SDK with custom log level const debugSdk = new PluginSDK({ logLevel: LoggerLevel.DEBUG }); // Create SDK with minimal logging const quietSdk = new PluginSDK({ logLevel: LoggerLevel.ERROR }); ``` ### See * PluginSDKOptions - Available configuration options * LoggerLevel - Available logging levels ``` -------------------------------- ### Get Command Image Based on State Source: https://logitech.github.io/actions-sdk-docs/csharp/tutorial/change-a-button-image Overrides `GetCommandImage` to return the appropriate image (thumb up or thumb down) based on the current command state. Reads the image using `PluginResources.ReadImage()`. ```csharp protected override BitmapImage GetCommandImage(String actionParameter, PluginImageSize imageSize) { var resourcePath = this._isThumbDown ? this._imageResourcePathThumbDown : this._imageResourcePathThumbUp; return PluginResources.ReadImage(resourcePath); } ``` -------------------------------- ### Extract Embedded Resource File in C# Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/install-and-uninstall This C# code demonstrates how to extract an embedded resource file from a plugin's assembly to a specified location. This is useful for installing application-side extensions or other required files. ```csharp var pluginFileName = Path.Combine(gimpDirectory, "plug-ins", "logi_plugin.py"); this.Assembly.ExtractFile("Loupedeck.Payload.plugin.logi_plugin.py", pluginFileName); ``` -------------------------------- ### Read Plugin Setting Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/managing-plugin-settings Use `TryGetPluginSetting` to retrieve a plugin setting. It returns `true` if the setting exists, setting `settingValue` to its value, and `false` otherwise, setting `settingValue` to `null`. ```csharp protected Boolean TryGetPluginSetting(String settingName, out String settingValue); ``` -------------------------------- ### Log an Info Message in Plugin Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/logging After initializing PluginLog, you can log informational messages using the Info method. ```csharp PluginLog.Info("Counter was reset"); ``` -------------------------------- ### Import PluginSDK Source: https://logitech.github.io/actions-sdk-docs/nodejs/using-sdk Import the PluginSDK class from the '@logitech/plugin-sdk' library. ```javascript import { PluginSDK } from '@logitech/plugin-sdk'; ``` -------------------------------- ### Connect and Execute Code After Connection Source: https://logitech.github.io/actions-sdk-docs/nodejs/using-sdk Connect to the Logi Plugin Service WebSocket server and execute code only after the connection is established. The connect function is awaitable. ```javascript await pluginSDK.connect(); myFunctionToRunAfterConnection(); ``` -------------------------------- ### Parameterless Constructor for PluginDynamicCommand Source: https://logitech.github.io/actions-sdk-docs/csharp/tutorial/add-a-command-with-a-parameter Create an empty, parameterless constructor that calls the parameterless constructor of the base class. ```csharp public ButtonSwitchesCommand() : base() { } ``` -------------------------------- ### Define Multiple States for a Dynamic Action Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/multistate-plugin-actions Call `AddState()` in the constructor for each desired state. Each state has a display name and description. ```csharp public LampSwitchDynamicCommand() { this.AddState("On", "Lamp is turned on"); this.AddState("Off", "Lamp is turned off"); } ``` -------------------------------- ### Create Profile Action (text) Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/profile-actions Use this to create a profile action of type 'text'. The parameter is entered by the user in a text box. ```csharp this.MakeProfileAction("text;Enter chat message to send:"); ``` ```csharp protected override void RunCommand(String actionParameter) => Chat.SendMessage(actionParameter); ``` -------------------------------- ### Build and Watch Plugin Changes Source: https://logitech.github.io/actions-sdk-docs/nodejs/introduction This script builds the plugin, links it to the Logi Plugin Service, and automatically reloads changes upon file modification. It also unloads the plugin when stopped. ```bash npm run watch ``` -------------------------------- ### Log Plugin Exception and Message (Info) Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/logging Use this method to log an exception along with a descriptive message from your plugin. Ensure the PluginLog class is initialized. ```csharp public static void Info(Exception ex, String text) => PluginLog._pluginLogFile?.Info(ex, text); ``` -------------------------------- ### Define a Dynamic Folder Class Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/implementing-dynamic-folders Inherit from PluginDynamicFolder to create a new dynamic folder. Set its display name and group in the constructor. ```csharp public class TaskSwitcherDynamicFolder : PluginDynamicFolder { public TaskSwitcherDynamicFolder() { this.DisplayName = "Alt+Tab"; this.GroupName = "System"; } } ``` -------------------------------- ### Verify .lplug4 Plugin Package Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-development/distributing-the-plugin Use the Logi Plugin Tool with the 'verify' command to check the integrity and validity of a .lplug4 package before distribution. ```bash logiplugintool verify ./Example.lplug4 ``` -------------------------------- ### Log Plugin Message (Info) Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/logging Use this method to log an informational message from your plugin. Ensure the PluginLog class is initialized. ```csharp public static void Info(String text) => PluginLog._pluginLogFile?.Info(text); ``` -------------------------------- ### Add Background Image and Text to Button Source: https://logitech.github.io/actions-sdk-docs/csharp/tutorial/change-a-button-image Demonstrates how to create a button image with a background and text using `BitmapBuilder`. The image must be an embedded resource. ```csharp protected override BitmapImage GetCommandImage(String actionParameter, PluginImageSize imageSize) { using (var bitmapBuilder = new BitmapBuilder(imageSize)) { bitmapBuilder.SetBackgroundImage(PluginResources.ReadImage("MyPlugin.EmbeddedResources.MyImage.png")); bitmapBuilder.DrawText("My text"); return bitmapBuilder.ToImage(); } } ``` -------------------------------- ### AdjustmentAction Constructor Source: https://logitech.github.io/actions-sdk-docs/nodejs/api/html/classes/AdjustmentAction.html Details on how to instantiate the AdjustmentAction class. ```APIDOC ## Constructors ### constructor * new AdjustmentAction(): AdjustmentAction #### Returns AdjustmentAction ``` -------------------------------- ### Enable Logi Plugin Service Logging Source: https://logitech.github.io/actions-sdk-docs/csharp/plugin-features/logging To enable logging for the Logi Plugin Service, create an empty file named 'enablelogs' (without any extension) in the service's data directory. Note that enabling logging can significantly slow down the service. ```text enablelogs ```