From 51ca9fde464bf99b857be57e8c75c24bb867ac55 Mon Sep 17 00:00:00 2001 From: Nirmall02 Date: Fri, 20 Mar 2026 16:29:15 +0000 Subject: [PATCH 1/2] DemoPlugin update version 6.2 - Restructured project to use src/, Actions/, Helpers/, images/ folders - Added ToggleMuteCommand with macOS and Windows support - Added ButtonSwitchesCommand with 4 toggle switches - Added ThumbUpDownCommand with embedded image toggle - Added CounterAdjustment for dial rotation tracking - Added .vscode config for debugging and build tasks - Added README.md for new developers --- DemoPlugin/.gitignore | 200 +++++++++++++----- DemoPlugin/.vscode/launch.json | 17 ++ DemoPlugin/.vscode/tasks.json | 40 ++++ DemoPlugin/DemoPlugin.sln | 18 +- .../DemoPlugin/ButtonSwitchesCommand.cs | 46 ---- DemoPlugin/DemoPlugin/CounterAdjustment.cs | 38 ---- DemoPlugin/DemoPlugin/DemoPlugin.csproj.user | 11 - DemoPlugin/DemoPlugin/ThumbUpDownCommand.cs | 30 --- DemoPlugin/DemoPlugin/ToggleMuteCommand.cs | 17 -- ...Loupedeck.DemoPlugin.ToggleMuteCommand.ict | 37 ---- .../package/metadata/DefaultIconTemplate.ict | 33 --- .../package/metadata/LoupedeckPackage.yaml | 53 ----- DemoPlugin/README.md | 73 +++++++ DemoPlugin/{ => src}/.editorconfig | 38 +++- .../src/Actions/ButtonSwitchesCommand.cs | 54 +++++ DemoPlugin/src/Actions/CounterAdjustment.cs | 49 +++++ DemoPlugin/src/Actions/ThumbUpDownCommand.cs | 44 ++++ DemoPlugin/src/Actions/ToggleMuteCommand.cs | 47 ++++ .../{DemoPlugin => src}/DemoApplication.cs | 7 +- DemoPlugin/{DemoPlugin => src}/DemoPlugin.cs | 2 + .../{DemoPlugin => src}/DemoPlugin.csproj | 27 ++- DemoPlugin/{ => src}/Directory.Build.props | 2 +- .../{DemoPlugin => src/Helpers}/PluginLog.cs | 2 +- .../Helpers}/PluginResources.cs | 0 .../{DemoPlugin => src}/images/ThumbDown.png | Bin .../{DemoPlugin => src}/images/ThumbUp.png | Bin DemoPlugin/src/images/VolumeOff.png | Bin 0 -> 878 bytes DemoPlugin/src/images/VolumeOn.png | Bin 0 -> 1490 bytes .../package/metadata/Icon256x256.png | Bin .../package/metadata/LoupedeckPackage.yaml | 80 +++++++ README.md | 12 -- 31 files changed, 629 insertions(+), 348 deletions(-) create mode 100644 DemoPlugin/.vscode/launch.json create mode 100644 DemoPlugin/.vscode/tasks.json delete mode 100644 DemoPlugin/DemoPlugin/ButtonSwitchesCommand.cs delete mode 100644 DemoPlugin/DemoPlugin/CounterAdjustment.cs delete mode 100644 DemoPlugin/DemoPlugin/DemoPlugin.csproj.user delete mode 100644 DemoPlugin/DemoPlugin/ThumbUpDownCommand.cs delete mode 100644 DemoPlugin/DemoPlugin/ToggleMuteCommand.cs delete mode 100644 DemoPlugin/DemoPlugin/package/icontemplates/Loupedeck.DemoPlugin.ToggleMuteCommand.ict delete mode 100644 DemoPlugin/DemoPlugin/package/metadata/DefaultIconTemplate.ict delete mode 100644 DemoPlugin/DemoPlugin/package/metadata/LoupedeckPackage.yaml create mode 100644 DemoPlugin/README.md rename DemoPlugin/{ => src}/.editorconfig (86%) create mode 100644 DemoPlugin/src/Actions/ButtonSwitchesCommand.cs create mode 100644 DemoPlugin/src/Actions/CounterAdjustment.cs create mode 100644 DemoPlugin/src/Actions/ThumbUpDownCommand.cs create mode 100644 DemoPlugin/src/Actions/ToggleMuteCommand.cs rename DemoPlugin/{DemoPlugin => src}/DemoApplication.cs (53%) rename DemoPlugin/{DemoPlugin => src}/DemoPlugin.cs (92%) rename DemoPlugin/{DemoPlugin => src}/DemoPlugin.csproj (64%) rename DemoPlugin/{ => src}/Directory.Build.props (74%) rename DemoPlugin/{DemoPlugin => src/Helpers}/PluginLog.cs (94%) rename DemoPlugin/{DemoPlugin => src/Helpers}/PluginResources.cs (100%) rename DemoPlugin/{DemoPlugin => src}/images/ThumbDown.png (100%) rename DemoPlugin/{DemoPlugin => src}/images/ThumbUp.png (100%) create mode 100644 DemoPlugin/src/images/VolumeOff.png create mode 100644 DemoPlugin/src/images/VolumeOn.png rename DemoPlugin/{DemoPlugin => src}/package/metadata/Icon256x256.png (100%) create mode 100644 DemoPlugin/src/package/metadata/LoupedeckPackage.yaml delete mode 100644 README.md diff --git a/DemoPlugin/.gitignore b/DemoPlugin/.gitignore index 783bc57..74ae05a 100644 --- a/DemoPlugin/.gitignore +++ b/DemoPlugin/.gitignore @@ -1,14 +1,21 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore # User-specific files +*.rsuser *.suo +*.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs +# Mono auto generated files +mono_crash.* + # Build results [Dd]ebug/ [Dd]ebugPublic/ @@ -16,42 +23,62 @@ [Rr]eleases/ x64/ x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ +[Ll]ogs/ -# Visual Studio 2015 cache/options directory +# Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ +# Visual Studio 2017 auto generated files +Generated\ Files/ + # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* -# NUNIT +# NUnit *.VisualState.xml TestResult.xml +nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c -# DNX +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core project.lock.json project.fragment.lock.json artifacts/ +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio *_i.c *_p.c -*_i.h +*_h.h *.ilk *.meta *.obj +*.iobj *.pch *.pdb +*.ipdb *.pgc *.pgd *.rsp @@ -61,7 +88,9 @@ artifacts/ *.tlh *.tmp *.tmp_proj +*_wpftmp.csproj *.log +*.tlog *.vspscc *.vssscc .builds @@ -89,6 +118,9 @@ ipch/ *.vspx *.sap +# Visual Studio Trace Files +*.e2e + # TFS 2012 Local Workspace $tf/ @@ -100,15 +132,25 @@ _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user -# JustCode is a .NET coding add-in -.JustCode - # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + # NCrunch _NCrunch_* .*crunch*.local.xml @@ -140,9 +182,9 @@ publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings +# Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted -#*.pubxml +*.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to @@ -152,13 +194,15 @@ PublishScripts/ # NuGet Packages *.nupkg +# NuGet Symbol Packages +*.snupkg # The packages folder can be ignored because of Package Restore -**/packages/* +**/[Pp]ackages/* # except build/, which is used as an MSBuild target. -!**/packages/build/ +!**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets @@ -175,12 +219,15 @@ AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt +*.appx +*.appxbundle +*.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache -!*.[Cc]ache/ +!?*.[Cc]ache/ # Others ClientBin/ @@ -191,9 +238,12 @@ ClientBin/ *.jfm *.pfx *.publishsettings -node_modules/ orleans.codegen.cs +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ @@ -208,15 +258,22 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak # SQL Server files *.mdf *.ldf +*.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ @@ -226,6 +283,7 @@ FakesAssemblies/ # Node.js Tools for Visual Studio .ntvs_analysis.dat +node_modules/ # Visual Studio 6 build log *.plg @@ -233,6 +291,20 @@ FakesAssemblies/ # Visual Studio 6 workspace options file *.opt +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -248,63 +320,81 @@ paket-files/ # FAKE - F# Make .fake/ -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ +# CodeRush personal settings +.cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs -# -# ANGULAR gitignore begin section -# +# OpenCover UI analysis results +OpenCover/ -# See http://help.github.com/ignore-files/ for more about ignoring files. +# Azure Stream Analytics local run output +ASALocalRun/ -# compiled output -/dist -/tmp -/out-tsc +# MSBuild Binary and Structured Log +*.binlog -# dependencies -/node_modules +# NVidia Nsight GPU debugger configuration file +*.nvuser -# IDEs and editors -/.idea -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace +# MFractors (Xamarin productivity tool) working folder +.mfractor/ -# IDE - VSCode +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json +*.code-workspace -# misc -/.sass-cache -/connect.lock -/coverage -/libpeerconnection.log -npm-debug.log -testem.log -/typings +# Local History for Visual Studio Code +.history/ -# e2e -/e2e/*.js -/e2e/*.map +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp -# System Files -*.xcuserstate -*.xcactivitylog +# JetBrains Rider +*.sln.iml -*.DotSettings +.DS_Store \ No newline at end of file diff --git a/DemoPlugin/.vscode/launch.json b/DemoPlugin/.vscode/launch.json new file mode 100644 index 0000000..f67e0ab --- /dev/null +++ b/DemoPlugin/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Logi Plugin Service", + "type": "coreclr", + "request": "attach", + "windows": { + "processName": "LogiPluginService.exe" + }, + "osx": { + "processName": "LogiPluginService" + }, + "justMyCode": true + } + ] +} diff --git a/DemoPlugin/.vscode/tasks.json b/DemoPlugin/.vscode/tasks.json new file mode 100644 index 0000000..9d9ae1b --- /dev/null +++ b/DemoPlugin/.vscode/tasks.json @@ -0,0 +1,40 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build (Debug)", + "type": "shell", + "command": "dotnet build -c Debug", + "group": "build", + "problemMatcher": "$msCompile" + }, + { + "label": "Build (Release)", + "type": "shell", + "command": "dotnet build -c Release", + "group": "build", + "problemMatcher": "$msCompile" + }, + { + "label": "Package Plugin", + "type": "shell", + "command": "logiplugintool pack ./bin/Release ./Demo.lplug4", + "group": "none", + "problemMatcher": [] + }, + { + "label": "Install Plugin", + "type": "shell", + "command": "logiplugintool install ./Demo.lplug4", + "group": "none", + "problemMatcher": [] + }, + { + "label": "Uninstall Plugin", + "type": "shell", + "command": "logiplugintool uninstall Demo", + "group": "none", + "problemMatcher": [] + } + ] +} diff --git a/DemoPlugin/DemoPlugin.sln b/DemoPlugin/DemoPlugin.sln index 6bd8cd4..c782f2e 100644 --- a/DemoPlugin/DemoPlugin.sln +++ b/DemoPlugin/DemoPlugin.sln @@ -3,7 +3,13 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.8.34408.163 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoPlugin", "DemoPlugin\DemoPlugin.csproj", "{58C04AC4-DFCD-49F9-9BF3-E8240592F3BF}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DemoPlugin", "src\DemoPlugin.csproj", "{A4AA1C9B-F4DA-4B58-A5ED-A95E06D70199}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BD08438B-1C4A-4FFA-A856-D5285D570BB8}" + ProjectSection(SolutionItems) = preProject + .vscode\launch.json = .vscode\launch.json + .vscode\tasks.json = .vscode\tasks.json + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -11,15 +17,15 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {58C04AC4-DFCD-49F9-9BF3-E8240592F3BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {58C04AC4-DFCD-49F9-9BF3-E8240592F3BF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {58C04AC4-DFCD-49F9-9BF3-E8240592F3BF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {58C04AC4-DFCD-49F9-9BF3-E8240592F3BF}.Release|Any CPU.Build.0 = Release|Any CPU + {A4AA1C9B-F4DA-4B58-A5ED-A95E06D70199}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A4AA1C9B-F4DA-4B58-A5ED-A95E06D70199}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A4AA1C9B-F4DA-4B58-A5ED-A95E06D70199}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A4AA1C9B-F4DA-4B58-A5ED-A95E06D70199}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {F627919D-59F2-470B-BFAB-8D932B3514F8} + SolutionGuid = {1C04A10A-A4D3-4205-94BE-47CB0006A47F} EndGlobalSection EndGlobal diff --git a/DemoPlugin/DemoPlugin/ButtonSwitchesCommand.cs b/DemoPlugin/DemoPlugin/ButtonSwitchesCommand.cs deleted file mode 100644 index cfc1f7b..0000000 --- a/DemoPlugin/DemoPlugin/ButtonSwitchesCommand.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Loupedeck.DemoPlugin -{ - using System; - - public class ButtonSwitchesCommand : PluginDynamicCommand - { - private const int NumberOfSwitches = 4; - private readonly Boolean[] _switches = new Boolean[NumberOfSwitches]; - - public ButtonSwitchesCommand() : base() - { - for (var i = 0; i < NumberOfSwitches; i++) - { - // Parameter is the switch index - var actionParameter = i.ToString(); - - // Add parameter - this.AddParameter(actionParameter, $"Switch {i}", "Switches"); - } - } - - protected override void RunCommand(String actionParameter) - { - if (Int32.TryParse(actionParameter, out var i)) - { - // Turn the switch - this._switches[i] = !this._switches[i]; - - // Inform Loupedeck that command display name and/or image has changed - this.ActionImageChanged(actionParameter); - } - } - - protected override String GetCommandDisplayName(String actionParameter, PluginImageSize imageSize) - { - if (Int32.TryParse(actionParameter, out var i)) - { - return $"Switch {i}: {this._switches[i]}"; - } - else - { - return null; - } - } - } -} diff --git a/DemoPlugin/DemoPlugin/CounterAdjustment.cs b/DemoPlugin/DemoPlugin/CounterAdjustment.cs deleted file mode 100644 index 20fbd93..0000000 --- a/DemoPlugin/DemoPlugin/CounterAdjustment.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Loupedeck.DemoPlugin -{ - using System; - - // This class implements an example adjustment that counts the rotation ticks of a dial. - - public class CounterAdjustment : PluginDynamicAdjustment - { - // This variable holds the current value of the counter. - private Int32 _counter = 0; - - // Initializes the adjustment class. - // When `hasReset` is set to true, a reset command is automatically created for this adjustment. - public CounterAdjustment() - : base(displayName: "Counter", description: "Counts rotation ticks", groupName: "Adjustments", hasReset: true) - { - } - - // This method is called when the dial associated to the plugin is rotated. - protected override void ApplyAdjustment(String actionParameter, Int32 diff) - { - this._counter += diff; // Increase or decrease the counter by the number of ticks. - this.AdjustmentValueChanged(); // Notify the Loupedeck service that the adjustment value has changed. - PluginLog.Info($"Counter value was changed by {diff} ticks"); - } - - // This method is called when the reset command related to the adjustment is executed. - protected override void RunCommand(String actionParameter) - { - this._counter = 0; // Reset the counter. - this.AdjustmentValueChanged(); // Notify the Loupedeck service that the adjustment value has changed. - PluginLog.Info("Counter was reset"); - } - - // Returns the adjustment value that is shown next to the dial. - protected override String GetAdjustmentValue(String actionParameter) => this._counter.ToString(); - } -} diff --git a/DemoPlugin/DemoPlugin/DemoPlugin.csproj.user b/DemoPlugin/DemoPlugin/DemoPlugin.csproj.user deleted file mode 100644 index c997f50..0000000 --- a/DemoPlugin/DemoPlugin/DemoPlugin.csproj.user +++ /dev/null @@ -1,11 +0,0 @@ - - - - Program - C:\Program Files\Logi\LogiPluginService\LogiPluginService.exe - - - Program - /Applications/Utilities/LogiPluginService.app - - \ No newline at end of file diff --git a/DemoPlugin/DemoPlugin/ThumbUpDownCommand.cs b/DemoPlugin/DemoPlugin/ThumbUpDownCommand.cs deleted file mode 100644 index 2aea404..0000000 --- a/DemoPlugin/DemoPlugin/ThumbUpDownCommand.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace Loupedeck.DemoPlugin -{ - using System; - - public class ThumbUpDownCommand : PluginDynamicCommand - { - private Boolean _isThumbDown = false; - - 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"); - } - - protected override void RunCommand(String actionParameter) - { - this._isThumbDown = !this._isThumbDown; - this.ActionImageChanged(); - } - - protected override BitmapImage GetCommandImage(String actionParameter, PluginImageSize imageSize) - { - var resourcePath = this._isThumbDown ? this._imageResourcePathThumbDown : this._imageResourcePathThumbUp; - return PluginResources.ReadImage(resourcePath); - } - } -} diff --git a/DemoPlugin/DemoPlugin/ToggleMuteCommand.cs b/DemoPlugin/DemoPlugin/ToggleMuteCommand.cs deleted file mode 100644 index a96e858..0000000 --- a/DemoPlugin/DemoPlugin/ToggleMuteCommand.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace Loupedeck.DemoPlugin -{ - using System; - - public class ToggleMuteCommand : PluginDynamicCommand - { - public ToggleMuteCommand() - : base(displayName: "Toggle Mute", description: "Mutes and unmutes system volume", groupName: "Audio") - { - } - - protected override void RunCommand(String actionParameter) - { - this.Plugin.ClientApplication.SendKeyboardShortcut(VirtualKeyCode.VolumeMute); - } - } -} diff --git a/DemoPlugin/DemoPlugin/package/icontemplates/Loupedeck.DemoPlugin.ToggleMuteCommand.ict b/DemoPlugin/DemoPlugin/package/icontemplates/Loupedeck.DemoPlugin.ToggleMuteCommand.ict deleted file mode 100644 index 0a43af6..0000000 --- a/DemoPlugin/DemoPlugin/package/icontemplates/Loupedeck.DemoPlugin.ToggleMuteCommand.ict +++ /dev/null @@ -1,37 +0,0 @@ -{ - "backgroundColor": 4278190080, - "items": [ - { - "$type": "Loupedeck.Service.ActionIconImageItem, LoupedeckShared", - "image": "iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAABwwAAAcMBOnufsAAAABh0RVh0U29mdHdhcmUAcGFpbnQubmV0IDQuMS42/U4J6AAAAe5JREFUeF7t2rFNA0EQhWEHFEIhBJRCCZRARoioAHLojgKOHYmVVqvf5glm70bWG+lL/l07mMA+LE7bttk/YDQdRtNhNB1G02E0HUbTYTQdRtNhNB1G02E0HUbTYTQdRtNhNB1G02E0HUbTYTQdRtNhNB1G02E0HUbTYTQdxkLeoZWCsYinJobOysBYwEPTh87LwHiwcXkxdKcMjAealxdD98rAeBBaXgzdLQPjAc4tL4bul4FxZ5eWF0OvKQNjstvm/ozH5reh97xrnqc2irO4Q2epMCbrz3N/nfn9YjFfTcxLM59Hi4k7y5eIMVn2At+accYl9uX1ibvja9NhTJa9wJvmoxknFjcvL+7E3fn1qTAmy15goCWOs8vyAsZkKxYYzi1xt+UFjMlWLTC8NvNEo7tLYEy2aoHzZ9444xfLUhiTrVjgvLzPH+PsskSMybIXGA/J4/TPPPpMvPSwnQJjsuwFjg/S8xfGuMSreZBe9adcPCTTt220OFu+vIBxZ/4xIYF/zkrgH1QT0BLpXhkYDzYvke6UgbGAcYl0XgbGIvrzI52VgbEQ/2vHtcNoOoymw2g6jKbDaDqMpsNoOoymw2g6jKbDaDqMpsNoOoymw2g6jKbDaDqMpsNoOoymw2g6jKbDaDqMpsNoqu30DbZ472o00s59AAAAAElFTkSuQmCC", - "imageFileName": "ToggleMute.png", - "imageColor": 4294967295, - "imageRotation": "None", - "isVisible": true, - "itemType": "Image", - "area": { - "x": 0, - "y": -10, - "width": 100, - "height": 100, - "isFullScreen": true - } - }, - { - "$type": "Loupedeck.Service.ActionIconTextItem, LoupedeckShared", - "text": "Toggle Mute", - "textColor": 4294967295, - "fontSize": 5, - "fontName": "Brown Logitech Pan Light", - "isVisible": true, - "itemType": "Text", - "area": { - "x": 0, - "y": 70, - "width": 100, - "height": 16, - "isFullScreen": false - } - } - ] -} \ No newline at end of file diff --git a/DemoPlugin/DemoPlugin/package/metadata/DefaultIconTemplate.ict b/DemoPlugin/DemoPlugin/package/metadata/DefaultIconTemplate.ict deleted file mode 100644 index cb606e1..0000000 --- a/DemoPlugin/DemoPlugin/package/metadata/DefaultIconTemplate.ict +++ /dev/null @@ -1,33 +0,0 @@ -{ - "backgroundColor": 4278869247, - "items": [ - { - "image": "", - "imageFileName": null, - "imageColor": 4294967295, - "imageRotation": "None", - "isVisible": true, - "itemType": "Image", - "area": { - "x": 15, - "y": 0, - "width": 70, - "height": 70 - } - }, - { - "text": "", - "textColor": 4294967295, - "fontSize": 5, - "fontName": "Brown Logitech Pan Light", - "isVisible": true, - "itemType": "Text", - "area": { - "x": 0, - "y": 70, - "width": 100, - "height": 30 - } - } - ] -} \ No newline at end of file diff --git a/DemoPlugin/DemoPlugin/package/metadata/LoupedeckPackage.yaml b/DemoPlugin/DemoPlugin/package/metadata/LoupedeckPackage.yaml deleted file mode 100644 index 36bfc9a..0000000 --- a/DemoPlugin/DemoPlugin/package/metadata/LoupedeckPackage.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# ================================================================================================== -# GENERAL SETTINGS -# ================================================================================================== - -# Package type. Must be plugin4 for plugins. -type: plugin4 - -# Name that identifies the plugin. -name: Demo - -# Plugin name that is shown to the user. -displayName: Demo - -# Short description of the plugin. -description: This is a demo plugin - -# Name of the plugin library file. -pluginFileName: DemoPlugin.dll - -# Plugin version. -version: 1.0 - -# Author of the plugin. The author can be a company or an individual developer. -author: Logitech Europe SA - -# Copyright information. -copyright: Copyright © 2025 Logitech Europe SA. All rights reserved. - -# Minimum SDK version supported by the plugin. -minimumLoupedeckVersion: 6.0 - - -# ================================================================================================== -# PLUGIN PROPERTIES -# ================================================================================================== - -# Location of plugin files on Windows (relative to the plugin base directory). -# This parameter is required to support Windows. -pluginFolderWin: bin - -# Location of plugin files on macOS (relative to the plugin base directory). -# This parameter is required to support Mac. -pluginFolderMac: bin - -# List of devices the plugin is optimized for. -supportedDevices: - # LoupedeckCtFamily covers the following devices: Loupedeck CT, Live and Live S, - # Razer Stream Controller, and Razer Stream Controller X. - - LoupedeckCtFamily - - # Logitech MX Creative Console family devices. - - LoupedeckExtendedFamily - diff --git a/DemoPlugin/README.md b/DemoPlugin/README.md new file mode 100644 index 0000000..1181174 --- /dev/null +++ b/DemoPlugin/README.md @@ -0,0 +1,73 @@ +# Welcome to Logi Actions SDK + +Here you can find an introduction to Logi Actions SDK, example plugin source code and the SDK documentation. + +## Documentation + +- [Logi Actions SDK Developer Docs](https://logitech.github.io/actions-sdk-docs/) +- [Logi Developer Discord](https://discord.gg/ptV2BfHCmm) + +--- + +# DemoPlugin + +A Logitech Actions SDK plugin built with C# (.NET 8) that works on both macOS and Windows. This project is intended as a learning resource for new developers joining the team — each file is structured and commented to help you understand how the SDK works. + +## Folder Structure + +``` +DemoPlugin/ +├── .vscode/ # VS Code setup — debugger config to attach to the Logi Plugin Service +│ # and build tasks for quick builds, packaging and installing +├── src/ +│ ├── Actions/ # Where all commands and adjustments live. +│ # Each file is one feature assigned to a button or dial +│ ├── Helpers/ # Shared utility classes used across all actions. +│ # PluginLog for logging, PluginResources for loading images +│ ├── images/ # PNG icons embedded into the plugin DLL. +│ # These are displayed on device buttons at runtime +│ └── package/ # Plugin identity files read by the Logi Plugin Service +│ # on startup — name, version, icon and supported devices +└── bin/ # Auto-generated build output. Never edit this folder manually. +``` + +## Actions + +| Action | Type | Description | +|---|---|---| +| Toggle Mute | Button | Mutes and unmutes system volume on macOS and Windows | +| Button Switches | Button | 4 independent on/off toggle switches | +| Thumb Up/Down | Button | Toggles between thumb up and thumb down image | +| Counter | Dial | Counts rotation ticks, press dial to reset | + +## Build + +```bash +# Debug — used during development and debugging +dotnet build -c Debug + +# Release — used for packaging and distribution +dotnet build -c Release +``` + +## Debug + +1. Open the project in VS Code +2. Run `dotnet build -c Debug` +3. Go to **Run > Start Debugging** (or press `F5`) +4. Select **Attach to Logi Plugin Service** + +You can now set breakpoints in any action file and step through your code live. + +## Package & Install + +```bash +# Package the plugin into a distributable .lplug4 file +logiplugintool pack ./bin/Release ./Demo.lplug4 + +# Install the plugin on this machine +logiplugintool install ./Demo.lplug4 + +# Uninstall the plugin +logiplugintool uninstall Demo +``` diff --git a/DemoPlugin/.editorconfig b/DemoPlugin/src/.editorconfig similarity index 86% rename from DemoPlugin/.editorconfig rename to DemoPlugin/src/.editorconfig index cc8b97a..8ec3771 100644 --- a/DemoPlugin/.editorconfig +++ b/DemoPlugin/src/.editorconfig @@ -199,8 +199,44 @@ dotnet_naming_style.begins_with_i.capitalization = pascal_case dotnet_diagnostic.CA1028.severity = none dotnet_diagnostic.CA1031.severity = none -dotnet_diagnostic.CA1303.severity = none +dotnet_diagnostic.CA1054.severity = none +dotnet_diagnostic.CA1056.severity = none dotnet_diagnostic.CA1060.severity = none +dotnet_diagnostic.CA1303.severity = none +dotnet_diagnostic.CA1308.severity = none +dotnet_diagnostic.CA1716.severity = none +dotnet_diagnostic.CA1720.severity = none dotnet_diagnostic.CA2101.severity = none +dotnet_diagnostic.CA2234.severity = none +dotnet_diagnostic.CA5350.severity = none +dotnet_diagnostic.CA9998.severity = none + +dotnet_diagnostic.CS1591.severity = none +dotnet_diagnostic.IDE0002.severity = none +dotnet_diagnostic.IDE0021.severity = warning +dotnet_diagnostic.IDE0022.severity = warning dotnet_diagnostic.IDE0058.severity = none +dotnet_diagnostic.IDE0059.severity = none + +dotnet_diagnostic.SA1108.severity = none +dotnet_diagnostic.SA1117.severity = none +dotnet_diagnostic.SA1121.severity = none +dotnet_diagnostic.SA1122.severity = none +dotnet_diagnostic.SA1131.severity = none +dotnet_diagnostic.SA1201.severity = none +dotnet_diagnostic.SA1202.severity = none +dotnet_diagnostic.SA1203.severity = none +dotnet_diagnostic.SA1204.severity = none +dotnet_diagnostic.SA1214.severity = none +dotnet_diagnostic.SA1309.severity = none +dotnet_diagnostic.SA1512.severity = none +dotnet_diagnostic.SA1513.severity = none +dotnet_diagnostic.SA1600.severity = none +dotnet_diagnostic.SA1601.severity = none +dotnet_diagnostic.SA1602.severity = none +dotnet_diagnostic.SA1629.severity = none +dotnet_diagnostic.SA1633.severity = none + +dotnet_diagnostic.SX1309.severity = warning +dotnet_diagnostic.SX1309S.severity = warning diff --git a/DemoPlugin/src/Actions/ButtonSwitchesCommand.cs b/DemoPlugin/src/Actions/ButtonSwitchesCommand.cs new file mode 100644 index 0000000..e715a8c --- /dev/null +++ b/DemoPlugin/src/Actions/ButtonSwitchesCommand.cs @@ -0,0 +1,54 @@ +namespace Loupedeck.DemoPlugin +{ + using System; + + // This command creates multiple toggle switches assigned to buttons. + // Each switch independently tracks its own on/off state. + + public class ButtonSwitchesCommand : PluginDynamicCommand + { + // Total number of switches available. + private const Int32 NumberOfSwitches = 4; + + // Array to store the on/off state of each switch. + private readonly Boolean[] _switches = new Boolean[NumberOfSwitches]; + + // Initializes the command and adds a parameter for each switch. + public ButtonSwitchesCommand() : base() + { + for (var i = 0; i < NumberOfSwitches; i++) + { + // Each switch uses its index as the action parameter. + var actionParameter = i.ToString(); + + // Register each switch as a separate button in the "Switches" group. + this.AddParameter(actionParameter, $"Switch {i}", "Switches"); + } + } + + // This method is called when the user presses a switch button. + protected override void RunCommand(String actionParameter) + { + if (Int32.TryParse(actionParameter, out var i)) + { + // Toggle the switch state. + this._switches[i] = !this._switches[i]; + + // Notify the Plugin Service to refresh the button label. + this.ActionImageChanged(actionParameter); + } + } + + // Returns the button label showing the switch index and its current state. + protected override String GetCommandDisplayName(String actionParameter, PluginImageSize imageSize) + { + if (Int32.TryParse(actionParameter, out var i)) + { + // Show "Switch 0: On" or "Switch 0: Off" based on state. + return $"Switch {i}: {(this._switches[i] ? "On" : "Off")}"; + } + + return null; + } + } +} diff --git a/DemoPlugin/src/Actions/CounterAdjustment.cs b/DemoPlugin/src/Actions/CounterAdjustment.cs new file mode 100644 index 0000000..f36b9c5 --- /dev/null +++ b/DemoPlugin/src/Actions/CounterAdjustment.cs @@ -0,0 +1,49 @@ +namespace Loupedeck.DemoPlugin +{ + using System; + + // This adjustment counts the rotation ticks of a dial/encoder. + // Rotating right increases the counter, rotating left decreases it. + // Pressing the dial resets the counter to zero. + + public class CounterAdjustment : PluginDynamicAdjustment + { + // Holds the current value of the counter. + private Int32 _counter = 0; + + // Initializes the adjustment. + // hasReset: true automatically creates a reset button for this adjustment. + public CounterAdjustment() + : base(displayName: "Counter", description: "Counts rotation ticks of the dial", groupName: "Adjustments", hasReset: true) + { + } + + // This method is called when the dial is rotated. + // diff is positive when rotating right, negative when rotating left. + protected override void ApplyAdjustment(String actionParameter, Int32 diff) + { + // Increase or decrease the counter by the number of ticks. + this._counter += diff; + + // Notify the Plugin Service that the value has changed. + this.AdjustmentValueChanged(); + + PluginLog.Info($"Counter changed by {diff}, new value: {this._counter}"); + } + + // This method is called when the reset button is pressed. + protected override void RunCommand(String actionParameter) + { + // Reset the counter back to zero. + this._counter = 0; + + // Notify the Plugin Service that the value has changed. + this.AdjustmentValueChanged(); + + PluginLog.Info("Counter reset to 0"); + } + + // Returns the current counter value shown next to the dial. + protected override String GetAdjustmentValue(String actionParameter) => this._counter.ToString(); + } +} diff --git a/DemoPlugin/src/Actions/ThumbUpDownCommand.cs b/DemoPlugin/src/Actions/ThumbUpDownCommand.cs new file mode 100644 index 0000000..51c8129 --- /dev/null +++ b/DemoPlugin/src/Actions/ThumbUpDownCommand.cs @@ -0,0 +1,44 @@ +namespace Loupedeck.DemoPlugin +{ + using System; + + // This command toggles between a Thumb Up and Thumb Down image on the button. + // It demonstrates how to use embedded image resources for button icons. + + public class ThumbUpDownCommand : PluginDynamicCommand + { + // Tracks whether the current state is thumb down or thumb up. + private Boolean _isThumbDown = false; + + // Resource paths for the thumb up and thumb down images. + private readonly String _imageResourcePathThumbUp; + private readonly String _imageResourcePathThumbDown; + + // Initializes the command and loads the embedded image resource paths. + public ThumbUpDownCommand() + : base(displayName: "Thumb Up/Down", description: "Toggles between thumb up and thumb down", groupName: "Switches") + { + // Find the embedded image resources by filename. + this._imageResourcePathThumbUp = PluginResources.FindFile("ThumbUp.png"); + this._imageResourcePathThumbDown = PluginResources.FindFile("ThumbDown.png"); + } + + // This method is called when the user presses the button. + protected override void RunCommand(String actionParameter) + { + // Toggle the thumb state. + this._isThumbDown = !this._isThumbDown; + + // Notify the Plugin Service to refresh the button image. + this.ActionImageChanged(); + } + + // Returns the correct image based on the current thumb state. + protected override BitmapImage GetCommandImage(String actionParameter, PluginImageSize imageSize) + { + // Show ThumbDown image when down, ThumbUp image when up. + var resourcePath = this._isThumbDown ? this._imageResourcePathThumbDown : this._imageResourcePathThumbUp; + return PluginResources.ReadImage(resourcePath); + } + } +} diff --git a/DemoPlugin/src/Actions/ToggleMuteCommand.cs b/DemoPlugin/src/Actions/ToggleMuteCommand.cs new file mode 100644 index 0000000..704fcc7 --- /dev/null +++ b/DemoPlugin/src/Actions/ToggleMuteCommand.cs @@ -0,0 +1,47 @@ +namespace Loupedeck.DemoPlugin +{ + using System; + using System.Runtime.InteropServices; + + // This command toggles the system mute on both macOS and Windows. + // It is a universal command (no application linked) so it works globally. + + public class ToggleMuteCommand : PluginDynamicCommand + { + // Tracks the current mute state to update the button text accordingly. + private Boolean _isMuted = false; + + // Initializes the command with display name, description, and group. + public ToggleMuteCommand() + : base(displayName: "Toggle Mute", description: "Mutes and unmutes system volume", groupName: "Audio") + { + } + + // This method is called when the user presses the button assigned to this command. + protected override void RunCommand(String actionParameter) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + // On macOS, use osascript to toggle the mute state. + // Reads the current mute state and flips it. + System.Diagnostics.Process.Start("osascript", "-e \"set volume output muted not (output muted of (get volume settings))\""); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // On Windows, use PowerShell to send the VolumeMute key (keycode 173). + System.Diagnostics.Process.Start("powershell", "-c \"(New-Object -ComObject WScript.Shell).SendKeys([char]173)\""); + } + + // Flip the mute state and refresh the button label. + this._isMuted = !this._isMuted; + this.ActionImageChanged(); + } + + // Returns the button label based on the current mute state. + protected override String GetCommandDisplayName(String actionParameter, PluginImageSize imageSize) + { + // Show "MUTED" when muted, "UNMUTED" when sound is on. + return this._isMuted ? "Mute" : "Unmute"; + } + } +} diff --git a/DemoPlugin/DemoPlugin/DemoApplication.cs b/DemoPlugin/src/DemoApplication.cs similarity index 53% rename from DemoPlugin/DemoPlugin/DemoApplication.cs rename to DemoPlugin/src/DemoApplication.cs index b73d462..377cd8b 100644 --- a/DemoPlugin/DemoPlugin/DemoApplication.cs +++ b/DemoPlugin/src/DemoApplication.cs @@ -2,6 +2,8 @@ namespace Loupedeck.DemoPlugin { using System; + // This class can be used to connect the Loupedeck plugin to an application. + public class DemoApplication : ClientApplication { public DemoApplication() @@ -9,9 +11,12 @@ public DemoApplication() } // This method can be used to link the plugin to a Windows application. - protected override String GetProcessName() => "DemoApplication"; + protected override String GetProcessName() => ""; // This method can be used to link the plugin to a macOS application. protected override String GetBundleName() => ""; + + // This method can be used to check whether the application is installed or not. + public override ClientApplicationStatus GetApplicationStatus() => ClientApplicationStatus.Unknown; } } diff --git a/DemoPlugin/DemoPlugin/DemoPlugin.cs b/DemoPlugin/src/DemoPlugin.cs similarity index 92% rename from DemoPlugin/DemoPlugin/DemoPlugin.cs rename to DemoPlugin/src/DemoPlugin.cs index 3582542..4b9e14b 100644 --- a/DemoPlugin/DemoPlugin/DemoPlugin.cs +++ b/DemoPlugin/src/DemoPlugin.cs @@ -2,6 +2,8 @@ namespace Loupedeck.DemoPlugin { using System; + // This class contains the plugin-level logic of the Loupedeck plugin. + public class DemoPlugin : Plugin { // Gets a value indicating whether this is an API-only plugin. diff --git a/DemoPlugin/DemoPlugin/DemoPlugin.csproj b/DemoPlugin/src/DemoPlugin.csproj similarity index 64% rename from DemoPlugin/DemoPlugin/DemoPlugin.csproj rename to DemoPlugin/src/DemoPlugin.csproj index 4cdaddb..3bd0672 100644 --- a/DemoPlugin/DemoPlugin/DemoPlugin.csproj +++ b/DemoPlugin/src/DemoPlugin.csproj @@ -1,4 +1,4 @@ - + net8.0 @@ -18,17 +18,20 @@ $(LocalAppData)\Logi\LogiPluginService\Plugins\ ~/Library/Application\ Support/Logi/LogiPluginService/Plugins/ + $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\bin\')) $(BaseOutputPath)$(Configuration)\bin\ + + Demo - + - + @@ -38,22 +41,34 @@ + + - + - + + + + + + + + + + + - \ No newline at end of file + diff --git a/DemoPlugin/Directory.Build.props b/DemoPlugin/src/Directory.Build.props similarity index 74% rename from DemoPlugin/Directory.Build.props rename to DemoPlugin/src/Directory.Build.props index 287f0b1..fccb8a7 100644 --- a/DemoPlugin/Directory.Build.props +++ b/DemoPlugin/src/Directory.Build.props @@ -2,6 +2,6 @@ latest $(SolutionDir)obj\ - $(SolutionDir)bin\ + $(SolutionDir)..\bin\ diff --git a/DemoPlugin/DemoPlugin/PluginLog.cs b/DemoPlugin/src/Helpers/PluginLog.cs similarity index 94% rename from DemoPlugin/DemoPlugin/PluginLog.cs rename to DemoPlugin/src/Helpers/PluginLog.cs index b10542d..760eb8a 100644 --- a/DemoPlugin/DemoPlugin/PluginLog.cs +++ b/DemoPlugin/src/Helpers/PluginLog.cs @@ -2,7 +2,7 @@ namespace Loupedeck.DemoPlugin { using System; - // A helper class to write to the plugin log. + // A helper class that enables logging from the plugin code. internal static class PluginLog { diff --git a/DemoPlugin/DemoPlugin/PluginResources.cs b/DemoPlugin/src/Helpers/PluginResources.cs similarity index 100% rename from DemoPlugin/DemoPlugin/PluginResources.cs rename to DemoPlugin/src/Helpers/PluginResources.cs diff --git a/DemoPlugin/DemoPlugin/images/ThumbDown.png b/DemoPlugin/src/images/ThumbDown.png similarity index 100% rename from DemoPlugin/DemoPlugin/images/ThumbDown.png rename to DemoPlugin/src/images/ThumbDown.png diff --git a/DemoPlugin/DemoPlugin/images/ThumbUp.png b/DemoPlugin/src/images/ThumbUp.png similarity index 100% rename from DemoPlugin/DemoPlugin/images/ThumbUp.png rename to DemoPlugin/src/images/ThumbUp.png diff --git a/DemoPlugin/src/images/VolumeOff.png b/DemoPlugin/src/images/VolumeOff.png new file mode 100644 index 0000000000000000000000000000000000000000..5a6f0b386103cf7d9a7a4eb32b99bf0109369c4b GIT binary patch literal 878 zcmV-!1CjiRP)JRTo=#ygqQk`o8Pzg_|m@wQ+cZ*ns1IKNX(H!82Fg z$&|hdm;-Nu^eCVQo{0i_;F%~O|KrUA$8wGp4;XpiAssOC#1jn|1;7&v7&&;~3*w0c zj1usUdTdV=U=$cn6kt>Wo*2L=0nbd3hDhrHqZ08N1!yKK4+9r~OF7$R2d@`z18IOe zffpH5>RGK<0$w8k$A&ECjDmNlr21+P_`oUhJ@6`{{aPfvMgV@X3cL#}$>_fd_-&0j zQ*wQ^2eb>!^K)y5GiGfK06X!;?UtUCmciS2JR3aeGUX%wh32&~*+H+d~JHWKl|1Ge^v#%JyyfCKEOenmz z0cIfv$7>_tu=Cq&!HbPJz_dLv=$_Yhz+s5N@FW1vC?JIo;UqjggmXkMBA&M~X}2mt zZ=faLNKc1EYztsVf6Dm*>SRJqrn4SN1e^#sq54qbl)lM1;99{~!aCOY^*)PA_i`*M zb)7|}v()oOdeJiLxvbfbUz!mMXwDZOoI*!!{Spyt4>&llJ+CR^LK6Uq&wU3xA1>;b zfY=y7pU2zgo!3=Q1>An?0ZopVh$sS(_yMC{35a3rCQiAu6CJq5|ebOqvQ??f{y3 zOO2I18HigKc>$}D*$sSl4(F-(-+*4XK7SLho@o-Y%Rx+PSCR&5{(a^4bqd}~V1?CJ zlae*SRp3($XV#w|1MAWTXwqYz5Li9rdyPh;(NJyv0D7e?V)bDWP5=M^07*qoM6N<$ Ef{!A4y#N3J literal 0 HcmV?d00001 diff --git a/DemoPlugin/src/images/VolumeOn.png b/DemoPlugin/src/images/VolumeOn.png new file mode 100644 index 0000000000000000000000000000000000000000..11766a66119f568c6db269047a28757240eebc12 GIT binary patch literal 1490 zcmV;@1ugoCP)^vgLlHFf?o-Cb2(H4qUI5z$f{4J-vd0+s_aT6?>CVGghb*e=F4;L>&* zRt3xiHY@TP<4<6(b{iNnP5}NAg!Kb=0RM>3E@-!rp<*(yQ4qBim~Fr75uabvW;=t# z0l;^Hr2l|!@qHxF0kfukrPjJdN+uGRf^ooFMcz#ba*@CUj0RRK@*YkSj0En85x}d8 zyr+OJk`W0MFeEKgiwweCn)cDB_p#kR0PgZ zp1^jS`QFEI&F;XDLjFZx1Fujw>a|Auj{X)0`+2AE1QmIh@rliZr{PNFA9^|dE5${t zY{Ih{^aM(v!7$)aMdAvFy!q|l2-#I6Qn;#t>}J6QR;XF5_}a?PAt#K4dV9Bp^iK_O$JkK-Ns-Vw6q ziA=)=A-5o}fmL_{4bA}m7IN>CjvJL4|ZP2emQzq+Q}Vj*V=JkzkE6Wo|F zHu0$)>Ej&wR_Ab}yX#7z4&?@HElwH^RiT`Da+5I8)2FOeGNBhZD?^tgyVq_!NtmaS z3B!sQ7&?L2f+ds3b76`~XC)Q1H?UmDy_TW376fKtq>X!h5~^d>InQOCp3?8KMeK4- zyWAmvb+ajb>Ak=1aR^-{0*9-0&y43C@+0he+K@FbI@UIM%#M z$eP`Hn(x2#p1M)h57y5Gep9xsw*^pXFqI2Gc^-f6fN}O9rLLtNZ`#TO7oHLF+kBrs zjYDibU!97JZu2M>xKP<|s#u2<<11X=cA~8dY~16sBIRwJR$zHJ@Ux0K@)W`kS@U#A z1WvWB4h`Ld_B=SqBJ`@v(r$`~8N4{FmC-d8jmX4Omw-R}Bj8{1v?r=qw^k+{w};8}pv%=^YUf5kU#~AJSUyZ4eI+>Hq)$07*qoM6N<$f?E>2>i_@% literal 0 HcmV?d00001 diff --git a/DemoPlugin/DemoPlugin/package/metadata/Icon256x256.png b/DemoPlugin/src/package/metadata/Icon256x256.png similarity index 100% rename from DemoPlugin/DemoPlugin/package/metadata/Icon256x256.png rename to DemoPlugin/src/package/metadata/Icon256x256.png diff --git a/DemoPlugin/src/package/metadata/LoupedeckPackage.yaml b/DemoPlugin/src/package/metadata/LoupedeckPackage.yaml new file mode 100644 index 0000000..d171daa --- /dev/null +++ b/DemoPlugin/src/package/metadata/LoupedeckPackage.yaml @@ -0,0 +1,80 @@ +# ================================================================================================== +# GENERAL SETTINGS +# ================================================================================================== + +# Package type. Must be plugin4 for plugins. +type: plugin4 + +# Name that identifies the plugin. +name: Demo + +# Plugin name that is shown to the user. +displayName: Demo + +# Short description of the plugin. +description: Add a short description of the plugin here. + +# Name of the plugin library file. +pluginFileName: DemoPlugin.dll + +# Plugin version. +version: 1.0 + +# Author of the plugin. The author can be a company or an individual developer. +author: nirmal + +# Copyright information. +copyright: Copyright © 2026 nirmal. All rights reserved. + + +# ================================================================================================== +# PLUGIN PROPERTIES +# ================================================================================================== + +# Location of plugin files on Windows (relative to the plugin base directory). +# This parameter is required to support Windows. +pluginFolderWin: bin + +# Location of plugin files on macOS (relative to the plugin base directory). +# This parameter is required to support Mac. +pluginFolderMac: bin + +# List of devices the plugin is optimized for. +supportedDevices: + # LoupedeckCtFamily covers the following devices: Loupedeck CT, Live and Live S, + # Razer Stream Controller, and Razer Stream Controller X. + - LoupedeckCtFamily + + # LoupedeckPlusFamily covers Loupedeck+ device. Uncomment the following line to support Loupedeck+. + #- LoupedeckPlusFamily + +# List of plugin capabilities. +pluginCapabilities: + # Uncomment the following line if this plugin is an application plugin. + #- HasApplication + + # Uncomment the following line if the plugin sends keyboard shortcuts to the target application. + #- ActivatesApplication + +# Minimum Loupedeck version supported by the plugin. +minimumLoupedeckVersion: 6.0 + + +# ================================================================================================== +# LOUPEDECK MARKETPLACE SETTINGS +# ================================================================================================== + +# Name of the license that the plugin is licensed under. Select the one that you prefer. +# NOTE: GPL license is not compatible with Loupedeck Marketplace. +license: MIT + +# URL of the plugin license. +licenseUrl: https://opensource.org/licenses/MIT + +# URL of the support page where the users can send improvement suggestions and report bugs. +# The URL is shown in Loupedeck Marketplace. The page can be for example a GitHub issues page. +# NOTE: This setting is recommended when publishing the plugin in Loupedeck Marketplace. +#supportPageUrl: https://github.com/myusername/myplugin/issues + +# URL of the plugin homepage. The URL is shown in Loupedeck Marketplace. +#homePageUrl: https://github.com/myusername/myplugin diff --git a/README.md b/README.md deleted file mode 100644 index f35178d..0000000 --- a/README.md +++ /dev/null @@ -1,12 +0,0 @@ -# Welcome to Logi Actions SDK - -Here you can find an introduction to Logi Actions SDK, example plugin source code and the SDK documentation. - -## Documentation - -* [Logi Actions SDK Developer Docs](https://logitech.github.io/actions-sdk-docs) - -## Developer Discord - -* [Logi Developer Discord](https://discord.gg/etJCPZytHg) - From 3d4033f9e8003462075cadbb1a4d950c5901d592 Mon Sep 17 00:00:00 2001 From: Nirmal Kumar Date: Sun, 22 Mar 2026 22:15:20 +0000 Subject: [PATCH 2/2] Updated README.md --- README.md | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..1181174 --- /dev/null +++ b/README.md @@ -0,0 +1,73 @@ +# Welcome to Logi Actions SDK + +Here you can find an introduction to Logi Actions SDK, example plugin source code and the SDK documentation. + +## Documentation + +- [Logi Actions SDK Developer Docs](https://logitech.github.io/actions-sdk-docs/) +- [Logi Developer Discord](https://discord.gg/ptV2BfHCmm) + +--- + +# DemoPlugin + +A Logitech Actions SDK plugin built with C# (.NET 8) that works on both macOS and Windows. This project is intended as a learning resource for new developers joining the team — each file is structured and commented to help you understand how the SDK works. + +## Folder Structure + +``` +DemoPlugin/ +├── .vscode/ # VS Code setup — debugger config to attach to the Logi Plugin Service +│ # and build tasks for quick builds, packaging and installing +├── src/ +│ ├── Actions/ # Where all commands and adjustments live. +│ # Each file is one feature assigned to a button or dial +│ ├── Helpers/ # Shared utility classes used across all actions. +│ # PluginLog for logging, PluginResources for loading images +│ ├── images/ # PNG icons embedded into the plugin DLL. +│ # These are displayed on device buttons at runtime +│ └── package/ # Plugin identity files read by the Logi Plugin Service +│ # on startup — name, version, icon and supported devices +└── bin/ # Auto-generated build output. Never edit this folder manually. +``` + +## Actions + +| Action | Type | Description | +|---|---|---| +| Toggle Mute | Button | Mutes and unmutes system volume on macOS and Windows | +| Button Switches | Button | 4 independent on/off toggle switches | +| Thumb Up/Down | Button | Toggles between thumb up and thumb down image | +| Counter | Dial | Counts rotation ticks, press dial to reset | + +## Build + +```bash +# Debug — used during development and debugging +dotnet build -c Debug + +# Release — used for packaging and distribution +dotnet build -c Release +``` + +## Debug + +1. Open the project in VS Code +2. Run `dotnet build -c Debug` +3. Go to **Run > Start Debugging** (or press `F5`) +4. Select **Attach to Logi Plugin Service** + +You can now set breakpoints in any action file and step through your code live. + +## Package & Install + +```bash +# Package the plugin into a distributable .lplug4 file +logiplugintool pack ./bin/Release ./Demo.lplug4 + +# Install the plugin on this machine +logiplugintool install ./Demo.lplug4 + +# Uninstall the plugin +logiplugintool uninstall Demo +```