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

Added SteelSeries-Support

This commit is contained in:
Darth Affe 2019-02-23 11:15:49 +01:00
parent afbc25e1b2
commit 65a291500b
19 changed files with 1048 additions and 0 deletions

View File

@ -0,0 +1,10 @@
using Newtonsoft.Json;
namespace RGB.NET.Devices.SteelSeries.API.Model
{
internal class CoreProps
{
[JsonProperty(PropertyName = "address")]
public string Address { get; set; }
}
}

View File

@ -0,0 +1,34 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace RGB.NET.Devices.SteelSeries.API.Model
{
internal class Event
{
#region Properties & Fields
[JsonProperty("game")]
public string Game { get; set; }
[JsonProperty("event")]
public string Name { get; set; }
[JsonProperty("data")]
public Dictionary<string, object> Data { get; } = new Dictionary<string, object>();
#endregion
#region Constructors
public Event()
{ }
public Event(Game game, string name)
{
this.Name = name;
Game = game.Name;
}
#endregion
}
}

View File

@ -0,0 +1,30 @@
using Newtonsoft.Json;
namespace RGB.NET.Devices.SteelSeries.API.Model
{
internal class Game
{
#region Properties & Fields
[JsonProperty("game")]
public string Name { get; set; }
[JsonProperty("game_display_name")]
public string DisplayName { get; set; }
#endregion
#region Constructors
public Game()
{ }
public Game(string name, string displayName)
{
Name = name;
DisplayName = displayName;
}
#endregion
}
}

View File

@ -0,0 +1,30 @@
using Newtonsoft.Json;
namespace RGB.NET.Devices.SteelSeries.API.Model
{
internal class GoLispHandler
{
#region Properties & Fields
[JsonProperty("game")]
public string Game { get; set; }
[JsonProperty("golisp")]
public string Handler { get; set; }
#endregion
#region Constructors
public GoLispHandler()
{ }
public GoLispHandler(Game game, string handler)
{
this.Handler = handler;
Game = game.Name;
}
#endregion
}
}

View File

