1
0
mirror of https://github.com/DarthAffe/RGB.NET.git synced 2025-12-13 10:08:31 +00:00

Compare commits

...

38 Commits

Author SHA1 Message Date
c0adbad599
Update release.yml 2024-03-09 12:15:21 +01:00
4773e0df74
Merge pull request #381 from DarthAffe/Development
v2.1
2024-03-09 12:11:38 +01:00
29e68ae8fe
Update release.yml 2024-03-09 00:44:57 +01:00
5aac20e982
Update ci.yml 2024-03-09 00:44:36 +01:00
d1e71ef827
Update ci.yml 2024-03-08 23:46:26 +01:00
08d526a7a4
Update ci.yml 2024-03-08 23:44:18 +01:00
acd4462b2a
Update ci.yml 2024-03-08 23:38:45 +01:00
e58d26d58d
Update ci.yml 2024-03-08 23:34:47 +01:00
417b9be3f9
Merge pull request #380 from DarthAffe/Actions
(MINOR) Updated workflows and bumped version for release
2024-03-08 21:47:22 +01:00
ced13e9ec2 (MINOR) Updated workflows and bumped version for release 2024-03-08 20:50:58 +01:00
4f0f25e34e
Merge pull request #379 from DarthAffe/RazerDebugDevices
Razer: Load Debug Device Properties for Each Device Type
2024-03-08 20:38:01 +01:00
58ed8bb2f1
Merge pull request #378 from diogotr7/feature/msi-pid
Add extra MSI pid to steelseries provider
2024-03-08 20:35:40 +01:00
Aytaç Kayadelen
d82eebd769 Razer: Load Debug Device Properties for Each Device Type 2024-03-08 20:28:09 +01:00
Diogo Trindade
3ca782a6a7
Add extra MSI pid to steelseries provider 2024-03-02 22:16:07 +00:00
a4bd797912
Merge pull request #375 from Aytackydln/logi-shutdown-on-dispose
Call LogiLedShutdown on Logitech provider dispose
2024-02-12 14:57:37 +01:00
Aytaç Kayadelen
b56a50ab08 call shutdown on Logitech provider dispose 2024-02-11 18:26:10 +01:00
50e20a7bdd
Merge pull request #374 from Aytackydln/num-lock-scroll-indicators
added Num/Caps/Scroll lock indicator mappings to OpenRGB
2024-01-28 22:20:43 +01:00
Aytaç Kayadelen
4959c6e8ad added Num/Caps/Scroll lock indicator mappings to OpenRGB 2024-01-27 22:19:46 +01:00
ef980f754c
Merge pull request #373 from DarthAffe/SDK/Wled
Changed WLED-devices to flush and reduced heartbeat timer
2024-01-18 23:41:52 +01:00
1df23a6b36 Changed WLED-devices to flush and reduced heartbeat timer 2024-01-18 23:35:19 +01:00
16b2877dce
Merge pull request #371 from DarthAffe/SDK/Wled
Added Provider for WLED-Devices
2024-01-18 20:40:07 +01:00
657bca29b0
Merge pull request #372 from DarthAffe/SmallFixes
Small fixes
2024-01-18 20:39:42 +01:00
6ba7e44e3c Added mising dispose in E131UpdateQueue 2024-01-17 23:39:39 +01:00
9004c50d78 Disabled resharper warning about missspelling of MSI 2024-01-17 23:39:06 +01:00
b2848cfbaa Fixed small mistake in WLED readme 2024-01-17 23:36:04 +01:00
23bd1119f2 Added helper to auto discover WLED devices to the readme 2024-01-17 23:34:43 +01:00
67672be54c Added Provider for WLED-Devices 2024-01-17 23:02:02 +01:00
3400edcf93
Merge pull request #370 from Myp3a/GE78LedMapping
Added MSI Raider GE78HX LED mapping
2024-01-17 10:25:33 +01:00
Myp3a
1fe8cab0a4 Added MSI GE78HX LED mapping 2024-01-16 17:42:02 +03:00
95f162de2d
Merge pull request #368 from DarthAffe/DarthAffe-patch-1
Update ci.yml
2024-01-09 23:45:30 +01:00
f07d228408
Update ci.yml 2024-01-09 22:44:33 +00:00
1312566eb0
Merge pull request #367 from DarthAffe/Devices/Razer
Added PID for Razer Naga Classic Edition
2024-01-09 23:18:06 +01:00
9aee9a1640 Renamed Razer Naga Classic Edition To Naga Classic 2024-01-09 22:57:28 +01:00
c89bbfea96 Added PID for Razer Naga Classic Edition 2024-01-09 22:56:13 +01:00
af43c0ae87
Merge pull request #365 from DarthAffe/Devices/Novation
Added Novation Launchpad Mini MK3
2024-01-04 20:12:24 +01:00
7898c50eed Fixed unexpected name of the Launchpad Mini MK3 2024-01-04 18:10:31 +01:00
505e7481f7 Small Novation-detection refactoring 2024-01-04 18:10:20 +01:00
4f478879c2 Added Novation Launchpad Mini MK3 2024-01-04 17:29:59 +01:00
25 changed files with 868 additions and 43 deletions

View File

