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:
commit
5e895f5806
41
.github/workflows/ci.yml
vendored
41
.github/workflows/ci.yml
vendored
@ -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
|
||||
|
||||
4
.github/workflows/pr_verify.yml
vendored
4
.github/workflows/pr_verify.yml
vendored
@ -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
|
||||
|
||||
34
.github/workflows/release.yml
vendored
34
.github/workflows/release.yml
vendored
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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 */ }
|
||||
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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,
|
||||
}
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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];
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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];
|
||||
|
||||
|
||||
@ -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];
|
||||
|
||||
|
||||
@ -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];
|
||||
|
||||
|
||||
@ -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];
|
||||
|
||||
|
||||
@ -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];
|
||||
|
||||
|
||||
@ -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()));
|
||||
}
|
||||
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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 },
|
||||
|
||||
33
RGB.NET.Devices.WLED/API/WledAPI.cs
Normal file
33
RGB.NET.Devices.WLED/API/WledAPI.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
156
RGB.NET.Devices.WLED/API/WledInfo.cs
Normal file
156
RGB.NET.Devices.WLED/API/WledInfo.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
8
RGB.NET.Devices.WLED/Generic/IWLedRGBDevice.cs
Normal file
8
RGB.NET.Devices.WLED/Generic/IWLedRGBDevice.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using RGB.NET.Core;
|
||||
|
||||
namespace RGB.NET.Devices.WLED;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a WLED-device.
|
||||
/// </summary>
|
||||
internal interface IWledRGBDevice : IRGBDevice;
|
||||
11
RGB.NET.Devices.WLED/Generic/IWledDeviceDefinition.cs
Normal file
11
RGB.NET.Devices.WLED/Generic/IWledDeviceDefinition.cs
Normal 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; }
|
||||
}
|
||||
102
RGB.NET.Devices.WLED/Generic/WLedDeviceUpdateQueue.cs
Normal file
102
RGB.NET.Devices.WLED/Generic/WLedDeviceUpdateQueue.cs
Normal 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
|
||||
}
|
||||
39
RGB.NET.Devices.WLED/Generic/WLedRGBDevice.cs
Normal file
39
RGB.NET.Devices.WLED/Generic/WLedRGBDevice.cs
Normal 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
|
||||
}
|
||||
52
RGB.NET.Devices.WLED/Generic/WLedRGBDeviceInfo.cs
Normal file
52
RGB.NET.Devices.WLED/Generic/WLedRGBDeviceInfo.cs
Normal 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
|
||||
}
|
||||
18
RGB.NET.Devices.WLED/Generic/WledDeviceDefinition.cs
Normal file
18
RGB.NET.Devices.WLED/Generic/WledDeviceDefinition.cs
Normal 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
|
||||
}
|
||||
82
RGB.NET.Devices.WLED/README.md
Normal file
82
RGB.NET.Devices.WLED/README.md
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
62
RGB.NET.Devices.WLED/RGB.NET.Devices.WLED.csproj
Normal file
62
RGB.NET.Devices.WLED/RGB.NET.Devices.WLED.csproj
Normal 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>
|
||||
@ -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>
|
||||
113
RGB.NET.Devices.WLED/WLedDeviceProvider.cs
Normal file
113
RGB.NET.Devices.WLED/WLedDeviceProvider.cs
Normal 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
|
||||
}
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user