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

Merge remote-tracking branch 'refs/remotes/origin/Development' into asus-remove-system-management

This commit is contained in:
Aytackydln 2024-07-02 17:31:41 +02:00
commit 5e895f5806
62 changed files with 972 additions and 116 deletions

View File

@ -1,12 +1,15 @@
name: RGB.NET-CI
on:
push:
branches: [ Development ]
paths:
- '**.cs'
- '**.csproj'
- '**.yml'
workflow_dispatch:
inputs:
version:
description: 'version'
required: true
type: string
increment:
required: true
type: string
jobs:
build:
@ -14,48 +17,42 @@ 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
7.0.x
6.0.x
- name: Git Semantic Version
id: versioning
uses: PaulHatch/semantic-version@v4.0.3
with:
short_tags: false
format: "${major}.${minor}.${patch}-prerelease.${increment}"
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore --configuration Release /p:Version=${{ steps.versioning.outputs.version }}
run: dotnet build --no-restore --configuration Release /p:Version=${{ github.event.inputs.version }}-prerelease.${{ github.event.inputs.increment }}
- 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 +61,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

@ -1,60 +1,54 @@
name: RGB.NET-Release
on:
push:
branches: [ master ]
paths:
- '**.cs'
- '**.csproj'
- '**.yml'
workflow_dispatch:
inputs:
version:
description: 'version'
required: true
type: string
jobs:
build:
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
7.0.x
6.0.x
- name: Git Semantic Version
id: versioning
uses: PaulHatch/semantic-version@v4.0.3
with:
short_tags: false
format: "${major}.${minor}.${patch}"
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore --configuration Release /p:Version=${{ steps.versioning.outputs.version }}
run: dotnet build --no-restore --configuration Release /p:Version=${{ github.event.inputs.version }}
- 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
@ -62,7 +56,7 @@ jobs:
- name: Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ steps.versioning.outputs.version_tag }}
tag_name: v${{ github.event.inputs.version }}
generate_release_notes: true
files: bin/net8.0/RGB.NET.*.dll
- name: Nuget Push

View File

@ -91,9 +91,8 @@ public static class FloatExtensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static byte GetByteValueFromPercentage(this float percentage)
{
if (float.IsNaN(percentage)) return 0;
if (float.IsNaN(percentage) || (percentage <= 0)) return 0;
percentage = percentage.Clamp(0, 1.0f);
return (byte)(percentage >= 1.0f ? 255 : percentage * 256.0f);
}

View File

@ -126,7 +126,7 @@ public abstract class PixelTexture<T> : ITexture
/// </summary>
/// <param name="pixel">The pixel-data to convert.</param>
/// <returns>The color represented by the specified pixel-data.</returns>
protected abstract Color GetColor(in ReadOnlySpan<T> pixel);
protected abstract Color GetColor(ReadOnlySpan<T> pixel);
/// <summary>
/// Gets the pixel-data at the specified location.
@ -189,7 +189,7 @@ public sealed class PixelTexture : PixelTexture<Color>
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override Color GetColor(in ReadOnlySpan<Color> pixel) => pixel[0];
protected override Color GetColor(ReadOnlySpan<Color> pixel) => pixel[0];
#endregion
}

View File

@ -22,7 +22,7 @@ public sealed class AverageColorSampler : ISampler<Color>
#region Methods
/// <inheritdoc />
public unsafe void Sample(in SamplerInfo<Color> info, in Span<Color> pixelData)
public unsafe void Sample(in SamplerInfo<Color> info, Span<Color> pixelData)
{
int count = info.Width * info.Height;
if (count == 0) return;

View File

@ -13,5 +13,5 @@ public interface ISampler<T>
/// </summary>
/// <param name="info">The information containing the data to sample.</param>
/// <param name="pixelData">The buffer used to write the resulting pixel to.</param>
void Sample(in SamplerInfo<T> info, in Span<T> pixelData);
void Sample(in SamplerInfo<T> info, Span<T> pixelData);
}

View File