@ -14,11 +14,11 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4.1.1
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
@ -37,25 +37,25 @@ jobs:
- name: Test
run: dotnet test --no-build --verbosity normal --configuration Release
- name: Upload a Build Artifact NET6
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET6
path: bin/net6.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload a Build Artifact NET7
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET7
path: bin/net7.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload a Build Artifact NET8
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET8
path: bin/net8.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload Nuget Build Artifact
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-Nugets
path: bin/*nupkg
@ -64,9 +64,3 @@ jobs:
run: dotnet nuget push **\*.nupkg --skip-duplicate --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json
- name: Symbols Push
run: dotnet nuget push **\*.snupkg --skip-duplicate --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json
- name: Create Tag
uses: mathieudutour/github-tag-action@v6.1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
custom_tag: ${{ steps.versioning.outputs.version }}
tag_prefix: v

View File

@ -10,9 +10,9 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4.1.1
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x

View File

@ -13,11 +13,11 @@ jobs:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4.1.1
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
8.0.x
@ -36,25 +36,25 @@ jobs:
- name: Test
run: dotnet test --no-build --verbosity normal --configuration Release
- name: Upload a Build Artifact NET6
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET6
path: bin/net6.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload a Build Artifact NET7
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET7
path: bin/net7.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload a Build Artifact NET8
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-NET8
path: bin/net8.0/RGB.NET.*.dll
if-no-files-found: error
- name: Upload Nuget Build Artifact
uses: actions/upload-artifact@v2.2.4
uses: actions/upload-artifact@v4.3.1
with:
name: RGB.NET-Nugets
path: bin/*nupkg

View File

@ -99,5 +99,12 @@ public sealed class E131UpdateQueue : UpdateQueue
return _sequenceNumber++;
}
public override void Dispose()
{
base.Dispose();
_socket.Dispose();
}
#endregion
}

View File

@ -277,6 +277,9 @@ public class LogitechDeviceProvider : AbstractRGBDeviceProvider
try { _LogitechGSDK.LogiLedRestoreLighting(); }
catch { /* at least we tried */ }
try { _LogitechGSDK.LogiLedShutdown(); }
catch { /* at least we tried */ }
try { _LogitechGSDK.UnloadLogitechGSDK(); }
catch { /* at least we tried */ }

View File

@ -34,5 +34,10 @@ public enum NovationDevices
[DeviceId("Launchpad Open")]
[ColorCapability(NovationColorCapabilities.RGB)]
[LedIdMapping(LedIdMappings.Pro)]
LaunchpadCustomFirmware
LaunchpadCustomFirmware,
[DeviceId("LPMiniMK3")]
[ColorCapability(NovationColorCapabilities.RGB)]
[LedIdMapping(LedIdMappings.Current)]
LaunchpadMiniMK3,
}

View File

@ -65,11 +65,10 @@ public sealed class NovationDeviceProvider : AbstractRGBDeviceProvider
MidiOutCaps outCaps = OutputDeviceBase.GetDeviceCapabilities(index);
if (outCaps.name == null) continue;
string deviceName = outCaps.name.ToUpperInvariant();
NovationDevices? deviceId = (NovationDevices?)Enum.GetValues(typeof(NovationDevices))
.Cast<Enum>()
.Where(x => x.GetDeviceId() != null)
.FirstOrDefault(x => deviceName.Contains(x.GetDeviceId()!.ToUpperInvariant()));
.FirstOrDefault(x => outCaps.name.Contains(x.GetDeviceId()!, StringComparison.InvariantCultureIgnoreCase));
if (deviceId == null) continue;

View File

@ -141,5 +141,8 @@ internal static class LedMappings
["Key: G9"] = LedId.Keyboard_Programmable9,
["Lighting"] = LedId.Keyboard_Brightness,
["Game Mode"] = LedId.Keyboard_WinLock,
["Num Lock Indicator"] = LedId.Keyboard_IndicatorNumLock,
["Caps Lock Indicator"] = LedId.Keyboard_IndicatorCapsLock,
["Scroll Lock Indicator"] = LedId.Keyboard_IndicatorScrollLock,
};
}

View File

@ -1,42 +1,55 @@
namespace RGB.NET.Devices.Razer;
using System;
namespace RGB.NET.Devices.Razer;
/// <summary>
/// Represents a type of Razer SDK endpoint
/// </summary>
[Flags]
public enum RazerEndpointType
{
/// <summary>
/// No endpoint
/// </summary>
None = 0,
/// <summary>
/// The keyboard endpoint
/// </summary>
Keyboard,
Keyboard = 1 << 0,
/// <summary>
/// The laptop keyboard endpoint, shares the <see cref="Keyboard"/> endpoint but has a different LED layout
/// </summary>
LaptopKeyboard,
LaptopKeyboard = 1 << 1,
/// <summary>
/// The mouse endpoint
/// </summary>
Mouse,
Mouse = 1 << 2,
/// <summary>
/// The headset endpoint
/// </summary>
Headset,
Headset = 1 << 3,
/// <summary>
/// The mousepad endpoint
/// </summary>
Mousepad,
Mousepad = 1 << 4,
/// <summary>
/// The keypad endpoint
/// </summary>
Keypad,
Keypad = 1 << 5,
/// <summary>
/// The Chroma Link endpoint
/// </summary>
ChromaLink,
}
ChromaLink = 1 << 6,
/// <summary>
/// All endpoints
/// </summary>
All = ~None
}

View File