@ -0,0 +1,120 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Text;
using Newtonsoft.Json;
using RGB.NET.Devices.SteelSeries.API.Model;
namespace RGB.NET.Devices.SteelSeries.API
{
internal static class SteelSeriesSDK
{
#region Constants
private const string GAME_NAME = "RGBNET";
private const string GAME_DISPLAYNAME = "RGB.NET";
private const string EVENT_NAME = "UPDATELEDS";
private const string HANDLER = @"(handler """ + EVENT_NAME + @"""
(lambda (data)
(let* ((device (value: data))
(zoneData (frame: data))
(zones (frame-keys zoneData)))
(do ((zoneDo zones (cdr zoneDo)))
((nil? zoneDo))
(let* ((zone (car zoneDo))
(color (get-slot zoneData zone)))
(on-device device show-on-zone: color zone))))))";
private const string CORE_PROPS_WINDOWS = "%PROGRAMDATA%/SteelSeries/SteelSeries Engine 3/coreProps.json";
private const string CORE_PROPS_OSX = "/Library/Application Support/SteelSeries Engine 3/coreProps.json";
#endregion
#region Properties & Fields
// ReSharper disable InconsistentNaming
private static readonly HttpClient _client = new HttpClient();
private static readonly Game _game = new Game(GAME_NAME, GAME_DISPLAYNAME);
private static readonly Event _event = new Event(_game, EVENT_NAME);
private static string _baseUrl;
internal static bool IsInitialized => !string.IsNullOrWhiteSpace(_baseUrl);
// ReSharper restore InconsistentNaming
#endregion
#region Methods
internal static bool Initialize()
{
try
{
string corePropsPath = GetCorePropsPath();
if (!string.IsNullOrWhiteSpace(corePropsPath) && File.Exists(corePropsPath))
{
CoreProps coreProps = JsonConvert.DeserializeObject<CoreProps>(File.ReadAllText(corePropsPath));
_baseUrl = coreProps.Address;
if (!_baseUrl.StartsWith("http://", StringComparison.Ordinal))
_baseUrl = "http://" + _baseUrl;
RegisterGame(_game);
RegisterGoLispHandler(new GoLispHandler(_game, HANDLER));
}
}
catch
{
_baseUrl = null;
}
return IsInitialized;
}
internal static void UpdateLeds(string device, Dictionary<string, int[]> data)
{
_event.Data.Clear();
_event.Data.Add("value", device);
_event.Data.Add("frame", data);
TriggerEvent(_event);
}
internal static void SendHeartbeat() => SendHeartbeat(_game);
internal static void ResetLeds() => StopGame(_game);
internal static void Dispose()
{
ResetLeds();
_client.Dispose();
}
private static string TriggerEvent(Event e) => PostJson("/game_event", e);
private static string RegisterGoLispHandler(GoLispHandler handler) => PostJson("/load_golisp_handlers", handler);
private static string RegisterEvent(Event e) => PostJson("/register_game_event", e);
private static string UnregisterEvent(Event e) => PostJson("/remove_game_event", e);
private static string RegisterGame(Game game) => PostJson("/game_metadata", game);
private static string UnregisterGame(Game game) => PostJson("/remove_game", game);
private static string StopGame(Game game) => PostJson("/stop_game", game);
private static string SendHeartbeat(Game game) => PostJson("/game_heartbeat", game);
private static string PostJson(string urlSuffix, object o)
{
string payload = JsonConvert.SerializeObject(o);
return _client.PostAsync(_baseUrl + urlSuffix, new StringContent(payload, Encoding.UTF8, "application/json")).Result.Content.ReadAsStringAsync().Result;
}
private static string GetCorePropsPath()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return Environment.ExpandEnvironmentVariables(CORE_PROPS_WINDOWS);
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
return CORE_PROPS_OSX;
throw new InvalidOperationException("Unknown operating system.");
}
#endregion
}
}

View File

@ -0,0 +1,20 @@
namespace RGB.NET.Devices.SteelSeries
{
internal class APIName : System.Attribute
{
#region Properties & Fields
public string Name { get; set; }
#endregion
#region Constructors
public APIName(string name)
{
this.Name = name;
}
#endregion
}
}

View File

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace RGB.NET.Devices.SteelSeries
{
internal static class SteelSeriesEnumExtension
{
#region Properties & Fields
// ReSharper disable InconsistentNaming
private static readonly Dictionary<SteelSeriesDeviceType, string> _deviceTypeNames = new Dictionary<SteelSeriesDeviceType, string>();
private static readonly Dictionary<SteelSeriesLedId, string> _ledIdNames = new Dictionary<SteelSeriesLedId, string>();
// ReSharper restore InconsistentNaming
#endregion
#region Methods
internal static string GetAPIName(this SteelSeriesDeviceType deviceType)
{
if (!_deviceTypeNames.TryGetValue(deviceType, out string apiName))
_deviceTypeNames.Add(deviceType, apiName = GetAPIName(typeof(SteelSeriesDeviceType), deviceType));
return apiName;
}
internal static string GetAPIName(this SteelSeriesLedId ledId)
{
if (!_ledIdNames.TryGetValue(ledId, out string apiName))
_ledIdNames.Add(ledId, apiName = GetAPIName(typeof(SteelSeriesLedId), ledId));
return apiName;
}
private static string GetAPIName(Type type, Enum value)
{
MemberInfo[] memInfo = type.GetMember(value.ToString());
if (memInfo.Length == 0) return null;
return (memInfo.FirstOrDefault()?.GetCustomAttributes(typeof(APIName), false).FirstOrDefault() as APIName)?.Name;
}
#endregion
}
}

View File

@ -0,0 +1,23 @@
namespace RGB.NET.Devices.SteelSeries
{
public enum SteelSeriesDeviceType
{
[APIName("rgb-per-key-zones")]
PerKey,
[APIName("rgb-1-zone")]
OneZone,
[APIName("rgb-2-zone")]
TwoZone,
[APIName("rgb-3-zone")]
ThreeZone,
[APIName("rgb-4-zone")]
FourZone,
[APIName("rgb-5-zone")]
FiveZone
}
}

View File

@ -0,0 +1,243 @@
namespace RGB.NET.Devices.SteelSeries
{
public enum SteelSeriesLedId
{
[APIName("one")]
ZoneOne,
[APIName("two")]
ZoneTwo,
[APIName("three")]
ZoneThree,
[APIName("four")]
ZoneFour,
[APIName("five")]
ZoneFive,
[APIName("logo")]
Logo,
[APIName("a")]
A,
[APIName("b")]
B,
[APIName("c")]
C,
[APIName("d")]
D,
[APIName("e")]
E,
[APIName("f")]
F,
[APIName("g")]
G,
[APIName("h")]
H,
[APIName("i")]
I,
[APIName("j")]
J,
[APIName("k")]
K,
[APIName("l")]
L,
[APIName("m")]
M,
[APIName("n")]
N,
[APIName("o")]
O,
[APIName("p")]
P,
[APIName("q")]
Q,
[APIName("r")]
R,
[APIName("s")]
S,
[APIName("t")]
T,
[APIName("u")]
U,
[APIName("v")]
V,
[APIName("w")]
W,
[APIName("x")]
X,
[APIName("y")]
Y,
[APIName("z")]
Z,
[APIName("keyboard-1")]
Keyboard1,
[APIName("keyboard-2")]
Keyboard2,
[APIName("keyboard-3")]
Keyboard3,
[APIName("keyboard-4")]
Keyboard4,
[APIName("keyboard-5")]
Keyboard5,
[APIName("keyboard-6")]
Keyboard6,
[APIName("keyboard-7")]
Keyboard7,
[APIName("keyboard-8")]
Keyboard8,
[APIName("keyboard-9")]
Keyboard9,
[APIName("keyboard-0")]
Keyboard0,
[APIName("return")]
Return,
[APIName("escape")]
Escape,
[APIName("backspace")]
Backspace,
[APIName("tab")]
Tab,
[APIName("spacebar")]
Spacebar,
[APIName("caps")]
Caps,
[APIName("dash")]
Dash,
[APIName("equal")]
Equal,
[APIName("l-bracket")]
LBracket,
[APIName("r-bracket")]
RBracket,
[APIName("backslash")]
Backslash,
[APIName("pound")]
Pound,
[APIName("semicolon")]
Semicolon,
[APIName("quote")]
Quote,
[APIName("backquote")]
Backqoute,
[APIName("comma")]
Comma,
[APIName("period")]
Period,
[APIName("slash")]
Slash,
[APIName("f1")]
F1,
[APIName("f2")]
F2,
[APIName("f3")]
F3,
[APIName("f4")]
F4,
[APIName("f5")]
F5,
[APIName("f6")]
F6,
[APIName("f7")]
F7,
[APIName("f8")]
F8,
[APIName("f9")]
F9,
[APIName("f10")]
F10,
[APIName("f11")]
F11,
[APIName("f12")]
F12,
[APIName("printscreen")]
PrintScreen,
[APIName("scrolllock")]
ScrollLock,
[APIName("pause")]
Pause,
[APIName("insert")]
Insert,
[APIName("home")]
Home,
[APIName("pageup")]
PageUp,
[APIName("delete")]
Delete,
[APIName("end")]
End,
[APIName("pagedown")]
PageDown,
[APIName("rightarrow")]
RightArrow,
[APIName("leftarrow")]
LeftArrow,
[APIName("downarrow")]
DownArrow,
[APIName("uparrow")]
UpArrow,
[APIName("keypad-num-lock")]
KeypadNumLock,
[APIName("keypad-divide")]
KeypadDivide,
[APIName("keypad-times")]
KeypadTimes,
[APIName("keypad-minus")]
KeypadMinus,
[APIName("keypad-plus")]
KeypadPlus,
[APIName("keypad-enter")]
KeypadEnter,
[APIName("keypad-period")]
KeypadPeriod,
[APIName("keypad-1")]
Keypad1,
[APIName("keypad-2")]
Keypad2,
[APIName("keypad-3")]
Keypad3,
[APIName("keypad-4")]
Keypad4,
[APIName("keypad-5")]
Keypad5,
[APIName("keypad-6")]
Keypad6,
[APIName("keypad-7")]
Keypad7,
[APIName("keypad-8")]
Keypad8,
[APIName("keypad-9")]
Keypad9,
[APIName("keypad-0")]
Keypad0,
[APIName("l-ctrl")]
LCtrl,
[APIName("l-shift")]
LShift,
[APIName("l-alt")]
LAlt,
[APIName("l-win")]
LWin,
[APIName("r-ctrl")]
RCtrl,
[APIName("r-shift")]
RShift,
[APIName("r-alt")]
RAlt,
[APIName("r-win")]
RWin,
[APIName("ss-key")]
SSKey,
[APIName("win-menu")]
WinMenu,
[APIName("m0")]
M0,
[APIName("m1")]
M1,
[APIName("m2")]
M2,
[APIName("m3")]
M3,
[APIName("m4")]
M4,
[APIName("m5")]
M5,
}
}

View File

@ -0,0 +1,13 @@
using System.Collections.Generic;
using RGB.NET.Core;
namespace RGB.NET.Devices.SteelSeries
{
/// <summary>
/// Represents a steelseries RGB-device.
/// </summary>
internal interface ISteelSeriesRGBDevice : IRGBDevice
{
void Initialize(UpdateQueue updateQueue, Dictionary<LedId, SteelSeriesLedId> ledMapping);
}
}

View File

@ -0,0 +1,45 @@
using System.Collections.Generic;
using System.Linq;
using RGB.NET.Core;
using RGB.NET.Devices.SteelSeries.API;
namespace RGB.NET.Devices.SteelSeries
{
/// <inheritdoc />
/// <summary>
/// Represents the update-queue performing updates for steelseries devices.
/// </summary>
internal class SteelSeriesDeviceUpdateQueue : UpdateQueue
{
#region Properties & Fields
private string _deviceType;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="SteelSeriesDeviceUpdateQueue"/> 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 SteelSeriesDeviceUpdateQueue(IDeviceUpdateTrigger updateTrigger, string deviceType)
: base(updateTrigger)
{
this._deviceType = deviceType;
}
#endregion
#region Methods
/// <inheritdoc />
protected override void Update(Dictionary<object, Color> dataSet)
{
SteelSeriesSDK.UpdateLeds(_deviceType, dataSet.ToDictionary(x => ((SteelSeriesLedId)x.Key).GetAPIName(), x => new int[] { x.Value.R, x.Value.G, x.Value.B }));
}
#endregion
}
}

View File

@ -0,0 +1,88 @@
using System.Collections.Generic;
using System.Linq;
using RGB.NET.Core;
namespace RGB.NET.Devices.SteelSeries
{
/// <inheritdoc cref="AbstractRGBDevice{TDeviceInfo}" />
/// <inheritdoc cref="ISteelSeriesRGBDevice" />
/// <summary>
/// Represents a SteelSeries-device. (keyboard, mouse, headset, mousepad).
/// </summary>
public class SteelSeriesRGBDevice : AbstractRGBDevice<SteelSeriesRGBDeviceInfo>, ISteelSeriesRGBDevice
{
#region Properties & Fields
private Dictionary<LedId, SteelSeriesLedId> _ledMapping;
/// <inheritdoc />
/// <summary>
/// Gets information about the <see cref="SteelSeriesRGBDevice" />.
/// </summary>
public override SteelSeriesRGBDeviceInfo DeviceInfo { get; }
/// <summary>
/// Gets or sets the update queue performing updates for this device.
/// </summary>
// ReSharper disable once MemberCanBePrivate.Global
protected UpdateQueue UpdateQueue { get; set; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="SteelSeriesRGBDevice"/> class.
/// </summary>
/// <param name="info">The generic information provided by SteelSeries for the device.</param>
internal SteelSeriesRGBDevice(SteelSeriesRGBDeviceInfo info)
{
this.DeviceInfo = info;
}
#endregion
#region Methods
/// <summary>
/// Initializes the device.
/// </summary>
void ISteelSeriesRGBDevice.Initialize(UpdateQueue updateQueue, Dictionary<LedId, SteelSeriesLedId> ledMapping)
{
_ledMapping = ledMapping;
int counter = 0;
foreach (KeyValuePair<LedId, SteelSeriesLedId> mapping in ledMapping)
InitializeLed(mapping.Key, new Rectangle((counter++) * 10, 0, 10, 10));
InitializeLayout();
if (Size == Size.Invalid)
{
Rectangle ledRectangle = new Rectangle(this.Select(x => x.LedRectangle));
Size = ledRectangle.Size + new Size(ledRectangle.Location.X, ledRectangle.Location.Y);
}
UpdateQueue = updateQueue;
}
protected override object CreateLedCustomData(LedId ledId) => _ledMapping[ledId];
/// <inheritdoc />
protected override void UpdateLeds(IEnumerable<Led> ledsToUpdate) => UpdateQueue.SetData(ledsToUpdate.Where(x => x.Color.A > 0));
/// <summary>
/// Initializes the <see cref="Led"/> and <see cref="Size"/> of the device.
/// </summary>
protected virtual void InitializeLayout()
{
if (!(DeviceInfo is SteelSeriesRGBDeviceInfo info)) return;
string layout = info.ImageLayout;
string layoutPath = info.LayoutPath;
ApplyLayoutFromFile(PathHelper.GetAbsolutePath($@"Layouts\SteelSeries\{layoutPath}.xml"), layout, true);
}
#endregion
}
}

View File

@ -0,0 +1,72 @@
using System;
using RGB.NET.Core;
namespace RGB.NET.Devices.SteelSeries
{
/// <inheritdoc />
/// <summary>
/// Represents a generic information for a SteelSeries-<see cref="T:RGB.NET.Core.IRGBDevice" />.
/// </summary>
public class SteelSeriesRGBDeviceInfo : IRGBDeviceInfo
{
#region Properties & Fields
/// <inheritdoc />
public RGBDeviceType DeviceType { get; }
/// <inheritdoc />
public string DeviceName { get; }
/// <inheritdoc />
public string Manufacturer => "SteelSeries";
/// <inheritdoc />
public string Model { get; }
/// <inheritdoc />
public Uri Image { get; set; }
/// <inheritdoc />
public RGBDeviceLighting Lighting => RGBDeviceLighting.Key;
/// <inheritdoc />
public bool SupportsSyncBack => false;
public SteelSeriesDeviceType SteelSeriesDeviceType { get; }
/// <summary>
/// Gets the layout used to decide which images to load.
/// </summary>
internal string ImageLayout { get; }
/// <summary>
/// Gets the path/name of the layout-file.
/// </summary>
internal string LayoutPath { get; }
#endregion
#region Constructors
/// <summary>
/// Internal constructor of managed <see cref="SteelSeriesRGBDeviceInfo"/>.
/// </summary>
/// <param name="deviceType">The type of the <see cref="IRGBDevice"/>.</param>
/// <param name="model">The represented device model.</param>
/// <param name="deviceCaps">The lighting-capabilities of the device.</param>
/// <param name="imageLayout">The layout used to decide which images to load.</param>
/// <param name="layoutPath">The path/name of the layout-file.</param>
internal SteelSeriesRGBDeviceInfo(RGBDeviceType deviceType, string model, SteelSeriesDeviceType steelSeriesDeviceType, string imageLayout, string layoutPath)
{
this.DeviceType = deviceType;
this.Model = model;
this.SteelSeriesDeviceType = steelSeriesDeviceType;
this.ImageLayout = imageLayout;
this.LayoutPath = layoutPath;
DeviceName = $"{Manufacturer} {Model}";
}
#endregion
}
}

View File

@ -0,0 +1,47 @@
using System.Collections.Generic;
using System.Linq;
using HidSharp;
using RGB.NET.Core;
using DeviceDataList = System.Collections.Generic.List<(string model, RGB.NET.Core.RGBDeviceType deviceType, int id, RGB.NET.Devices.SteelSeries.SteelSeriesDeviceType steelSeriesDeviceType, string imageLayout, string layoutPath, System.Collections.Generic.Dictionary<RGB.NET.Core.LedId, RGB.NET.Devices.SteelSeries.SteelSeriesLedId> ledMapping)>;
using LedMapping = System.Collections.Generic.Dictionary<RGB.NET.Core.LedId, RGB.NET.Devices.SteelSeries.SteelSeriesLedId>;
namespace RGB.NET.Devices.SteelSeries.HID
{
internal static class DeviceChecker
{
#region Constants
private const int VENDOR_ID = 0x1038;
//TODO DarthAffe 16.02.2019: Add devices
private static readonly DeviceDataList DEVICES = new DeviceDataList
{
("Rival 500", RGBDeviceType.Mouse, 0x170E, SteelSeriesDeviceType.TwoZone, "default", @"Mice\Rival500", new LedMapping { { LedId.Mouse1, SteelSeriesLedId.ZoneOne},
{ LedId.Mouse2, SteelSeriesLedId.ZoneTwo} }),
};
#endregion
#region Properties & Fields
public static DeviceDataList ConnectedDevices { get; } = new DeviceDataList();
#endregion
#region Methods
internal static void LoadDeviceList(RGBDeviceType loadFilter)
{
ConnectedDevices.Clear();
HashSet<int> ids = new HashSet<int>(DeviceList.Local.GetHidDevices(VENDOR_ID).Select(x => x.ProductID).Distinct());
DeviceDataList connectedDevices = DEVICES.Where(d => ids.Contains(d.id) && loadFilter.HasFlag(d.deviceType)).ToList();
List<SteelSeriesDeviceType> connectedDeviceTypes = connectedDevices.Select(d => d.steelSeriesDeviceType).ToList();
foreach (SteelSeriesDeviceType deviceType in connectedDeviceTypes)
ConnectedDevices.Add(connectedDevices.Where(d => d.steelSeriesDeviceType == deviceType).OrderByDescending(d => d.ledMapping.Count).First());
}
#endregion
}
}

View File

@ -0,0 +1,62 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<RuntimeIdentifiers>win7-x86;win7-x64</RuntimeIdentifiers>
<Authors>Darth Affe</Authors>
<Company>Wyrez</Company>
<Language>en-US</Language>
<NeutralLanguage>en-US</NeutralLanguage>
<Title>RGB.NET.Devices.SteelSeries</Title>
<AssemblyName>RGB.NET.Devices.SteelSeries</AssemblyName>
<AssemblyTitle>RGB.NET.Devices.SteelSeries</AssemblyTitle>
<PackageId>RGB.NET.Devices.SteelSeries</PackageId>
<RootNamespace>RGB.NET.Devices.SteelSeries</RootNamespace>
<Description>SteelSeries-Device-Implementations of RGB.NET</Description>
<Summary>SteelSeries-Device-Implementations of RGB.NET, a C# (.NET) library for accessing various RGB-peripherals</Summary>
<Copyright>Copyright © Wyrez 2017</Copyright>
<PackageCopyright>Copyright © Wyrez 2017</PackageCopyright>
<PackageIconUrl>http://lib.arge.be/icon.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/DarthAffe/RGB.NET</PackageProjectUrl>
<PackageLicenseUrl>https://raw.githubusercontent.com/DarthAffe/RGB.NET/master/LICENSE</PackageLicenseUrl>
<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>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<DefineConstants>NETCORE;NETSTANDARD;NETSTANDARD2_0</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
<DefineConstants>$(DefineConstants);TRACE;DEBUG</DefineConstants>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<NoWarn>$(NoWarn);CS1591;CS1572;CS1573</NoWarn>
<DefineConstants>$(DefineConstants);RELEASE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\RGB.NET.Core\RGB.NET.Core.csproj" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="HidSharp" Version="2.0.1" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,4 @@
<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/=attribute/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=enum/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=generic/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using RGB.NET.Core;
using RGB.NET.Devices.SteelSeries.API;
using RGB.NET.Devices.SteelSeries.HID;
namespace RGB.NET.Devices.SteelSeries
{
/// <inheritdoc />
/// <summary>
/// Represents a device provider responsible for SteelSeries- devices.
/// </summary>
public class SteelSeriesDeviceProvider : IRGBDeviceProvider
{
#region Properties & Fields
private static SteelSeriesDeviceProvider _instance;
/// <summary>
/// Gets the singleton <see cref="SteelSeriesDeviceProvider"/> instance.
/// </summary>
public static SteelSeriesDeviceProvider Instance => _instance ?? new SteelSeriesDeviceProvider();
/// <inheritdoc />
/// <summary>
/// Indicates if the SDK is initialized and ready to use.
/// </summary>
public bool IsInitialized { get; private set; }
/// <inheritdoc />
/// <summary>
/// Gets whether the application has exclusive access to the SDK or not.
/// </summary>
public bool HasExclusiveAccess => false;
/// <inheritdoc />
public IEnumerable<IRGBDevice> Devices { get; private set; }
/// <summary>
/// The <see cref="DeviceUpdateTrigger"/> used to trigger the updates for SteelSeries devices.
/// </summary>
public DeviceUpdateTrigger UpdateTrigger { get; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="SteelSeriesDeviceProvider"/> class.
/// </summary>
/// <exception cref="InvalidOperationException">Thrown if this constructor is called even if there is already an instance of this class.</exception>
public SteelSeriesDeviceProvider()
{
if (_instance != null) throw new InvalidOperationException($"There can be only one instance of type {nameof(SteelSeriesDeviceProvider)}");
_instance = this;
UpdateTrigger = new DeviceUpdateTrigger();
}
#endregion
#region Methods
/// <inheritdoc />
public bool Initialize(RGBDeviceType loadFilter = RGBDeviceType.All, bool exclusiveAccessIfPossible = false, bool throwExceptions = false)
{
try
{
IsInitialized = false;
UpdateTrigger?.Stop();
if (!SteelSeriesSDK.IsInitialized)
SteelSeriesSDK.Initialize();
IList<IRGBDevice> devices = new List<IRGBDevice>();
DeviceChecker.LoadDeviceList(loadFilter);
try
{
foreach ((string model, RGBDeviceType deviceType, int _, SteelSeriesDeviceType steelSeriesDeviceType, string imageLayout, string layoutPath, Dictionary<LedId, SteelSeriesLedId> ledMapping) in DeviceChecker.ConnectedDevices)
{
ISteelSeriesRGBDevice device = new SteelSeriesRGBDevice(new SteelSeriesRGBDeviceInfo(deviceType, model, steelSeriesDeviceType, imageLayout, layoutPath));
SteelSeriesDeviceUpdateQueue updateQueue = new SteelSeriesDeviceUpdateQueue(UpdateTrigger, steelSeriesDeviceType.GetAPIName());
device.Initialize(updateQueue, ledMapping);
devices.Add(device);
}
}
catch { if (throwExceptions) throw; }
UpdateTrigger?.Start();
Devices = new ReadOnlyCollection<IRGBDevice>(devices);
IsInitialized = true;
}
catch
{
IsInitialized = false;
if (throwExceptions) throw;
return false;
}
return true;
}
/// <inheritdoc />
public void ResetDevices()
{
if (IsInitialized)
try
{
SteelSeriesSDK.ResetLeds();
}
catch {/* shit happens */}
}
/// <inheritdoc />
public void Dispose()
{
try
{
SteelSeriesSDK.Dispose();
}
catch {/* shit happens */}
}
#endregion
}
}

View File

@ -0,0 +1,25 @@
using RGB.NET.Core;
namespace RGB.NET.Devices.SteelSeries
{
/// <summary>
/// Represents a device provider loaded used to dynamically load steelseries devices into an application.
/// </summary>
// ReSharper disable once UnusedMember.Global
public class SteelSeriesDeviceProviderLoader : IRGBDeviceProviderLoader
{
#region Properties & Fields
/// <inheritdoc />
public bool RequiresInitialization => false;
#endregion
#region Methods
/// <inheritdoc />
public IRGBDeviceProvider GetDeviceProvider() => SteelSeriesDeviceProvider.Instance;
#endregion
}
}

View File

@ -39,6 +39,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Groups", "RGB.NET.G
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.WS281X", "RGB.NET.Devices.WS281X\RGB.NET.Devices.WS281X.csproj", "{0AD382DA-E999-4F74-9658-8D402EE9BF3F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RGB.NET.Devices.SteelSeries", "RGB.NET.Devices.SteelSeries\RGB.NET.Devices.SteelSeries.csproj", "{FFDE4387-60F2-47B6-9704-3A57D02B8C64}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -109,6 +111,10 @@ Global
{0AD382DA-E999-4F74-9658-8D402EE9BF3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0AD382DA-E999-4F74-9658-8D402EE9BF3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0AD382DA-E999-4F74-9658-8D402EE9BF3F}.Release|Any CPU.Build.0 = Release|Any CPU
{FFDE4387-60F2-47B6-9704-3A57D02B8C64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FFDE4387-60F2-47B6-9704-3A57D02B8C64}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FFDE4387-60F2-47B6-9704-3A57D02B8C64}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FFDE4387-60F2-47B6-9704-3A57D02B8C64}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -129,6 +135,7 @@ Global
{8725C448-818C-41F7-B23F-F97E062BF233} = {EBC33090-8494-4DF4-B4B6-64D0E531E93F}
{6FEBDC9E-909D-4EE2-B003-EDFBEF5FFF40} = {EBC33090-8494-4DF4-B4B6-64D0E531E93F}
{0AD382DA-E999-4F74-9658-8D402EE9BF3F} = {D13032C6-432E-4F43-8A32-071133C22B16}
{FFDE4387-60F2-47B6-9704-3A57D02B8C64} = {D13032C6-432E-4F43-8A32-071133C22B16}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {7F222AD4-1F9E-4AAB-9D69-D62372D4C1BA}