@ -44,7 +44,7 @@ public readonly ref struct SamplerInfo<T>
/// <param name="width">The width of the region the data comes from.</param>
/// <param name="height">The height of region the data comes from.</param>
/// <param name="data">The data to sample.</param>
public SamplerInfo(int x, int y, int width, int height, int stride, int dataPerPixel, in ReadOnlySpan<T> data)
public SamplerInfo(int x, int y, int width, int height, int stride, int dataPerPixel, ReadOnlySpan<T> data)
{
this._x = x;
this._y = y;

View File

@ -80,7 +80,7 @@ public abstract class UpdateQueue<TIdentifier, TData> : AbstractReferenceCountin
/// Performs the update this queue is responsible for.
/// </summary>
/// <param name="dataSet">The set of data that needs to be updated.</param>
protected abstract bool Update(in ReadOnlySpan<(TIdentifier key, TData color)> dataSet);
protected abstract bool Update(ReadOnlySpan<(TIdentifier key, TData color)> dataSet);
/// <summary>
/// Sets or merges the provided data set in the current dataset and notifies the trigger that there is new data available.

View File

@ -43,7 +43,7 @@ public sealed class AsusUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -37,7 +37,7 @@ public sealed class CoolerMasterUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -40,7 +40,7 @@ public sealed class CorsairDeviceUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override unsafe bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override unsafe bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -47,6 +47,9 @@ internal static unsafe class _CUESDK
#region Properties & Fields
// ReSharper disable once NotAccessedField.Local - This is important, the delegate can be collected if it's not stored!
private static readonly CorsairSessionStateChangedHandler SESSION_STATE_CHANGED_CALLBACK;
internal static bool IsConnected => SesionState == CorsairSessionState.Connected;
internal static CorsairSessionState SesionState { get; private set; }
@ -58,6 +61,15 @@ internal static unsafe class _CUESDK
#endregion
#region Constructors
static _CUESDK()
{
SESSION_STATE_CHANGED_CALLBACK = CorsairSessionStateChangedCallback;
}
#endregion
#region Methods
private static void CorsairSessionStateChangedCallback(nint context, _CorsairSessionStateChanged eventdata)
@ -174,7 +186,7 @@ internal static unsafe class _CUESDK
{
if (_corsairConnectPtr == null) throw new RGBDeviceException("The Corsair-SDK is not initialized.");
if (IsConnected) throw new RGBDeviceException("The Corsair-SDK is already connected.");
return _corsairConnectPtr(CorsairSessionStateChangedCallback, 0);
return _corsairConnectPtr(SESSION_STATE_CHANGED_CALLBACK, 0);
}
internal static CorsairError CorsairGetSessionDetails(out _CorsairSessionDetails? details)

View File

@ -35,7 +35,7 @@ public class CorsairDeviceUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -59,7 +59,7 @@ public sealed class E131UpdateQueue : UpdateQueue
}
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{
@ -99,5 +99,12 @@ public sealed class E131UpdateQueue : UpdateQueue
return _sequenceNumber++;
}
public override void Dispose()
{
base.Dispose();
_socket.Dispose();
}
#endregion
}

View File

@ -7,7 +7,7 @@ internal sealed class DebugDeviceUpdateQueue() : UpdateQueue(new DeviceUpdateTri
{
#region Methods
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet) => true;
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet) => true;
#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

@ -25,7 +25,7 @@ public sealed class LogitechPerDeviceUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -24,7 +24,7 @@ public sealed class LogitechPerKeyUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -33,7 +33,7 @@ public sealed class LogitechZoneUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -34,7 +34,7 @@ public sealed class MsiDeviceUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

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

@ -35,7 +35,7 @@ public abstract class MidiUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

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