@ -50,7 +50,7 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
/// <summary>
/// Forces to load the devices represented by the emulator even if they aren't reported to exist.
/// </summary>
public bool LoadEmulatorDevices { get; set; } = false;
public RazerEndpointType LoadEmulatorDevices { get; set; } = RazerEndpointType.None;
private const int VENDOR_ID = 0x1532;
@ -216,6 +216,7 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{ 0x008F, RGBDeviceType.Mouse, "Naga Pro", LedMappings.Mouse, RazerEndpointType.Mouse }, //this is via usb connection
{ 0x0090, RGBDeviceType.Mouse, "Naga Pro", LedMappings.Mouse, RazerEndpointType.Mouse }, //this is via bluetooth connection
{ 0x0091, RGBDeviceType.Mouse, "Viper 8khz", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x0093, RGBDeviceType.Mouse, "Naga Classic", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x0094, RGBDeviceType.Mouse, "Orochi V2", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x0096, RGBDeviceType.Mouse, "Naga X", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x0099, RGBDeviceType.Mouse, "Basilisk v3", LedMappings.Mouse, RazerEndpointType.Mouse },
@ -312,21 +313,26 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{
DeviceDefinitions.LoadFilter = loadFilter;
IList<IRGBDevice> devices = base.GetLoadedDevices(loadFilter).ToList();
List<IRGBDevice> devices = base.GetLoadedDevices(loadFilter).ToList();
if (LoadEmulatorDevices)
if (LoadEmulatorDevices != RazerEndpointType.None)
{
if (loadFilter.HasFlag(RGBDeviceType.Keyboard) && devices.All(d => d is not RazerKeyboardRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Keyboard) && (LoadEmulatorDevices.HasFlag(RazerEndpointType.Keyboard) || LoadEmulatorDevices.HasFlag(RazerEndpointType.LaptopKeyboard)) && devices.All(d => d is not RazerKeyboardRGBDevice))
devices.Add(new RazerKeyboardRGBDevice(new RazerKeyboardRGBDeviceInfo("Emulator Keyboard", RazerEndpointType.Keyboard), GetUpdateTrigger(), LedMappings.Keyboard));
if (loadFilter.HasFlag(RGBDeviceType.Mouse) && devices.All(d => d is not RazerMouseRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Mouse) && LoadEmulatorDevices.HasFlag(RazerEndpointType.Mouse) && devices.All(d => d is not RazerMouseRGBDevice))
devices.Add(new RazerMouseRGBDevice(new RazerRGBDeviceInfo(RGBDeviceType.Mouse, RazerEndpointType.Mouse, "Emulator Mouse"), GetUpdateTrigger(), LedMappings.Mouse));
if (loadFilter.HasFlag(RGBDeviceType.Headset) && devices.All(d => d is not RazerHeadsetRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Headset) && LoadEmulatorDevices.HasFlag(RazerEndpointType.Headset) && devices.All(d => d is not RazerHeadsetRGBDevice))
devices.Add(new RazerHeadsetRGBDevice(new RazerRGBDeviceInfo(RGBDeviceType.Headset, RazerEndpointType.Headset, "Emulator Headset"), GetUpdateTrigger()));
if (loadFilter.HasFlag(RGBDeviceType.Mousepad) && devices.All(d => d is not RazerMousepadRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Mousepad) && LoadEmulatorDevices.HasFlag(RazerEndpointType.Mousepad) && devices.All(d => d is not RazerMousepadRGBDevice))
devices.Add(new RazerMousepadRGBDevice(new RazerRGBDeviceInfo(RGBDeviceType.Mousepad, RazerEndpointType.Mousepad, "Emulator Mousepad"), GetUpdateTrigger()));
if (loadFilter.HasFlag(RGBDeviceType.Keypad) && devices.All(d => d is not RazerMousepadRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Keypad) && LoadEmulatorDevices.HasFlag(RazerEndpointType.Keypad) && devices.All(d => d is not RazerMousepadRGBDevice))
devices.Add(new RazerKeypadRGBDevice(new RazerRGBDeviceInfo(RGBDeviceType.Keypad, RazerEndpointType.Keypad, "Emulator Keypad"), GetUpdateTrigger()));
if (loadFilter.HasFlag(RGBDeviceType.Unknown) && devices.All(d => d is not RazerChromaLinkRGBDevice))
if (loadFilter.HasFlag(RGBDeviceType.Unknown) && LoadEmulatorDevices.HasFlag(RazerEndpointType.ChromaLink) && devices.All(d => d is not RazerChromaLinkRGBDevice))
devices.Add(new RazerChromaLinkRGBDevice(new RazerRGBDeviceInfo(RGBDeviceType.Unknown, RazerEndpointType.ChromaLink, "Emulator Chroma Link"), GetUpdateTrigger()));
}

View File

@ -315,6 +315,113 @@ public static class LedMappings
{ LedId.Keyboard_Custom1, SteelSeriesLedId.Power },
};
/// <summary>
/// Gets the mapping for GE78HX keyboards.
/// </summary>
// ReSharper disable once InconsistentNaming
public static LedMapping<SteelSeriesLedId> KeyboardMSIGE78Mapping { get; } = new()
{
{ LedId.Keyboard_Escape, SteelSeriesLedId.Escape },
{ LedId.Keyboard_F1, SteelSeriesLedId.F1 },
{ LedId.Keyboard_F2, SteelSeriesLedId.F2 },
{ LedId.Keyboard_F3, SteelSeriesLedId.F3 },
{ LedId.Keyboard_F4, SteelSeriesLedId.F4 },
{ LedId.Keyboard_F5, SteelSeriesLedId.F5 },
{ LedId.Keyboard_F6, SteelSeriesLedId.F6 },
{ LedId.Keyboard_F7, SteelSeriesLedId.F7 },
{ LedId.Keyboard_F8, SteelSeriesLedId.F8 },
{ LedId.Keyboard_F9, SteelSeriesLedId.F9 },
{ LedId.Keyboard_F10, SteelSeriesLedId.F10 },
{ LedId.Keyboard_F11, SteelSeriesLedId.F11 },
{ LedId.Keyboard_F12, SteelSeriesLedId.F12 },
{ LedId.Keyboard_PrintScreen, SteelSeriesLedId.PrintScreen },
{ LedId.Keyboard_Insert, SteelSeriesLedId.Insert },
{ LedId.Keyboard_Delete, SteelSeriesLedId.Delete },
{ LedId.Keyboard_GraveAccentAndTilde, SteelSeriesLedId.Backqoute },
{ LedId.Keyboard_1, SteelSeriesLedId.Keyboard1 },
{ LedId.Keyboard_2, SteelSeriesLedId.Keyboard2 },
{ LedId.Keyboard_3, SteelSeriesLedId.Keyboard3 },
{ LedId.Keyboard_4, SteelSeriesLedId.Keyboard4 },
{ LedId.Keyboard_5, SteelSeriesLedId.Keyboard5 },
{ LedId.Keyboard_6, SteelSeriesLedId.Keyboard6 },
{ LedId.Keyboard_7, SteelSeriesLedId.Keyboard7 },
{ LedId.Keyboard_8, SteelSeriesLedId.Keyboard8 },
{ LedId.Keyboard_9, SteelSeriesLedId.Keyboard9 },
{ LedId.Keyboard_0, SteelSeriesLedId.Keyboard0 },
{ LedId.Keyboard_MinusAndUnderscore, SteelSeriesLedId.Dash },
{ LedId.Keyboard_EqualsAndPlus, SteelSeriesLedId.Equal },
{ LedId.Keyboard_Backspace, SteelSeriesLedId.Backspace },
{ LedId.Keyboard_Tab, SteelSeriesLedId.Tab },
{ LedId.Keyboard_Q, SteelSeriesLedId.Q },
{ LedId.Keyboard_W, SteelSeriesLedId.W },
{ LedId.Keyboard_E, SteelSeriesLedId.E },
{ LedId.Keyboard_R, SteelSeriesLedId.R },
{ LedId.Keyboard_T, SteelSeriesLedId.T },
{ LedId.Keyboard_Y, SteelSeriesLedId.Y },
{ LedId.Keyboard_U, SteelSeriesLedId.U },
{ LedId.Keyboard_I, SteelSeriesLedId.I },
{ LedId.Keyboard_O, SteelSeriesLedId.O },
{ LedId.Keyboard_P, SteelSeriesLedId.P },
{ LedId.Keyboard_BracketLeft, SteelSeriesLedId.LBracket },
{ LedId.Keyboard_BracketRight, SteelSeriesLedId.RBracket },
{ LedId.Keyboard_Backslash, SteelSeriesLedId.Backslash },
{ LedId.Keyboard_CapsLock, SteelSeriesLedId.Caps },
{ LedId.Keyboard_A, SteelSeriesLedId.A },
{ LedId.Keyboard_S, SteelSeriesLedId.S },
{ LedId.Keyboard_D, SteelSeriesLedId.D },
{ LedId.Keyboard_F, SteelSeriesLedId.F },
{ LedId.Keyboard_G, SteelSeriesLedId.G },
{ LedId.Keyboard_H, SteelSeriesLedId.H },
{ LedId.Keyboard_J, SteelSeriesLedId.J },
{ LedId.Keyboard_K, SteelSeriesLedId.K },
{ LedId.Keyboard_L, SteelSeriesLedId.L },
{ LedId.Keyboard_SemicolonAndColon, SteelSeriesLedId.Semicolon },
{ LedId.Keyboard_ApostropheAndDoubleQuote, SteelSeriesLedId.Quote },
{ LedId.Keyboard_Enter, SteelSeriesLedId.Return },
{ LedId.Keyboard_LeftShift, SteelSeriesLedId.LShift },
{ LedId.Keyboard_Z, SteelSeriesLedId.Z },
{ LedId.Keyboard_X, SteelSeriesLedId.X },
{ LedId.Keyboard_C, SteelSeriesLedId.C },
{ LedId.Keyboard_V, SteelSeriesLedId.V },
{ LedId.Keyboard_B, SteelSeriesLedId.B },
{ LedId.Keyboard_N, SteelSeriesLedId.N },
{ LedId.Keyboard_M, SteelSeriesLedId.M },
{ LedId.Keyboard_CommaAndLessThan, SteelSeriesLedId.Comma },
{ LedId.Keyboard_PeriodAndBiggerThan, SteelSeriesLedId.Period },
{ LedId.Keyboard_SlashAndQuestionMark, SteelSeriesLedId.Slash },
{ LedId.Keyboard_RightShift, SteelSeriesLedId.RShift },
{ LedId.Keyboard_LeftCtrl, SteelSeriesLedId.LCtrl },
{ LedId.Keyboard_LeftGui, SteelSeriesLedId.LWin },
{ LedId.Keyboard_LeftAlt, SteelSeriesLedId.LAlt },
{ LedId.Keyboard_Space, SteelSeriesLedId.Spacebar },
{ LedId.Keyboard_RightAlt, SteelSeriesLedId.RAlt },
{ LedId.Keyboard_NonUsBackslash, SteelSeriesLedId.NonUsBackslash },
{ LedId.Keyboard_RightCtrl, SteelSeriesLedId.RCtrl },
{ LedId.Keyboard_Function, SteelSeriesLedId.Fn },
{ LedId.Keyboard_ArrowUp, SteelSeriesLedId.UpArrow },
{ LedId.Keyboard_ArrowLeft, SteelSeriesLedId.LeftArrow },
{ LedId.Keyboard_ArrowDown, SteelSeriesLedId.DownArrow },
{ LedId.Keyboard_ArrowRight, SteelSeriesLedId.RightArrow },
{ LedId.Keyboard_NumAsterisk, SteelSeriesLedId.KeypadTimes },
{ LedId.Keyboard_NumSlash, SteelSeriesLedId.KeypadDivide },
{ LedId.Logo, SteelSeriesLedId.Power },
{ LedId.Keyboard_NumPlus, SteelSeriesLedId.KeypadPlus },
{ LedId.Keyboard_NumMinus, SteelSeriesLedId.KeypadMinus },
{ LedId.Keyboard_NumLock, SteelSeriesLedId.KeypadNumLock },
{ LedId.Keyboard_Num7, SteelSeriesLedId.Keypad7 },
{ LedId.Keyboard_Num8, SteelSeriesLedId.Keypad8 },
{ LedId.Keyboard_Num9, SteelSeriesLedId.Keypad9 },
{ LedId.Keyboard_Num4, SteelSeriesLedId.Keypad4 },
{ LedId.Keyboard_Num5, SteelSeriesLedId.Keypad5 },
{ LedId.Keyboard_Num6, SteelSeriesLedId.Keypad6 },
{ LedId.Keyboard_Num1, SteelSeriesLedId.Keypad1 },
{ LedId.Keyboard_Num2, SteelSeriesLedId.Keypad2 },
{ LedId.Keyboard_Num3, SteelSeriesLedId.Keypad3 },
{ LedId.Keyboard_Num0, SteelSeriesLedId.Keypad0 },
{ LedId.Keyboard_NumPeriodAndDelete, SteelSeriesLedId.KeypadPeriod },
{ LedId.Keyboard_NumEnter, SteelSeriesLedId.KeypadEnter },
};
/// <summary>
/// Gets the mapping for one-zone mice.
/// </summary>

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using RGB.NET.Core;
using RGB.NET.Devices.SteelSeries.API;
@ -76,7 +76,9 @@ public sealed class SteelSeriesDeviceProvider : AbstractRGBDeviceProvider
{ 0x1600, RGBDeviceType.Keyboard, "Apex M800", LedMappings.KeyboardMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x1610, RGBDeviceType.Keyboard, "Apex Pro", LedMappings.KeyboardMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x1614, RGBDeviceType.Keyboard, "Apex Pro TKL", LedMappings.KeyboardTklMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x2036, RGBDeviceType.Keyboard, "MSI Notebook", LedMappings.KeyboardNotebookMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x2036, RGBDeviceType.Keyboard, "MSI Notebook", LedMappings.KeyboardNotebookMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x113A, RGBDeviceType.Keyboard, "MSI GE78HX", LedMappings.KeyboardMSIGE78Mapping, SteelSeriesDeviceType.PerKey },
{ 0x1122, RGBDeviceType.Keyboard, "MSI Notebook", LedMappings.KeyboardNotebookMappingUk, SteelSeriesDeviceType.PerKey },
//Headsets
{ 0x12AA, RGBDeviceType.Headset, "Arctis 5", LedMappings.HeadsetTwoZone, SteelSeriesDeviceType.TwoZone },

