diff --git a/Demo/Program.cs b/Demo/Program.cs index 4fb9b36..8dc5300 100644 --- a/Demo/Program.cs +++ b/Demo/Program.cs @@ -1,6 +1,5 @@ using System; using System.Threading; -using System.Threading.Tasks; using Illumilib; namespace Demo { @@ -9,50 +8,50 @@ namespace Demo { private static void Main(string[] args) { IllumilibLighting.Initialize(); - Console.WriteLine("Setting specific positions"); - IllumilibLighting.SetKeyboardLighting(0, 1, 0); - IllumilibLighting.SetKeyboardLighting(6, 1, 1, 0, 1); - IllumilibLighting.SetKeyboardLighting(16, 5, 1, 0, 1); - Thread.Sleep(TimeSpan.FromSeconds(5)); - IllumilibLighting.SetKeyboardLighting(1, 0, 0); - IllumilibLighting.SetKeyboardLighting(8, 2, 2, 2, 0, 1, 0); - Thread.Sleep(TimeSpan.FromSeconds(5)); - Console.WriteLine("Setting all lights to blue"); - IllumilibLighting.SetAllLighting(0, 0, 1); + IllumilibLighting.SetAllLighting(r: 0, g: 0, b: 1); Thread.Sleep(TimeSpan.FromSeconds(3)); - IllumilibLighting.SetAllLighting(0, 0, 0); + IllumilibLighting.SetAllLighting(r: 0, g: 0, b: 0); + + Console.WriteLine("Setting specific positions"); + IllumilibLighting.SetKeyboardLighting(x: 6, y: 1, r: 1, g: 0, b: 1); + IllumilibLighting.SetKeyboardLighting(x: 16, y: 5, r: 1, g: 0, b: 1); + Thread.Sleep(TimeSpan.FromSeconds(5)); + IllumilibLighting.SetKeyboardLighting(r: 0, g: 0, b: 0); + IllumilibLighting.SetKeyboardLighting(x: 8, y: 2, width: 2, height: 2, r: 0, g: 1, b: 0); + Thread.Sleep(TimeSpan.FromSeconds(5)); + IllumilibLighting.SetKeyboardLighting(r: 0, g: 0, b: 0); Console.WriteLine("Doing a fun effect"); for (var x = 0; x < IllumilibLighting.KeyboardWidth; x++) { - IllumilibLighting.SetKeyboardLighting(x, 0, 1, IllumilibLighting.KeyboardHeight, 0, 0, 1); + IllumilibLighting.SetKeyboardLighting(x: x, y: 0, width: 1, height: IllumilibLighting.KeyboardHeight, r: 0, g: 0, b: 1); Thread.Sleep(TimeSpan.FromSeconds(0.25F)); } for (var x = IllumilibLighting.KeyboardWidth - 1; x >= 0; x--) { - IllumilibLighting.SetKeyboardLighting(x, 0, 1, IllumilibLighting.KeyboardHeight, 0, 0, 0); + IllumilibLighting.SetKeyboardLighting(x: x, y: 0, width: 1, height: IllumilibLighting.KeyboardHeight, r: 0, g: 0, b: 0); Thread.Sleep(TimeSpan.FromSeconds(0.25F)); } Console.WriteLine("Going through the alphabet"); for (var i = 65; i <= 90; i++) { var key = (KeyboardKeys) i; - IllumilibLighting.SetKeyboardLighting(key, 0, 1, 0); + IllumilibLighting.SetKeyboardLighting(key: key, r: 0, g: 1, b: 0); Thread.Sleep(TimeSpan.FromSeconds(0.25F)); - IllumilibLighting.SetKeyboardLighting(key, 0, 0, 0); + IllumilibLighting.SetKeyboardLighting(key: key, r: 0, g: 0, b: 0); } Thread.Sleep(TimeSpan.FromSeconds(1)); Console.WriteLine("Pulsing"); for (var i = 0; i < 500; i++) { var value = (MathF.Sin(i / 50F * MathF.PI) + 1) / 2; - IllumilibLighting.SetAllLighting(value, 0, value); + IllumilibLighting.SetAllLighting(r: value, g: 0, b: value); Thread.Sleep(10); } - IllumilibLighting.SetAllLighting(0, 0, 0); + IllumilibLighting.SetAllLighting(r: 0, g: 0, b: 0); Console.WriteLine("Setting all supported keys"); foreach (var key in Enum.GetValues()) { - IllumilibLighting.SetKeyboardLighting(key, 1, 0, 0); + IllumilibLighting.SetKeyboardLighting(key: key, r: 1, g: 0, b: 0); Thread.Sleep(50); } Thread.Sleep(TimeSpan.FromSeconds(15)); diff --git a/Illumilib/Illumilib.csproj b/Illumilib/Illumilib.csproj index 1db112e..87a42de 100644 --- a/Illumilib/Illumilib.csproj +++ b/Illumilib/Illumilib.csproj @@ -4,7 +4,7 @@ netstandard2.0 true Ellpeck - A simple keyboard and mouse lighting library with support for Razer and Logitech devices + A simple keyboard and mouse lighting library with support for Razer, Logitech and Corsair devices lighting keyboard mouse logitech lightsync razer chroma https://github.com/Ellpeck/Illumilib https://github.com/Ellpeck/Illumilib @@ -22,5 +22,6 @@ + diff --git a/Illumilib/IllumilibLighting.cs b/Illumilib/IllumilibLighting.cs index 4a304e2..c36a152 100644 --- a/Illumilib/IllumilibLighting.cs +++ b/Illumilib/IllumilibLighting.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; using Illumilib.System; namespace Illumilib { @@ -35,7 +34,7 @@ namespace Illumilib { if (Initialized) throw new InvalidOperationException("Illumilib has already been initialized"); systems = new List(); - foreach (var system in new LightingSystem[] {new LogitechLighting(), new RazerLighting()}) { + foreach (var system in new LightingSystem[] {new LogitechLighting(), new RazerLighting(), new CorsairLighting()}) { if (system.Initialize()) systems.Add(system); } @@ -74,7 +73,7 @@ namespace Illumilib { /// /// Sets the lighting for the given x, y position on the keyboard to the given color. - /// The position is zero-based, with 0, 0 being in the top left corner of the keyboard. + /// The position is zero-based, with 0, 0 being the key in the top left corner of the keyboard. /// /// The zero-based x position of the key /// The zero-based y position of the key @@ -92,7 +91,7 @@ namespace Illumilib { /// /// Sets the lighting in the given area on the keyboard to the given color. - /// The position is zero-based, with 0, 0 being in the top left corner of the keyboard. + /// The position is zero-based, with 0, 0 being the key in the top left corner of the keyboard. /// The position is the top left corner of the rectangle that represents the area to set colors in. /// /// The zero-based x position of the key diff --git a/Illumilib/System/CorsairLighting.cs b/Illumilib/System/CorsairLighting.cs new file mode 100644 index 0000000..a3718f9 --- /dev/null +++ b/Illumilib/System/CorsairLighting.cs @@ -0,0 +1,382 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Corsair.CUE.SDK; + +namespace Illumilib.System { + internal class CorsairLighting : LightingSystem { + + private DeviceInfo[] devices; + + public override bool Initialize() { + try { + CUESDK.CorsairPerformProtocolHandshake(); + if (CUESDK.CorsairGetLastError() != CorsairError.CE_Success) + return false; + + // initialize device information + this.devices = new DeviceInfo[CUESDK.CorsairGetDeviceCount()]; + for (var d = 0; d < this.devices.Length; d++) + this.devices[d] = new DeviceInfo(d); + + return true; + } catch { + return false; + } + } + + public override void Dispose() { + // no op + } + + public override void SetAllLighting(float r, float g, float b) { + foreach (var device in this.devices) { + device.SetAllColors(r, g, b); + device.UpdateColors(); + } + CUESDK.CorsairSetLedsColorsFlushBuffer(); + } + + public override void SetKeyboardLighting(float r, float g, float b) { + foreach (var device in this.devices) { + if (!device.IsKeyboard()) + continue; + device.SetAllColors(r, g, b); + device.UpdateColors(); + } + CUESDK.CorsairSetLedsColorsFlushBuffer(); + } + + public override void SetKeyboardLighting(int x, int y, float r, float g, float b) { + foreach (var device in this.devices) { + if (!device.IsKeyboard()) + continue; + if (device.Positions.TryGetValue((x, y), out var leds)) { + foreach (var led in leds) + device.SetColorForId(led, r, g, b); + device.UpdateColors(); + } + } + CUESDK.CorsairSetLedsColorsFlushBuffer(); + } + + public override void SetKeyboardLighting(int x, int y, int width, int height, float r, float g, float b) { + foreach (var device in this.devices) { + if (!device.IsKeyboard()) + continue; + for (var xAdd = 0; xAdd < width; xAdd++) { + for (var yAdd = 0; yAdd < height; yAdd++) { + if (device.Positions.TryGetValue((x + xAdd, y + yAdd), out var leds)) { + foreach (var led in leds) + device.SetColorForId(led, r, g, b); + } + } + } + device.UpdateColors(); + } + CUESDK.CorsairSetLedsColorsFlushBuffer(); + } + + public override void SetKeyboardLighting(KeyboardKeys key, float r, float g, float b) { + var id = ConvertKey(key); + foreach (var device in this.devices) { + if (!device.IsKeyboard()) + continue; + if (device.SetColorForId(id, r, g, b)) { + device.UpdateColors(); + break; + } + } + CUESDK.CorsairSetLedsColorsFlushBuffer(); + } + + public override void SetMouseLighting(float r, float g, float b) { + foreach (var device in this.devices) { + if (!device.IsMouse()) + continue; + device.SetAllColors(r, g, b); + device.UpdateColors(); + } + CUESDK.CorsairSetLedsColorsFlushBuffer(); + } + + private static CorsairLedId ConvertKey(KeyboardKeys key) { + switch (key) { + case KeyboardKeys.Back: + return CorsairLedId.CLK_Backspace; + case KeyboardKeys.Tab: + return CorsairLedId.CLK_Tab; + case KeyboardKeys.Enter: + return CorsairLedId.CLK_Enter; + case KeyboardKeys.Pause: + return CorsairLedId.CLK_PauseBreak; + case KeyboardKeys.CapsLock: + return CorsairLedId.CLK_CapsLock; + case KeyboardKeys.Escape: + return CorsairLedId.CLK_Escape; + case KeyboardKeys.Space: + return CorsairLedId.CLK_Space; + case KeyboardKeys.PageUp: + return CorsairLedId.CLK_PageUp; + case KeyboardKeys.PageDown: + return CorsairLedId.CLK_PageDown; + case KeyboardKeys.End: + return CorsairLedId.CLK_End; + case KeyboardKeys.Home: + return CorsairLedId.CLK_Home; + case KeyboardKeys.Left: + return CorsairLedId.CLK_LeftArrow; + case KeyboardKeys.Up: + return CorsairLedId.CLK_UpArrow; + case KeyboardKeys.Right: + return CorsairLedId.CLK_RightArrow; + case KeyboardKeys.Down: + return CorsairLedId.CLK_DownArrow; + case KeyboardKeys.PrintScreen: + return CorsairLedId.CLK_PrintScreen; + case KeyboardKeys.Insert: + return CorsairLedId.CLK_Insert; + case KeyboardKeys.Delete: + return CorsairLedId.CLK_Delete; + case KeyboardKeys.D0: + return CorsairLedId.CLK_0; + case KeyboardKeys.D1: + return CorsairLedId.CLK_1; + case KeyboardKeys.D2: + return CorsairLedId.CLK_2; + case KeyboardKeys.D3: + return CorsairLedId.CLK_3; + case KeyboardKeys.D4: + return CorsairLedId.CLK_4; + case KeyboardKeys.D5: + return CorsairLedId.CLK_5; + case KeyboardKeys.D6: + return CorsairLedId.CLK_6; + case KeyboardKeys.D7: + return CorsairLedId.CLK_7; + case KeyboardKeys.D8: + return CorsairLedId.CLK_8; + case KeyboardKeys.D9: + return CorsairLedId.CLK_9; + case KeyboardKeys.A: + return CorsairLedId.CLK_A; + case KeyboardKeys.B: + return CorsairLedId.CLK_B; + case KeyboardKeys.C: + return CorsairLedId.CLK_C; + case KeyboardKeys.D: + return CorsairLedId.CLK_D; + case KeyboardKeys.E: + return CorsairLedId.CLK_E; + case KeyboardKeys.F: + return CorsairLedId.CLK_F; + case KeyboardKeys.G: + return CorsairLedId.CLK_G; + case KeyboardKeys.H: + return CorsairLedId.CLK_H; + case KeyboardKeys.I: + return CorsairLedId.CLK_I; + case KeyboardKeys.J: + return CorsairLedId.CLK_J; + case KeyboardKeys.K: + return CorsairLedId.CLK_K; + case KeyboardKeys.L: + return CorsairLedId.CLK_L; + case KeyboardKeys.M: + return CorsairLedId.CLK_M; + case KeyboardKeys.N: + return CorsairLedId.CLK_N; + case KeyboardKeys.O: + return CorsairLedId.CLK_O; + case KeyboardKeys.P: + return CorsairLedId.CLK_P; + case KeyboardKeys.Q: + return CorsairLedId.CLK_Q; + case KeyboardKeys.R: + return CorsairLedId.CLK_R; + case KeyboardKeys.S: + return CorsairLedId.CLK_S; + case KeyboardKeys.T: + return CorsairLedId.CLK_T; + case KeyboardKeys.U: + return CorsairLedId.CLK_U; + case KeyboardKeys.V: + return CorsairLedId.CLK_V; + case KeyboardKeys.W: + return CorsairLedId.CLK_W; + case KeyboardKeys.X: + return CorsairLedId.CLK_X; + case KeyboardKeys.Y: + return CorsairLedId.CLK_Y; + case KeyboardKeys.Z: + return CorsairLedId.CLK_Z; + case KeyboardKeys.LWin: + return CorsairLedId.CLH_LeftLogo; + case KeyboardKeys.RWin: + return CorsairLedId.CLH_RightLogo; + case KeyboardKeys.NumPad0: + return CorsairLedId.CLK_Keypad0; + case KeyboardKeys.NumPad1: + return CorsairLedId.CLK_Keypad1; + case KeyboardKeys.NumPad2: + return CorsairLedId.CLK_Keypad2; + case KeyboardKeys.NumPad3: + return CorsairLedId.CLK_Keypad3; + case KeyboardKeys.NumPad4: + return CorsairLedId.CLK_Keypad4; + case KeyboardKeys.NumPad5: + return CorsairLedId.CLK_Keypad5; + case KeyboardKeys.NumPad6: + return CorsairLedId.CLK_Keypad6; + case KeyboardKeys.NumPad7: + return CorsairLedId.CLK_Keypad7; + case KeyboardKeys.NumPad8: + return CorsairLedId.CLK_Keypad8; + case KeyboardKeys.NumPad9: + return CorsairLedId.CLK_Keypad9; + case KeyboardKeys.Multiply: + return CorsairLedId.CLK_KeypadAsterisk; + case KeyboardKeys.Add: + return CorsairLedId.CLK_KeypadPlus; + case KeyboardKeys.Subtract: + return CorsairLedId.CLK_KeypadMinus; + case KeyboardKeys.Decimal: + return CorsairLedId.CLK_KeypadPeriodAndDelete; + case KeyboardKeys.Divide: + return CorsairLedId.CLK_KeypadSlash; + case KeyboardKeys.F1: + return CorsairLedId.CLK_F1; + case KeyboardKeys.F2: + return CorsairLedId.CLK_F2; + case KeyboardKeys.F3: + return CorsairLedId.CLK_F3; + case KeyboardKeys.F4: + return CorsairLedId.CLK_F4; + case KeyboardKeys.F5: + return CorsairLedId.CLK_F5; + case KeyboardKeys.F6: + return CorsairLedId.CLK_F6; + case KeyboardKeys.F7: + return CorsairLedId.CLK_F7; + case KeyboardKeys.F8: + return CorsairLedId.CLK_F8; + case KeyboardKeys.F9: + return CorsairLedId.CLK_F9; + case KeyboardKeys.F10: + return CorsairLedId.CLK_F10; + case KeyboardKeys.F11: + return CorsairLedId.CLK_F11; + case KeyboardKeys.F12: + return CorsairLedId.CLK_F12; + case KeyboardKeys.NumLock: + return CorsairLedId.CLK_NumLock; + case KeyboardKeys.Scroll: + return CorsairLedId.CLK_ScrollLock; + case KeyboardKeys.LShiftKey: + return CorsairLedId.CLK_LeftShift; + case KeyboardKeys.RShiftKey: + return CorsairLedId.CLK_RightShift; + case KeyboardKeys.LControlKey: + return CorsairLedId.CLK_LeftCtrl; + case KeyboardKeys.RControlKey: + return CorsairLedId.CLK_RightCtrl; + case KeyboardKeys.LMenu: + return CorsairLedId.CLK_LeftAlt; + case KeyboardKeys.RMenu: + return CorsairLedId.CLK_RightAlt; + case KeyboardKeys.OemSemicolon: + return CorsairLedId.CLK_SemicolonAndColon; + case KeyboardKeys.OemComma: + return CorsairLedId.CLK_CommaAndLessThan; + case KeyboardKeys.OemMinus: + return CorsairLedId.CLK_MinusAndUnderscore; + case KeyboardKeys.OemPeriod: + return CorsairLedId.CLK_PeriodAndBiggerThan; + case KeyboardKeys.OemTilde: + return CorsairLedId.CLK_GraveAccentAndTilde; + case KeyboardKeys.OemOpenBrackets: + return CorsairLedId.CLK_BracketLeft; + case KeyboardKeys.OemCloseBrackets: + return CorsairLedId.CLK_BracketRight; + case KeyboardKeys.OemBackslash: + return CorsairLedId.CLK_Backslash; + default: + return 0; + } + } + + private class DeviceInfo { + + public readonly Dictionary<(int, int), List> Positions; + + private readonly int id; + private readonly CorsairDeviceInfo info; + private readonly CorsairLedColor[] colors; + private readonly Dictionary ledIdToColorIndex; + + public DeviceInfo(int id) { + this.id = id; + this.info = CUESDK.CorsairGetDeviceInfo(id); + + var positions = CUESDK.CorsairGetLedPositionsByDeviceIndex(id); + this.ledIdToColorIndex = new Dictionary(); + this.colors = new CorsairLedColor[positions.numberOfLeds]; + for (var c = 0; c < this.colors.Length; c++) { + var led = positions.pLedPosition[c].ledId; + this.colors[c] = new CorsairLedColor {ledId = led}; + this.ledIdToColorIndex.Add(led, c); + } + + // corsair doesn't supply index-based key positions so we're approximating it using millimeter width and height + this.Positions = new Dictionary<(int, int), List>(); + var minX = positions.pLedPosition.Min(p => p.left); + var minY = positions.pLedPosition.Min(p => p.top); + var width = positions.pLedPosition.Max(p => p.left + p.width) - minX; + var height = positions.pLedPosition.Max(p => p.top + p.height) - minY; + foreach (var led in positions.pLedPosition) { + var pos = ( + (int) ((led.left + led.width / 2 - minX) / width * IllumilibLighting.KeyboardWidth), + (int) ((led.top + led.height / 2 - minY) / height * IllumilibLighting.KeyboardHeight)); + if (!this.Positions.TryGetValue(pos, out var leds)) { + leds = new List(); + this.Positions.Add(pos, leds); + } + leds.Add(led.ledId); + } + } + + public void SetAllColors(float r, float g, float b) { + foreach (var color in this.colors) + SetColor(color, r, g, b); + } + + public bool SetColorForId(CorsairLedId id, float r, float g, float b) { + if (this.ledIdToColorIndex.TryGetValue(id, out var index)) { + SetColor(this.colors[index], r, g, b); + return true; + } + return false; + } + + public void UpdateColors() { + CUESDK.CorsairSetLedsColorsBufferByDeviceIndex(this.id, this.colors.Length, this.colors); + } + + public bool IsKeyboard() { + return this.info.logicalLayout != CorsairLogicalLayout.CLL_Invalid; + } + + public bool IsMouse() { + return this.info.physicalLayout != CorsairPhysicalLayout.CPL_Invalid && !this.IsKeyboard(); + } + + private static void SetColor(CorsairLedColor color, float r, float g, float b) { + color.r = (int) (r * 255); + color.g = (int) (g * 255); + color.b = (int) (b * 255); + } + + } + + } +} \ No newline at end of file diff --git a/Illumilib/System/LightingSystem.cs b/Illumilib/System/LightingSystem.cs index 4ef2bb4..d4e7fcc 100644 --- a/Illumilib/System/LightingSystem.cs +++ b/Illumilib/System/LightingSystem.cs @@ -1,5 +1,4 @@ using System; -using System.Threading.Tasks; namespace Illumilib.System { internal abstract class LightingSystem : IDisposable { diff --git a/Illumilib/System/LogitechLighting.cs b/Illumilib/System/LogitechLighting.cs index 437b20c..50f3751 100644 --- a/Illumilib/System/LogitechLighting.cs +++ b/Illumilib/System/LogitechLighting.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using Illumilib.Lib; +using Illumilib.Lib; namespace Illumilib.System { internal class LogitechLighting : LightingSystem { diff --git a/Illumilib/System/RazerLighting.cs b/Illumilib/System/RazerLighting.cs index 3a3f425..1dfb97f 100644 --- a/Illumilib/System/RazerLighting.cs +++ b/Illumilib/System/RazerLighting.cs @@ -1,5 +1,4 @@ -using System.Threading.Tasks; -using Colore; +using Colore; using Colore.Data; using Colore.Effects.Keyboard; diff --git a/README.md b/README.md index 640bfa5..f50ab84 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ # Illumilib -A simple keyboard and mouse lighting library with support for Razer and Logitech devices. +A simple keyboard and mouse lighting library with support for Razer, Logitech and Corsair devices. See the [Demo](https://github.com/Ellpeck/Illumilib/blob/main/Demo/Program.cs) to check out the features, or the [IllumilibLighting](https://github.com/Ellpeck/Illumilib/blob/main/Illumilib/IllumilibLighting.cs) class for API documentation. \ No newline at end of file