diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 36bab7a..db64c8c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,16 +11,19 @@ on:
jobs:
build:
- runs-on: windows-2022
+ runs-on: windows-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup .NET
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
- dotnet-version: 7.0.x
+ dotnet-version: |
+ 8.0.x
+ 7.0.x
+ 6.0.x
- name: Git Semantic Version
id: versioning
uses: PaulHatch/semantic-version@v4.0.3
@@ -45,6 +48,12 @@ jobs:
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
+ 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
with:
@@ -53,3 +62,5 @@ jobs:
if-no-files-found: error
- name: Nuget Push
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
diff --git a/.github/workflows/pr_verify.yml b/.github/workflows/pr_verify.yml
index b47d33e..d556fa2 100644
--- a/.github/workflows/pr_verify.yml
+++ b/.github/workflows/pr_verify.yml
@@ -7,14 +7,17 @@ on:
jobs:
build:
- runs-on: windows-2022
+ runs-on: windows-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Setup .NET
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
- dotnet-version: 7.0.x
+ dotnet-version: |
+ 8.0.x
+ 7.0.x
+ 6.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 121fb30..f6e3df3 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -10,16 +10,19 @@ on:
jobs:
build:
- runs-on: windows-2022
+ runs-on: windows-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup .NET
- uses: actions/setup-dotnet@v1
+ uses: actions/setup-dotnet@v3
with:
- dotnet-version: 7.0.x
+ dotnet-version: |
+ 8.0.x
+ 7.0.x
+ 6.0.x
- name: Git Semantic Version
id: versioning
uses: PaulHatch/semantic-version@v4.0.3
@@ -44,6 +47,12 @@ jobs:
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
+ 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
with:
@@ -55,6 +64,6 @@ jobs:
with:
tag_name: ${{ steps.versioning.outputs.version_tag }}
generate_release_notes: true
- files: bin/net7.0/RGB.NET.*.dll
+ files: bin/net8.0/RGB.NET.*.dll
- name: Nuget Push
run: dotnet nuget push **\*.nupkg --skip-duplicate --api-key ${{ secrets.NUGET_TOKEN }} --source https://api.nuget.org/v3/index.json
diff --git a/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs b/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs
index e76554e..2d1f2eb 100644
--- a/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs
+++ b/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs
@@ -12,6 +12,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
{
#region Properties & Fields
+ private bool _isDisposed = false;
+
private readonly double _defaultUpdateRateHardLimit;
///
@@ -60,6 +62,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
this._defaultUpdateRateHardLimit = defaultUpdateRateHardLimit;
}
+ ~AbstractRGBDeviceProvider() => Dispose(false);
+
#endregion
#region Methods
@@ -67,6 +71,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
///
public bool Initialize(RGBDeviceType loadFilter = RGBDeviceType.All, bool throwExceptions = false)
{
+ if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
+
ThrowsExceptions = throwExceptions;
try
@@ -108,6 +114,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
/// The filtered collection of loaded devices.
protected virtual IEnumerable GetLoadedDevices(RGBDeviceType loadFilter)
{
+ if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
+
List devices = new();
foreach (IRGBDevice device in LoadDevices())
{
@@ -152,6 +160,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
/// The update trigger mapped to the specified id.
protected virtual IDeviceUpdateTrigger GetUpdateTrigger(int id = -1, double? updateRateHardLimit = null)
{
+ if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
+
if (!UpdateTriggerMapping.TryGetValue(id, out IDeviceUpdateTrigger? updaeTrigger))
UpdateTriggerMapping[id] = (updaeTrigger = CreateUpdateTrigger(id, updateRateHardLimit ?? _defaultUpdateRateHardLimit));
@@ -171,6 +181,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
///
protected virtual void Reset()
{
+ if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
+
foreach (IDeviceUpdateTrigger updateTrigger in UpdateTriggerMapping.Values)
updateTrigger.Dispose();
@@ -192,6 +204,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
/// true if the device was added successfully; otherwise false.
protected virtual bool AddDevice(IRGBDevice device)
{
+ if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
+
if (InternalDevices.Contains(device)) return false;
InternalDevices.Add(device);
@@ -207,6 +221,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
/// true if the device was removed successfully; otherwise false.
protected virtual bool RemoveDevice(IRGBDevice device)
{
+ if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
+
if (!InternalDevices.Remove(device)) return false;
try { OnDevicesChanged(DevicesChangedEventArgs.CreateDevicesRemovedArgs(device)); } catch { /* we don't want to throw due to bad event handlers */ }
@@ -241,12 +257,26 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider
protected virtual void OnDevicesChanged(DevicesChangedEventArgs args) => DevicesChanged?.Invoke(this, args);
///
- public virtual void Dispose()
+ public void Dispose()
{
- Reset();
+ if (_isDisposed) return;
+
+ try
+ {
+ Dispose(true);
+ }
+ catch { /* don't throw in dispose! */ }
GC.SuppressFinalize(this);
+
+ _isDisposed = true;
}
+ ///
+ /// Disposes the object and frees all resources.
+ ///
+ /// true if explicitely called through the Dispose-Method, false if called by the destructor.
+ protected virtual void Dispose(bool disposing) => Reset();
+
#endregion
}
\ No newline at end of file
diff --git a/RGB.NET.Core/Leds/LedId.cs b/RGB.NET.Core/Leds/LedId.cs
index dff98a5..43a6a70 100644
--- a/RGB.NET.Core/Leds/LedId.cs
+++ b/RGB.NET.Core/Leds/LedId.cs
@@ -372,6 +372,14 @@ public enum LedId
Keyboard_Custom127 = 0x0000707F,
Keyboard_Custom128 = 0x00007080,
+ Keyboard_IndicatorNumLock = 0x00008001,
+ Keyboard_IndicatorCapsLock = 0x00008002,
+ Keyboard_IndicatorScrollLock = 0x00008003,
+ Keyboard_IndicatorWinLock = 0x00008004,
+ Keyboard_IndicatorPower = 0x00008005,
+ Keyboard_IndicatorMuted = 0x00008006,
+ Keyboard_IndicatorMacro = 0x00008007,
+
/*### Mouse ###*/
Mouse1 = 0x00100001,
Mouse2 = 0x00100002,
diff --git a/RGB.NET.Core/Positioning/Scale.cs b/RGB.NET.Core/Positioning/Scale.cs
index 973bf9c..18644e6 100644
--- a/RGB.NET.Core/Positioning/Scale.cs
+++ b/RGB.NET.Core/Positioning/Scale.cs
@@ -50,6 +50,12 @@ public readonly struct Scale : IEquatable
#region Methods
+ ///
+ /// Converts the and value of this to a human-readable string.
+ ///
+ /// A string that contains the and value of this . For example "[Horizontal: 1, Vertical: 0.5]".
+ public override string ToString() => $"[Horizontal: {Horizontal}, Vertical: {Vertical}]\"";
+
///
/// Tests whether the specified is equivalent to this .
///
diff --git a/RGB.NET.Core/README.md b/RGB.NET.Core/README.md
index d31978b..b07d190 100644
--- a/RGB.NET.Core/README.md
+++ b/RGB.NET.Core/README.md
@@ -17,7 +17,7 @@ surface.AlignDevices();
surface.RegisterUpdateTrigger(new TimerUpdateTrigger());
```
-## Basis Rendering
+## Basic Rendering
```csharp
// Create a led-group containing all leds on the surface
ILedGroup allLeds = new ListLedGroup(surface, surface.Leds);
diff --git a/RGB.NET.Core/RGB.NET.Core.csproj b/RGB.NET.Core/RGB.NET.Core.csproj
index 8499b1e..1022bf0 100644
--- a/RGB.NET.Core/RGB.NET.Core.csproj
+++ b/RGB.NET.Core/RGB.NET.Core.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.Asus/AsusDeviceProvider.cs b/RGB.NET.Devices.Asus/AsusDeviceProvider.cs
index 1f0784e..f939cb5 100644
--- a/RGB.NET.Devices.Asus/AsusDeviceProvider.cs
+++ b/RGB.NET.Devices.Asus/AsusDeviceProvider.cs
@@ -16,11 +16,21 @@ public sealed class AsusDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static AsusDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static AsusDeviceProvider Instance => _instance ?? new AsusDeviceProvider();
+ public static AsusDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new AsusDeviceProvider();
+ }
+ }
private IAuraSdk2? _sdk;
private IAuraSyncDeviceCollection? _devices; //HACK DarthAffe 05.04.2021: Due to some researches this might fix the access violation in the asus-sdk
@@ -35,8 +45,11 @@ public sealed class AsusDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public AsusDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(AsusDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(AsusDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -80,15 +93,19 @@ public sealed class AsusDeviceProvider : AbstractRGBDeviceProvider
}
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
+ lock (_lock)
+ {
+ base.Dispose(disposing);
- try { _sdk?.ReleaseControl(0); }
- catch { /* at least we tried */ }
+ try { _sdk?.ReleaseControl(0); }
+ catch { /* at least we tried */ }
- _devices = null;
- _sdk = null;
+ _devices = null;
+ _sdk = null;
+ _instance = null;
+ }
}
#endregion
diff --git a/RGB.NET.Devices.Asus/RGB.NET.Devices.Asus.csproj b/RGB.NET.Devices.Asus/RGB.NET.Devices.Asus.csproj
index 6d14d24..b19d2d4 100644
--- a/RGB.NET.Devices.Asus/RGB.NET.Devices.Asus.csproj
+++ b/RGB.NET.Devices.Asus/RGB.NET.Devices.Asus.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs b/RGB.NET.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs
index ab16a45..8678e1a 100644
--- a/RGB.NET.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs
+++ b/RGB.NET.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs
@@ -17,11 +17,21 @@ public sealed class CoolerMasterDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static CoolerMasterDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static CoolerMasterDeviceProvider Instance => _instance ?? new CoolerMasterDeviceProvider();
+ public static CoolerMasterDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new CoolerMasterDeviceProvider();
+ }
+ }
///
/// Gets a modifiable list of paths used to find the native SDK-dlls for x86 applications.
@@ -45,8 +55,11 @@ public sealed class CoolerMasterDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public CoolerMasterDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(CoolerMasterDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(CoolerMasterDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -94,12 +107,17 @@ public sealed class CoolerMasterDeviceProvider : AbstractRGBDeviceProvider
}
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
+ lock (_lock)
+ {
+ base.Dispose(disposing);
- try { _CoolerMasterSDK.Reload(); }
- catch { /* Unlucky.. */ }
+ try { _CoolerMasterSDK.Reload(); }
+ catch { /* Unlucky.. */ }
+
+ _instance = null;
+ }
}
#endregion
diff --git a/RGB.NET.Devices.CoolerMaster/RGB.NET.Devices.CoolerMaster.csproj b/RGB.NET.Devices.CoolerMaster/RGB.NET.Devices.CoolerMaster.csproj
index 2adfaa5..73017c6 100644
--- a/RGB.NET.Devices.CoolerMaster/RGB.NET.Devices.CoolerMaster.csproj
+++ b/RGB.NET.Devices.CoolerMaster/RGB.NET.Devices.CoolerMaster.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs b/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs
index 87ab725..89f4684 100644
--- a/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs
+++ b/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs
@@ -17,11 +17,21 @@ public sealed class CorsairDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static CorsairDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static CorsairDeviceProvider Instance => _instance ?? new CorsairDeviceProvider();
+ public static CorsairDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new CorsairDeviceProvider();
+ }
+ }
///
/// Gets a modifiable list of paths used to find the native SDK-dlls for x86 applications.
@@ -80,8 +90,11 @@ public sealed class CorsairDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public CorsairDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(CorsairDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(CorsairDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -300,12 +313,20 @@ public sealed class CorsairDeviceProvider : AbstractRGBDeviceProvider
}
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
+ lock (_lock)
+ {
+ base.Dispose(disposing);
- try { _CUESDK.CorsairDisconnect(); } catch { /* at least we tried */ }
- try { _CUESDK.UnloadCUESDK(); } catch { /* at least we tried */ }
+ try { _CUESDK.CorsairDisconnect(); }
+ catch { /* at least we tried */ }
+
+ try { _CUESDK.UnloadCUESDK(); }
+ catch { /* at least we tried */ }
+
+ _instance = null;
+ }
}
#endregion
diff --git a/RGB.NET.Devices.Corsair/RGB.NET.Devices.Corsair.csproj b/RGB.NET.Devices.Corsair/RGB.NET.Devices.Corsair.csproj
index ccb143e..ee6cfca 100644
--- a/RGB.NET.Devices.Corsair/RGB.NET.Devices.Corsair.csproj
+++ b/RGB.NET.Devices.Corsair/RGB.NET.Devices.Corsair.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.Corsair_Legacy/CorsairLegacyDeviceProvider.cs b/RGB.NET.Devices.Corsair_Legacy/CorsairLegacyDeviceProvider.cs
index 20a1b58..f82bec2 100644
--- a/RGB.NET.Devices.Corsair_Legacy/CorsairLegacyDeviceProvider.cs
+++ b/RGB.NET.Devices.Corsair_Legacy/CorsairLegacyDeviceProvider.cs
@@ -18,11 +18,21 @@ public sealed class CorsairLegacyDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static CorsairLegacyDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static CorsairLegacyDeviceProvider Instance => _instance ?? new CorsairLegacyDeviceProvider();
+ public static CorsairLegacyDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new CorsairLegacyDeviceProvider();
+ }
+ }
///
/// Gets a modifiable list of paths used to find the native SDK-dlls for x86 applications.
@@ -56,8 +66,11 @@ public sealed class CorsairLegacyDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public CorsairLegacyDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(CorsairLegacyDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(CorsairLegacyDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -201,12 +214,17 @@ public sealed class CorsairLegacyDeviceProvider : AbstractRGBDeviceProvider
}
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
+ lock (_lock)
+ {
+ base.Dispose(disposing);
- try { _CUESDK.UnloadCUESDK(); }
- catch { /* at least we tried */ }
+ try { _CUESDK.UnloadCUESDK(); }
+ catch { /* at least we tried */ }
+
+ _instance = null;
+ }
}
#endregion
diff --git a/RGB.NET.Devices.Corsair_Legacy/Custom/CorsairCustomRGBDevice.cs b/RGB.NET.Devices.Corsair_Legacy/Custom/CorsairCustomRGBDevice.cs
index 4e15555..c285e5a 100644
--- a/RGB.NET.Devices.Corsair_Legacy/Custom/CorsairCustomRGBDevice.cs
+++ b/RGB.NET.Devices.Corsair_Legacy/Custom/CorsairCustomRGBDevice.cs
@@ -53,6 +53,8 @@ public class CorsairCustomRGBDevice : CorsairRGBDevice
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.DMX/DMXDeviceProvider.cs b/RGB.NET.Devices.DMX/DMXDeviceProvider.cs
index 2d85a44..d5f2456 100644
--- a/RGB.NET.Devices.DMX/DMXDeviceProvider.cs
+++ b/RGB.NET.Devices.DMX/DMXDeviceProvider.cs
@@ -16,11 +16,21 @@ public sealed class DMXDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static DMXDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static DMXDeviceProvider Instance => _instance ?? new DMXDeviceProvider();
+ public static DMXDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new DMXDeviceProvider();
+ }
+ }
///
/// Gets a list of all defined device-definitions.
@@ -37,8 +47,11 @@ public sealed class DMXDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public DMXDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(DMXDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(DMXDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -86,5 +99,16 @@ public sealed class DMXDeviceProvider : AbstractRGBDeviceProvider
return updateTrigger;
}
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ lock (_lock)
+ {
+ base.Dispose(disposing);
+
+ _instance = null;
+ }
+ }
+
#endregion
}
\ No newline at end of file
diff --git a/RGB.NET.Devices.DMX/RGB.NET.Devices.DMX.csproj b/RGB.NET.Devices.DMX/RGB.NET.Devices.DMX.csproj
index e6e876e..df8e547 100644
--- a/RGB.NET.Devices.DMX/RGB.NET.Devices.DMX.csproj
+++ b/RGB.NET.Devices.DMX/RGB.NET.Devices.DMX.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.Debug/DebugDeviceProvider.cs b/RGB.NET.Devices.Debug/DebugDeviceProvider.cs
index f88ad50..836c6db 100644
--- a/RGB.NET.Devices.Debug/DebugDeviceProvider.cs
+++ b/RGB.NET.Devices.Debug/DebugDeviceProvider.cs
@@ -16,11 +16,21 @@ public sealed class DebugDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static DebugDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static DebugDeviceProvider Instance => _instance ?? new DebugDeviceProvider();
+ public static DebugDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new DebugDeviceProvider();
+ }
+ }
private List<(IDeviceLayout layout, Action>? updateLedsAction)> _fakeDeviceDefinitions = new();
@@ -34,8 +44,11 @@ public sealed class DebugDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public DebugDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(DebugDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(DebugDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -66,11 +79,16 @@ public sealed class DebugDeviceProvider : AbstractRGBDeviceProvider
}
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
+ lock (_lock)
+ {
+ base.Dispose(disposing);
- _fakeDeviceDefinitions.Clear();
+ _fakeDeviceDefinitions.Clear();
+
+ _instance = null;
+ }
}
#endregion
diff --git a/RGB.NET.Devices.Debug/RGB.NET.Devices.Debug.csproj b/RGB.NET.Devices.Debug/RGB.NET.Devices.Debug.csproj
index 980153c..1f17728 100644
--- a/RGB.NET.Devices.Debug/RGB.NET.Devices.Debug.csproj
+++ b/RGB.NET.Devices.Debug/RGB.NET.Devices.Debug.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs
index 4ebd163..4a12b39 100644
--- a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs
+++ b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs
@@ -20,11 +20,21 @@ public class LogitechDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static LogitechDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static LogitechDeviceProvider Instance => _instance ?? new LogitechDeviceProvider();
+ public static LogitechDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new LogitechDeviceProvider();
+ }
+ }
///
/// Gets a modifiable list of paths used to find the native SDK-dlls for x86 applications.
@@ -112,7 +122,7 @@ public class LogitechDeviceProvider : AbstractRGBDeviceProvider
{ 0x0A78, RGBDeviceType.Speaker, "G560", LedMappings.ZoneSpeaker, (LogitechDeviceType.Speaker, 4, 0) },
};
-
+
///
/// Gets the HID-definitions for wireless per-zone-devices.
///
@@ -164,8 +174,12 @@ public class LogitechDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public LogitechDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(LogitechDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null)
+ throw new InvalidOperationException($"There can be only one instance of type {nameof(LogitechDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -254,17 +268,20 @@ public class LogitechDeviceProvider : AbstractRGBDeviceProvider
}
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
+ lock (_lock)
+ {
+ base.Dispose(disposing);
- try { _LogitechGSDK.LogiLedRestoreLighting(); }
- catch { /* at least we tried */ }
+ try { _LogitechGSDK.LogiLedRestoreLighting(); }
+ catch { /* at least we tried */ }
- try { _LogitechGSDK.UnloadLogitechGSDK(); }
- catch { /* at least we tried */ }
+ try { _LogitechGSDK.UnloadLogitechGSDK(); }
+ catch { /* at least we tried */ }
- GC.SuppressFinalize(this);
+ _instance = null;
+ }
}
#endregion
diff --git a/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj b/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj
index fd412e7..6ae10dd 100644
--- a/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj
+++ b/RGB.NET.Devices.Logitech/RGB.NET.Devices.Logitech.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.Msi/MsiDeviceProvider.cs b/RGB.NET.Devices.Msi/MsiDeviceProvider.cs
index fb18827..1a305cc 100644
--- a/RGB.NET.Devices.Msi/MsiDeviceProvider.cs
+++ b/RGB.NET.Devices.Msi/MsiDeviceProvider.cs
@@ -17,11 +17,21 @@ public class MsiDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static MsiDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static MsiDeviceProvider Instance => _instance ?? new MsiDeviceProvider();
+ public static MsiDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new MsiDeviceProvider();
+ }
+ }
///
/// Gets a modifiable list of paths used to find the native SDK-dlls for x86 applications.
@@ -45,8 +55,11 @@ public class MsiDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public MsiDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(MsiDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(MsiDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -98,14 +111,17 @@ public class MsiDeviceProvider : AbstractRGBDeviceProvider
private void ThrowMsiError(int errorCode, bool isCritical = false) => Throw(new MysticLightException(errorCode, _MsiSDK.GetErrorMessage(errorCode)), isCritical);
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
+ lock (_lock)
+ {
+ base.Dispose(disposing);
- try { _MsiSDK.UnloadMsiSDK(); }
- catch { /* at least we tried */ }
+ try { _MsiSDK.UnloadMsiSDK(); }
+ catch { /* at least we tried */ }
- GC.SuppressFinalize(this);
+ _instance = null;
+ }
}
#endregion
diff --git a/RGB.NET.Devices.Msi/RGB.NET.Devices.Msi.csproj b/RGB.NET.Devices.Msi/RGB.NET.Devices.Msi.csproj
index 7d604a6..12f416f 100644
--- a/RGB.NET.Devices.Msi/RGB.NET.Devices.Msi.csproj
+++ b/RGB.NET.Devices.Msi/RGB.NET.Devices.Msi.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.Novation/NovationDeviceProvider.cs b/RGB.NET.Devices.Novation/NovationDeviceProvider.cs
index 837a82c..9a86f6f 100644
--- a/RGB.NET.Devices.Novation/NovationDeviceProvider.cs
+++ b/RGB.NET.Devices.Novation/NovationDeviceProvider.cs
@@ -17,11 +17,21 @@ public sealed class NovationDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static NovationDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static NovationDeviceProvider Instance => _instance ?? new NovationDeviceProvider();
+ public static NovationDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new NovationDeviceProvider();
+ }
+ }
#endregion
@@ -33,8 +43,11 @@ public sealed class NovationDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
private NovationDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(NovationDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(NovationDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -67,5 +80,16 @@ public sealed class NovationDeviceProvider : AbstractRGBDeviceProvider
}
}
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ lock (_lock)
+ {
+ base.Dispose(disposing);
+
+ _instance = null;
+ }
+ }
+
#endregion
}
\ No newline at end of file
diff --git a/RGB.NET.Devices.Novation/RGB.NET.Devices.Novation.csproj b/RGB.NET.Devices.Novation/RGB.NET.Devices.Novation.csproj
index cda9c5e..c249fc2 100644
--- a/RGB.NET.Devices.Novation/RGB.NET.Devices.Novation.csproj
+++ b/RGB.NET.Devices.Novation/RGB.NET.Devices.Novation.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs b/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs
index 4d19484..4ad82cc 100644
--- a/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs
+++ b/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs
@@ -14,6 +14,9 @@ public sealed class OpenRGBDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private readonly List _clients = new();
private static OpenRGBDeviceProvider? _instance;
@@ -21,7 +24,14 @@ public sealed class OpenRGBDeviceProvider : AbstractRGBDeviceProvider
///
/// Gets the singleton instance.
///
- public static OpenRGBDeviceProvider Instance => _instance ?? new OpenRGBDeviceProvider();
+ public static OpenRGBDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new OpenRGBDeviceProvider();
+ }
+ }
///
/// Gets a list of all defined device-definitions.
@@ -48,8 +58,11 @@ public sealed class OpenRGBDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public OpenRGBDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(OpenRGBDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(OpenRGBDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -107,22 +120,22 @@ public sealed class OpenRGBDeviceProvider : AbstractRGBDeviceProvider
continue;
}
- if (device.Zones.Length == 0)
+ if (device.Zones.Length == 0)
continue;
- if (device.Zones.All(z => z.LedCount == 0))
+ if (device.Zones.All(z => z.LedCount == 0))
continue;
OpenRGBUpdateQueue updateQueue = new(GetUpdateTrigger(), i, openRgb, device);
-
+
bool anyZoneHasSegments = device.Zones.Any(z => z.Segments.Length > 0);
- bool splitDeviceByZones = anyZoneHasSegments || PerZoneDeviceFlag.HasFlag(Helper.GetRgbNetDeviceType(device.Type));
+ bool splitDeviceByZones = anyZoneHasSegments || PerZoneDeviceFlag.HasFlag(Helper.GetRgbNetDeviceType(device.Type));
if (!splitDeviceByZones)
{
yield return new OpenRGBGenericDevice(new OpenRGBDeviceInfo(device), updateQueue);
continue;
}
-
+
int totalLedCount = 0;
foreach (Zone zone in device.Zones)
@@ -149,18 +162,23 @@ public sealed class OpenRGBDeviceProvider : AbstractRGBDeviceProvider
}
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
-
- foreach (OpenRgbClient client in _clients)
+ lock (_lock)
{
- try { client.Dispose(); }
- catch { /* at least we tried */ }
- }
+ base.Dispose(disposing);
- _clients.Clear();
- DeviceDefinitions.Clear();
+ foreach (OpenRgbClient client in _clients)
+ {
+ try { client.Dispose(); }
+ catch { /* at least we tried */ }
+ }
+
+ _clients.Clear();
+ DeviceDefinitions.Clear();
+
+ _instance = null;
+ }
}
#endregion
diff --git a/RGB.NET.Devices.OpenRGB/RGB.NET.Devices.OpenRGB.csproj b/RGB.NET.Devices.OpenRGB/RGB.NET.Devices.OpenRGB.csproj
index f3b3a81..6b32521 100644
--- a/RGB.NET.Devices.OpenRGB/RGB.NET.Devices.OpenRGB.csproj
+++ b/RGB.NET.Devices.OpenRGB/RGB.NET.Devices.OpenRGB.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.PicoPi/PicoPiDeviceProvider.cs b/RGB.NET.Devices.PicoPi/PicoPiDeviceProvider.cs
index f18116f..c799460 100644
--- a/RGB.NET.Devices.PicoPi/PicoPiDeviceProvider.cs
+++ b/RGB.NET.Devices.PicoPi/PicoPiDeviceProvider.cs
@@ -25,11 +25,21 @@ public sealed class PicoPiDeviceProvider : AbstractRGBDeviceProvider
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static PicoPiDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static PicoPiDeviceProvider Instance => _instance ?? new PicoPiDeviceProvider();
+ public static PicoPiDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new PicoPiDeviceProvider();
+ }
+ }
///
/// Gets the HID-definitions for PicoPi-devices.
@@ -57,8 +67,11 @@ public sealed class PicoPiDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public PicoPiDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(PicoPiDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(PicoPiDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -126,5 +139,16 @@ public sealed class PicoPiDeviceProvider : AbstractRGBDeviceProvider
_sdks.Clear();
}
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ lock (_lock)
+ {
+ base.Dispose(disposing);
+
+ _instance = null;
+ }
+ }
+
#endregion
}
\ No newline at end of file
diff --git a/RGB.NET.Devices.PicoPi/RGB.NET.Devices.PicoPi.csproj b/RGB.NET.Devices.PicoPi/RGB.NET.Devices.PicoPi.csproj
index 6cf8a2c..a2b134f 100644
--- a/RGB.NET.Devices.PicoPi/RGB.NET.Devices.PicoPi.csproj
+++ b/RGB.NET.Devices.PicoPi/RGB.NET.Devices.PicoPi.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.Razer/RGB.NET.Devices.Razer.csproj b/RGB.NET.Devices.Razer/RGB.NET.Devices.Razer.csproj
index 27f7261..3632399 100644
--- a/RGB.NET.Devices.Razer/RGB.NET.Devices.Razer.csproj
+++ b/RGB.NET.Devices.Razer/RGB.NET.Devices.Razer.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.Razer/RazerDeviceProvider.cs b/RGB.NET.Devices.Razer/RazerDeviceProvider.cs
index 15f2657..9abc8c8 100644
--- a/RGB.NET.Devices.Razer/RazerDeviceProvider.cs
+++ b/RGB.NET.Devices.Razer/RazerDeviceProvider.cs
@@ -19,11 +19,21 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static RazerDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static RazerDeviceProvider Instance => _instance ?? new RazerDeviceProvider();
+ public static RazerDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new RazerDeviceProvider();
+ }
+ }
///
/// Gets a modifiable list of paths used to find the native SDK-dlls for x86 applications.
@@ -124,6 +134,7 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{ 0x0279, RGBDeviceType.Keyboard, "Blade 17 Pro (Mid 2021)", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x027A, RGBDeviceType.Keyboard, "Blade 15 Base (2022)", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x0282, RGBDeviceType.Keyboard, "Huntsman Mini Analog", LedMappings.Keyboard, RazerEndpointType.Keyboard },
+ { 0x0287, RGBDeviceType.Keyboard, "BlackWidow V4", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x028A, RGBDeviceType.Keyboard, "Blade 15 Advanced (Early 2022)", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x028B, RGBDeviceType.Keyboard, "Blade 17 (2022)", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x028C, RGBDeviceType.Keyboard, "Blade 14 (2022)", LedMappings.Keyboard, RazerEndpointType.Keyboard },
@@ -135,7 +146,9 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{ 0x0295, RGBDeviceType.Keyboard, "DeathStalker V2", LedMappings.Keyboard, RazerEndpointType.Keyboard },
{ 0x0296, RGBDeviceType.Keyboard, "DeathStalker V2 Pro TKL", LedMappings.Keyboard, RazerEndpointType.Keyboard }, // Wireless
{ 0x0298, RGBDeviceType.Keyboard, "DeathStalker V2 Pro TKL", LedMappings.Keyboard, RazerEndpointType.Keyboard }, // Wired
+ { 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 },
{ 0x0A24, RGBDeviceType.Keyboard, "BlackWidow V3 TKL", LedMappings.Keyboard, RazerEndpointType.Keyboard },
// Mice
@@ -211,6 +224,7 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{ 0x00A1, RGBDeviceType.Mouse, "DeathAdder V2 Lite", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x00A5, RGBDeviceType.Mouse, "Viper V2 Pro (Wired)", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x00A6, RGBDeviceType.Mouse, "Viper V2 Pro (Wireless)", LedMappings.Mouse, RazerEndpointType.Mouse },
+ { 0x00A7, RGBDeviceType.Mouse, "Naga V2 Pro", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x00A8, RGBDeviceType.Mouse, "Naga V2 Pro", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x00AA, RGBDeviceType.Mouse, "Basilisk V3 Pro (Wired)", LedMappings.Mouse, RazerEndpointType.Mouse },
{ 0x00AB, RGBDeviceType.Mouse, "Basilisk V3 Pro (Wireless)", LedMappings.Mouse, RazerEndpointType.Mouse },
@@ -232,6 +246,7 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{ 0x051A, RGBDeviceType.Headset, "Nari Ultimate", LedMappings.Headset, RazerEndpointType.Headset },
{ 0x051C, RGBDeviceType.Headset, "Nari", LedMappings.Headset, RazerEndpointType.Headset },
{ 0x0527, RGBDeviceType.Headset, "Kraken Ultimate", LedMappings.Headset, RazerEndpointType.Headset },
+ { 0x0560, RGBDeviceType.Headset, "Kraken Kitty V2", LedMappings.Headset, RazerEndpointType.Headset },
{ 0x0F19, RGBDeviceType.Headset, "Kraken Kitty Edition", LedMappings.Headset, RazerEndpointType.Headset },
// Keypads
@@ -248,6 +263,7 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{ 0x0F08, RGBDeviceType.HeadsetStand, "Base Station Chroma", LedMappings.Mousepad, RazerEndpointType.Mousepad }, // DarthAffe 16.12.2022: Not tested but based on the V2 I assume this is also a mousepad
{ 0x0F20, RGBDeviceType.HeadsetStand, "Base Station V2 Chroma", LedMappings.Mousepad, RazerEndpointType.Mousepad }, // DarthAffe 16.12.2022: Not sure why, but it's handled as a mousepad
{ 0x007E, RGBDeviceType.LedStripe, "Razer Mouse Dock Chroma", LedMappings.Mousepad, RazerEndpointType.Mousepad }, //roxaskeyheart 06.02.2023: Probably handled the same as a mousepad
+ { 0x00A4, RGBDeviceType.LedStripe, "Mouse Dock Pro", LedMappings.Mousepad, RazerEndpointType.Mousepad }, // DarthAffe 22.09.2023: Most likely also a mousepad?
{ 0x0517, RGBDeviceType.Speaker, "Nommo Chroma", LedMappings.ChromaLink, RazerEndpointType.ChromaLink },
{ 0x0518, RGBDeviceType.Speaker, "Nommo Pro", LedMappings.ChromaLink, RazerEndpointType.ChromaLink },
{ 0x0F07, RGBDeviceType.Unknown, "Chroma Mug Holder", LedMappings.ChromaLink, RazerEndpointType.ChromaLink },
@@ -255,7 +271,7 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
{ 0x0F13, RGBDeviceType.Unknown, "Lian Li O11", LedMappings.ChromaLink, RazerEndpointType.ChromaLink },
{ 0x0F1D, RGBDeviceType.Unknown, "Mouse Bungee V3 Chroma", LedMappings.ChromaLink, RazerEndpointType.ChromaLink },
{ 0x0F1F, RGBDeviceType.LedController, "Addressable RGB Controller", LedMappings.ChromaLink, RazerEndpointType.ChromaLink },
-
+
};
#endregion
@@ -268,8 +284,11 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public RazerDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(RazerDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(RazerDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -343,15 +362,20 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider
}
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
+ lock (_lock)
+ {
+ base.Dispose(disposing);
- TryUnInit();
+ TryUnInit();
- // DarthAffe 03.03.2020: Fails with an access-violation - verify if an unload is already triggered by uninit
- //try { _RazerSDK.UnloadRazerSDK(); }
- //catch { /* at least we tried */ }
+ // DarthAffe 03.03.2020: Fails with an access-violation - verify if an unload is already triggered by uninit
+ //try { _RazerSDK.UnloadRazerSDK(); }
+ //catch { /* at least we tried */ }
+
+ _instance = null;
+ }
}
#endregion
diff --git a/RGB.NET.Devices.SteelSeries/RGB.NET.Devices.SteelSeries.csproj b/RGB.NET.Devices.SteelSeries/RGB.NET.Devices.SteelSeries.csproj
index f75e2d8..76525ce 100644
--- a/RGB.NET.Devices.SteelSeries/RGB.NET.Devices.SteelSeries.csproj
+++ b/RGB.NET.Devices.SteelSeries/RGB.NET.Devices.SteelSeries.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs b/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs
index 61f3254..0bf1958 100644
--- a/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs
+++ b/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs
@@ -20,11 +20,21 @@ public sealed class SteelSeriesDeviceProvider : AbstractRGBDeviceProvider
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static SteelSeriesDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static SteelSeriesDeviceProvider Instance => _instance ?? new SteelSeriesDeviceProvider();
+ public static SteelSeriesDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new SteelSeriesDeviceProvider();
+ }
+ }
private const int VENDOR_ID = 0x1038;
@@ -93,8 +103,11 @@ public sealed class SteelSeriesDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public SteelSeriesDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(SteelSeriesDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(SteelSeriesDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -133,12 +146,17 @@ public sealed class SteelSeriesDeviceProvider : AbstractRGBDeviceProvider
protected override IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) => new DeviceUpdateTrigger(updateRateHardLimit) { HeartbeatTimer = HEARTBEAT_TIMER };
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
+ lock (_lock)
+ {
+ base.Dispose(disposing);
- try { SteelSeriesSDK.Dispose(); }
- catch { /* shit happens */ }
+ try { SteelSeriesSDK.Dispose(); }
+ catch { /* shit happens */ }
+
+ _instance = null;
+ }
}
#endregion
diff --git a/RGB.NET.Devices.WS281X/RGB.NET.Devices.WS281X.csproj b/RGB.NET.Devices.WS281X/RGB.NET.Devices.WS281X.csproj
index 5487a8e..39f4d52 100644
--- a/RGB.NET.Devices.WS281X/RGB.NET.Devices.WS281X.csproj
+++ b/RGB.NET.Devices.WS281X/RGB.NET.Devices.WS281X.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs b/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs
index 4d2e047..e150028 100644
--- a/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs
+++ b/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs
@@ -16,11 +16,21 @@ public sealed class WS281XDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static WS281XDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static WS281XDeviceProvider Instance => _instance ?? new WS281XDeviceProvider();
+ public static WS281XDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new WS281XDeviceProvider();
+ }
+ }
///
/// Gets a list of all defined device-definitions.
@@ -39,8 +49,11 @@ public sealed class WS281XDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public WS281XDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(WS281XDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(WS281XDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -70,11 +83,16 @@ public sealed class WS281XDeviceProvider : AbstractRGBDeviceProvider
}
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
+ lock (_lock)
+ {
+ base.Dispose(disposing);
- DeviceDefinitions.Clear();
+ DeviceDefinitions.Clear();
+
+ _instance = null;
+ }
}
#endregion
diff --git a/RGB.NET.Devices.Wooting/Enum/WootingDeviceType.cs b/RGB.NET.Devices.Wooting/Enum/WootingDeviceType.cs
index 513fae5..63ff83a 100644
--- a/RGB.NET.Devices.Wooting/Enum/WootingDeviceType.cs
+++ b/RGB.NET.Devices.Wooting/Enum/WootingDeviceType.cs
@@ -1,24 +1,29 @@
-// ReSharper disable InconsistentNaming
-
-namespace RGB.NET.Devices.Wooting.Enum;
-
-///
-/// Represents the type of a wooting device
-///
-public enum WootingDeviceType
-{
- ///
- /// 10 Keyless Keyboard. E.g. Wooting One
- ///
- KeyboardTKL = 1,
-
- ///
- /// Full Size keyboard. E.g. Wooting Two
- ///
+// ReSharper disable InconsistentNaming
+
+namespace RGB.NET.Devices.Wooting.Enum;
+
+///
+/// Represents the type of a wooting device
+///
+public enum WootingDeviceType
+{
+ ///
+ /// 10 Keyless Keyboard. E.g. Wooting One
+ ///
+ KeyboardTKL = 1,
+
+ ///
+ /// Full Size keyboard. E.g. Wooting Two
+ ///
Keyboard = 2,
- ///
- /// Full Size keyboard. E.g. Wooting Two
- ///
- KeyboardSixtyPercent = 3
+ ///
+ /// 60 percent keyboard, E.g. Wooting 60HE
+ ///
+ KeyboardSixtyPercent = 3,
+
+ ///
+ /// Three key keypad. E.g. Wooting Uwu
+ ///
+ Keypad3Keys = 4,
}
\ No newline at end of file
diff --git a/RGB.NET.Devices.Wooting/Enum/WootingLayoutType.cs b/RGB.NET.Devices.Wooting/Enum/WootingLayoutType.cs
index e01a6d1..70c1520 100644
--- a/RGB.NET.Devices.Wooting/Enum/WootingLayoutType.cs
+++ b/RGB.NET.Devices.Wooting/Enum/WootingLayoutType.cs
@@ -13,6 +13,7 @@ namespace RGB.NET.Devices.Wooting.Enum;
///
public enum WootingLayoutType
{
+ Unknown = -1,
ANSI = 0,
ISO = 1
}
\ No newline at end of file
diff --git a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardLedMappings.cs b/RGB.NET.Devices.Wooting/Generic/WootingLedMappings.cs
similarity index 91%
rename from RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardLedMappings.cs
rename to RGB.NET.Devices.Wooting/Generic/WootingLedMappings.cs
index 0b44237..081e993 100644
--- a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardLedMappings.cs
+++ b/RGB.NET.Devices.Wooting/Generic/WootingLedMappings.cs
@@ -1,15 +1,15 @@
-// ReSharper disable InconsistentNaming
+// ReSharper disable InconsistentNaming
+using System.Collections.Generic;
using RGB.NET.Core;
using RGB.NET.Devices.Wooting.Enum;
-using System.Collections.Generic;
-namespace RGB.NET.Devices.Wooting.Keyboard;
+namespace RGB.NET.Devices.Wooting.Generic;
///
/// Contains all the hardware-id mappings for Wooting devices.
///
-internal static class WootingKeyboardLedMappings
+internal static class WootingLedMappings
{
#region Properties & Fields
@@ -305,6 +305,36 @@ internal static class WootingKeyboardLedMappings
{ LedId.Keyboard_Function, (5, 13) }
};
+ private static readonly Dictionary ThreeKeyKeypad = new()
+ {
+ //left (from top to bottom)
+ [LedId.LedStripe1] = (1, 0),
+ [LedId.LedStripe2] = (2, 0),
+ [LedId.LedStripe3] = (3, 0),
+
+ //bottom (from left to right)
+ [LedId.LedStripe4] = (4, 1),
+ [LedId.LedStripe5] = (4, 2),
+ [LedId.LedStripe6] = (4, 4),
+ [LedId.LedStripe7] = (4, 5),
+
+ //right (from bottom to top)
+ [LedId.LedStripe8] = (3, 6),
+ [LedId.LedStripe9] = (2, 6),
+ [LedId.LedStripe10] = (1, 6),
+
+ //top (from right to left)
+ [LedId.LedStripe11] = (0, 6),
+ [LedId.LedStripe12] = (0, 4),
+ [LedId.LedStripe13] = (0, 2),
+ [LedId.LedStripe14] = (0, 0),
+
+ //analog keys
+ [LedId.Keypad1] = (2, 1),
+ [LedId.Keypad2] = (2, 3),
+ [LedId.Keypad3] = (2, 5),
+ };
+
///
/// Contains all the hardware-id mappings for Wooting devices.
///
@@ -312,8 +342,9 @@ internal static class WootingKeyboardLedMappings
{
[WootingDeviceType.Keyboard] = Fullsize,
[WootingDeviceType.KeyboardTKL] = TKL,
- [WootingDeviceType.KeyboardSixtyPercent] = SixtyPercent
+ [WootingDeviceType.KeyboardSixtyPercent] = SixtyPercent,
+ [WootingDeviceType.Keypad3Keys] = ThreeKeyKeypad
};
#endregion
-}
\ No newline at end of file
+}
diff --git a/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs b/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs
index 8697eb1..7bc089e 100644
--- a/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs
+++ b/RGB.NET.Devices.Wooting/Generic/WootingRGBDevice.cs
@@ -1,4 +1,5 @@
using RGB.NET.Core;
+using RGB.NET.Devices.Wooting.Native;
namespace RGB.NET.Devices.Wooting.Generic;
@@ -23,4 +24,17 @@ public abstract class WootingRGBDevice : AbstractRGBDevice
-/// Offers some extensions and helper-methods for enum related things.
-///
-internal static class EnumExtension
-{
- ///
- /// Gets the value of the .
- ///
- /// The enum value to get the description from.
- /// The value of the or the result of the source.
- internal static string GetDescription(this System.Enum source)
- => source.GetAttribute()?.Description ?? source.ToString();
-
- ///
- /// Gets the attribute of type T.
- ///
- /// The enum value to get the attribute from
- /// The generic attribute type
- /// The .
- private static T? GetAttribute(this System.Enum source)
- where T : Attribute
- {
- FieldInfo? fi = source.GetType().GetField(source.ToString());
- if (fi == null) return null;
- T[] attributes = (T[])fi.GetCustomAttributes(typeof(T), false);
- return attributes.Length > 0 ? attributes[0] : null;
- }
-}
\ No newline at end of file
diff --git a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs
index 79e1baf..0ba3600 100644
--- a/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs
+++ b/RGB.NET.Devices.Wooting/Keyboard/WootingKeyboardRGBDevice.cs
@@ -1,7 +1,6 @@
using System.Collections.Generic;
using RGB.NET.Core;
using RGB.NET.Devices.Wooting.Generic;
-using RGB.NET.Devices.Wooting.Native;
namespace RGB.NET.Devices.Wooting.Keyboard;
@@ -37,22 +36,14 @@ public sealed class WootingKeyboardRGBDevice : WootingRGBDevice mapping = WootingKeyboardLedMappings.Mapping[DeviceInfo.WootingDeviceType];
+ Dictionary mapping = WootingLedMappings.Mapping[DeviceInfo.WootingDeviceType];
foreach (KeyValuePair led in mapping)
AddLed(led.Key, new Point(led.Value.column * 19, led.Value.row * 19), new Size(19, 19));
}
///
- protected override object GetLedCustomData(LedId ledId) => WootingKeyboardLedMappings.Mapping[DeviceInfo.WootingDeviceType][ledId];
-
- public override void Dispose()
- {
- _WootingSDK.SelectDevice(DeviceInfo.WootingDeviceIndex);
- _WootingSDK.Reset();
-
- base.Dispose();
- }
+ protected override object GetLedCustomData(LedId ledId) => WootingLedMappings.Mapping[DeviceInfo.WootingDeviceType][ledId];
#endregion
}
\ No newline at end of file
diff --git a/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDevice.cs b/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDevice.cs
new file mode 100644
index 0000000..984072b
--- /dev/null
+++ b/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDevice.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+using RGB.NET.Core;
+using RGB.NET.Devices.Wooting.Generic;
+
+namespace RGB.NET.Devices.Wooting.Keypad;
+
+///
+///
+/// Represents a Wooting keyboard.
+///
+public sealed class WootingKeypadRGBDevice : WootingRGBDevice, IKeypad
+{
+ #region Constructors
+
+ ///
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The specific information provided by Wooting for the keyboard
+ /// The update queue used to update this device.
+ internal WootingKeypadRGBDevice(WootingKeypadRGBDeviceInfo info, IUpdateQueue updateQueue)
+ : base(info, updateQueue)
+ {
+ InitializeLayout();
+ }
+
+ #endregion
+
+ #region Methods
+
+ private void InitializeLayout()
+ {
+ Dictionary mapping = WootingLedMappings.Mapping[DeviceInfo.WootingDeviceType];
+
+ foreach (KeyValuePair led in mapping)
+ AddLed(led.Key, new Point(led.Value.column * 19, led.Value.row * 19), new Size(19, 19));
+ }
+
+ ///
+ protected override object GetLedCustomData(LedId ledId) => WootingLedMappings.Mapping[DeviceInfo.WootingDeviceType][ledId];
+
+ #endregion
+}
\ No newline at end of file
diff --git a/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDeviceInfo.cs b/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDeviceInfo.cs
new file mode 100644
index 0000000..55088e1
--- /dev/null
+++ b/RGB.NET.Devices.Wooting/Keypad/WootingKeypadRGBDeviceInfo.cs
@@ -0,0 +1,17 @@
+using RGB.NET.Core;
+using RGB.NET.Devices.Wooting.Generic;
+using RGB.NET.Devices.Wooting.Native;
+
+namespace RGB.NET.Devices.Wooting.Keypad;
+
+///
+/// Represents a generic information for a .
+///
+public sealed class WootingKeypadRGBDeviceInfo : WootingRGBDeviceInfo
+{
+ internal WootingKeypadRGBDeviceInfo(_WootingDeviceInfo deviceInfo, byte deviceIndex)
+ : base(RGBDeviceType.Keypad, deviceInfo, deviceIndex)
+ {
+
+ }
+}
diff --git a/RGB.NET.Devices.Wooting/Native/_WootingDeviceInfo.cs b/RGB.NET.Devices.Wooting/Native/_WootingDeviceInfo.cs
index a672f31..6a59c81 100644
--- a/RGB.NET.Devices.Wooting/Native/_WootingDeviceInfo.cs
+++ b/RGB.NET.Devices.Wooting/Native/_WootingDeviceInfo.cs
@@ -17,11 +17,13 @@ internal struct _WootingDeviceInfo
internal byte MaxColumns { get; private set; }
- internal byte KeycodeLimit { get; private set; }
+ internal byte MaxLedIndex { get; private set; }
internal WootingDeviceType DeviceType { get; private set; }
- internal bool V2Interface { get; set; }
+ internal bool V2Interface { get; private set; }
internal WootingLayoutType LayoutType { get; private set; }
+
+ internal bool UsesSmallPackets { get; private set; }
}
\ No newline at end of file
diff --git a/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj b/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj
index 8a34dcd..37d84ab 100644
--- a/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj
+++ b/RGB.NET.Devices.Wooting/RGB.NET.Devices.Wooting.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs b/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs
index 484bbaf..c92661f 100644
--- a/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs
+++ b/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs
@@ -2,8 +2,10 @@
using System.Collections.Generic;
using System.Runtime.InteropServices;
using RGB.NET.Core;
+using RGB.NET.Devices.Wooting.Enum;
using RGB.NET.Devices.Wooting.Generic;
using RGB.NET.Devices.Wooting.Keyboard;
+using RGB.NET.Devices.Wooting.Keypad;
using RGB.NET.Devices.Wooting.Native;
namespace RGB.NET.Devices.Wooting;
@@ -16,11 +18,21 @@ public sealed class WootingDeviceProvider : AbstractRGBDeviceProvider
{
#region Properties & Fields
+ // ReSharper disable once InconsistentNaming
+ private static readonly object _lock = new();
+
private static WootingDeviceProvider? _instance;
///
/// Gets the singleton instance.
///
- public static WootingDeviceProvider Instance => _instance ?? new WootingDeviceProvider();
+ public static WootingDeviceProvider Instance
+ {
+ get
+ {
+ lock (_lock)
+ return _instance ?? new WootingDeviceProvider();
+ }
+ }
///
/// Gets a modifiable list of paths used to find the native SDK-dlls for x86 windows applications.
@@ -57,8 +69,11 @@ public sealed class WootingDeviceProvider : AbstractRGBDeviceProvider
/// Thrown if this constructor is called even if there is already an instance of this class.
public WootingDeviceProvider()
{
- if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(WootingDeviceProvider)}");
- _instance = this;
+ lock (_lock)
+ {
+ if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(WootingDeviceProvider)}");
+ _instance = this;
+ }
}
#endregion
@@ -86,22 +101,35 @@ public sealed class WootingDeviceProvider : AbstractRGBDeviceProvider
WootingUpdateQueue updateQueue = new(GetUpdateTrigger(), i);
_WootingSDK.SelectDevice(i);
_WootingDeviceInfo nativeDeviceInfo = (_WootingDeviceInfo)Marshal.PtrToStructure(_WootingSDK.GetDeviceInfo(), typeof(_WootingDeviceInfo))!;
+
+ //Uwu non-rgb returns zero here.
+ if (nativeDeviceInfo.MaxLedIndex == 0)
+ continue;
- yield return new WootingKeyboardRGBDevice(new WootingKeyboardRGBDeviceInfo(nativeDeviceInfo, i), updateQueue);
+ yield return nativeDeviceInfo.DeviceType switch
+ {
+ WootingDeviceType.Keypad3Keys => new WootingKeypadRGBDevice(new WootingKeypadRGBDeviceInfo(nativeDeviceInfo, i), updateQueue),
+ _ => new WootingKeyboardRGBDevice(new WootingKeyboardRGBDeviceInfo(nativeDeviceInfo, i), updateQueue),
+ };
}
}
}
}
///
- public override void Dispose()
+ protected override void Dispose(bool disposing)
{
- base.Dispose();
-
- lock (_WootingSDK.SdkLock)
+ lock (_lock)
{
- try { _WootingSDK.UnloadWootingSDK(); }
- catch { /* at least we tried */ }
+ base.Dispose(disposing);
+
+ lock (_WootingSDK.SdkLock)
+ {
+ try { _WootingSDK.UnloadWootingSDK(); }
+ catch { /* at least we tried */ }
+ }
+
+ _instance = null;
}
}
diff --git a/RGB.NET.HID/RGB.NET.HID.csproj b/RGB.NET.HID/RGB.NET.HID.csproj
index 7bf502b..58b5b0f 100644
--- a/RGB.NET.HID/RGB.NET.HID.csproj
+++ b/RGB.NET.HID/RGB.NET.HID.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Layout/DeviceLayout.cs b/RGB.NET.Layout/DeviceLayout.cs
index 24efd37..e33e760 100644
--- a/RGB.NET.Layout/DeviceLayout.cs
+++ b/RGB.NET.Layout/DeviceLayout.cs
@@ -174,7 +174,7 @@ public class DeviceLayout : IDeviceLayout
/// The deserialized custom data object.
protected virtual object? GetCustomData(object? customData, Type? type)
{
- XmlNode? node = (customData as XmlNode) ?? (customData as IEnumerable)?.FirstOrDefault()?.ParentNode; //HACK DarthAffe 16.01.2021: This gives us the CustomData-Node
+ XmlNode? node = (customData as XmlNode) ?? (customData as IEnumerable)?.FirstOrDefault(x => x.ParentNode != null)?.ParentNode; //HACK DarthAffe 16.01.2021: This gives us the CustomData-Node
if ((node == null) || (type == null)) return null;
using MemoryStream ms = new();
diff --git a/RGB.NET.Layout/LayoutExtension.cs b/RGB.NET.Layout/LayoutExtension.cs
index a666637..0426e3b 100644
--- a/RGB.NET.Layout/LayoutExtension.cs
+++ b/RGB.NET.Layout/LayoutExtension.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
+using System.Xml.Serialization;
using RGB.NET.Core;
namespace RGB.NET.Layout;
@@ -51,4 +53,48 @@ public static class LayoutExtension
device.RemoveLed(led);
}
}
+
+ ///
+ /// Saves the specified layout to the given location.
+ ///
+ /// The layout to save.
+ /// The location to save to.
+ public static void Save(this IDeviceLayout layout, string targetFile)
+ {
+ using FileStream fs = new(targetFile, FileMode.Create);
+ layout.Save(fs);
+ }
+
+ ///
+ /// Saves the specified layout to the given stream.
+ ///
+ /// The layout to save.
+ /// The stream to save to.
+ public static void Save(this IDeviceLayout layout, Stream stream)
+ {
+ Type? customDataType = layout.CustomData?.GetType();
+ Type? customLedDataType = layout.Leds.FirstOrDefault(x => x.CustomData != null)?.CustomData?.GetType();
+
+ Type[] customTypes;
+ if ((customDataType != null) && (customLedDataType != null))
+ customTypes = new[] { customDataType, customLedDataType };
+ else if (customDataType != null)
+ customTypes = new[] { customDataType };
+ else if (customLedDataType != null)
+ customTypes = new[] { customLedDataType };
+ else
+ customTypes = Array.Empty();
+
+ if (layout is DeviceLayout deviceLayout)
+ {
+ deviceLayout.InternalCustomData = deviceLayout.CustomData;
+
+ foreach (ILedLayout led in deviceLayout.Leds)
+ if (led is LedLayout ledLayout)
+ ledLayout.InternalCustomData = ledLayout.CustomData;
+ }
+
+ XmlSerializer serializer = new(typeof(DeviceLayout), null, customTypes, null, null);
+ serializer.Serialize(stream, layout);
+ }
}
\ No newline at end of file
diff --git a/RGB.NET.Layout/RGB.NET.Layout.csproj b/RGB.NET.Layout/RGB.NET.Layout.csproj
index 3c90185..473f421 100644
--- a/RGB.NET.Layout/RGB.NET.Layout.csproj
+++ b/RGB.NET.Layout/RGB.NET.Layout.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/RGB.NET.Presets/RGB.NET.Presets.csproj b/RGB.NET.Presets/RGB.NET.Presets.csproj
index 048087a..c7b6129 100644
--- a/RGB.NET.Presets/RGB.NET.Presets.csproj
+++ b/RGB.NET.Presets/RGB.NET.Presets.csproj
@@ -1,6 +1,6 @@
- net7.0;net6.0
+ net8.0;net7.0;net6.0
latest
enable
diff --git a/Tests/RGB.NET.Core.Tests/RGB.NET.Core.Tests.csproj b/Tests/RGB.NET.Core.Tests/RGB.NET.Core.Tests.csproj
index 7e98ef5..7fb09e7 100644
--- a/Tests/RGB.NET.Core.Tests/RGB.NET.Core.Tests.csproj
+++ b/Tests/RGB.NET.Core.Tests/RGB.NET.Core.Tests.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net8.0
false
diff --git a/Tests/RGB.NET.Presets.Tests/RGB.NET.Presets.Tests.csproj b/Tests/RGB.NET.Presets.Tests/RGB.NET.Presets.Tests.csproj
index ca57230..ba91ec3 100644
--- a/Tests/RGB.NET.Presets.Tests/RGB.NET.Presets.Tests.csproj
+++ b/Tests/RGB.NET.Presets.Tests/RGB.NET.Presets.Tests.csproj
@@ -1,7 +1,7 @@
- net7.0
+ net8.0
false