View File

@ -0,0 +1,33 @@
using System.Net.Http;
using System.Net.Http.Json;
namespace RGB.NET.Devices.WLED;
/// <summary>
/// Partial implementation of the WLED-JSON-API
/// </summary>
public static class WledAPI
{
/// <summary>
/// Gets the data returned by the 'info' endpoint of the WLED-device.
/// </summary>
/// <param name="address">The address of the device to request data from.</param>
/// <returns>The data returned by the WLED-device.</returns>
public static WledInfo? Info(string address)
{
if (string.IsNullOrEmpty(address)) return null;
using HttpClient client = new();
try
{
return client.Send(new HttpRequestMessage(HttpMethod.Get, $"http://{address}/json/info"))
.Content
.ReadFromJsonAsync<WledInfo>()
.Result;
}
catch
{
return null;
}
}
}

View File

@ -0,0 +1,156 @@
// ReSharper disable InconsistentNaming
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace RGB.NET.Devices.WLED;
public class WledInfo
{
[JsonPropertyName("ver")]
public string Version { get; set; } = "";
[JsonPropertyName("vid")]
public uint BuildId { get; set; }
[JsonPropertyName("leds")]
public LedsInfo Leds { get; set; } = new();
[JsonPropertyName("str")]
public bool SyncReceive { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; } = "";
[JsonPropertyName("udpport")]
public ushort UDPPort { get; set; }
[JsonPropertyName("live")]
public bool IsLive { get; set; }
[JsonPropertyName("liveseg")]
public short MainSegment { get; set; }
[JsonPropertyName("lm")]
public string RealtimeDataSource { get; set; } = "";
[JsonPropertyName("lip")]
public string RealtimeDataSourceIpAddress { get; set; } = "";
[JsonPropertyName("ws")]
public byte ConnectedWebSocketCount { get; set; }
[JsonPropertyName("fxcount")]
public byte EffectCount { get; set; }
[JsonPropertyName("palcount")]
public short PaletteCount { get; set; }
[JsonPropertyName("maps")]
public List<Map> LedMaps { get; set; } = [];
[JsonPropertyName("wifi")]
public Wifi WifiInfo { get; set; } = new();
[JsonPropertyName("fs")]
public Fs FilesystemInfo { get; set; } = new();
[JsonPropertyName("ndc")]
public short DiscoveredDeviceCount { get; set; }
[JsonPropertyName("arch")]
public string PlatformName { get; set; } = "";
[JsonPropertyName("core")]
public string ArduinoCoreVersion { get; set; } = "";
[JsonPropertyName("freeheap")]
public uint FreeHeap { get; set; }
[JsonPropertyName("uptime")]
public uint Uptime { get; set; }
[JsonPropertyName("time")]
public string Time { get; set; } = "";
[JsonPropertyName("brand")]
public string Brand { get; set; } = "";
[JsonPropertyName("product")]
public string Product { get; set; } = "";
[JsonPropertyName("ip")]
public string IpAddress { get; set; } = "";
public class LedsInfo
{
[JsonPropertyName("count")]
public ushort Count { get; set; }
[JsonPropertyName("pwr")]
public ushort PowerUsage { get; set; }
[JsonPropertyName("fps")]
public ushort RefreshRate { get; set; }
[JsonPropertyName("maxpwr")]
public ushort MaxPower { get; set; }
[JsonPropertyName("maxseg")]
public byte MaxSegments { get; set; }
[JsonPropertyName("matrix")]
public MatrixDims? Matrix { get; set; }
[JsonPropertyName("seglc")]
public List<byte> SegmentLightCapabilities { get; set; } = [];
[JsonPropertyName("lc")]
public byte CombinedSegmentLightCapabilities { get; set; }
}
public class Map
{
[JsonPropertyName("id")]
public byte Id { get; set; }
[JsonPropertyName("n")]
public string Name { get; set; } = "";
}
public class Wifi
{
[JsonPropertyName("bssid")]
public string BSSID { get; set; } = "";
[JsonPropertyName("rssi")]
public long RSSI { get; set; }
[JsonPropertyName("signal")]
public byte SignalQuality { get; set; }
[JsonPropertyName("channel")]
public int Channel { get; set; }
}
public class Fs
{
[JsonPropertyName("u")]
public uint UsedSpace { get; set; }
[JsonPropertyName("t")]
public uint TotalSpace { get; set; }
[JsonPropertyName("pmt")]
public ulong LastPresetsJsonModificationTime { get; set; }
}
public class MatrixDims
{
[JsonPropertyName("w")]
public ushort Width { get; set; }
[JsonPropertyName("h")]
public ushort Height { get; set; }
}
}