@ -48,7 +48,7 @@ public sealed class OpenRGBUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -44,7 +44,7 @@ public sealed class PicoPiBulkUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -41,7 +41,7 @@ public sealed class PicoPiHIDUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -212,7 +212,7 @@ public sealed class PicoPiSDK : IDisposable
/// </summary>
/// <param name="data">The data to send.</param>
/// <param name="channel">The channel to update.</param>
public void SendHidUpdate(in Span<byte> buffer, int channel)
public void SendHidUpdate(Span<byte> buffer, int channel)
{
int chunks = buffer.Length / HID_OFFSET_MULTIPLIER;
if ((chunks * HID_OFFSET_MULTIPLIER) < buffer.Length) chunks++;
@ -232,7 +232,7 @@ public sealed class PicoPiSDK : IDisposable
/// <param name="channel">The channel to update.</param>
/// <param name="chunk">The chunk id of the packet. (Required if packets are fragmented.)</param>
/// <param name="update">A value indicating if the device should update directly after receiving this packet. (If packets are fragmented this should only be true for the last chunk.)</param>
public void SendHidUpdate(in Span<byte> data, int channel, int chunk, bool update)
public void SendHidUpdate(Span<byte> data, int channel, int chunk, bool update)
{
if (data.Length == 0) return;
@ -253,7 +253,7 @@ public sealed class PicoPiSDK : IDisposable
/// </remarks>
/// <param name="data">The data packet to send.</param>
/// <param name="channel">The channel to update.</param>
public void SendBulkUpdate(in Span<byte> data, int channel)
public void SendBulkUpdate(Span<byte> data, int channel)
{
if ((data.Length == 0) || !IsBulkSupported) return;

View File

@ -25,7 +25,7 @@ public sealed class RazerChromaLinkUpdateQueue : RazerUpdateQueue
#region Methods
/// <inheritdoc />
protected override nint CreateEffectParams(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override nint CreateEffectParams(ReadOnlySpan<(object key, Color color)> dataSet)
{
_Color[] colors = new _Color[_Defines.CHROMALINK_MAX_LEDS];

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

@ -13,10 +13,17 @@ public static class LedMappings
/// </summary>
public static LedMapping<int> Keyboard { get; } = new()
{
//Row 0 is empty
#region Row 0
[LedId.LedStripe1] = (_Defines.KEYBOARD_MAX_COLUMN * 0) + 0,
[LedId.LedStripe16] = (_Defines.KEYBOARD_MAX_COLUMN * 0) + 23,
#endregion
#region Row 1
[LedId.LedStripe2] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 0,
[LedId.Custom1] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 1,
[LedId.Keyboard_Escape] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 2,
[LedId.Keyboard_F1] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 4,
[LedId.Keyboard_F2] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 5,
@ -33,12 +40,17 @@ public static class LedMappings
[LedId.Keyboard_PrintScreen] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 16,
[LedId.Keyboard_ScrollLock] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 17,
[LedId.Keyboard_PauseBreak] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 18,
[LedId.Logo] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 21,
[LedId.Keyboard_MediaPreviousTrack] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 19,
[LedId.Keyboard_MediaPlay] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 20,
[LedId.Keyboard_MediaNextTrack] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 21,
[LedId.Keyboard_MediaMute] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 22,
[LedId.LedStripe15] = (_Defines.KEYBOARD_MAX_COLUMN * 1) + 23,
#endregion
#region Row 2
[LedId.LedStripe3] = (_Defines.KEYBOARD_MAX_COLUMN * 2) + 0,
[LedId.Keyboard_Programmable1] = (_Defines.KEYBOARD_MAX_COLUMN * 2) + 1,
[LedId.Keyboard_GraveAccentAndTilde] = (_Defines.KEYBOARD_MAX_COLUMN * 2) + 2,
[LedId.Keyboard_1] = (_Defines.KEYBOARD_MAX_COLUMN * 2) + 3,
@ -61,11 +73,13 @@ public static class LedMappings
[LedId.Keyboard_NumSlash] = (_Defines.KEYBOARD_MAX_COLUMN * 2) + 20,
[LedId.Keyboard_NumAsterisk] = (_Defines.KEYBOARD_MAX_COLUMN * 2) + 21,
[LedId.Keyboard_NumMinus] = (_Defines.KEYBOARD_MAX_COLUMN * 2) + 22,
[LedId.LedStripe14] = (_Defines.KEYBOARD_MAX_COLUMN * 2) + 23,
#endregion
#region Row 3
[LedId.LedStripe4] = (_Defines.KEYBOARD_MAX_COLUMN * 3) + 0,
[LedId.Keyboard_Programmable2] = (_Defines.KEYBOARD_MAX_COLUMN * 3) + 1,
[LedId.Keyboard_Tab] = (_Defines.KEYBOARD_MAX_COLUMN * 3) + 2,
[LedId.Keyboard_Q] = (_Defines.KEYBOARD_MAX_COLUMN * 3) + 3,
@ -88,11 +102,13 @@ public static class LedMappings
[LedId.Keyboard_Num8] = (_Defines.KEYBOARD_MAX_COLUMN * 3) + 20,
[LedId.Keyboard_Num9] = (_Defines.KEYBOARD_MAX_COLUMN * 3) + 21,
[LedId.Keyboard_NumPlus] = (_Defines.KEYBOARD_MAX_COLUMN * 3) + 22,
[LedId.LedStripe13] = (_Defines.KEYBOARD_MAX_COLUMN * 3) + 23,
#endregion
#region Row 4
[LedId.LedStripe5] = (_Defines.KEYBOARD_MAX_COLUMN * 4) + 0,
[LedId.Keyboard_Programmable3] = (_Defines.KEYBOARD_MAX_COLUMN * 4) + 1,
[LedId.Keyboard_CapsLock] = (_Defines.KEYBOARD_MAX_COLUMN * 4) + 2,
[LedId.Keyboard_A] = (_Defines.KEYBOARD_MAX_COLUMN * 4) + 3,
@ -111,11 +127,13 @@ public static class LedMappings
[LedId.Keyboard_Num4] = (_Defines.KEYBOARD_MAX_COLUMN * 4) + 19,
[LedId.Keyboard_Num5] = (_Defines.KEYBOARD_MAX_COLUMN * 4) + 20,
[LedId.Keyboard_Num6] = (_Defines.KEYBOARD_MAX_COLUMN * 4) + 21,
[LedId.LedStripe12] = (_Defines.KEYBOARD_MAX_COLUMN * 4) + 23,
#endregion
#region Row 5
[LedId.LedStripe6] = (_Defines.KEYBOARD_MAX_COLUMN * 5) + 0,
[LedId.Keyboard_Programmable4] = (_Defines.KEYBOARD_MAX_COLUMN * 5) + 1,
[LedId.Keyboard_LeftShift] = (_Defines.KEYBOARD_MAX_COLUMN * 5) + 2,
[LedId.Keyboard_NonUsBackslash] = (_Defines.KEYBOARD_MAX_COLUMN * 5) + 3,
@ -135,11 +153,13 @@ public static class LedMappings
[LedId.Keyboard_Num2] = (_Defines.KEYBOARD_MAX_COLUMN * 5) + 20,
[LedId.Keyboard_Num3] = (_Defines.KEYBOARD_MAX_COLUMN * 5) + 21,
[LedId.Keyboard_NumEnter] = (_Defines.KEYBOARD_MAX_COLUMN * 5) + 22,
[LedId.LedStripe11] = (_Defines.KEYBOARD_MAX_COLUMN * 5) + 23,
#endregion
#region Row 6
[LedId.LedStripe7] = (_Defines.KEYBOARD_MAX_COLUMN * 6) + 0,
[LedId.Keyboard_Programmable5] = (_Defines.KEYBOARD_MAX_COLUMN * 6) + 1,
[LedId.Keyboard_LeftCtrl] = (_Defines.KEYBOARD_MAX_COLUMN * 6) + 2,
[LedId.Keyboard_LeftGui] = (_Defines.KEYBOARD_MAX_COLUMN * 6) + 3,
@ -152,12 +172,18 @@ public static class LedMappings
[LedId.Keyboard_ArrowLeft] = (_Defines.KEYBOARD_MAX_COLUMN * 6) + 16,
[LedId.Keyboard_ArrowDown] = (_Defines.KEYBOARD_MAX_COLUMN * 6) + 17,
[LedId.Keyboard_ArrowRight] = (_Defines.KEYBOARD_MAX_COLUMN * 6) + 18,
[LedId.LedStripe9] = (_Defines.KEYBOARD_MAX_COLUMN * 6) + 19,
[LedId.Keyboard_Num0] = (_Defines.KEYBOARD_MAX_COLUMN * 6) + 20,
[LedId.Keyboard_NumPeriodAndDelete] = (_Defines.KEYBOARD_MAX_COLUMN * 6) + 21,
[LedId.LedStripe10] = (_Defines.KEYBOARD_MAX_COLUMN * 6) + 23,
#endregion
//Row 7 is also empty
#region Row 6
[LedId.LedStripe8] = (_Defines.KEYBOARD_MAX_COLUMN * 7) + 0,
#endregion
};

View File

@ -30,7 +30,7 @@ public abstract class RazerUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{
@ -77,7 +77,7 @@ public abstract class RazerUpdateQueue : UpdateQueue
/// </summary>
/// <param name="dataSet">The data to be updated.</param>
/// <returns>An <see cref="IntPtr"/> pointing to the effect parameter struct.</returns>
protected abstract nint CreateEffectParams(in ReadOnlySpan<(object key, Color color)> dataSet);
protected abstract nint CreateEffectParams(ReadOnlySpan<(object key, Color color)> dataSet);
#endregion
}

View File

@ -25,7 +25,7 @@ public sealed class RazerHeadsetUpdateQueue : RazerUpdateQueue
#region Methods
/// <inheritdoc />
protected override nint CreateEffectParams(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override nint CreateEffectParams(ReadOnlySpan<(object key, Color color)> dataSet)
{
_Color[] colors = new _Color[_Defines.HEADSET_MAX_LEDS];

View File

@ -25,7 +25,7 @@ public sealed class RazerKeyboardUpdateQueue : RazerUpdateQueue
#region Methods
/// <inheritdoc />
protected override nint CreateEffectParams(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override nint CreateEffectParams(ReadOnlySpan<(object key, Color color)> dataSet)
{
_Color[] colors = new _Color[_Defines.KEYBOARD_MAX_LEDS];

View File

@ -25,7 +25,7 @@ public sealed class RazerKeypadUpdateQueue : RazerUpdateQueue
#region Methods
/// <inheritdoc />
protected override nint CreateEffectParams(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override nint CreateEffectParams(ReadOnlySpan<(object key, Color color)> dataSet)
{
_Color[] colors = new _Color[_Defines.KEYPAD_MAX_LEDS];

View File

@ -25,7 +25,7 @@ public sealed class RazerMouseUpdateQueue : RazerUpdateQueue
#region Methods
/// <inheritdoc />
protected override nint CreateEffectParams(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override nint CreateEffectParams(ReadOnlySpan<(object key, Color color)> dataSet)
{
_Color[] colors = new _Color[_Defines.MOUSE_MAX_LEDS];

View File

@ -25,7 +25,7 @@ public sealed class RazerMousepadUpdateQueue : RazerUpdateQueue
#region Methods
/// <inheritdoc />
protected override nint CreateEffectParams(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override nint CreateEffectParams(ReadOnlySpan<(object key, Color color)> dataSet)
{
_Color[] colors = new _Color[_Defines.MOUSEPAD_MAX_LEDS];

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;
@ -139,7 +139,7 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{ 0x028B, RGBDeviceType.Keyboard, "Blade 17 (2022)", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x028C, RGBDeviceType.Keyboard, "Blade 14 (2022)", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x029F, RGBDeviceType.Keyboard, "Blade 16 (2023)", LedMappings.Blade, RazerEndpointType.Keyboard },
{ 0x028D, RGBDeviceType.Keyboard, "BlackWidow V4", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x028D, RGBDeviceType.Keyboard, "BlackWidow V4 Pro", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x0290, RGBDeviceType.Keyboard, "DeathStalker V2 Pro", LedMappings.Keyboard, RazerEndpointType.Keyboard }, // Wireless
{ 0x0292, RGBDeviceType.Keyboard, "DeathStalker V2 Pro", LedMappings.Keyboard, RazerEndpointType.Keyboard }, // Wired
{ 0x0294, RGBDeviceType.Keyboard, "Ornata V3 X", LedMappings.Keyboard, RazerEndpointType.Keyboard },
@ -149,6 +149,7 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{ 0x02A0, RGBDeviceType.Keyboard, "Blade 18", LedMappings.Blade, RazerEndpointType.Keyboard },
{ 0x02A1, RGBDeviceType.Keyboard, "Ornata V3", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x02A5, RGBDeviceType.Keyboard, "BlackWidow V4 75%", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x02A7, RGBDeviceType.Keyboard, "Huntsman V3 Pro TKL", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x0A24, RGBDeviceType.Keyboard, "BlackWidow V3 TKL", LedMappings.Keyboard, RazerEndpointType.Keyboard },
// Mice
@ -216,6 +217,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 +314,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

@ -51,7 +51,7 @@ internal sealed class SteelSeriesDeviceUpdateQueue : UpdateQueue
}
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using RGB.NET.Core;
using RGB.NET.Devices.SteelSeries.API;
@ -69,6 +69,7 @@ public sealed class SteelSeriesDeviceProvider : AbstractRGBDeviceProvider
{ 0x1852, RGBDeviceType.Mouse, "Aerox 5 Wireless", LedMappings.MouseThreeZone, SteelSeriesDeviceType.ThreeZone },
//Keyboards
{ 0x161A, RGBDeviceType.Keyboard, "Apex 3", LedMappings.KeyboardMappingUk, SteelSeriesDeviceType.TenZone },
{ 0x161C, RGBDeviceType.Keyboard, "Apex 5", LedMappings.KeyboardMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x1612, RGBDeviceType.Keyboard, "Apex 7", LedMappings.KeyboardMappingUk, SteelSeriesDeviceType.PerKey },
{ 0x1618, RGBDeviceType.Keyboard, "Apex 7 TKL", LedMappings.KeyboardTklMappingUk, SteelSeriesDeviceType.PerKey },
@ -76,7 +77,10 @@ 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 },
{ 0x1630, RGBDeviceType.Keyboard, "Apex Pro TKL", LedMappings.KeyboardTklMappingUk, SteelSeriesDeviceType.PerKey }, // DarthAffe 27.05.2024: This could be a generic wireless connector
{ 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(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

@ -56,7 +56,7 @@ public abstract class SerialConnectionUpdateQueue<TData> : UpdateQueue
}
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -77,7 +77,7 @@ public sealed class NodeMCUWS2812USBUpdateQueue : UpdateQueue
}
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -33,7 +33,7 @@ public sealed class WootingUpdateQueue : UpdateQueue
#region Methods
/// <inheritdoc />
protected override bool Update(in ReadOnlySpan<(object key, Color color)> dataSet)
protected override bool Update(ReadOnlySpan<(object key, Color color)> dataSet)
{
try
{

View File

@ -61,7 +61,7 @@ public sealed class BytePixelTexture : PixelTexture<byte>
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override Color GetColor(in ReadOnlySpan<byte> pixel)
protected override Color GetColor(ReadOnlySpan<byte> pixel)
{
return ColorFormat switch
{

View File

@ -61,7 +61,7 @@ public sealed class FloatPixelTexture : PixelTexture<float>
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override Color GetColor(in ReadOnlySpan<float> pixel)
protected override Color GetColor(ReadOnlySpan<float> pixel)
{
return ColorFormat switch
{

View File

@ -18,7 +18,7 @@ public sealed class AverageByteSampler : ISampler<byte>
#region Methods
/// <inheritdoc />
public unsafe void Sample(in SamplerInfo<byte> info, in Span<byte> pixelData)
public unsafe void Sample(in SamplerInfo<byte> info, Span<byte> pixelData)
{
int count = info.Width * info.Height;
if (count == 0) return;

View File

@ -12,7 +12,7 @@ public sealed class AverageFloatSampler : ISampler<float>
#region Methods
/// <inheritdoc />
public unsafe void Sample(in SamplerInfo<float> info, in Span<float> pixelData)
public unsafe void Sample(in SamplerInfo<float> info, Span<float> pixelData)
{
int count = info.Width * info.Height;
if (count == 0) return;

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}