View File

@ -0,0 +1,8 @@
using RGB.NET.Core;
namespace RGB.NET.Devices.WLED;
/// <summary>
/// Represents a WLED-device.
/// </summary>
internal interface IWledRGBDevice : IRGBDevice;

View File

@ -0,0 +1,11 @@
namespace RGB.NET.Devices.WLED;
/// <summary>
/// Represents the data used to create a WLED-device.
/// </summary>
public interface IWledDeviceDefinition
{
string Address { get; }
string? Manufacturer { get; }
string? Model { get; }
}

View File

@ -0,0 +1,102 @@
using System;
using System.Net.Sockets;
using RGB.NET.Core;
namespace RGB.NET.Devices.WLED;
/// <inheritdoc />
/// <summary>
/// Represents the update-queue performing updates for WLED devices.
/// </summary>
internal sealed class WledDeviceUpdateQueue : UpdateQueue
{
#region Properties & Fields
/// <summary>
/// The UDP-Connection used to send data.
/// </summary>
private readonly UdpClient _socket;
/// <summary>
/// The buffer the UDP-data is stored in.
/// </summary>
private byte[] _buffer;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="WledDeviceUpdateQueue"/> class.
/// </summary>
/// <param name="updateTrigger">The update trigger used by this queue.</param>
/// <param name="deviceType">The device type used to identify the device.</param>
public WledDeviceUpdateQueue(IDeviceUpdateTrigger updateTrigger, string address, int port, int ledCount)
: base(updateTrigger)
{
_buffer = new byte[2 + (ledCount * 3)];
_buffer[0] = 2; // protocol: DRGB
_buffer[1] = 2; // Timeout 2s
_socket = new UdpClient();
_socket.Connect(address, port);
}
#endregion
#region Methods
/// <inheritdoc />
protected override void OnUpdate(object? sender, CustomUpdateData customData)
{
try
{
if (customData[CustomUpdateDataIndex.HEARTBEAT] as bool? ?? false)
Update(Array.Empty<(object key, Color color)>());
else
base.OnUpdate(sender, customData);
}
catch (Exception ex)
{
WledDeviceProvider.Instance.Throw(ex);
}
}
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{
Span<byte> data = _buffer.AsSpan()[2..];
foreach ((object key, Color color) in dataSet)
{
int ledIndex = (int)key;
int offset = (ledIndex * 3);
data[offset] = color.GetR();
data[offset + 1] = color.GetG();
data[offset + 2] = color.GetB();
}
_socket.Send(_buffer);
return true;
}
catch (Exception ex)
{
WledDeviceProvider.Instance.Throw(ex);
}
return false;
}
/// <inheritdoc />
public override void Dispose()
{
base.Dispose();
_socket.Dispose();
_buffer = [];
}
#endregion
}

View File

@ -0,0 +1,39 @@
using RGB.NET.Core;
namespace RGB.NET.Devices.WLED;
/// <inheritdoc cref="AbstractRGBDevice{WledRGBDeviceInfo}" />
/// <inheritdoc cref="IWledRGBDevice" />
/// <summary>
/// Represents a WLED-device.
/// </summary>
public sealed class WledRGBDevice : AbstractRGBDevice<WledRGBDeviceInfo>, IWledRGBDevice, ILedStripe
{
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="WledRGBDevice"/> class.
/// </summary>
internal WledRGBDevice(WledRGBDeviceInfo info, string address, IDeviceUpdateTrigger updateTrigger)
: base(info, new WledDeviceUpdateQueue(updateTrigger, address, info.Info.UDPPort, info.Info.Leds.Count))
{
InitializeLayout();
RequiresFlush = true;
}
#endregion
#region Methods
private void InitializeLayout()
{
for (int i = 0; i < DeviceInfo.Info.Leds.Count; i++)
AddLed(LedId.LedStripe1 + i, new Point(i * 10, 0), new Size(10, 10));
}
/// <inheritdoc />
protected override object GetLedCustomData(LedId ledId) => ledId - LedId.LedStripe1;
#endregion
}

View File

@ -0,0 +1,52 @@
using RGB.NET.Core;
namespace RGB.NET.Devices.WLED;
/// <inheritdoc />
/// <summary>
/// Represents a generic information for a WLED-<see cref="T:RGB.NET.Core.IRGBDevice" />.
/// </summary>
public sealed class WledRGBDeviceInfo : IRGBDeviceInfo
{
#region Properties & Fields
/// <inheritdoc />
public RGBDeviceType DeviceType => RGBDeviceType.LedStripe;
/// <inheritdoc />
public string DeviceName { get; }
/// <inheritdoc />
public string Manufacturer { get; }
/// <inheritdoc />
public string Model { get; }
/// <inheritdoc />
public object? LayoutMetadata { get; set; }
/// <summary>
/// Gets some info returned by the WLED-device.
/// </summary>
public WledInfo Info { get; }
#endregion
#region Constructors
/// <summary>
/// Internal constructor of managed <see cref="WledRGBDeviceInfo"/>.
/// </summary>
/// <param name="manufacturer">The manufacturer of the device.</param>
/// <param name="model">The represented device model.</param>
internal WledRGBDeviceInfo(WledInfo info, string? manufacturer, string? model)
{
this.Info = info;
this.Manufacturer = manufacturer ?? info.Brand;
this.Model = model ?? info.Name;
DeviceName = DeviceHelper.CreateDeviceName(Manufacturer, Model);
}
#endregion
}

View File

@ -0,0 +1,18 @@
namespace RGB.NET.Devices.WLED;
/// <inheritdoc />
public class WledDeviceDefinition(string address, string? manufacturer = null, string? model = null) : IWledDeviceDefinition
{
#region Properties & Fields
/// <inheritdoc />
public string Address { get; } = address;
/// <inheritdoc />
public string? Manufacturer { get; } = manufacturer;
/// <inheritdoc />
public string? Model { get; } = model;
#endregion
}

View File

@ -0,0 +1,82 @@
[RGB.NET](https://github.com/DarthAffe/RGB.NET) Device-Provider-Package for [WLED](https://kno.wled.ge/)-devices.
## Usage
This provider does not load anything by default and requires additional configuration to work.
```csharp
// Add as many WLED-devices as you like
WledDeviceProvider.Instance.AddDeviceDefinition(new WledDeviceDefinition("<hostname>"));
surface.Load(WledDeviceProvider.Instance);
```
You can also override the manufacturer and device model in the DeviceDefinition.
# Required SDK
This provider does not require an additional SDK.
UDP realtime needs to be enabled on the WLED device.
# Automatic device discovery
Due to the requirement of an additional dependency and the requirement to be able to configure devices manually anywy automatic discovery is not part of the provider.
Using the nuget `Tmds.MDns` you can use the following Helper to do this:
```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using Tmds.MDns;
namespace RGB.NET.Devices.WLED;
public static class WledDiscoveryHelper
{
/// <summary>
/// Searches for WLED devices and returns a list of devices found.
/// </summary>
/// <param name="waitFor">The time the discovery is waiting for responses. Choose this as short as possible as the method is blocking </param>
/// <param name="maxDevices">The maximum amount of devices that are expected in the network. The discovery will stop early if the given amount of devices is found.</param>
/// <returns>A list of addresses and device-infos.</returns>
public static IEnumerable<(string address, WledInfo info)> DiscoverDevices(int waitFor = 500, int maxDevices = -1)
{
List<(string address, WledInfo info)> devices = [];
using ManualResetEventSlim waitEvent = new(false);
int devicesToDetect = maxDevices <= 0 ? int.MaxValue : maxDevices;
ServiceBrowser mdns = new();
mdns.ServiceAdded += OnServiceAdded;
mdns.StartBrowse("_http._tcp");
waitEvent.Wait(TimeSpan.FromMilliseconds(waitFor));
mdns.StopBrowse();
mdns.ServiceAdded -= OnServiceAdded;
return devices;
void OnServiceAdded(object? sender, ServiceAnnouncementEventArgs args)
{
string address = args.Announcement.Addresses.FirstOrDefault()?.ToString() ?? string.Empty;
if (!string.IsNullOrWhiteSpace(address))
{
WledInfo? info = null;
try
{
info = WledAPI.Info(address);
}
catch { }
if (info != null)
{
devices.Add((address, info));
if (--devicesToDetect <= 0)
waitEvent.Set();
}
}
}
}
}
```

View File

@ -0,0 +1,62 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0;net7.0;net6.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Nullable>enable</Nullable>
<Authors>Darth Affe</Authors>
<Company>Wyrez</Company>
<Language>en-US</Language>
<NeutralLanguage>en-US</NeutralLanguage>
<Title>RGB.NET.Devices.WLED</Title>
<AssemblyName>RGB.NET.Devices.WLED</AssemblyName>
<AssemblyTitle>RGB.NET.Devices.WLED</AssemblyTitle>
<PackageId>RGB.NET.Devices.WLED</PackageId>
<RootNamespace>RGB.NET.Devices.WLED</RootNamespace>
<Description>WLED-Device-Implementations of RGB.NET</Description>
<Summary>WLED-Device-Implementations of RGB.NET, a C# (.NET) library for accessing various RGB-peripherals</Summary>
<Copyright>Copyright © Darth Affe 2024</Copyright>
<PackageCopyright>Copyright © Darth Affe 2024</PackageCopyright>
<PackageIcon>icon.png</PackageIcon>
<PackageReadmeFile>README.md</PackageReadmeFile>
<PackageProjectUrl>https://github.com/DarthAffe/RGB.NET</PackageProjectUrl>
<PackageLicenseExpression>LGPL-2.1-only</PackageLicenseExpression>
<RepositoryType>Github</RepositoryType>
<RepositoryUrl>https://github.com/DarthAffe/RGB.NET</RepositoryUrl>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageReleaseNotes></PackageReleaseNotes>
<Version>0.0.1</Version>
<AssemblyVersion>0.0.1</AssemblyVersion>
<FileVersion>0.0.1</FileVersion>
<OutputPath>..\bin\</OutputPath>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IncludeSource>True</IncludeSource>
<IncludeSymbols>True</IncludeSymbols>
<DebugType>portable</DebugType>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DefineConstants>TRACE;DEBUG</DefineConstants>
<DebugSymbols>true</DebugSymbols>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<Optimize>true</Optimize>
<NoWarn>$(NoWarn);CS1591;CS1572;CS1573</NoWarn>
<DefineConstants>RELEASE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Content Include="..\Resources\icon.png" Link="icon.png" Pack="true" PackagePath="\" />
<None Include="README.md" Pack="true" PackagePath="\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\RGB.NET.Core\RGB.NET.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=api/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generic/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -0,0 +1,113 @@
// ReSharper disable MemberCanBePrivate.Global
using System;
using System.Collections.Generic;
using RGB.NET.Core;
namespace RGB.NET.Devices.WLED;
/// <inheritdoc />
/// <summary>
/// Represents a device provider responsible for WS2812B- and WS2811-Led-devices.
/// </summary>
// ReSharper disable once InconsistentNaming
// ReSharper disable once UnusedType.Global
public sealed class WledDeviceProvider : AbstractRGBDeviceProvider
{
#region Constants
private const int HEARTBEAT_TIMER = 250;
#endregion
#region Properties & Fields
// ReSharper disable once InconsistentNaming
private static readonly object _lock = new();
private static WledDeviceProvider? _instance;
/// <summary>
/// Gets the singleton <see cref="WledDeviceProvider"/> instance.
/// </summary>
public static WledDeviceProvider Instance
{
get
{
lock (_lock)
return _instance ?? new WledDeviceProvider();
}
}
/// <summary>
/// Gets a list of all defined device-definitions.
/// </summary>
public List<IWledDeviceDefinition> DeviceDefinitions { get; } = [];
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="WledDeviceProvider"/> class.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if this constructor is called even if there is already an instance of this class.</exception>
public WledDeviceProvider()
{
lock (_lock)
{
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(WledDeviceProvider)}");
_instance = this;
}
}
#endregion
#region Methods
/// <summary>
/// Adds the specified <see cref="IWledDeviceDefinition" /> to this device-provider.
/// </summary>
/// <param name="deviceDefinition">The <see cref="IWledDeviceDefinition"/> to add.</param>
public void AddDeviceDefinition(IWledDeviceDefinition deviceDefinition) => DeviceDefinitions.Add(deviceDefinition);
/// <inheritdoc />
protected override void InitializeSDK() { }
/// <inheritdoc />
protected override IEnumerable<IRGBDevice> LoadDevices()
{
int i = 0;
foreach (IWledDeviceDefinition deviceDefinition in DeviceDefinitions)
{
IDeviceUpdateTrigger updateTrigger = GetUpdateTrigger(i++);
WledRGBDevice? device = CreateWledDevice(deviceDefinition, updateTrigger);
if (device != null)
yield return device;
}
}
private static WledRGBDevice? CreateWledDevice(IWledDeviceDefinition deviceDefinition, IDeviceUpdateTrigger updateTrigger)
{
WledInfo? wledInfo = WledAPI.Info(deviceDefinition.Address);
if (wledInfo == null) return null;
return new WledRGBDevice(new WledRGBDeviceInfo(wledInfo, deviceDefinition.Manufacturer, deviceDefinition.Model), deviceDefinition.Address, updateTrigger);
}
protected override IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) => new DeviceUpdateTrigger(updateRateHardLimit) { HeartbeatTimer = HEARTBEAT_TIMER };
/// <inheritdoc />
protected override void Dispose(bool disposing)
{
lock (_lock)
{
base.Dispose(disposing);
DeviceDefinitions.Clear();
_instance = null;
}
}
#endregion
}

View File

@ -49,6 +49,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.OpenRGB", "
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.Corsair_Legacy", "RGB.NET.Devices.Corsair_Legacy\RGB.NET.Devices.Corsair_Legacy.csproj", "{66AF690C-27A1-4097-AC53-57C0ED89E286}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.WLED", "RGB.NET.Devices.WLED\RGB.NET.Devices.WLED.csproj", "{C533C5EA-66A8-4826-A814-80791E7593ED}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -139,6 +141,10 @@ Global
{66AF690C-27A1-4097-AC53-57C0ED89E286}.Debug|Any CPU.Build.0 = Debug|Any CPU
{66AF690C-27A1-4097-AC53-57C0ED89E286}.Release|Any CPU.ActiveCfg = Release|Any CPU
{66AF690C-27A1-4097-AC53-57C0ED89E286}.Release|Any CPU.Build.0 = Release|Any CPU
{C533C5EA-66A8-4826-A814-80791E7593ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C533C5EA-66A8-4826-A814-80791E7593ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C533C5EA-66A8-4826-A814-80791E7593ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C533C5EA-66A8-4826-A814-80791E7593ED}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -161,6 +167,7 @@ Global
{EDBA49D6-AE96-4E96-9E6A-30154D93BD5F} = {92D7C263-D4C9-4D26-93E2-93C1F9C2CD16}
{F29A96E5-CDD0-469F-A871-A35A7519BC49} = {D13032C6-432E-4F43-8A32-071133C22B16}
{66AF690C-27A1-4097-AC53-57C0ED89E286} = {D13032C6-432E-4F43-8A32-071133C22B16}
{C533C5EA-66A8-4826-A814-80791E7593ED} = {D13032C6-432E-4F43-8A32-071133C22B16}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7F222AD4-1F9E-4AAB-9D69-D62372D4C1BA}