1
0
mirror of https://github.com/DarthAffe/CUE.NET.git synced 2025-12-12 16:58:29 +00:00

Compare commits

...

85 Commits

Author SHA1 Message Date
589bd12441
Update README.md 2021-08-05 23:27:28 +02:00
850eb66b3b
Merge pull request #70 from hmmwhatsthisdo/enablekeypresscallback_issue69
Add sanity-check to CueSDK.EnableKeypressHandler()
2018-04-22 16:45:09 +02:00
hmmwhatsthisdo
f3f7f498af Add sanity-check to CueSDK.EnableKeypressHandler() to ensure handlers are only enabled once. Resolves #69. 2018-04-22 06:27:10 -07:00
3b4649604f
Updated readme 2018-01-01 20:02:50 +01:00
83c67195fd Updated version number 2017-11-25 09:14:37 +01:00
811a296867 Added method to opt in to the keypress-callback since this prevents reinitializing 2017-11-25 09:12:57 +01:00
897162926a Updated changenotes and version number 2017-11-18 19:42:55 +01:00
8bcf64a9f9
Merge pull request #65 from DarthAffe/SdkUpdate
Sdk update
2017-11-18 18:27:27 +01:00
5091b33864 Added an event to get the key-change of special keys (G and M) 2017-11-18 12:29:03 +01:00
c4ac6f0e40 Added methods to use the new GetColor method 2017-11-18 11:17:25 +01:00
SpoinkyNL
6840813529 Updated SDK to 2.18.127
Added headset stand support
Added Glaive support
2017-11-13 21:59:33 +01:00
220953bfe7 Fixed an issue that prevents further reinitializing if an exception was thrown earlier 2017-08-13 08:22:18 +02:00
c786710b65 Correctly persisted update-rate in the ambilight example 2017-08-03 18:57:10 +02:00
63ef78f8fc Fixed missing LoadedArchitecture assignment 2017-07-16 12:11:57 +02:00
565e5ca1b2 Updated version number 2017-04-27 20:52:53 +02:00
86c9fb3860 Added an effect-list to the effect-target 2017-04-27 20:50:19 +02:00
33bd76ef0a Added two lists to modify the dative-dll-paths (#58) 2017-04-27 20:43:38 +02:00
5cc1748461 Fixed a bug in the SimpleDevTest and made it a bit more fancy 2017-04-27 20:42:38 +02:00
d17be4a976 Updated Ambilight-example version 2017-04-08 15:19:25 +02:00
0b92068fe6 Fixed DPI-scaling problem in the Ambilight-Example 2017-04-08 15:17:36 +02:00
295a56ca00 Updated CUE.NET package in ambilight example 2017-04-03 17:40:31 +02:00
34394caceb Updated version number 2017-03-18 09:50:51 +01:00
e6719c06a8 Updated SDK to 2.10.91 (this adds lightbar support) 2017-03-17 23:32:30 +01:00
7249da461f Updated version number 2017-02-01 19:47:26 +01:00
8781ce126e Added missing native-reload when calling IsSDKAvailable without initializing 2017-02-01 19:46:54 +01:00
0d5123aca1 Updated changenotes and version number 2017-01-28 14:19:05 +01:00
27562a4787 Added missing null-check while rendering groups 2017-01-28 12:16:46 +01:00
e0790cbc2a Added check for SDK-dll existance 2017-01-15 21:35:47 +01:00
28232a768b Improved performance of the LinearGradient 2017-01-15 14:30:41 +01:00
5e90779398 Fixed wrong region in RainbowGradient 2017-01-15 13:58:02 +01:00
7ef07ed99d Added ConicalGradientBrush 2017-01-15 13:57:44 +01:00
92fcbcff2a Fixed possible cache-issue in the RectangleKeyGroup 2017-01-08 10:51:10 +01:00
8a5581c660 Typo 2017-01-08 10:50:14 +01:00
8404985a55 Adjusted ambilight-example to take profit from the latest version 2017-01-05 20:21:02 +01:00
46c6fc62e3 Updated changenotes and version number 2017-01-05 17:23:33 +01:00
af754af27a Removed pdb from nuget.
Documentation states that this is bad practice.
2017-01-05 17:00:52 +01:00
619b389f7d Fixed some more code issues 2017-01-05 16:50:57 +01:00
d741318462 Added the associated device to CorsairLeds 2017-01-05 16:50:34 +01:00
925e02f146 Fixed some code-issues 2017-01-05 16:37:00 +01:00
8523a4ddb3 Cloned colors assigned to render-targets in the AbstractBrush to prevent reference-issues 2017-01-05 15:08:41 +01:00
1298f59d5a Fixed references in the ambilighte xample to prevent build-errors on the build-server 2017-01-05 15:00:39 +01:00
78dccd2603 Updated some comments and stuff 2017-01-03 22:43:10 +01:00
7fe3ece615 Marked profile-api as obsolete. Wontfix that to work with CUE 2. This closes #54. 2017-01-02 16:28:39 +01:00
74973df040 Updated test-project 2016-12-22 12:28:07 +01:00
9a9bf52fe9 Added new brush-effect to move gradients 2016-12-22 12:27:53 +01:00
55dff06380 Implemented Gradient-Wrapping 2016-12-22 12:03:38 +01:00
da15638817 Added color-corrections for brushes 2016-12-17 14:16:57 +01:00
c13d103566 Updated Ambilight Example to 1.0.1.1 2016-12-11 16:34:00 +01:00
947963a81c Updated Ambilight-Example to use the new gamma-correction 2016-12-11 16:28:28 +01:00
eb3f92d7b0 Fixed stupid bug in the order of applying gamma-correction and brightness/alpha-values 2016-12-11 16:27:54 +01:00
1b4af74b14 Added gamma-value to brushes to allow a simple color correction 2016-12-11 15:41:22 +01:00
17d05d9527 Updated ambilight-example version to 1.0.1 2016-11-12 13:46:53 +01:00
8373863f8c Added MinLightness-Setting to the Ambilight-example 2016-11-12 13:46:22 +01:00
633636efda Fixed wrong offset validation in the Ambilight-example 2016-11-12 13:46:02 +01:00
deb043b6b2 Added key-rectangle to BrushRenderTarget 2016-11-06 17:38:01 +01:00
74824e3363 Added Ambilight-Example-Project 2016-11-06 00:32:40 +01:00
662085a346 Enabled XML-Documentation for help-generation using sandcastle 2016-10-08 20:01:33 +02:00
288a5cf985 Updated version to 1.1.0.2 2016-10-06 20:13:39 +02:00
4a8f6c5928 Correctly implemented equality operators for CorsairColors
This fixes #52
2016-10-06 20:07:02 +02:00
77e4e86777 Updated version to 1.1.0.1 2016-09-11 19:42:48 +02:00
c611675355 Fixed wrong device-rectangle initialize 2016-09-11 19:39:15 +02:00
69a9a122d0 Added missing 'char' indexer for keyboards 2016-09-11 19:36:57 +02:00
102d8656bc Updated version to 1.1.0 2016-09-11 17:21:02 +02:00
072f0c24ed Fixed use before initialize 2016-09-11 12:47:47 +02:00
1eba5c66be Code cleanup 2016-09-11 10:55:14 +02:00
381ec55349 Added own color-type to have more control over and easier manipulation of collors 2016-09-11 10:40:01 +02:00
5c6dba769b Added method to check if an effect can be applied to a specific target 2016-09-11 09:44:05 +02:00
8b87270b69 Refactored auto-update to be SDK-wide 2016-09-11 08:39:18 +02:00
16c297611e Added small test 2016-09-10 18:51:09 +02:00
b392ceb6e4 Added operators for lazy guyz 2016-09-10 18:50:56 +02:00
aeca5aa060 Fixed naming 2016-09-10 18:50:37 +02:00
2b314091eb Code cleanup 2016-09-10 18:30:22 +02:00
8390c7da68 Code cleanup 2016-09-10 18:06:07 +02:00
f8c537aaff Improved LedId enums (now constants) 2016-09-10 17:44:35 +02:00
223c0e8886 Removed CorsairKey since it wasn't of any use anyway 2016-09-10 17:34:32 +02:00
5a018d0743 Refactored to do everything based on LEDs.
This will adapt the devices and reduces the importance of the "special case keyboard"
2016-09-10 14:59:25 +02:00
bfe51add66 Refactored the positionen to be stored in the LED 2016-09-10 10:40:44 +02:00
4b5263221a Removed accidentally added PositionedLed, added full list of LedIds 2016-09-10 10:23:30 +02:00
8ab40180b3 Merged PR #49 2016-09-10 10:14:43 +02:00
d9a3678b81 Fixed a few typos 2016-09-10 10:11:14 +02:00
SpoinkyNL
6c1a3d6744 Updated CUE SDK to 2.4.67
Implemented SDK change: ledsCount added to DeviceInfo
Implemented SDK change: CorsairGetLedPositionsByDeviceIndex method added
Added mousemat support
2016-09-09 10:25:32 +02:00
4e47275c7e Removed todos 2016-08-21 20:14:28 +02:00
0fc32243c8 Added missing comments 2016-08-21 20:06:02 +02:00
8d32c73b6d Refactored brushes to perform a multi-pass rendering.
This allows effects to change the calculated values.
2016-08-21 18:14:31 +02:00
ba80ef9848 First attempt to rewrite Effects 2016-08-21 13:11:07 +02:00
134 changed files with 5565 additions and 1703 deletions

View File

@ -1,7 +1,14 @@
// ReSharper disable VirtualMemberNeverOverriden.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable VirtualMemberNeverOverridden.Global
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using CUE.NET.ColorCorrection;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Keyboard.Enums;
using CUE.NET.Effects;
using CUE.NET.Helper;
namespace CUE.NET.Brushes
@ -9,7 +16,7 @@ namespace CUE.NET.Brushes
/// <summary>
/// Represents a basic brush.
/// </summary>
public abstract class AbstractBrush : IBrush
public abstract class AbstractBrush : AbstractEffectTarget<IBrush>, IBrush
{
#region Properties & Fields
@ -28,6 +35,26 @@ namespace CUE.NET.Brushes
/// </summary>
public float Opacity { get; set; }
/// <summary>
/// Gets a list of <see cref="IColorCorrection"/> used to correct the colors of the brush.
/// </summary>
public IList<IColorCorrection> ColorCorrections { get; } = new List<IColorCorrection>();
/// <summary>
/// Gets the Rectangle used in the last render pass.
/// </summary>
public RectangleF RenderedRectangle { get; protected set; }
/// <summary>
/// Gets a dictionary containing all colors for points calculated in the last render pass.
/// </summary>
public Dictionary<BrushRenderTarget, CorsairColor> RenderedTargets { get; } = new Dictionary<BrushRenderTarget, CorsairColor>();
/// <summary>
/// Gets the strongly-typed target used for the effect.
/// </summary>
protected override IBrush EffectTarget => this;
#endregion
#region Constructors
@ -47,28 +74,57 @@ namespace CUE.NET.Brushes
#region Methods
/// <summary>
/// Performas the render pass of the brush and calculates the raw colors for all requested points.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="renderTargets">The targets (keys/points) of which the color should be calculated.</param>
public virtual void PerformRender(RectangleF rectangle, IEnumerable<BrushRenderTarget> renderTargets)
{
RenderedRectangle = rectangle;
RenderedTargets.Clear();
foreach (BrushRenderTarget point in renderTargets)
RenderedTargets[point] = new CorsairColor(GetColorAtPoint(rectangle, point)); // Clone the color, we don't want to have reference issues here and brushes might return the same color multiple times!
}
/// <summary>
/// Performs the finalize pass of the brush and calculates the final colors for all previously calculated points.
/// </summary>
public virtual void PerformFinalize()
{
List<BrushRenderTarget> renderTargets = RenderedTargets.Keys.ToList();
foreach (BrushRenderTarget renderTarget in renderTargets)
RenderedTargets[renderTarget] = FinalizeColor(RenderedTargets[renderTarget]); // Cloning here again shouldn't be needed since we did this above.
}
/// <summary>
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
public abstract Color GetColorAtPoint(RectangleF rectangle, PointF point);
protected abstract CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget);
/// <summary>
/// Finalizes the color by appliing the overall brightness and opacity.<br/>
/// This method should always be the last call of a <see cref="GetColorAtPoint" /> implementation.
/// If you overwrite this method please make sure that you never return the same color-object twice to prevent reference-issues!
/// </summary>
/// <param name="color">The color to finalize.</param>
/// <returns>The finalized color.</returns>
protected virtual Color FinalizeColor(Color color)
protected virtual CorsairColor FinalizeColor(CorsairColor color)
{
foreach (IColorCorrection colorCorrection in ColorCorrections)
colorCorrection.ApplyTo(color);
// Since we use HSV to calculate there is no way to make a color 'brighter' than 100%
// Be carefull with the naming: Since we use HSV the correct term is 'value' but outside we call it 'brightness'
// THIS IS NOT A HSB CALCULATION!!!
float finalBrightness = color.GetHSVValue() * (Brightness < 0 ? 0 : (Brightness > 1f ? 1f : Brightness));
byte finalAlpha = (byte)(color.A * (Opacity < 0 ? 0 : (Opacity > 1f ? 1f : Opacity)));
return ColorHelper.ColorFromHSV(color.GetHue(), color.GetHSVSaturation(), finalBrightness, finalAlpha);
return ColorHelper.ColorFromHSV(color.GetHSVHue(), color.GetHSVSaturation(), finalBrightness, finalAlpha);
}
#endregion

View File

@ -0,0 +1,51 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
using System.Drawing;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Helper;
namespace CUE.NET.Brushes
{
/// <summary>
/// Represents a single target of a brush render.
/// </summary>
public class BrushRenderTarget
{
#region Properties & Fields
/// <summary>
/// Gets the ID of the target-LED.
/// </summary>
public CorsairLedId LedId { get; }
/// <summary>
/// Gets the rectangle representing the area to render the target-LED.
/// </summary>
public RectangleF Rectangle { get; }
/// <summary>
/// Gets the point representing the position to render the target-LED.
/// </summary>
public PointF Point { get; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="BrushRenderTarget"/> class.
/// </summary>
/// <param name="ledId">The ID of the target-LED.</param>
/// <param name="rectangle">The rectangle representing the area to render the target-LED.</param>
public BrushRenderTarget(CorsairLedId ledId, RectangleF rectangle)
{
this.Rectangle = rectangle;
this.LedId = ledId;
Point = rectangle.GetCenter();
}
#endregion
}
}

View File

@ -0,0 +1,103 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable MemberCanBeProtected.Global
// ReSharper disable ReturnTypeCanBeEnumerable.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
// ReSharper disable UnusedMember.Global
using System;
using System.Drawing;
using CUE.NET.Devices.Generic;
using CUE.NET.Gradients;
namespace CUE.NET.Brushes
{
/// <summary>
/// Represents a brush drawing a conical gradient.
/// </summary>
public class ConicalGradientBrush : AbstractBrush, IGradientBrush
{
#region Properties & Fields
/// <summary>
/// Gets or sets the origin (radian-angle) the brush is drawn to. (default: -π/2)
/// </summary>
public float Origin { get; set; } = (float)Math.Atan2(-1, 0);
/// <summary>
/// Gets or sets the center point (as percentage in the range [0..1]) of the gradient drawn by the brush. (default: 0.5f, 0.5f)
/// </summary>
public PointF Center { get; set; } = new PointF(0.5f, 0.5f);
/// <summary>
/// Gets or sets the gradient drawn by the brush. If null it will default to full transparent.
/// </summary>
public IGradient Gradient { get; set; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ConicalGradientBrush"/> class.
/// </summary>
public ConicalGradientBrush()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="ConicalGradientBrush"/> class.
/// </summary>
/// <param name="gradient">The gradient drawn by the brush.</param>
public ConicalGradientBrush(IGradient gradient)
{
this.Gradient = gradient;
}
/// <summary>
/// Initializes a new instance of the <see cref="ConicalGradientBrush"/> class.
/// </summary>
/// <param name="center">The center point (as percentage in the range [0..1]).</param>
/// <param name="gradient">The gradient drawn by the brush.</param>
public ConicalGradientBrush(PointF center, IGradient gradient)
{
this.Center = center;
this.Gradient = gradient;
}
/// <summary>
/// Initializes a new instance of the <see cref="ConicalGradientBrush"/> class.
/// </summary>
/// <param name="center">The center point (as percentage in the range [0..1]).</param>
/// <param name="origin">The origin (radian-angle) the brush is drawn to.</param>
/// <param name="gradient">The gradient drawn by the brush.</param>
public ConicalGradientBrush(PointF center, float origin, IGradient gradient)
{
this.Center = center;
this.Origin = origin;
this.Gradient = gradient;
}
#endregion
#region Methods
/// <summary>
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
float centerX = rectangle.Width * Center.X;
float centerY = rectangle.Height * Center.Y;
double angle = Math.Atan2(renderTarget.Point.Y - centerY, renderTarget.Point.X - centerX) - Origin;
if (angle < 0) angle += Math.PI * 2;
float offset = (float)(angle / (Math.PI * 2));
return Gradient.GetColor(offset);
}
#endregion
}
}

View File

@ -1,14 +1,20 @@
// ReSharper disable UnusedMemberInSuper.Global
// ReSharper disable UnusedMember.Global
// ReSharper disable ReturnTypeCanBeEnumerable.Global
using System.Collections.Generic;
using System.Drawing;
using CUE.NET.ColorCorrection;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Keyboard.Enums;
using CUE.NET.Effects;
namespace CUE.NET.Brushes
{
/// <summary>
/// Represents a basic brush.
/// </summary>
public interface IBrush
public interface IBrush : IEffectTarget<IBrush>
{
/// <summary>
/// Gets or sets the calculation mode used for the rectangle/points used for color-selection in brushes.
@ -26,11 +32,30 @@ namespace CUE.NET.Brushes
float Opacity { get; set; }
/// <summary>
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// Gets a list of color-corrections used to correct the colors of the brush.
/// </summary>
IList<IColorCorrection> ColorCorrections { get; }
/// <summary>
/// Gets the Rectangle used in the last render pass.
/// </summary>
RectangleF RenderedRectangle { get; }
/// <summary>
/// Gets a dictionary containing all colors for points calculated in the last render pass.
/// </summary>
Dictionary<BrushRenderTarget, CorsairColor> RenderedTargets { get; }
/// <summary>
/// Performas the render pass of the brush and calculates the raw colors for all requested points.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
Color GetColorAtPoint(RectangleF rectangle, PointF point);
/// <param name="renderTargets">The targets (keys/points) of which the color should be calculated.</param>
void PerformRender(RectangleF rectangle, IEnumerable<BrushRenderTarget> renderTargets);
/// <summary>
/// Performs the finalize pass of the brush and calculates the final colors for all previously calculated points.
/// </summary>
void PerformFinalize();
}
}

15
Brushes/IGradientBRush.cs Normal file
View File

@ -0,0 +1,15 @@
using CUE.NET.Gradients;
namespace CUE.NET.Brushes
{
/// <summary>
/// Represents a basic gradient-brush.
/// </summary>
public interface IGradientBrush : IBrush
{
/// <summary>
/// Gets the gradient used by this <see cref="IGradientBrush"/>.
/// </summary>
IGradient Gradient { get; }
}
}

View File

@ -1,8 +1,10 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable UnusedMember.Global
using System;
using System.Drawing;
using CUE.NET.Devices.Generic;
namespace CUE.NET.Brushes
{
@ -57,29 +59,29 @@ namespace CUE.NET.Brushes
#endregion
#region Methods
/// <summary>
/// Gets the color at an specific point getting the color of the key at the given point.
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <returns>The color of the key at the specified point.</returns>
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
if (Image == null || Image.Width == 0 || Image.Height == 0)
return Color.Transparent;
return CorsairColor.Transparent;
//TODO DarthAffe 16.03.2016: Refactor to allow more scale-/interpolation-modes
float scaleX = Image.Width / rectangle.Width;
float scaleY = Image.Height / rectangle.Height;
int x = (int)(point.X * scaleX);
int y = (int)(point.Y * scaleY);
int x = (int)(renderTarget.Point.X * scaleX);
int y = (int)(renderTarget.Point.Y * scaleY);
x = Math.Max(0, Math.Min(x, Image.Width - 1));
y = Math.Max(0, Math.Min(y, Image.Height - 1));
return FinalizeColor(Image.GetPixel(x, y));
return Image.GetPixel(x, y);
}
#endregion

View File

@ -6,6 +6,7 @@
// ReSharper disable UnusedMember.Global
using System.Drawing;
using CUE.NET.Devices.Generic;
using CUE.NET.Gradients;
using CUE.NET.Helper;
@ -14,7 +15,7 @@ namespace CUE.NET.Brushes
/// <summary>
/// Represents a brush drawing a linear gradient.
/// </summary>
public class LinearGradientBrush : AbstractBrush
public class LinearGradientBrush : AbstractBrush, IGradientBrush
{
#region Properties & Fields
@ -72,17 +73,17 @@ namespace CUE.NET.Brushes
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
if (Gradient == null) return Color.Transparent;
if (Gradient == null) return CorsairColor.Transparent;
PointF startPoint = new PointF(StartPoint.X * rectangle.Width, StartPoint.Y * rectangle.Height);
PointF endPoint = new PointF(EndPoint.X * rectangle.Width, EndPoint.Y * rectangle.Height);
float offset = GradientHelper.CalculateLinearGradientOffset(startPoint, endPoint, point);
return FinalizeColor(Gradient.GetColor(offset));
float offset = GradientHelper.CalculateLinearGradientOffset(startPoint, endPoint, renderTarget.Point);
return Gradient.GetColor(offset);
}
#endregion

View File

@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Drawing;
using CUE.NET.Devices.Keyboard.Enums;
using CUE.NET.Devices.Keyboard.Keys;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.Brushes
{
@ -12,7 +12,7 @@ namespace CUE.NET.Brushes
{
#region Properties & Fields
private Dictionary<CorsairKeyboardKeyId, Color> _keyLights;
private Dictionary<CorsairLedId, CorsairColor> _colors;
#endregion
@ -22,9 +22,9 @@ namespace CUE.NET.Brushes
/// Initializes a new instance of the <see cref="ProfileBrush"/> class.
/// </summary>
/// <param name="keyLights">The light settings of the CUE profile.</param>
internal ProfileBrush(Dictionary<CorsairKeyboardKeyId, Color> keyLights)
internal ProfileBrush(Dictionary<CorsairLedId, CorsairColor> keyLights)
{
this._keyLights = keyLights;
this._colors = keyLights;
}
#endregion
@ -32,21 +32,18 @@ namespace CUE.NET.Brushes
#region Methods
/// <summary>
/// Gets the color at an specific point getting the color of the key at the given point.
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <returns>The color of the key at the specified point.</returns>
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
CorsairKey key = CueSDK.KeyboardSDK[point];
if (key == null) return Color.Transparent;
CorsairLed led = CueSDK.KeyboardSDK[renderTarget.LedId];
if (led == null) return CorsairColor.Transparent;
Color color;
if (!_keyLights.TryGetValue(key.KeyId, out color))
return Color.Transparent;
return FinalizeColor(color);
CorsairColor color;
return !_colors.TryGetValue(led.Id, out color) ? CorsairColor.Transparent : color;
}
#endregion

View File

@ -4,6 +4,7 @@
using System;
using System.Drawing;
using CUE.NET.Devices.Generic;
using CUE.NET.Gradients;
using CUE.NET.Helper;
@ -12,7 +13,7 @@ namespace CUE.NET.Brushes
/// <summary>
/// Represents a brush drawing a radial gradient around a center point.
/// </summary>
public class RadialGradientBrush : AbstractBrush
public class RadialGradientBrush : AbstractBrush, IGradientBrush
{
#region Properties & Fields
@ -64,11 +65,11 @@ namespace CUE.NET.Brushes
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="point">The point from which the color should be taken.</param>
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
if(Gradient == null) return Color.Transparent;
if(Gradient == null) return CorsairColor.Transparent;
PointF centerPoint = new PointF(rectangle.X + rectangle.Width * Center.X, rectangle.Y + rectangle.Height * Center.Y);
@ -79,9 +80,9 @@ namespace CUE.NET.Brushes
GradientHelper.CalculateDistance(new PointF(rectangle.X, rectangle.Y + rectangle.Height), centerPoint)),
GradientHelper.CalculateDistance(new PointF(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height), centerPoint));
float distance = GradientHelper.CalculateDistance(point, centerPoint);
float distance = GradientHelper.CalculateDistance(renderTarget.Point, centerPoint);
float offset = distance / refDistance;
return FinalizeColor(Gradient.GetColor(offset));
return Gradient.GetColor(offset);
}
#endregion

View File

@ -2,6 +2,7 @@
using System;
using System.Drawing;
using CUE.NET.Devices.Generic;
using CUE.NET.Helper;
namespace CUE.NET.Brushes
@ -14,7 +15,7 @@ namespace CUE.NET.Brushes
public class RandomColorBrush : AbstractBrush
{
#region Properties & Fields
private Random _random = new Random();
#endregion
@ -22,14 +23,14 @@ namespace CUE.NET.Brushes
#region Methods
/// <summary>
/// Gets a random color.
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">This value isn't used.</param>
/// <param name="point">This value isn't used.</param>
/// <returns>A random color.</returns>
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
return FinalizeColor(ColorHelper.ColorFromHSV((float)_random.NextDouble() * 360f, 1, 1));
return ColorHelper.ColorFromHSV((float)_random.NextDouble() * 360f, 1, 1);
}
#endregion

View File

@ -2,6 +2,7 @@
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
using System.Drawing;
using CUE.NET.Devices.Generic;
namespace CUE.NET.Brushes
{
@ -15,7 +16,7 @@ namespace CUE.NET.Brushes
/// <summary>
/// Gets or sets the color drawn by the brush.
/// </summary>
public Color Color { get; set; }
public CorsairColor Color { get; set; }
#endregion
@ -25,7 +26,7 @@ namespace CUE.NET.Brushes
/// Initializes a new instance of the <see cref="SolidColorBrush"/> class.
/// </summary>
/// <param name="color">The color drawn by the brush.</param>
public SolidColorBrush(Color color)
public SolidColorBrush(CorsairColor color)
{
this.Color = color;
}
@ -35,14 +36,54 @@ namespace CUE.NET.Brushes
#region Methods
/// <summary>
/// Returns the <see cref="Color" /> of the brush.
/// Gets the color at an specific point assuming the brush is drawn into the given rectangle.
/// </summary>
/// <param name="rectangle">This value isn't used.</param>
/// <param name="point">This value isn't used.</param>
/// <returns>The <see cref="Color" /> of the brush.</returns>
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
/// <param name="rectangle">The rectangle in which the brush should be drawn.</param>
/// <param name="renderTarget">The target (key/point) from which the color should be taken.</param>
/// <returns>The color at the specified point.</returns>
protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
return FinalizeColor(Color);
return Color;
}
#endregion
#region Operators
/// <summary>
/// Converts a <see cref="Color" /> to a <see cref="SolidColorBrush" />.
/// </summary>
/// <param name="color">The <see cref="Color"/> to convert.</param>
public static explicit operator SolidColorBrush(Color color)
{
return new SolidColorBrush(color);
}
/// <summary>
/// Converts a <see cref="SolidColorBrush" /> to a <see cref="Color" />.
/// </summary>
/// <param name="brush">The <see cref="Color"/> to convert.</param>
public static implicit operator Color(SolidColorBrush brush)
{
return brush.Color;
}
/// <summary>
/// Converts a <see cref="CorsairColor" /> to a <see cref="SolidColorBrush" />.
/// </summary>
/// <param name="color">The <see cref="Color"/> to convert.</param>
public static explicit operator SolidColorBrush(CorsairColor color)
{
return new SolidColorBrush(color);
}
/// <summary>
/// Converts a <see cref="SolidColorBrush" /> to a <see cref="CorsairColor" />.
/// </summary>
/// <param name="brush">The <see cref="Color"/> to convert.</param>
public static implicit operator CorsairColor(SolidColorBrush brush)
{
return brush.Color;
}
#endregion

View File

@ -22,6 +22,7 @@
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
<DocumentationFile>bin\CUE.NET.XML</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
<OutputPath>bin\</OutputPath>
@ -32,6 +33,7 @@
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
<DocumentationFile>bin\CUE.NET.XML</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
@ -45,11 +47,20 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Brushes\ConicalGradientBrush.cs" />
<Compile Include="Brushes\IGradientBrush.cs" />
<Compile Include="Brushes\ImageBrush.cs" />
<Compile Include="Brushes\ProfileBrush.cs" />
<Compile Include="Brushes\BrushRenderTarget.cs" />
<Compile Include="ColorCorrection\GammaCorrection.cs" />
<Compile Include="ColorCorrection\IColorCorrection.cs" />
<Compile Include="CueSDKAutoUpdate.cs" />
<Compile Include="Devices\Generic\CorsairColor.cs" />
<Compile Include="Devices\Generic\Enums\CorsairAccessMode.cs" />
<Compile Include="Devices\Generic\Enums\CorsairDeviceCaps.cs" />
<Compile Include="Devices\Generic\Enums\CorsairDeviceType.cs" />
<Compile Include="Devices\Generic\Enums\CorsairKeyId.cs" />
<Compile Include="Devices\Generic\Enums\CorsairLedId.cs" />
<Compile Include="Devices\Generic\EventArgs\ExceptionEventArgs.cs" />
<Compile Include="Brushes\AbstractBrush.cs" />
<Compile Include="Devices\Generic\EventArgs\LedsUpdatedEventArgs.cs" />
@ -57,7 +68,21 @@
<Compile Include="Devices\Generic\EventArgs\UpdatedEventArgs.cs" />
<Compile Include="Devices\Generic\EventArgs\UpdatingEventArgs.cs" />
<Compile Include="Devices\Generic\LedUpateRequest.cs" />
<Compile Include="Devices\HeadsetStand\CorsairHeadsetStand.cs" />
<Compile Include="Devices\HeadsetStand\CorsairHeadsetStandDeviceInfo.cs" />
<Compile Include="Devices\HeadsetStand\Enums\CorsairHeadsetStandLedId.cs" />
<Compile Include="Devices\Keyboard\Enums\BrushCalculationMode.cs" />
<Compile Include="Devices\Keyboard\Enums\CorsairKeyboardKeyId.cs" />
<Compile Include="Devices\Mouse\Enums\CorsairMouseKeyId.cs" />
<Compile Include="Effects\AbstractLedGroupEffect.cs" />
<Compile Include="Effects\AbstractBrushEffect.cs" />
<Compile Include="Effects\AbstractEffectTarget.cs" />
<Compile Include="Effects\IEffectTarget.cs" />
<Compile Include="Devices\Mousemat\CorsairMousemat.cs" />
<Compile Include="Devices\Mousemat\CorsairMousematDeviceInfo.cs" />
<Compile Include="Devices\Mousemat\Enums\CorsairMousematLedId.cs" />
<Compile Include="Effects\MoveGradientEffect.cs" />
<Compile Include="EventArgs\KeyPressedEventArgs.cs" />
<Compile Include="Gradients\AbstractGradient.cs" />
<Compile Include="Gradients\GradientStop.cs" />
<Compile Include="Gradients\IGradient.cs" />
@ -67,20 +92,19 @@
<Compile Include="Brushes\RadialGradientBrush.cs" />
<Compile Include="Brushes\RandomColorBrush.cs" />
<Compile Include="Brushes\SolidColorBrush.cs" />
<Compile Include="Effects\AbstractEffect.cs" />
<Compile Include="Effects\FlashEffect.cs" />
<Compile Include="Effects\IEffect.cs" />
<Compile Include="Effects\EffectTimeContainer.cs" />
<Compile Include="Devices\Keyboard\Enums\CorsairLogicalKeyboardLayout.cs" />
<Compile Include="Devices\Headset\Enums\CorsairHeadsetLedId.cs" />
<Compile Include="Devices\Keyboard\Enums\CorsairKeyboardKeyId.cs" />
<Compile Include="Devices\Keyboard\Enums\CorsairKeyboardLedId.cs" />
<Compile Include="Devices\Keyboard\Enums\CorsairPhysicalKeyboardLayout.cs" />
<Compile Include="Devices\Generic\Enums\UpdateMode.cs" />
<Compile Include="Devices\Keyboard\Keys\BaseKeyGroup.cs" />
<Compile Include="Devices\Keyboard\Keys\IKeyGroup.cs" />
<Compile Include="Devices\Keyboard\Keys\RectangleKeyGroup.cs" />
<Compile Include="Devices\Keyboard\Keys\ListKeyGroup.cs" />
<Compile Include="Devices\Mouse\Enums\CorsairMouseButtonId.cs" />
<Compile Include="Groups\AbstractLedGroup.cs" />
<Compile Include="Groups\ILedGroup.cs" />
<Compile Include="Groups\RectangleLedGroup.cs" />
<Compile Include="Groups\ListLedGroup.cs" />
<Compile Include="Devices\Mouse\Enums\CorsairMouseLedId.cs" />
<Compile Include="Devices\Mouse\Enums\CorsairPhysicalMouseLayout.cs" />
<Compile Include="Exceptions\CUEException.cs" />
<Compile Include="Exceptions\WrapperException.cs" />
@ -90,11 +114,10 @@
<Compile Include="Devices\Headset\CorsairHeadset.cs" />
<Compile Include="Devices\Headset\CorsairHeadsetDeviceInfo.cs" />
<Compile Include="Devices\IDeviceInfo.cs" />
<Compile Include="Devices\Keyboard\Keys\CorsairKey.cs" />
<Compile Include="Devices\Keyboard\CorsairKeyboard.cs" />
<Compile Include="Devices\Mouse\CorsairMouseDeviceInfo.cs" />
<Compile Include="Devices\Mouse\CorsairMouse.cs" />
<Compile Include="Devices\Keyboard\Extensions\KeyGroupExtension.cs" />
<Compile Include="Groups\Extensions\LedGroupExtension.cs" />
<Compile Include="Helper\ColorHelper.cs" />
<Compile Include="Gradients\LinearGradient.cs" />
<Compile Include="Helper\GradientHelper.cs" />

View File

@ -3,7 +3,7 @@
<metadata>
<id>CUE.NET</id>
<title>CUE.NET</title>
<version>1.0.3.0</version>
<version>1.2.0.1</version>
<authors>Darth Affe</authors>
<owners>Darth Affe</owners>
<projectUrl>https://github.com/DarthAffe/CUE.NET</projectUrl>
@ -11,13 +11,14 @@
<requireLicenseAcceptance>true</requireLicenseAcceptance>
<description>Corsair HID SDK Wrapper</description>
<releaseNotes>
Added IEnumerable-overloads to all param-methods,
Added events in the update-process,
Finished work on BrushCalculationModes,
Added a method to check for SDK availability
- Updated SDK to 2.18.127
- Added methods to use the new GetColor method
- Added an event to get the key-change of special keys (G and M)
- Fixed missing LoadedArchitecture assignment
- Fixed an issue that prevents further reinitializing if an exception was thrown earlier
</releaseNotes>
<summary>C# (.NET) Wrapper library around the Corsair CUE-SDK</summary>
<copyright>Copyright © Wyrez 2016</copyright>
<copyright>Copyright © Wyrez 2017</copyright>
<language>en-US</language>
</metadata>
<files>

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.23107.0
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CUE.NET", "CUE.NET.csproj", "{70A266B5-E9D4-4EAA-A91A-947C0039FFB6}"
EndProject
@ -20,18 +20,22 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libs", "libs", "{D69EF6D8-6
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "x86", "x86", "{0525D895-E706-4920-8733-DABD9194BFB1}"
ProjectSection(SolutionItems) = preProject
libs\x86\CUESDK_2013.dll = libs\x86\CUESDK_2013.dll
bin\x86\CUESDK_2015.dll = bin\x86\CUESDK_2015.dll
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "x64", "x64", "{2F99124B-FAED-432D-B797-45566D373411}"
ProjectSection(SolutionItems) = preProject
libs\x64\CUESDK_2013.dll = libs\x64\CUESDK_2013.dll
bin\x64\CUESDK_2015.dll = bin\x64\CUESDK_2015.dll
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AudioAnalyzer", "AudioAnalyzer", "{BE16A0BF-6794-4718-AF27-F2A50078D880}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example_AudioAnalyzer_full", "Examples\AudioAnalyzer\Example_AudioAnalyzer_full\Example_AudioAnalyzer_full.csproj", "{E06B4E1D-9735-4CB4-BC11-9ECDF27A0972}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Ambilight", "Ambilight", "{1ABADCA4-AC96-4E9F-91C5-232EB824D6DE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Example_Ambilight_full", "Examples\Ambilight\Example_Ambilight_full\Example_Ambilight_full.csproj", "{6D7BAF89-A705-4FFA-A3A2-AF93EC3A909C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -50,6 +54,10 @@ Global
{E06B4E1D-9735-4CB4-BC11-9ECDF27A0972}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E06B4E1D-9735-4CB4-BC11-9ECDF27A0972}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E06B4E1D-9735-4CB4-BC11-9ECDF27A0972}.Release|Any CPU.Build.0 = Release|Any CPU
{6D7BAF89-A705-4FFA-A3A2-AF93EC3A909C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D7BAF89-A705-4FFA-A3A2-AF93EC3A909C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D7BAF89-A705-4FFA-A3A2-AF93EC3A909C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D7BAF89-A705-4FFA-A3A2-AF93EC3A909C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -61,5 +69,7 @@ Global
{2F99124B-FAED-432D-B797-45566D373411} = {D69EF6D8-68FF-4C56-B5CB-253971B1DF91}
{BE16A0BF-6794-4718-AF27-F2A50078D880} = {1F52DDC9-E9D0-4A7B-8E78-930528203EE6}
{E06B4E1D-9735-4CB4-BC11-9ECDF27A0972} = {BE16A0BF-6794-4718-AF27-F2A50078D880}
{1ABADCA4-AC96-4E9F-91C5-232EB824D6DE} = {1F52DDC9-E9D0-4A7B-8E78-930528203EE6}
{6D7BAF89-A705-4FFA-A3A2-AF93EC3A909C} = {1ABADCA4-AC96-4E9F-91C5-232EB824D6DE}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,108 @@
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System;
using CUE.NET.Devices.Generic;
using CUE.NET.Helper;
namespace CUE.NET.ColorCorrection
{
/// <summary>
/// Represents a gamma-color-correction.
/// </summary>
public class GammaCorrection : IColorCorrection
{
#region Properties & Fields
/// <summary>
/// Gets or sets the gamma-value of the color 'red' used for color-correction.
/// Values greater than one will make colors brighter, values less than one will make colors darker.
/// </summary>
public float R { get; set; }
/// <summary>
/// Gets or sets the gamma-value of the color 'green' used for color-correction.
/// Values greater than one will make colors brighter, values less than one will make colors darker.
/// </summary>
public float G { get; set; }
/// <summary>
/// Gets or sets the gamma-value of the color 'blue' used for color-correction.
/// Values greater than one will make colors brighter, values less than one will make colors darker.
/// </summary>
public float B { get; set; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="GammaCorrection"/> class using the default-value 1f (no correction) for all colors.
/// </summary>
public GammaCorrection() : this(1f) { }
/// <summary>
/// Initializes a new instance of the <see cref="GammaCorrection"/> class.
/// </summary>
/// <param name="gamma">The gamma-value for all colors used for color-correction.
/// Values greater than one will make colors brighter, values less than one will make colors darker.</param>
public GammaCorrection(float gamma)
{
this.R = gamma;
this.G = gamma;
this.B = gamma;
}
/// <summary>
/// Initializes a new instance of the <see cref="GammaCorrection"/> class.
/// </summary>
/// <param name="r">The gamma-value for the color 'red' used for color-correction.
/// Values greater than one will make colors brighter, values less than one will make colors darker.</param>
/// <param name="g">The gamma-value for the color 'green' used for color-correction. Values
/// greater than one will make colors brighter, values less than one will make colors darker.</param>
/// <param name="b">The gamma-value for the color 'blue' used for color-correction. Values
/// greater than one will make colors brighter, values less than one will make colors darker.</param>
public GammaCorrection(float r, float g, float b)
{
this.R = r;
this.G = g;
this.B = b;
}
#endregion
#region Methods
/// <summary>
/// Applies the gamma-correction to the given color.
/// </summary>
/// <param name="color">The color to correct.</param>
public void ApplyTo(CorsairColor color)
{
if (Math.Abs(R - 1f) > float.Epsilon)
color.R = ColorHelper.GetIntColorFromFloat((float)Math.Pow(color.GetFloatR(), 1.0 / R));
if (Math.Abs(G - 1f) > float.Epsilon)
color.G = ColorHelper.GetIntColorFromFloat((float)Math.Pow(color.GetFloatG(), 1.0 / G));
if (Math.Abs(B - 1f) > float.Epsilon)
color.B = ColorHelper.GetIntColorFromFloat((float)Math.Pow(color.GetFloatB(), 1.0 / B));
}
#endregion
#region Operators
/// <summary>
/// Converts a <see cref="float" /> to a <see cref="GammaCorrection" /> using the same value for all colors.
/// </summary>
/// <param name="gamma">The float-value to convert.</param>
public static implicit operator GammaCorrection(float gamma)
{
return new GammaCorrection(gamma);
}
#endregion
}
}

View File

@ -0,0 +1,16 @@
using CUE.NET.Devices.Generic;
namespace CUE.NET.ColorCorrection
{
/// <summary>
/// Represents generic color-correction.
/// </summary>
public interface IColorCorrection
{
/// <summary>
/// Applies the color-correction to the given color.
/// </summary>
/// <param name="color">The color to correct.</param>
void ApplyTo(CorsairColor color);
}
}

170
CueSDK.cs
View File

@ -1,23 +1,45 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using CUE.NET.Devices;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Devices.Headset;
using CUE.NET.Devices.HeadsetStand;
using CUE.NET.Devices.Keyboard;
using CUE.NET.Devices.Mouse;
using CUE.NET.Devices.Mousemat;
using CUE.NET.EventArgs;
using CUE.NET.Exceptions;
using CUE.NET.Native;
namespace CUE.NET
{
public static class CueSDK
/// <summary>
/// Static entry point to work with the Corsair-SDK.
/// </summary>
public static partial class CueSDK
{
#region Properties & Fields
// ReSharper disable UnusedAutoPropertyAccessor.Global
/// <summary>
/// Gets a modifiable list of paths used to find the native SDK-dlls for x86 applications.
/// The first match will be used.
/// </summary>
public static List<string> PossibleX86NativePaths { get; } = new List<string> { "x86/CUESDK_2015.dll", "x86/CUESDK.dll" };
/// <summary>
/// Gets a modifiable list of paths used to find the native SDK-dlls for x64 applications.
/// The first match will be used.
/// </summary>
public static List<string> PossibleX64NativePaths { get; } = new List<string> { "x64/CUESDK_2015.dll", "x64/CUESDK.dll" };
/// <summary>
/// Indicates if the SDK is initialized and ready to use.
/// </summary>
@ -43,6 +65,11 @@ namespace CUE.NET
/// </summary>
public static CorsairError LastError => _CUESDK.CorsairGetLastError();
/// <summary>
/// Gets all initialized devices managed by the CUE-SDK.
/// </summary>
public static IEnumerable<ICueDevice> InitializedDevices { get; private set; }
/// <summary>
/// Gets the managed representation of a keyboard managed by the CUE-SDK.
/// Note that currently only one connected keyboard is supported.
@ -61,8 +88,36 @@ namespace CUE.NET
/// </summary>
public static CorsairHeadset HeadsetSDK { get; private set; }
/// <summary>
/// Gets the managed representation of a mousemat managed by the CUE-SDK.
/// Note that currently only one connected mousemat is supported.
/// </summary>
public static CorsairMousemat MousematSDK { get; private set; }
/// <summary>
/// Gets the managed representation of a headset stand managed by the CUE-SDK.
/// Note that currently only one connected headset stand is supported.
/// </summary>
public static CorsairHeadsetStand HeadsetStandSDK { get; private set; }
// ReSharper restore UnusedAutoPropertyAccessor.Global
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void OnKeyPressedDelegate(IntPtr context, CorsairKeyId keyId, [MarshalAs(UnmanagedType.I1)] bool pressed);
private static OnKeyPressedDelegate _onKeyPressedDelegate;
#endregion
#region Events
/// <summary>
/// Occurs when the SDK reports that a key is pressed.
/// Notice that right now only G- (keyboard) and M- (mouse) keys are supported.
///
/// To enable this event <see cref="EnableKeypressCallback"/> needs to be called.
/// </summary>
public static event EventHandler<KeyPressedEventArgs> KeyPressed;
#endregion
#region Methods
@ -70,14 +125,16 @@ namespace CUE.NET
/// <summary>
/// Checks if the SDK for the provided <see cref="CorsairDeviceType"/> is available or checks if CUE is installed and SDK supported enabled if null is provided.
/// </summary>
/// <param name="sdkType">The <see cref="CorsairDeviceType"/> to check or null to check for generall SDK availability.</param>
/// <param name="sdkType">The <see cref="CorsairDeviceType"/> to check or null to check for general SDK availability.</param>
/// <returns>The availability of the provided <see cref="CorsairDeviceType"/>.</returns>
public static bool IsSDKAvailable(CorsairDeviceType? sdkType = null)
{
try
{
// ReSharper disable once RedundantIfElseBlock
if (IsInitialized)
{
// ReSharper disable once SwitchStatementMissingSomeCases - everything else is true
switch (sdkType)
{
case CorsairDeviceType.Keyboard:
@ -86,12 +143,17 @@ namespace CUE.NET
return MouseSDK != null;
case CorsairDeviceType.Headset:
return HeadsetSDK != null;
case CorsairDeviceType.Mousemat:
return MousematSDK != null;
case CorsairDeviceType.HeadsetStand:
return HeadsetStandSDK != null;
default:
return true;
}
}
else
{
_CUESDK.Reload();
_CUESDK.CorsairPerformProtocolHandshake();
if (sdkType == null || sdkType == CorsairDeviceType.Unknown)
@ -125,11 +187,13 @@ namespace CUE.NET
if (IsInitialized)
throw new WrapperException("CueSDK is already initialized.");
_CUESDK.Reload();
ProtocolDetails = new CorsairProtocolDetails(_CUESDK.CorsairPerformProtocolHandshake());
CorsairError error = LastError;
if (error != CorsairError.Success)
Throw(error);
Throw(error, true);
if (ProtocolDetails.BreakingChanges)
throw new WrapperException("The SDK currently used isn't compatible with the installed version of CUE.\r\n"
@ -139,11 +203,12 @@ namespace CUE.NET
if (exclusiveAccess)
{
if (!_CUESDK.CorsairRequestControl(CorsairAccessMode.ExclusiveLightingControl))
Throw(LastError);
Throw(LastError, true);
HasExclusiveAccess = true;
}
IList<ICueDevice> devices = new List<ICueDevice>();
int deviceCount = _CUESDK.CorsairGetDeviceCount();
for (int i = 0; i < deviceCount; i++)
{
@ -152,32 +217,74 @@ namespace CUE.NET
if (!info.CapsMask.HasFlag(CorsairDeviceCaps.Lighting))
continue; // Everything that doesn't support lighting control is useless
ICueDevice device;
switch (info.Type)
{
case CorsairDeviceType.Keyboard:
KeyboardSDK = new CorsairKeyboard(new CorsairKeyboardDeviceInfo(nativeDeviceInfo));
device = KeyboardSDK = new CorsairKeyboard(new CorsairKeyboardDeviceInfo(nativeDeviceInfo));
break;
case CorsairDeviceType.Mouse:
MouseSDK = new CorsairMouse(new CorsairMouseDeviceInfo(nativeDeviceInfo));
device = MouseSDK = new CorsairMouse(new CorsairMouseDeviceInfo(nativeDeviceInfo));
break;
case CorsairDeviceType.Headset:
HeadsetSDK = new CorsairHeadset(new CorsairHeadsetDeviceInfo(nativeDeviceInfo));
device = HeadsetSDK = new CorsairHeadset(new CorsairHeadsetDeviceInfo(nativeDeviceInfo));
break;
case CorsairDeviceType.Mousemat:
device = MousematSDK = new CorsairMousemat(new CorsairMousematDeviceInfo(nativeDeviceInfo));
break;
case CorsairDeviceType.HeadsetStand:
device = HeadsetStandSDK = new CorsairHeadsetStand(new CorsairHeadsetStandDeviceInfo(nativeDeviceInfo));
break;
// ReSharper disable once RedundantCaseLabel
case CorsairDeviceType.Unknown:
default:
throw new WrapperException("Unknown Device-Type");
}
device.Initialize();
devices.Add(device);
error = LastError;
if (error != CorsairError.Success)
Throw(error);
Throw(error, true);
}
error = LastError;
if (error != CorsairError.Success)
Throw(error, false);
InitializedDevices = new ReadOnlyCollection<ICueDevice>(devices);
IsInitialized = true;
}
/// <summary>
/// Enables the keypress-callback.
/// This method needs to be called to enable the <see cref="KeyPressed"/>-event.
///
/// WARNING: AFTER THIS METHOD IS CALLED IT'S NO LONGER POSSIBLE TO REINITIALIZE THE SDK!
/// </summary>
public static void EnableKeypressCallback()
{
if (!IsInitialized)
throw new WrapperException("CueSDK isn't initialized.");
if (_onKeyPressedDelegate != null)
return;
_onKeyPressedDelegate = OnKeyPressed;
_CUESDK.CorsairRegisterKeypressCallback(Marshal.GetFunctionPointerForDelegate(_onKeyPressedDelegate), IntPtr.Zero);
}
/// <summary>
/// Resets the colors of all devices back to the last saved color-data. (If there wasn't a manual save, that's the data from the time the SDK was initialized.)
/// </summary>
public static void Reset()
{
foreach (ICueDevice device in InitializedDevices)
device.RestoreColors();
}
/// <summary>
/// Reinitialize the CUE-SDK and temporarily hand back full control to CUE.
/// </summary>
@ -195,9 +302,14 @@ namespace CUE.NET
if (!IsInitialized)
throw new WrapperException("CueSDK isn't initialized.");
if (_onKeyPressedDelegate != null)
throw new WrapperException("Keypress-Callback is enabled.");
KeyboardSDK?.ResetLeds();
MouseSDK?.ResetLeds();
HeadsetSDK?.ResetLeds();
MousematSDK?.ResetLeds();
HeadsetStandSDK?.ResetLeds();
_CUESDK.Reload();
@ -205,7 +317,7 @@ namespace CUE.NET
CorsairError error = LastError;
if (error != CorsairError.Success)
Throw(error);
Throw(error, false);
if (ProtocolDetails.BreakingChanges)
throw new WrapperException("The SDK currently used isn't compatible with the installed version of CUE.\r\n"
@ -214,7 +326,7 @@ namespace CUE.NET
if (exclusiveAccess)
if (!_CUESDK.CorsairRequestControl(CorsairAccessMode.ExclusiveLightingControl))
Throw(LastError);
Throw(LastError, false);
HasExclusiveAccess = exclusiveAccess;
int deviceCount = _CUESDK.CorsairGetDeviceCount();
@ -229,7 +341,7 @@ namespace CUE.NET
error = LastError;
if (error != CorsairError.Success)
Throw(error);
Throw(error, false);
}
if (KeyboardSDK != null)
@ -244,22 +356,42 @@ namespace CUE.NET
if (!reloadedDevices.ContainsKey(CorsairDeviceType.Headset)
|| HeadsetSDK.HeadsetDeviceInfo.Model != reloadedDevices[CorsairDeviceType.Headset].Model)
throw new WrapperException("The previously loaded Headset got disconnected.");
if (MousematSDK != null)
if (!reloadedDevices.ContainsKey(CorsairDeviceType.Mousemat)
|| MousematSDK.MousematDeviceInfo.Model != reloadedDevices[CorsairDeviceType.Mousemat].Model)
throw new WrapperException("The previously loaded Mousemat got disconnected.");
if (HeadsetStandSDK != null)
if (!reloadedDevices.ContainsKey(CorsairDeviceType.HeadsetStand)
|| HeadsetStandSDK.HeadsetStandDeviceInfo.Model != reloadedDevices[CorsairDeviceType.HeadsetStand].Model)
throw new WrapperException("The previously loaded Headset Stand got disconnected.");
error = LastError;
if (error != CorsairError.Success)
Throw(error, false);
IsInitialized = true;
}
private static void Throw(CorsairError error)
private static void Throw(CorsairError error, bool reset)
{
ProtocolDetails = null;
HasExclusiveAccess = false;
KeyboardSDK = null;
MouseSDK = null;
HeadsetSDK = null;
IsInitialized = false;
if (reset)
{
ProtocolDetails = null;
HasExclusiveAccess = false;
KeyboardSDK = null;
MouseSDK = null;
HeadsetSDK = null;
MousematSDK = null;
HeadsetStandSDK = null;
IsInitialized = false;
}
throw new CUEException(error);
}
private static void OnKeyPressed(IntPtr context, CorsairKeyId keyId, bool pressed)
=> KeyPressed?.Invoke(null, new KeyPressedEventArgs(keyId, pressed));
#endregion
}
}

97
CueSDKAutoUpdate.cs Normal file
View File

@ -0,0 +1,97 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
using System;
using System.Threading;
using System.Threading.Tasks;
using CUE.NET.Devices;
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET
{
/// <summary>
/// Static entry point to work with the Corsair-SDK.
/// </summary>
public static partial class CueSDK
{
#region Properties & Fields
private static CancellationTokenSource _updateTokenSource;
private static CancellationToken _updateToken;
private static Task _updateTask;
/// <summary>
/// Gets or sets the update-frequency in seconds. (Calculate by using '1f / updates per second')
/// </summary>
public static float UpdateFrequency { get; set; } = 1f / 30f;
private static UpdateMode _updateMode = UpdateMode.Manual;
/// <summary>
/// Gets or sets the update-mode for the device.
/// </summary>
public static UpdateMode UpdateMode
{
get { return _updateMode; }
set
{
_updateMode = value;
CheckUpdateLoop();
}
}
#endregion
#region Methods
/// <summary>
/// Checks if automatic updates should occur and starts/stops the update-loop if needed.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">Thrown if the requested update-mode is not available.</exception>
private static async void CheckUpdateLoop()
{
bool shouldRun;
switch (UpdateMode)
{
case UpdateMode.Manual:
shouldRun = false;
break;
case UpdateMode.Continuous:
shouldRun = true;
break;
default:
throw new ArgumentOutOfRangeException();
}
if (shouldRun && _updateTask == null) // Start task
{
_updateTokenSource?.Dispose();
_updateTokenSource = new CancellationTokenSource();
_updateTask = Task.Factory.StartNew(UpdateLoop, (_updateToken = _updateTokenSource.Token));
}
else if (!shouldRun && _updateTask != null) // Stop task
{
_updateTokenSource.Cancel();
await _updateTask;
_updateTask.Dispose();
_updateTask = null;
}
}
private static void UpdateLoop()
{
while (!_updateToken.IsCancellationRequested)
{
long preUpdateTicks = DateTime.Now.Ticks;
foreach (ICueDevice device in InitializedDevices)
device.Update();
int sleep = (int)((UpdateFrequency * 1000f) - ((DateTime.Now.Ticks - preUpdateTicks) / 10000f));
if (sleep > 0)
Thread.Sleep(sleep);
}
}
#endregion
}
}

View File

@ -1,16 +1,21 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMethodReturnValue.Global
// ReSharper disable VirtualMemberNeverOverridden.Global
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Devices.Generic.EventArgs;
using CUE.NET.Devices.Keyboard.Enums;
using CUE.NET.Effects;
using CUE.NET.Groups;
using CUE.NET.Helper;
using CUE.NET.Native;
namespace CUE.NET.Devices.Generic
@ -22,49 +27,80 @@ namespace CUE.NET.Devices.Generic
{
#region Properties & Fields
private static DateTime _lastUpdate = DateTime.Now;
private Dictionary<CorsairLedId, CorsairColor> _colorDataSave;
/// <summary>
/// Gets generic information provided by CUE for the device.
/// </summary>
public IDeviceInfo DeviceInfo { get; }
private UpdateMode _updateMode = UpdateMode.AutoOnEffect;
/// <summary>
/// Gets or sets the update-mode for the device.
/// Gets the rectangle containing all LEDs of the device.
/// </summary>
public UpdateMode UpdateMode
{
get { return _updateMode; }
set
{
_updateMode = value;
CheckUpdateLoop();
}
}
/// <summary>
/// Gets or sets the update-frequency in seconds. (Calculate by using '1f / updates per second')
/// </summary>
public float UpdateFrequency { get; set; } = 1f / 30f;
public RectangleF DeviceRectangle { get; protected set; }
/// <summary>
/// Gets a dictionary containing all LEDs of the device.
/// </summary>
protected Dictionary<int, CorsairLed> Leds { get; } = new Dictionary<int, CorsairLed>();
protected Dictionary<CorsairLedId, CorsairLed> LedMapping { get; } = new Dictionary<CorsairLedId, CorsairLed>();
/// <summary>
/// Indicates if the device has an active effect to deal with.
/// Gets a read-only collection containing the LEDs of the device.
/// </summary>
protected abstract bool HasEffect { get; }
public IEnumerable<CorsairLed> Leds => new ReadOnlyCollection<CorsairLed>(LedMapping.Values.ToList());
/// <summary>
///
/// Gets a list of attached ledgroups.
/// </summary>
protected LinkedList<EffectTimeContainer> Effects { get; } = new LinkedList<EffectTimeContainer>();
protected LinkedList<ILedGroup> LedGroups { get; } = new LinkedList<ILedGroup>();
private CancellationTokenSource _updateTokenSource;
private CancellationToken _updateToken;
private Task _updateTask;
private DateTime _lastUpdate = DateTime.Now;
/// <summary>
/// Gets or sets the background brush of the keyboard.
/// If this is null the last saved color-data is used as background.
/// </summary>
public IBrush Brush { get; set; }
/// <summary>
/// Gets or sets the z-index of the background brush of the keyboard.<br />
/// This value has absolutely no effect.
/// </summary>
public int ZIndex { get; set; } = 0;
#region Indexers
/// <summary>
/// Gets the <see cref="CorsairLed" /> with the specified ID.
/// </summary>
/// <param name="ledId">The ID of the LED to get.</param>
/// <returns>The LED with the specified ID or null if no LED is found.</returns>
public CorsairLed this[CorsairLedId ledId]
{
get
{
CorsairLed key;
return LedMapping.TryGetValue(ledId, out key) ? key : null;
}
}
/// <summary>
/// Gets the <see cref="CorsairLed" /> at the given physical location.
/// </summary>
/// <param name="location">The point to get the location from.</param>
/// <returns>The LED at the given point or null if no location is found.</returns>
public CorsairLed this[PointF location] => LedMapping.Values.FirstOrDefault(x => x.LedRectangle.Contains(location));
/// <summary>
/// Gets a list of <see cref="CorsairLed" /> inside the given rectangle.
/// </summary>
/// <param name="referenceRect">The rectangle to check.</param>
/// <param name="minOverlayPercentage">The minimal percentage overlay a location must have with the <see cref="Rectangle" /> to be taken into the list.</param>
/// <returns></returns>
public IEnumerable<CorsairLed> this[RectangleF referenceRect, float minOverlayPercentage = 0.5f] => LedMapping.Values
.Where(x => RectangleHelper.CalculateIntersectPercentage(x.LedRectangle, referenceRect) >= minOverlayPercentage);
#endregion
#endregion
@ -106,91 +142,82 @@ namespace CUE.NET.Devices.Generic
protected AbstractCueDevice(IDeviceInfo info)
{
this.DeviceInfo = info;
CheckUpdateLoop();
}
#endregion
#region Methods
#region Initialize
/// <summary>
/// Gets the LED-Object with the specified id.
/// Initializes the device.
/// </summary>
/// <param name="ledId">The LED-Id to look for.</param>
public virtual void Initialize()
{
DeviceRectangle = RectangleHelper.CreateRectangleFromRectangles((this).Select(x => x.LedRectangle));
SaveColors();
}
/// <summary>
/// Initializes the LED-Object with the specified id.
/// </summary>
/// <param name="ledId">The LED-Id to initialize.</param>
/// <param name="ledRectangle">The rectangle representing the position of the LED to initialize.</param>
/// <returns></returns>
protected CorsairLed GetLed(int ledId)
protected CorsairLed InitializeLed(CorsairLedId ledId, RectangleF ledRectangle)
{
if (!Leds.ContainsKey(ledId))
Leds.Add(ledId, new CorsairLed());
if (LedMapping.ContainsKey(ledId)) return null;
return Leds[ledId];
CorsairLed led = new CorsairLed(this, ledId, ledRectangle);
LedMapping.Add(ledId, led);
return led;
}
/// <summary>
/// Checks if automatic updates should occur and starts/stops the update-loop if needed.
/// Resets all loaded LEDs back to default.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">Thrown if the requested update-mode is not available.</exception>
protected async void CheckUpdateLoop()
internal void ResetLeds()
{
bool shouldRun;
switch (UpdateMode)
{
case UpdateMode.Manual:
shouldRun = false;
break;
case UpdateMode.AutoOnEffect:
shouldRun = HasEffect;
break;
case UpdateMode.Continuous:
shouldRun = true;
break;
default:
throw new ArgumentOutOfRangeException();
}
if (shouldRun && _updateTask == null) // Start task
{
_updateTokenSource?.Dispose();
_updateTokenSource = new CancellationTokenSource();
_updateTask = Task.Factory.StartNew(UpdateLoop, (_updateToken = _updateTokenSource.Token));
}
else if (!shouldRun && _updateTask != null) // Stop task
{
_updateTokenSource.Cancel();
await _updateTask;
_updateTask.Dispose();
_updateTask = null;
}
foreach (CorsairLed led in LedMapping.Values)
led.Reset();
}
private void UpdateLoop()
{
while (!_updateToken.IsCancellationRequested)
{
long preUpdateTicks = DateTime.Now.Ticks;
Update();
int sleep = (int)((UpdateFrequency * 1000f) - ((DateTime.Now.Ticks - preUpdateTicks) / 10000f));
if (sleep > 0)
Thread.Sleep(sleep);
}
}
#endregion
#region Update
/// <summary>
/// Performs an update for all dirty keys, or all keys if flushLeds is set to true.
/// </summary>
/// <param name="flushLeds">Specifies whether all keys (including clean ones) should be updated.</param>
public void Update(bool flushLeds = false)
/// <param name="noRender">Only updates the hardware-leds skippin effects and the render-pass. Only use this if you know what that means!</param>
public void Update(bool flushLeds = false, bool noRender = false)
{
OnUpdating();
if (!noRender)
{
// Update effects
foreach (ILedGroup ledGroup in LedGroups)
ledGroup.UpdateEffects();
// Render brushes
if (Brush != null)
Render(this);
else
ApplyColorData(_colorDataSave);
foreach (ILedGroup ledGroup in LedGroups.OrderBy(x => x.ZIndex))
Render(ledGroup);
}
// Device-specific updates
DeviceUpdate();
UpdateEffects();
ICollection<LedUpateRequest> ledsToUpdate = (flushLeds ? Leds : Leds.Where(x => x.Value.IsDirty)).Select(x => new LedUpateRequest(x.Key, x.Value.RequestedColor)).ToList();
foreach (CorsairLed led in Leds.Values)
led.Update();
// Send LEDs to SDK
ICollection<LedUpateRequest> ledsToUpdate = (flushLeds ? LedMapping : LedMapping.Where(x => x.Value.IsDirty)).Select(x => new LedUpateRequest(x.Key, x.Value.RequestedColor)).ToList();
foreach (LedUpateRequest updateRequest in ledsToUpdate)
LedMapping[updateRequest.LedId].Update();
UpdateLeds(ledsToUpdate);
@ -198,56 +225,57 @@ namespace CUE.NET.Devices.Generic
}
/// <summary>
/// Empty method which can be overwritten to perform device specific updates.
/// Performs device specific updates.
/// </summary>
protected virtual void DeviceUpdate()
{ }
private void UpdateEffects()
{
List<IEffect> effectsToRemove = new List<IEffect>();
lock (Effects)
{
long currentTicks = DateTime.Now.Ticks;
foreach (EffectTimeContainer effect in Effects.OrderBy(x => x.ZIndex))
{
try
{
float deltaTime;
if (effect.TicksAtLastUpdate < 0)
{
effect.TicksAtLastUpdate = currentTicks;
deltaTime = 0f;
}
else
deltaTime = (currentTicks - effect.TicksAtLastUpdate) / 10000000f;
effect.TicksAtLastUpdate = currentTicks;
effect.Effect.Update(deltaTime);
ApplyEffect(effect.Effect);
if (effect.Effect.IsDone)
effectsToRemove.Add(effect.Effect);
}
// ReSharper disable once CatchAllClause
catch (Exception ex) { OnException(ex); }
}
}
foreach (IEffect effect in effectsToRemove)
DetachEffect(effect);
}
/// <summary>
/// Applies the given effect to the device LEDs.
/// Renders a ledgroup.
/// </summary>
/// <param name="effect">The effect to apply.</param>
protected abstract void ApplyEffect(IEffect effect);
/// <param name="ledGroup">The led group to render.</param>
// ReSharper disable once MemberCanBeMadeStatic.Local - idc
protected virtual void Render(ILedGroup ledGroup)
{
if (ledGroup == null) return;
IList<CorsairLed> leds = ledGroup.GetLeds().ToList();
IBrush brush = ledGroup.Brush;
if (brush == null) return;
try
{
switch (brush.BrushCalculationMode)
{
case BrushCalculationMode.Relative:
RectangleF brushRectangle = RectangleHelper.CreateRectangleFromRectangles(leds.Select(x => x.LedRectangle));
float offsetX = -brushRectangle.X;
float offsetY = -brushRectangle.Y;
brushRectangle.X = 0;
brushRectangle.Y = 0;
brush.PerformRender(brushRectangle, leds.Select(x => new BrushRenderTarget(x.Id, x.LedRectangle.Move(offsetX, offsetY))));
break;
case BrushCalculationMode.Absolute:
brush.PerformRender(DeviceRectangle, leds.Select(x => new BrushRenderTarget(x.Id, x.LedRectangle)));
break;
default:
throw new ArgumentException();
}
brush.UpdateEffects();
brush.PerformFinalize();
foreach (KeyValuePair<BrushRenderTarget, CorsairColor> renders in brush.RenderedTargets)
this[renders.Key.LedId].Color = renders.Value;
}
// ReSharper disable once CatchAllClause
catch (Exception ex) { OnException(ex); }
}
private void UpdateLeds(ICollection<LedUpateRequest> updateRequests)
{
updateRequests = updateRequests.Where(x => x.Color != Color.Transparent).ToList();
updateRequests = updateRequests.Where(x => x.Color != CorsairColor.Transparent).ToList();
OnLedsUpdating(updateRequests);
@ -260,7 +288,7 @@ namespace CUE.NET.Devices.Generic
{
_CorsairLedColor color = new _CorsairLedColor
{
ledId = ledUpdateRequest.LedId,
ledId = (int)ledUpdateRequest.LedId,
r = ledUpdateRequest.Color.R,
g = ledUpdateRequest.Color.G,
b = ledUpdateRequest.Color.B
@ -276,62 +304,149 @@ namespace CUE.NET.Devices.Generic
OnLedsUpdated(updateRequests);
}
/// <summary>
/// Attaches the given effect.
/// </summary>
/// <param name="effect">The effect to attach.</param>
/// <returns><c>true</c> if the effect could be attached; otherwise, <c>false</c>.</returns>
public bool AttachEffect(IEffect effect)
/// <inheritdoc />
public void SyncColors()
{
bool retVal = false;
lock (Effects)
Dictionary<CorsairLedId, CorsairColor> colorData = GetColors();
ApplyColorData(colorData);
Update(true, true);
}
/// <inheritdoc />
public void SaveColors()
{
_colorDataSave = GetColors();
}
/// <inheritdoc />
public void RestoreColors()
{
ApplyColorData(_colorDataSave);
Update(true, true);
}
private void ApplyColorData(Dictionary<CorsairLedId, CorsairColor> colorData)
{
if (colorData == null) return;
foreach (KeyValuePair<CorsairLedId, CorsairColor> corsairColor in _colorDataSave)
LedMapping[corsairColor.Key].Color = corsairColor.Value;
}
private Dictionary<CorsairLedId, CorsairColor> GetColors()
{
int structSize = Marshal.SizeOf(typeof(_CorsairLedColor));
IntPtr ptr = Marshal.AllocHGlobal(structSize * LedMapping.Count);
IntPtr addPtr = new IntPtr(ptr.ToInt64());
foreach (KeyValuePair<CorsairLedId, CorsairLed> led in LedMapping)
{
if (effect != null && Effects.All(x => x.Effect != effect))
{
effect.OnAttach();
Effects.AddLast(new EffectTimeContainer(effect, -1));
retVal = true;
}
_CorsairLedColor color = new _CorsairLedColor { ledId = (int)led.Value.Id };
Marshal.StructureToPtr(color, addPtr, false);
addPtr = new IntPtr(addPtr.ToInt64() + structSize);
}
_CUESDK.CorsairGetLedsColors(LedMapping.Count, ptr);
IntPtr readPtr = ptr;
Dictionary<CorsairLedId, CorsairColor> colorData = new Dictionary<CorsairLedId, CorsairColor>();
for (int i = 0; i < LedMapping.Count; i++)
{
_CorsairLedColor ledColor = (_CorsairLedColor)Marshal.PtrToStructure(readPtr, typeof(_CorsairLedColor));
colorData.Add((CorsairLedId)ledColor.ledId, new CorsairColor((byte)ledColor.r, (byte)ledColor.g, (byte)ledColor.b));
readPtr = new IntPtr(readPtr.ToInt64() + structSize);
}
CheckUpdateLoop();
return retVal;
Marshal.FreeHGlobal(ptr);
return colorData;
}
#endregion
#region LedGroup
/// <summary>
/// Detaches the given effect.
/// Attaches the given ledgroup.
/// </summary>
/// <param name="effect">The effect to detached.</param>
/// <returns><c>true</c> if the effect could be detached; otherwise, <c>false</c>.</returns>
public bool DetachEffect(IEffect effect)
/// <param name="ledGroup">The ledgroup to attach.</param>
/// <returns><c>true</c> if the ledgroup could be attached; otherwise, <c>false</c>.</returns>
public bool AttachLedGroup(ILedGroup ledGroup)
{
bool retVal = false;
lock (Effects)
lock (LedGroups)
{
if (effect != null)
{
EffectTimeContainer val = Effects.FirstOrDefault(x => x.Effect == effect);
if (val != null)
{
effect.OnDetach();
Effects.Remove(val);
retVal = true;
}
}
if (ledGroup == null || LedGroups.Contains(ledGroup)) return false;
LedGroups.AddLast(ledGroup);
return true;
}
CheckUpdateLoop();
return retVal;
}
/// <summary>
/// Resets all loaded LEDs back to default.
/// Detaches the given ledgroup.
/// </summary>
internal void ResetLeds()
/// <param name="ledGroup">The ledgroup to detached.</param>
/// <returns><c>true</c> if the ledgroup could be detached; otherwise, <c>false</c>.</returns>
public bool DetachLedGroup(ILedGroup ledGroup)
{
foreach (CorsairLed led in Leds.Values)
led.Reset();
lock (LedGroups)
{
if (ledGroup == null) return false;
LinkedListNode<ILedGroup> node = LedGroups.Find(ledGroup);
if (node == null) return false;
LedGroups.Remove(node);
return true;
}
}
/// <summary>
/// Gets a list containing all LEDs of this group.
/// </summary>
/// <returns>The list containing all LEDs of this group.</returns>
public IEnumerable<CorsairLed> GetLeds()
{
return Leds;
}
#endregion
#region Effects
/// <summary>
/// Gets a list of all active effects of this target.
/// For this device this is always null.
/// </summary>
public IList<IEffect<ILedGroup>> Effects => null;
/// <summary>
/// NOT IMPLEMENTED: Effects can't be applied directly to the device. Add it to the Brush or create a ledgroup instead.
/// </summary>
public void UpdateEffects()
{
throw new NotSupportedException("Effects can't be applied directly to the device. Add it to the Brush or create a ledgroup instead.");
}
/// <summary>
/// NOT IMPLEMENTED: Effects can't be applied directly to the device. Add it to the Brush or create a ledgroup instead.
/// </summary>
/// <param name="effect">The effect to add.</param>
public void AddEffect(IEffect<ILedGroup> effect)
{
throw new NotSupportedException("Effects can't be applied directly to the device. Add it to the Brush or create a ledgroup instead.");
}
/// <summary>
/// NOT IMPLEMENTED: Effects can't be applied directly to the device. Add it to the Brush or create a ledgroup instead.
/// </summary>
/// <param name="effect">The effect to remove.</param>
public void RemoveEffect(IEffect<ILedGroup> effect)
{
throw new NotSupportedException("Effects can't be applied directly to the device. Add it to the Brush or create a ledgroup instead.");
}
#endregion
#region EventCaller
/// <summary>
@ -359,7 +474,7 @@ namespace CUE.NET.Devices.Generic
{
long lastUpdateTicks = _lastUpdate.Ticks;
_lastUpdate = DateTime.Now;
Updating?.Invoke(this, new UpdatingEventArgs((float)((DateTime.Now.Ticks - lastUpdateTicks) / 10000000f)));
Updating?.Invoke(this, new UpdatingEventArgs((DateTime.Now.Ticks - lastUpdateTicks) / 10000000f));
}
catch
{
@ -413,6 +528,28 @@ namespace CUE.NET.Devices.Generic
}
#endregion
#region IEnumerable
/// <summary>
/// Returns an enumerator that iterates over all LEDs of the device.
/// </summary>
/// <returns>An enumerator for all LEDs of the device.</returns>
public IEnumerator<CorsairLed> GetEnumerator()
{
return LedMapping.Values.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates over all LEDs of the device.
/// </summary>
/// <returns>An enumerator for all LEDs of the device.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#endregion
}
}

View File

@ -0,0 +1,182 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
// ReSharper disable UnusedMember.Global
using System.Diagnostics;
using System.Drawing;
namespace CUE.NET.Devices.Generic
{
/// <summary>
/// Represents an ARGB (alpha, red, green, blue) color used by CUE.NET.
/// </summary>
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
public class CorsairColor
{
#region Constants
/// <summary>
/// Gets an transparent color [A: 0, R: 0, G: 0, B: 0]
/// </summary>
public static CorsairColor Transparent => Color.Transparent;
#endregion
#region Properties & Fields
/// <summary>
/// Gets or sets the alpha component value of this <see cref="CorsairColor"/>.
/// </summary>
public byte A { get; set; }
/// <summary>
/// Gets or sets the red component value of this <see cref="CorsairColor"/>.
/// </summary>
public byte R { get; set; }
/// <summary>
/// Gets or sets the green component value of this <see cref="CorsairColor"/>.
/// </summary>
public byte G { get; set; }
/// <summary>
/// Gets or sets the blue component value of this <see cref="CorsairColor"/>.
/// </summary>
public byte B { get; set; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="CorsairColor"/> class.
/// The class created by this constructor equals <see cref="Transparent"/>.
/// </summary>
public CorsairColor()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="CorsairColor"/> class using only RGB-Values.
/// Alpha defaults to 255.
/// </summary>
/// <param name="r">The red component value of this <see cref="CorsairColor"/>.</param>
/// <param name="g">The green component value of this <see cref="CorsairColor"/>.</param>
/// <param name="b">The blue component value of this <see cref="CorsairColor"/>.</param>
public CorsairColor(byte r, byte g, byte b)
: this(255, r, g, b)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="CorsairColor"/> class using ARGB-values.
/// </summary>
/// <param name="a">The alpha component value of this <see cref="CorsairColor"/>.</param>
/// <param name="r">The red component value of this <see cref="CorsairColor"/>.</param>
/// <param name="g">The green component value of this <see cref="CorsairColor"/>.</param>
/// <param name="b">The blue component value of this <see cref="CorsairColor"/>.</param>
public CorsairColor(byte a, byte r, byte g, byte b)
{
this.A = a;
this.R = r;
this.G = g;
this.B = b;
}
/// <summary>
/// Initializes a new instance of the <see cref="CorsairColor"/> class by cloning a existing <see cref="CorsairColor"/>.
/// </summary>
/// <param name="color">The <see cref="CorsairColor"/> the values are copied from.</param>
public CorsairColor(CorsairColor color)
: this(color.A, color.R, color.G, color.B)
{ }
#endregion
#region Operators
/// <summary>
/// Converts the individual byte-values of this <see cref="CorsairColor"/> to a human-readable string.
/// </summary>
/// <returns>A string that contains the individual byte-values of this <see cref="CorsairColor"/>. For example "[A: 255, R: 255, G: 0, B: 0]".</returns>
public override string ToString()
{
return $"[A: {A}, R: {R}, G: {G}, B: {B}]";
}
/// <summary>
/// Tests whether the specified object is a <see cref="CorsairColor" /> and is equivalent to this <see cref="CorsairColor" />.
/// </summary>
/// <param name="obj">The object to test.</param>
/// <returns>true if <paramref name="obj" /> is a <see cref="CorsairColor" /> equivalent to this <see cref="CorsairColor" /> ; otherwise, false.</returns>
public override bool Equals(object obj)
{
CorsairColor compareColor = obj as CorsairColor;
if (ReferenceEquals(compareColor, null))
return false;
if (ReferenceEquals(this, compareColor))
return true;
if (GetType() != compareColor.GetType())
return false;
return (compareColor.A == A) && (compareColor.R == R) && (compareColor.G == G) && (compareColor.B == B);
}
/// <summary>
/// Returns a hash code for this <see cref="CorsairColor" />.
/// </summary>
/// <returns>An integer value that specifies the hash code for this <see cref="CorsairColor" />.</returns>
public override int GetHashCode()
{
unchecked
{
int hashCode = A.GetHashCode();
hashCode = (hashCode * 397) ^ R.GetHashCode();
hashCode = (hashCode * 397) ^ G.GetHashCode();
hashCode = (hashCode * 397) ^ B.GetHashCode();
return hashCode;
}
}
/// <summary>
/// Returns a value that indicates whether two specified <see cref="CorsairColor" /> are equal.
/// </summary>
/// <param name="color1">The first <see cref="CorsairColor" /> color to compare.</param>
/// <param name="color2">The second <see cref="CorsairColor" /> color to compare.</param>
/// <returns>true if <paramref name="color1" /> and <paramref name="color2" /> are equal; otherwise, false.</returns>
public static bool operator ==(CorsairColor color1, CorsairColor color2)
{
return ReferenceEquals(color1, null) ? ReferenceEquals(color2, null) : color1.Equals(color2);
}
/// <summary>
/// Returns a value that indicates whether two specified <see cref="CorsairColor" /> are equal.
/// </summary>
/// <param name="color1">The first <see cref="CorsairColor" /> color to compare.</param>
/// <param name="color2">The second <see cref="CorsairColor" /> color to compare.</param>
/// <returns>true if <paramref name="color1" /> and <paramref name="color2" /> are not equal; otherwise, false.</returns>
public static bool operator !=(CorsairColor color1, CorsairColor color2)
{
return !(color1 == color2);
}
/// <summary>
/// Converts a <see cref="Color" /> to a <see cref="CorsairColor" />.
/// </summary>
/// <param name="color">The <see cref="Color"/> to convert.</param>
public static implicit operator CorsairColor(Color color)
{
return new CorsairColor(color.A, color.R, color.G, color.B);
}
/// <summary>
/// Converts a <see cref="CorsairColor" /> to a <see cref="Color" />.
/// </summary>
/// <param name="color">The <see cref="CorsairColor"/> to convert.</param>
public static implicit operator Color(CorsairColor color)
{
return Color.FromArgb(color.A, color.R, color.G, color.B);
}
#endregion
}
}

View File

@ -2,7 +2,9 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
using System.Diagnostics;
using System.Drawing;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Helper;
namespace CUE.NET.Devices.Generic
@ -10,64 +12,91 @@ namespace CUE.NET.Devices.Generic
/// <summary>
/// Represents a single LED of a CUE-device.
/// </summary>
[DebuggerDisplay("{Id} {Color}")]
public class CorsairLed
{
#region Properties & Fields
/// <summary>
/// Gets the Device this <see cref="CorsairLed"/> is associated with.
/// </summary>
public ICueDevice Device { get; }
/// <summary>
/// Gets the key-ID of the Led.
/// </summary>
public CorsairLedId Id { get; }
/// <summary>
/// Gets a rectangle representing the physical location of the led.
/// </summary>
public RectangleF LedRectangle { get; }
/// <summary>
/// Indicates whether the LED has changed an internal state.
/// </summary>
public bool IsDirty => RequestedColor != _color;
/// <summary>
/// Indicate whether the Color of the LED was set since the last update.
/// </summary>
public bool IsUpdated { get; private set; }
/// <summary>
/// Gets the Color the LED should be set to on the next update.
/// </summary>
public Color RequestedColor { get; private set; } = Color.Transparent;
public CorsairColor RequestedColor { get; private set; } = CorsairColor.Transparent;
private Color _color = Color.Transparent;
private CorsairColor _color = CorsairColor.Transparent;
/// <summary>
/// Gets the current color of the LED. Sets the <see cref="RequestedColor" /> for the next update and mark the LED as <see cref="IsUpdated" />.
/// Gets the current color of the LED. Sets the <see cref="RequestedColor" /> for the next update. />.
/// </summary>
public Color Color
public CorsairColor Color
{
get { return _color; }
set
{
if (!IsLocked)
{
RequestedColor = RequestedColor.Blend(value);
IsUpdated = true;
}
}
}
/// <summary>
/// Gets or sets if the color of this LED can be changed.
/// </summary>
public bool IsLocked { get; set; } = false;
public bool IsLocked { get; set; }
#endregion
#region Constructors
internal CorsairLed() { }
/// <summary>
/// Initializes a new instance of the <see cref="CorsairLed"/> class.
/// </summary>
/// <param name="device">The <see cref="ICueDevice"/> the <see cref="CorsairLed"/> is associated with.</param>
/// <param name="id">The <see cref="CorsairLedId"/> of the <see cref="CorsairLed"/>.</param>
/// <param name="ledRectangle">The rectangle representing the physical location of the <see cref="CorsairLed"/>.</param>
internal CorsairLed(ICueDevice device, CorsairLedId id, RectangleF ledRectangle)
{
this.Device = device;
this.Id = id;
this.LedRectangle = ledRectangle;
}
#endregion
#region Methods
/// <summary>
/// Converts the Id and the <see cref="Color"/> of this <see cref="CorsairLed"/> to a human-readable string.
/// </summary>
/// <returns>A string that contains the Id and the <see cref="Color"/> of this <see cref="CorsairLed"/>. For example "Enter [A: 255, R: 255, G: 0, B: 0]".</returns>
public override string ToString()
{
return $"{Id} {Color}";
}
/// <summary>
/// Updates the LED to the requested color.
/// </summary>
internal void Update()
{
_color = RequestedColor;
IsUpdated = false;
}
/// <summary>
@ -75,12 +104,33 @@ namespace CUE.NET.Devices.Generic
/// </summary>
internal void Reset()
{
_color = Color.Transparent;
RequestedColor = Color.Transparent;
IsUpdated = false;
_color = CorsairColor.Transparent;
RequestedColor = CorsairColor.Transparent;
IsLocked = false;
}
#endregion
#region Operators
/// <summary>
/// Converts a <see cref="CorsairLed" /> to a <see cref="CorsairLedId" />.
/// </summary>
/// <param name="led">The <see cref="CorsairLed"/> to convert.</param>
public static implicit operator CorsairLedId(CorsairLed led)
{
return led?.Id ?? CorsairLedId.Invalid;
}
/// <summary>
/// Converts a <see cref="CorsairLed" /> to a <see cref="CorsairColor" />.
/// </summary>
/// <param name="led">The <see cref="CorsairLed"/> to convert.</param>
public static implicit operator CorsairColor(CorsairLed led)
{
return led?.Color;
}
#endregion
}
}

View File

@ -1,6 +1,8 @@
// ReSharper disable InconsistentNaming
// ReSharper disable UnusedMember.Global
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
namespace CUE.NET.Devices.Generic.Enums
{
/// <summary>

View File

@ -1,6 +1,8 @@
// ReSharper disable InconsistentNaming
// ReSharper disable UnusedMember.Global
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
namespace CUE.NET.Devices.Generic.Enums
{
/// <summary>
@ -8,9 +10,12 @@ namespace CUE.NET.Devices.Generic.Enums
/// </summary>
public enum CorsairDeviceType
{
Unknown = 0,
Mouse = 1,
Keyboard = 2,
Headset = 3
Headset = 3,
Mousemat = 4,
HeadsetStand = 5
};
}

View File

@ -0,0 +1,46 @@
// ReSharper disable InconsistentNaming
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
namespace CUE.NET.Devices.Generic.Enums
{
/// <summary>
/// Contains list of all KeyIds available for all corsair devices.
/// </summary>
public enum CorsairKeyId
{
Invalid = 0,
G1 = 1,
G2 = 2,
G3 = 3,
G4 = 4,
G5 = 5,
G6 = 6,
G7 = 7,
G8 = 8,
G9 = 9,
G10 = 10,
G11 = 11,
G12 = 12,
G13 = 13,
G14 = 14,
G15 = 15,
G16 = 16,
G17 = 17,
G18 = 18,
M1 = 19,
M2 = 20,
M3 = 21,
M4 = 22,
M5 = 23,
M6 = 24,
M7 = 25,
M8 = 26,
M9 = 27,
M10 = 28,
M11 = 29,
M12 = 30,
}
}

View File

@ -0,0 +1,219 @@
// ReSharper disable InconsistentNaming
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
namespace CUE.NET.Devices.Generic.Enums
{
/// <summary>
/// Contains list of all LEDs available for all corsair devices.
/// </summary>
public enum CorsairLedId
{
Invalid = 0,
Escape = 1,
F1 = 2,
F2 = 3,
F3 = 4,
F4 = 5,
F5 = 6,
F6 = 7,
F7 = 8,
F8 = 9,
F9 = 10,
F10 = 11,
F11 = 12,
GraveAccentAndTilde = 13,
D1 = 14,
D2 = 15,
D3 = 16,
D4 = 17,
D5 = 18,
D6 = 19,
D7 = 20,
D8 = 21,
D9 = 22,
D0 = 23,
MinusAndUnderscore = 24,
Tab = 25,
Q = 26,
W = 27,
E = 28,
R = 29,
T = 30,
Y = 31,
U = 32,
I = 33,
O = 34,
P = 35,
BracketLeft = 36,
CapsLock = 37,
A = 38,
S = 39,
D = 40,
F = 41,
G = 42,
H = 43,
J = 44,
K = 45,
L = 46,
SemicolonAndColon = 47,
ApostropheAndDoubleQuote = 48,
LeftShift = 49,
NonUsBackslash = 50,
Z = 51,
X = 52,
C = 53,
V = 54,
B = 55,
N = 56,
M = 57,
CommaAndLessThan = 58,
PeriodAndBiggerThan = 59,
SlashAndQuestionMark = 60,
LeftCtrl = 61,
LeftGui = 62,
LeftAlt = 63,
Lang2 = 64,
Space = 65,
Lang1 = 66,
International2 = 67,
RightAlt = 68,
RightGui = 69,
Application = 70,
LedProgramming = 71,
Brightness = 72,
F12 = 73,
PrintScreen = 74,
ScrollLock = 75,
PauseBreak = 76,
Insert = 77,
Home = 78,
PageUp = 79,
BracketRight = 80,
Backslash = 81,
NonUsTilde = 82,
Enter = 83,
International1 = 84,
EqualsAndPlus = 85,
International3 = 86,
Backspace = 87,
Delete = 88,
End = 89,
PageDown = 90,
RightShift = 91,
RightCtrl = 92,
UpArrow = 93,
LeftArrow = 94,
DownArrow = 95,
RightArrow = 96,
WinLock = 97,
Mute = 98,
Stop = 99,
ScanPreviousTrack = 100,
PlayPause = 101,
ScanNextTrack = 102,
NumLock = 103,
KeypadSlash = 104,
KeypadAsterisk = 105,
KeypadMinus = 106,
KeypadPlus = 107,
KeypadEnter = 108,
Keypad7 = 109,
Keypad8 = 110,
Keypad9 = 111,
KeypadComma = 112,
Keypad4 = 113,
Keypad5 = 114,
Keypad6 = 115,
Keypad1 = 116,
Keypad2 = 117,
Keypad3 = 118,
Keypad0 = 119,
KeypadPeriodAndDelete = 120,
G1 = 121,
G2 = 122,
G3 = 123,
G4 = 124,
G5 = 125,
G6 = 126,
G7 = 127,
G8 = 128,
G9 = 129,
G10 = 130,
VolumeUp = 131,
VolumeDown = 132,
MR = 133,
M1 = 134,
M2 = 135,
M3 = 136,
G11 = 137,
G12 = 138,
G13 = 139,
G14 = 140,
G15 = 141,
G16 = 142,
G17 = 143,
G18 = 144,
International5 = 145,
International4 = 146,
Fn = 147,
B1 = 148,
B2 = 149,
B3 = 150,
B4 = 151,
B5 = 189,
B6 = 190,
LeftLogo = 152,
RightLogo = 153,
Logo = 154,
Zone1 = 155,
Zone2 = 156,
Zone3 = 157,
Zone4 = 158,
Zone5 = 159,
Zone6 = 160,
Zone7 = 161,
Zone8 = 162,
Zone9 = 163,
Zone10 = 164,
Zone11 = 165,
Zone12 = 166,
Zone13 = 167,
Zone14 = 168,
Zone15 = 169,
Lightbar1 = 170,
Lightbar2 = 171,
Lightbar3 = 172,
Lightbar4 = 173,
Lightbar5 = 174,
Lightbar6 = 175,
Lightbar7 = 176,
Lightbar8 = 177,
Lightbar9 = 178,
Lightbar10 = 179,
Lightbar11 = 180,
Lightbar12 = 181,
Lightbar13 = 182,
Lightbar14 = 183,
Lightbar15 = 184,
Lightbar16 = 185,
Lightbar17 = 186,
Lightbar18 = 187,
Lightbar19 = 188,
HeadsetStandZone1 = 191,
HeadsetStandZone2 = 192,
HeadsetStandZone3 = 193,
HeadsetStandZone4 = 194,
HeadsetStandZone5 = 195,
HeadsetStandZone6 = 196,
HeadsetStandZone7 = 197,
HeadsetStandZone8 = 198,
HeadsetStandZone9 = 199,
}
}

View File

@ -1,6 +1,4 @@
using CUE.NET.Effects;
namespace CUE.NET.Devices.Generic.Enums
namespace CUE.NET.Devices.Generic.Enums
{
/// <summary>
/// Contains list of available update modes.
@ -8,18 +6,12 @@ namespace CUE.NET.Devices.Generic.Enums
public enum UpdateMode
{
/// <summary>
/// The device will not perform automatic updates. Updates will only occur if <see cref="CUE.NET.Devices.ICueDevice.Update" /> is called.
/// The device will not perform automatic updates. Updates will only occur if <see cref="ICueDevice.Update" /> is called.
/// </summary>
Manual,
/// <summary>
/// The device will perform automatic updates at the rate set in <see cref="CUE.NET.Devices.ICueDevice.UpdateFrequency" />
/// as long as an <see cref="IEffect" /> is attached.
/// </summary>
AutoOnEffect,
/// <summary>
/// The device will perform automatic updates at the rate set in <see cref="CUE.NET.Devices.ICueDevice.UpdateFrequency" />.
/// The device will perform automatic updates at the rate set in <see cref="CueSDK.UpdateFrequency" />.
/// </summary>
Continuous
}

View File

@ -6,7 +6,7 @@ using System;
namespace CUE.NET.Devices.Generic.EventArgs
{
/// <summary>
/// Represents the information supplied with an Exception-event.
/// Represents the information supplied with an <see cref="ICueDevice.Exception"/>-event.
/// </summary>
public class ExceptionEventArgs : System.EventArgs
{

View File

@ -5,16 +5,26 @@ using System.Collections.Generic;
namespace CUE.NET.Devices.Generic.EventArgs
{
/// <summary>
/// Represents the information supplied with an <see cref="ICueDevice.LedsUpdated"/>-event.
/// </summary>
public class LedsUpdatedEventArgs : System.EventArgs
{
#region Properties & Fields
/// <summary>
/// Gets a list of <see cref="LedUpateRequest"/> from the updated leds.
/// </summary>
public IEnumerable<LedUpateRequest> UpdatedLeds { get; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="LedsUpdatedEventArgs"/> class.
/// </summary>
/// <param name="updatedLeds">The updated leds.</param>
public LedsUpdatedEventArgs(IEnumerable<LedUpateRequest> updatedLeds)
{
this.UpdatedLeds = updatedLeds;

View File

@ -5,16 +5,26 @@ using System.Collections.Generic;
namespace CUE.NET.Devices.Generic.EventArgs
{
/// <summary>
/// Represents the information supplied with an <see cref="ICueDevice.LedsUpdating"/>-event.
/// </summary>
public class LedsUpdatingEventArgs : System.EventArgs
{
#region Properties & Fields
/// <summary>
/// Gets a list of <see cref="LedUpateRequest"/> from the updating leds.
/// </summary>
public ICollection<LedUpateRequest> UpdatingLeds { get; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="LedsUpdatingEventArgs"/> class.
/// </summary>
/// <param name="updatingLeds">The updating leds.</param>
public LedsUpdatingEventArgs(ICollection<LedUpateRequest> updatingLeds)
{
this.UpdatingLeds = updatingLeds;

View File

@ -1,5 +1,8 @@
namespace CUE.NET.Devices.Generic.EventArgs
{
/// <summary>
/// Represents the information supplied with an <see cref="ICueDevice.Updated"/>-event.
/// </summary>
public class UpdatedEventArgs : System.EventArgs
{ }
}

View File

@ -1,15 +1,28 @@
namespace CUE.NET.Devices.Generic.EventArgs
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace CUE.NET.Devices.Generic.EventArgs
{
/// <summary>
/// Represents the information supplied with an <see cref="ICueDevice.Updating"/>-event.
/// </summary>
public class UpdatingEventArgs : System.EventArgs
{
#region Properties & Fields
/// <summary>
/// Gets the elapsed time (in seconds) sonce the last update.
/// </summary>
public float DeltaTime { get; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="UpdatingEventArgs"/> class.
/// </summary>
/// <param name="deltaTime">The elapsed time (in seconds) sonce the last update.</param>
public UpdatingEventArgs(float deltaTime)
{
this.DeltaTime = deltaTime;

View File

@ -1,23 +1,37 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
using System.Drawing;
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.Devices.Generic
{
/// <summary>
/// Represents a request to update a led.
/// </summary>
public class LedUpateRequest
{
#region Properties & Fields
public int LedId { get; }
/// <summary>
/// Gets the id of the led to update.
/// </summary>
public CorsairLedId LedId { get; }
public Color Color { get; set; }
/// <summary>
/// Gets the requested color of the led.
/// </summary>
public CorsairColor Color { get; set; }
#endregion
#region Constructors
public LedUpateRequest(int ledId, Color color)
/// <summary>
/// Initializes a new instance of the <see cref="LedUpateRequest"/> class.
/// </summary>
/// <param name="ledId">The id of the led to update.</param>
/// <param name="color">The requested color of the led.</param>
public LedUpateRequest(CorsairLedId ledId, CorsairColor color)
{
this.LedId = ledId;
this.Color = color;

View File

@ -2,57 +2,24 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Headset.Enums;
using CUE.NET.Effects;
namespace CUE.NET.Devices.Headset
{
/// <summary>
/// Represents the SDK for a corsair headset.
/// </summary>
public class CorsairHeadset : AbstractCueDevice, IEnumerable<CorsairLed>
public class CorsairHeadset : AbstractCueDevice
{
#region Properties & Fields
#region Indexer
/// <summary>
/// Gets the <see cref="CorsairLed" /> with the specified ID.
/// </summary>
/// <param name="ledId">The ID of the LED to get.</param>
/// <returns>The LED with the specified ID.</returns>
public CorsairLed this[CorsairHeadsetLedId ledId]
{
get
{
CorsairLed led;
return base.Leds.TryGetValue((int)ledId, out led) ? led : null;
}
}
#endregion
/// <summary>
/// Gets specific information provided by CUE for the headset.
/// </summary>
public CorsairHeadsetDeviceInfo HeadsetDeviceInfo { get; }
/// <summary>
/// Gets a value indicating if the headset has an active effect to deal with or not.
/// </summary>
protected override bool HasEffect => false;
/// <summary>
/// Gets a read-only collection containing all LEDs of the headset.
/// </summary>
public new IEnumerable<CorsairLed> Leds => new ReadOnlyCollection<CorsairLed>(base.Leds.Values.ToList());
#endregion
#region Constructors
@ -65,44 +32,23 @@ namespace CUE.NET.Devices.Headset
: base(info)
{
this.HeadsetDeviceInfo = info;
InitializeLeds();
}
#endregion
#region Methods
protected override void ApplyEffect(IEffect effect)
{
//TODO DarthAffe 18.10.2015: How should brushes be applied to headsets?
foreach (CorsairLed led in effect.LedList)
led.Color = effect.EffectBrush.GetColorAtPoint(new RectangleF(0, 0, 2, 2), new PointF(1, 1));
}
private void InitializeLeds()
{
GetLed((int)CorsairHeadsetLedId.LeftLogo);
GetLed((int)CorsairHeadsetLedId.RightLogo);
}
#region IEnumerable
/// <summary>
/// Returns an enumerator that iterates over all LEDs of the headset.
/// Initializes the the headset.
/// </summary>
/// <returns>An enumerator for all LDS of the headset.</returns>
public IEnumerator<CorsairLed> GetEnumerator()
public override void Initialize()
{
return Leds.GetEnumerator();
}
InitializeLed(CorsairHeadsetLedId.LeftLogo, new RectangleF(0, 0, 1, 1));
InitializeLed(CorsairHeadsetLedId.RightLogo, new RectangleF(1, 0, 1, 1));
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
base.Initialize();
}
#endregion
#endregion
}
}

View File

@ -8,6 +8,8 @@ namespace CUE.NET.Devices.Headset
/// </summary>
public class CorsairHeadsetDeviceInfo : GenericDeviceInfo
{
#region Constructors
/// <summary>
/// Internal constructor of managed <see cref="CorsairHeadsetDeviceInfo" />.
/// </summary>
@ -15,5 +17,7 @@ namespace CUE.NET.Devices.Headset
internal CorsairHeadsetDeviceInfo(_CorsairDeviceInfo nativeInfo)
: base(nativeInfo)
{ }
#endregion
}
}

View File

@ -1,15 +1,19 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable InconsistentNaming
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.Devices.Headset.Enums
{
/// <summary>
/// Contains list of all LEDs available for corsair headsets.
/// </summary>
public enum CorsairHeadsetLedId
public static class CorsairHeadsetLedId
{
Invalid = 0,
LeftLogo = 152,
RightLogo = 153
public const CorsairLedId Invalid = CorsairLedId.Invalid;
public const CorsairLedId LeftLogo = CorsairLedId.LeftLogo;
public const CorsairLedId RightLogo = CorsairLedId.RightLogo;
}
}

View File

@ -0,0 +1,91 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Exceptions;
using CUE.NET.Native;
namespace CUE.NET.Devices.HeadsetStand
{
/// <summary>
/// Represents the SDK for a corsair headset stand.
/// </summary>
public class CorsairHeadsetStand : AbstractCueDevice
{
#region Properties & Fields
/// <summary>
/// Gets specific information provided by CUE for the headset stand.
/// </summary>
public CorsairHeadsetStandDeviceInfo HeadsetStandDeviceInfo { get; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="CorsairHeadsetStand"/> class.
/// </summary>
/// <param name="info">The specific information provided by CUE for the headset stand</param>
internal CorsairHeadsetStand(CorsairHeadsetStandDeviceInfo info)
: base(info)
{
this.HeadsetStandDeviceInfo = info;
}
#endregion
#region Methods
/// <summary>
/// Initializes the headset stand.
/// </summary>
public override void Initialize()
{
int deviceCount = _CUESDK.CorsairGetDeviceCount();
// Get headset stand device index
int headsetStandIndex = -1;
for (int i = 0; i < deviceCount; i++)
{
_CorsairDeviceInfo nativeDeviceInfo = (_CorsairDeviceInfo)Marshal.PtrToStructure(_CUESDK.CorsairGetDeviceInfo(i), typeof(_CorsairDeviceInfo));
GenericDeviceInfo info = new GenericDeviceInfo(nativeDeviceInfo);
if (info.Type != CorsairDeviceType.HeadsetStand)
continue;
headsetStandIndex = i;
break;
}
if (headsetStandIndex < 0)
throw new WrapperException("Can't determine headset stand device index");
_CorsairLedPositions nativeLedPositions = (_CorsairLedPositions)Marshal.PtrToStructure(_CUESDK.CorsairGetLedPositionsByDeviceIndex(headsetStandIndex), typeof(_CorsairLedPositions));
int structSize = Marshal.SizeOf(typeof(_CorsairLedPosition));
IntPtr ptr = nativeLedPositions.pLedPosition;
// Put the positions in an array for sorting later on
List<_CorsairLedPosition> positions = new List<_CorsairLedPosition>();
for (int i = 0; i < nativeLedPositions.numberOfLed; i++)
{
_CorsairLedPosition ledPosition = (_CorsairLedPosition)Marshal.PtrToStructure(ptr, typeof(_CorsairLedPosition));
ptr = new IntPtr(ptr.ToInt64() + structSize);
positions.Add(ledPosition);
}
// Sort for easy iteration by clients
foreach (_CorsairLedPosition ledPosition in positions.OrderBy(p => p.ledId))
InitializeLed(ledPosition.ledId, new RectangleF((float)ledPosition.left, (float)ledPosition.top, (float)ledPosition.width, (float)ledPosition.height));
base.Initialize();
}
#endregion
}
}

View File

@ -0,0 +1,26 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
using CUE.NET.Devices.Generic;
using CUE.NET.Native;
namespace CUE.NET.Devices.HeadsetStand
{
/// <summary>
/// Represents specific information for a CUE headset stand.
/// </summary>
public class CorsairHeadsetStandDeviceInfo : GenericDeviceInfo
{
#region Constructors
/// <summary>
/// Internal constructor of managed <see cref="CorsairHeadsetStandDeviceInfo" />.
/// </summary>
/// <param name="nativeInfo">The native <see cref="_CorsairDeviceInfo" />-struct</param>
internal CorsairHeadsetStandDeviceInfo(_CorsairDeviceInfo nativeInfo)
: base(nativeInfo)
{ }
#endregion
}
}

View File

@ -0,0 +1,26 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable InconsistentNaming
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.Devices.HeadsetStand.Enums
{
/// <summary>
/// Contains list of all LEDs available for corsair headset stands.
/// </summary>
public static class CorsairHeadsetStandLedId
{
public const CorsairLedId Invalid = CorsairLedId.Invalid;
public const CorsairLedId HeadsetStandZone1 = CorsairLedId.HeadsetStandZone1;
public const CorsairLedId HeadsetStandZone2 = CorsairLedId.HeadsetStandZone2;
public const CorsairLedId HeadsetStandZone3 = CorsairLedId.HeadsetStandZone3;
public const CorsairLedId HeadsetStandZone4 = CorsairLedId.HeadsetStandZone4;
public const CorsairLedId HeadsetStandZone5 = CorsairLedId.HeadsetStandZone5;
public const CorsairLedId HeadsetStandZone6 = CorsairLedId.HeadsetStandZone6;
public const CorsairLedId HeadsetStandZone7 = CorsairLedId.HeadsetStandZone7;
public const CorsairLedId HeadsetStandZone8 = CorsairLedId.HeadsetStandZone8;
public const CorsairLedId HeadsetStandZone9 = CorsairLedId.HeadsetStandZone9;
}
}

View File

@ -1,11 +1,17 @@
// ReSharper disable UnusedMemberInSuper.Global
// ReSharper disable UnusedMember.Global
using System.Collections.Generic;
using System.Drawing;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Devices.Generic.EventArgs;
using CUE.NET.Groups;
namespace CUE.NET.Devices
{
#region EventHandler
/// <summary>
/// Represents the event-handler of the Exception-event.
/// </summary>
@ -41,25 +47,59 @@ namespace CUE.NET.Devices
/// <param name="args">The arguments provided by the event.</param>
public delegate void LedsUpdatedEventHandler(object sender, LedsUpdatedEventArgs args);
#endregion
/// <summary>
/// Represents a generic cue device.
/// </summary>
public interface ICueDevice
public interface ICueDevice : ILedGroup, IEnumerable<CorsairLed>
{
#region Properties
/// <summary>
/// Gets generic information provided by CUE for the device.
/// </summary>
IDeviceInfo DeviceInfo { get; }
/// <summary>
/// Gets or sets the update-mode for the device.
/// Gets the rectangle containing all LEDs of the device.
/// </summary>
UpdateMode UpdateMode { get; set; }
RectangleF DeviceRectangle { get; }
/// <summary>
/// Gets or sets the update-frequency in seconds. (Calculate by using '1f / updates per second')
/// Gets a read-only collection containing the LEDs of the device.
/// </summary>
float UpdateFrequency { get; set; }
IEnumerable<CorsairLed> Leds { get; }
#endregion
#region Indexer
/// <summary>
/// Gets the <see cref="CorsairLed" /> with the specified ID.
/// </summary>
/// <param name="ledId">The ID of the LED to get.</param>
/// <returns>The LED with the specified ID or null if no LED is found.</returns>
CorsairLed this[CorsairLedId ledId] { get; }
/// <summary>
/// Gets the <see cref="CorsairLed" /> at the given physical location.
/// </summary>
/// <param name="location">The point to get the location from.</param>
/// <returns>The LED at the given point or null if no location is found.</returns>
CorsairLed this[PointF location] { get; }
/// <summary>
/// Gets a list of <see cref="CorsairLed" /> inside the given rectangle.
/// </summary>
/// <param name="referenceRect">The rectangle to check.</param>
/// <param name="minOverlayPercentage">The minimal percentage overlay a location must have with the <see cref="Rectangle" /> to be taken into the list.</param>
/// <returns></returns>
IEnumerable<CorsairLed> this[RectangleF referenceRect, float minOverlayPercentage = 0.5f] { get; }
#endregion
#region Events
// ReSharper disable EventNeverSubscribedTo.Global
@ -90,10 +130,51 @@ namespace CUE.NET.Devices
// ReSharper restore EventNeverSubscribedTo.Global
#endregion
#region Methods
/// <summary>
/// Perform an update for all dirty keys, or all keys if flushLeds is set to true.
/// Initializes the device.
/// </summary>
void Initialize();
/// <summary>
/// Performs an update for all dirty keys, or all keys if flushLeds is set to true.
/// </summary>
/// <param name="flushLeds">Specifies whether all keys (including clean ones) should be updated.</param>
void Update(bool flushLeds = false);
/// <param name="noRender">Only updates the hardware-leds skippin effects and the render-pass. Only use this if you know what that means!</param>
void Update(bool flushLeds = false, bool noRender = false);
/// <summary>
/// Reads the currently active colors from the device and sync them with the internal state.
/// </summary>
void SyncColors();
/// <summary>
/// Saves the currently active colors from the device.
/// </summary>
void SaveColors();
/// <summary>
/// Restores the last saved colors.
/// </summary>
void RestoreColors();
/// <summary>
/// Attaches the given ledgroup.
/// </summary>
/// <param name="ledGroup">The ledgroup to attach.</param>
/// <returns><c>true</c> if the ledgroup could be attached; otherwise, <c>false</c>.</returns>
bool AttachLedGroup(ILedGroup ledGroup);
/// <summary>
/// Detaches the given ledgroup.
/// </summary>
/// <param name="ledGroup">The ledgroup to detached.</param>
/// <returns><c>true</c> if the ledgroup could be detached; otherwise, <c>false</c>.</returns>
bool DetachLedGroup(ILedGroup ledGroup);
#endregion
}
}

View File

@ -4,18 +4,10 @@
// ReSharper disable UnusedMember.Global
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Keyboard.Enums;
using CUE.NET.Devices.Keyboard.Keys;
using CUE.NET.Effects;
using CUE.NET.Helper;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Native;
namespace CUE.NET.Devices.Keyboard
@ -23,103 +15,37 @@ namespace CUE.NET.Devices.Keyboard
/// <summary>
/// Represents the SDK for a corsair keyboard.
/// </summary>
public class CorsairKeyboard : AbstractCueDevice, IEnumerable<CorsairKey>, IKeyGroup
public class CorsairKeyboard : AbstractCueDevice
{
#region Properties & Fields
#region Indexer
/// <summary>
/// Gets the <see cref="CorsairKey" /> with the specified ID.
/// </summary>
/// <param name="keyId">The ID of the key to get.</param>
/// <returns>The key with the specified ID or null if no key is found.</returns>
public CorsairKey this[CorsairKeyboardKeyId keyId]
{
get
{
CorsairKey key;
return _keys.TryGetValue(keyId, out key) ? key : null;
}
}
/// <summary>
/// Gets the <see cref="CorsairKey" /> representing the given character by calling the SDK-method 'CorsairGetLedIdForKeyName'.<br />
/// Note that this currently only works for letters.
/// </summary>
/// <param name="key">The character of the key.</param>
/// <returns>The key representing the given character or null if no key is found.</returns>
public CorsairKey this[char key]
{
get
{
CorsairKeyboardKeyId keyId = _CUESDK.CorsairGetLedIdForKeyName(key);
CorsairKey cKey;
return _keys.TryGetValue(keyId, out cKey) ? cKey : null;
}
}
/// <summary>
/// Gets the <see cref="CorsairKey" /> at the given physical location.
/// </summary>
/// <param name="location">The point to get the key from.</param>
/// <returns>The key at the given point or null if no key is found.</returns>
public CorsairKey this[PointF location] => _keys.Values.FirstOrDefault(x => x.KeyRectangle.Contains(location));
/// <summary>
/// Gets a list of <see cref="CorsairKey" /> inside the given rectangle.
/// </summary>
/// <param name="referenceRect">The rectangle to check.</param>
/// <param name="minOverlayPercentage">The minimal percentage overlay a key must have with the <see cref="Rectangle" /> to be taken into the list.</param>
/// <returns></returns>
public IEnumerable<CorsairKey> this[RectangleF referenceRect, float minOverlayPercentage = 0.5f] => _keys.Values.Where(x => RectangleHelper.CalculateIntersectPercentage(x.KeyRectangle, referenceRect) >= minOverlayPercentage);
#endregion
private readonly LinkedList<IKeyGroup> _keyGroups = new LinkedList<IKeyGroup>();
private Dictionary<CorsairKeyboardKeyId, CorsairKey> _keys = new Dictionary<CorsairKeyboardKeyId, CorsairKey>();
/// <summary>
/// Gets a read-only collection containing the keys of the keyboard.
/// </summary>
public IEnumerable<CorsairKey> Keys => new ReadOnlyCollection<CorsairKey>(_keys.Values.ToList());
/// <summary>
/// Gets specific information provided by CUE for the keyboard.
/// </summary>
public CorsairKeyboardDeviceInfo KeyboardDeviceInfo { get; }
/// <summary>
/// Gets the rectangle containing all keys of the keyboard.
/// </summary>
public RectangleF KeyboardRectangle { get; }
#region Indexers
/// <summary>
/// Gets or sets the background brush of the keyboard.
/// Gets the <see cref="CorsairLed" /> representing the given character by calling the SDK-method 'CorsairGetLedIdForKeyName'.<br />
/// Note that this currently only works for letters.
/// </summary>
public IBrush Brush { get; set; }
/// <summary>
/// Gets or sets the z-index of the background brush of the keyboard.<br />
/// This value has absolutely no effect.
/// </summary>
public int ZIndex { get; set; } = 0;
/// <summary>
/// Gets a value indicating if the keyboard has an active effect to deal with or not.
/// </summary>
protected override bool HasEffect
/// <param name="key">The character of the key.</param>
/// <returns>The led representing the given character or null if no led is found.</returns>
public CorsairLed this[char key]
{
get
{
lock (Effects)
return Effects.Any();
CorsairLedId ledId = _CUESDK.CorsairGetLedIdForKeyName(key);
CorsairLed led;
return LedMapping.TryGetValue(ledId, out led) ? led : null;
}
}
#endregion
#endregion
#region Constructors
/// <summary>
@ -130,112 +56,16 @@ namespace CUE.NET.Devices.Keyboard
: base(info)
{
this.KeyboardDeviceInfo = info;
InitializeKeys();
KeyboardRectangle = RectangleHelper.CreateRectangleFromRectangles(this.Select(x => x.KeyRectangle));
}
#endregion
#region Methods
#region Update
/// <summary>
/// Updates all brushes on the keyboard and on groups.
/// Initializes the keyboard.
/// </summary>
protected override void DeviceUpdate()
{
if (Brush != null)
ApplyBrush(this.ToList(), Brush);
lock (_keyGroups)
{
foreach (IKeyGroup keyGroup in _keyGroups.OrderBy(x => x.ZIndex))
ApplyBrush(keyGroup.Keys.ToList(), keyGroup.Brush);
}
}
protected override void ApplyEffect(IEffect effect)
{
if (effect == null) return;
//TODO DarthAffe 18.10.2015: This is really dirty and might have a really negative performance impact - find a better solution.
IEnumerable<CorsairKey> keys = effect.LedList?.Select(x => this.FirstOrDefault(y => y.Led == x));
ApplyBrush((keys ?? this).ToList(), effect.EffectBrush);
}
// ReSharper disable once MemberCanBeMadeStatic.Local - idc
private void ApplyBrush(ICollection<CorsairKey> keys, IBrush brush)
{
try
{
switch (brush.BrushCalculationMode)
{
case BrushCalculationMode.Relative:
RectangleF brushRectangle = RectangleHelper.CreateRectangleFromRectangles(keys.Select(x => x.KeyRectangle));
float offsetX = -brushRectangle.X;
float offsetY = -brushRectangle.Y;
brushRectangle.X = 0;
brushRectangle.Y = 0;
foreach (CorsairKey key in keys)
key.Led.Color = brush.GetColorAtPoint(brushRectangle, key.KeyRectangle.GetCenter(offsetX, offsetY));
break;
case BrushCalculationMode.Absolute:
foreach (CorsairKey key in keys)
key.Led.Color = brush.GetColorAtPoint(KeyboardRectangle, key.KeyRectangle.GetCenter());
break;
default:
throw new ArgumentException();
}
}
// ReSharper disable once CatchAllClause
catch (Exception ex) { OnException(ex); }
}
public IEnumerable<CorsairLed> GetLeds()
{
return this.Select(x => x.Led);
}
#endregion
/// <summary>
/// Attaches the given keygroup.
/// </summary>
/// <param name="keyGroup">The keygroup to attach.</param>
/// <returns><c>true</c> if the keygroup could be attached; otherwise, <c>false</c>.</returns>
public bool AttachKeyGroup(IKeyGroup keyGroup)
{
lock (_keyGroups)
{
if (keyGroup == null || _keyGroups.Contains(keyGroup)) return false;
_keyGroups.AddLast(keyGroup);
return true;
}
}
/// <summary>
/// Detaches the given keygroup.
/// </summary>
/// <param name="keyGroup">The keygroup to detached.</param>
/// <returns><c>true</c> if the keygroup could be detached; otherwise, <c>false</c>.</returns>
public bool DetachKeyGroup(IKeyGroup keyGroup)
{
lock (_keyGroups)
{
if (keyGroup == null) return false;
LinkedListNode<IKeyGroup> node = _keyGroups.Find(keyGroup);
if (node == null) return false;
_keyGroups.Remove(node);
return true;
}
}
private void InitializeKeys()
public override void Initialize()
{
_CorsairLedPositions nativeLedPositions = (_CorsairLedPositions)Marshal.PtrToStructure(_CUESDK.CorsairGetLedPositions(), typeof(_CorsairLedPositions));
int structSize = Marshal.SizeOf(typeof(_CorsairLedPosition));
@ -243,32 +73,14 @@ namespace CUE.NET.Devices.Keyboard
for (int i = 0; i < nativeLedPositions.numberOfLed; i++)
{
_CorsairLedPosition ledPosition = (_CorsairLedPosition)Marshal.PtrToStructure(ptr, typeof(_CorsairLedPosition));
CorsairLed led = GetLed((int)ledPosition.ledId);
_keys.Add(ledPosition.ledId, new CorsairKey(ledPosition.ledId, led,
new RectangleF((float)ledPosition.left, (float)ledPosition.top, (float)ledPosition.width, (float)ledPosition.height)));
InitializeLed(ledPosition.ledId, new RectangleF((float)ledPosition.left, (float)ledPosition.top, (float)ledPosition.width, (float)ledPosition.height));
ptr = new IntPtr(ptr.ToInt64() + structSize);
}
base.Initialize();
}
#region IEnumerable
/// <summary>
/// Returns an enumerator that iterates over all keys of the keyboard.
/// </summary>
/// <returns>An enumerator for all keys of the keyboard.</returns>
public IEnumerator<CorsairKey> GetEnumerator()
{
return _keys.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#endregion
}
}

View File

@ -1,12 +1,12 @@
namespace CUE.NET.Devices.Keyboard.Enums
{
/// <summary>
/// Contains list of all brush calculation modes.
/// Contains a list of all brush calculation modes.
/// </summary>
public enum BrushCalculationMode
{
/// <summary>
/// The calculation rectangle for brushes will be the rectangle around the keygroup the brush is applied to.
/// The calculation rectangle for brushes will be the rectangle around the ledgroup the brush is applied to.
/// </summary>
Relative,
/// <summary>

View File

@ -1,161 +1,36 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable InconsistentNaming
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.Devices.Keyboard.Enums
{
/// <summary>
/// Contains list of all LEDs available for corsair keyboards.
/// </summary>
public enum CorsairKeyboardKeyId
public static class CorsairKeyboardKeyId
{
Invalid = 0,
Escape = 1,
F1 = 2,
F2 = 3,
F3 = 4,
F4 = 5,
F5 = 6,
F6 = 7,
F7 = 8,
F8 = 9,
F9 = 10,
F10 = 11,
F11 = 12,
GraveAccentAndTilde = 13,
D1 = 14,
D2 = 15,
D3 = 16,
D4 = 17,
D5 = 18,
D6 = 19,
D7 = 20,
D8 = 21,
D9 = 22,
D0 = 23,
MinusAndUnderscore = 24,
Tab = 25,
Q = 26,
W = 27,
E = 28,
R = 29,
T = 30,
Y = 31,
U = 32,
I = 33,
O = 34,
P = 35,
BracketLeft = 36,
CapsLock = 37,
A = 38,
S = 39,
D = 40,
F = 41,
G = 42,
H = 43,
J = 44,
K = 45,
L = 46,
SemicolonAndColon = 47,
ApostropheAndDoubleQuote = 48,
LeftShift = 49,
NonUsBackslash = 50,
Z = 51,
X = 52,
C = 53,
V = 54,
B = 55,
N = 56,
M = 57,
CommaAndLessThan = 58,
PeriodAndBiggerThan = 59,
SlashAndQuestionMark = 60,
LeftCtrl = 61,
LeftGui = 62,
LeftAlt = 63,
Lang2 = 64,
Space = 65,
Lang1 = 66,
International2 = 67,
RightAlt = 68,
RightGui = 69,
Application = 70,
LedProgramming = 71,
Brightness = 72,
F12 = 73,
PrintScreen = 74,
ScrollLock = 75,
PauseBreak = 76,
Insert = 77,
Home = 78,
PageUp = 79,
BracketRight = 80,
Backslash = 81,
NonUsTilde = 82,
Enter = 83,
International1 = 84,
EqualsAndPlus = 85,
International3 = 86,
Backspace = 87,
Delete = 88,
End = 89,
PageDown = 90,
RightShift = 91,
RightCtrl = 92,
UpArrow = 93,
LeftArrow = 94,
DownArrow = 95,
RightArrow = 96,
WinLock = 97,
Mute = 98,
Stop = 99,
ScanPreviousTrack = 100,
PlayPause = 101,
ScanNextTrack = 102,
NumLock = 103,
KeypadSlash = 104,
KeypadAsterisk = 105,
KeypadMinus = 106,
KeypadPlus = 107,
KeypadEnter = 108,
Keypad7 = 109,
Keypad8 = 110,
Keypad9 = 111,
KeypadComma = 112,
Keypad4 = 113,
Keypad5 = 114,
Keypad6 = 115,
Keypad1 = 116,
Keypad2 = 117,
Keypad3 = 118,
Keypad0 = 119,
KeypadPeriodAndDelete = 120,
G1 = 121,
G2 = 122,
G3 = 123,
G4 = 124,
G5 = 125,
G6 = 126,
G7 = 127,
G8 = 128,
G9 = 129,
G10 = 130,
VolumeUp = 131,
VolumeDown = 132,
MR = 133,
M1 = 134,
M2 = 135,
M3 = 136,
G11 = 137,
G12 = 138,
G13 = 139,
G14 = 140,
G15 = 141,
G16 = 142,
G17 = 143,
G18 = 144,
International5 = 145,
International4 = 146,
Fn = 147,
CLK_Logo = 154
public const CorsairKeyId Invalid = CorsairKeyId.Invalid;
public const CorsairKeyId G1 = CorsairKeyId.G1;
public const CorsairKeyId G2 = CorsairKeyId.G2;
public const CorsairKeyId G3 = CorsairKeyId.G3;
public const CorsairKeyId G4 = CorsairKeyId.G4;
public const CorsairKeyId G5 = CorsairKeyId.G5;
public const CorsairKeyId G6 = CorsairKeyId.G6;
public const CorsairKeyId G7 = CorsairKeyId.G7;
public const CorsairKeyId G8 = CorsairKeyId.G8;
public const CorsairKeyId G9 = CorsairKeyId.G9;
public const CorsairKeyId G10 = CorsairKeyId.G10;
public const CorsairKeyId G11 = CorsairKeyId.G11;
public const CorsairKeyId G12 = CorsairKeyId.G12;
public const CorsairKeyId G13 = CorsairKeyId.G13;
public const CorsairKeyId G14 = CorsairKeyId.G14;
public const CorsairKeyId G15 = CorsairKeyId.G15;
public const CorsairKeyId G16 = CorsairKeyId.G16;
public const CorsairKeyId G17 = CorsairKeyId.G17;
public const CorsairKeyId G18 = CorsairKeyId.G18;
}
}

View File

@ -0,0 +1,184 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable InconsistentNaming
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.Devices.Keyboard.Enums
{
/// <summary>
/// Contains list of all LEDs available for corsair keyboards.
/// </summary>
public static class CorsairKeyboardLedId
{
public const CorsairLedId Invalid = CorsairLedId.Invalid;
public const CorsairLedId Escape = CorsairLedId.Escape;
public const CorsairLedId F1 = CorsairLedId.F1;
public const CorsairLedId F2 = CorsairLedId.F2;
public const CorsairLedId F3 = CorsairLedId.F3;
public const CorsairLedId F4 = CorsairLedId.F4;
public const CorsairLedId F5 = CorsairLedId.F5;
public const CorsairLedId F6 = CorsairLedId.F6;
public const CorsairLedId F7 = CorsairLedId.F7;
public const CorsairLedId F8 = CorsairLedId.F8;
public const CorsairLedId F9 = CorsairLedId.F9;
public const CorsairLedId F10 = CorsairLedId.F10;
public const CorsairLedId F11 = CorsairLedId.F11;
public const CorsairLedId GraveAccentAndTilde = CorsairLedId.GraveAccentAndTilde;
public const CorsairLedId D1 = CorsairLedId.D1;
public const CorsairLedId D2 = CorsairLedId.D2;
public const CorsairLedId D3 = CorsairLedId.D3;
public const CorsairLedId D4 = CorsairLedId.D4;
public const CorsairLedId D5 = CorsairLedId.D5;
public const CorsairLedId D6 = CorsairLedId.D6;
public const CorsairLedId D7 = CorsairLedId.D7;
public const CorsairLedId D8 = CorsairLedId.D8;
public const CorsairLedId D9 = CorsairLedId.D9;
public const CorsairLedId D0 = CorsairLedId.D0;
public const CorsairLedId MinusAndUnderscore = CorsairLedId.MinusAndUnderscore;
public const CorsairLedId Tab = CorsairLedId.Tab;
public const CorsairLedId Q = CorsairLedId.Q;
public const CorsairLedId W = CorsairLedId.W;
public const CorsairLedId E = CorsairLedId.E;
public const CorsairLedId R = CorsairLedId.R;
public const CorsairLedId T = CorsairLedId.T;
public const CorsairLedId Y = CorsairLedId.Y;
public const CorsairLedId U = CorsairLedId.U;
public const CorsairLedId I = CorsairLedId.I;
public const CorsairLedId O = CorsairLedId.O;
public const CorsairLedId P = CorsairLedId.P;
public const CorsairLedId BracketLeft = CorsairLedId.BracketLeft;
public const CorsairLedId CapsLock = CorsairLedId.CapsLock;
public const CorsairLedId A = CorsairLedId.A;
public const CorsairLedId S = CorsairLedId.S;
public const CorsairLedId D = CorsairLedId.D;
public const CorsairLedId F = CorsairLedId.F;
public const CorsairLedId G = CorsairLedId.G;
public const CorsairLedId H = CorsairLedId.H;
public const CorsairLedId J = CorsairLedId.J;
public const CorsairLedId K = CorsairLedId.K;
public const CorsairLedId L = CorsairLedId.L;
public const CorsairLedId SemicolonAndColon = CorsairLedId.SemicolonAndColon;
public const CorsairLedId ApostropheAndDoubleQuote = CorsairLedId.ApostropheAndDoubleQuote;
public const CorsairLedId LeftShift = CorsairLedId.LeftShift;
public const CorsairLedId NonUsBackslash = CorsairLedId.NonUsBackslash;
public const CorsairLedId Z = CorsairLedId.Z;
public const CorsairLedId X = CorsairLedId.X;
public const CorsairLedId C = CorsairLedId.C;
public const CorsairLedId V = CorsairLedId.V;
public const CorsairLedId B = CorsairLedId.B;
public const CorsairLedId N = CorsairLedId.N;
public const CorsairLedId M = CorsairLedId.M;
public const CorsairLedId CommaAndLessThan = CorsairLedId.CommaAndLessThan;
public const CorsairLedId PeriodAndBiggerThan = CorsairLedId.PeriodAndBiggerThan;
public const CorsairLedId SlashAndQuestionMark = CorsairLedId.SlashAndQuestionMark;
public const CorsairLedId LeftCtrl = CorsairLedId.LeftCtrl;
public const CorsairLedId LeftGui = CorsairLedId.LeftGui;
public const CorsairLedId LeftAlt = CorsairLedId.LeftAlt;
public const CorsairLedId Lang2 = CorsairLedId.Lang2;
public const CorsairLedId Space = CorsairLedId.Space;
public const CorsairLedId Lang1 = CorsairLedId.Lang1;
public const CorsairLedId International2 = CorsairLedId.International2;
public const CorsairLedId RightAlt = CorsairLedId.RightAlt;
public const CorsairLedId RightGui = CorsairLedId.RightGui;
public const CorsairLedId Application = CorsairLedId.Application;
public const CorsairLedId LedProgramming = CorsairLedId.LedProgramming;
public const CorsairLedId Brightness = CorsairLedId.Brightness;
public const CorsairLedId F12 = CorsairLedId.F12;
public const CorsairLedId PrintScreen = CorsairLedId.PrintScreen;
public const CorsairLedId ScrollLock = CorsairLedId.ScrollLock;
public const CorsairLedId PauseBreak = CorsairLedId.PauseBreak;
public const CorsairLedId Insert = CorsairLedId.Insert;
public const CorsairLedId Home = CorsairLedId.Home;
public const CorsairLedId PageUp = CorsairLedId.PageUp;
public const CorsairLedId BracketRight = CorsairLedId.BracketRight;
public const CorsairLedId Backslash = CorsairLedId.Backslash;
public const CorsairLedId NonUsTilde = CorsairLedId.NonUsTilde;
public const CorsairLedId Enter = CorsairLedId.Enter;
public const CorsairLedId International1 = CorsairLedId.International1;
public const CorsairLedId EqualsAndPlus = CorsairLedId.EqualsAndPlus;
public const CorsairLedId International3 = CorsairLedId.International3;
public const CorsairLedId Backspace = CorsairLedId.Backspace;
public const CorsairLedId Delete = CorsairLedId.Delete;
public const CorsairLedId End = CorsairLedId.End;
public const CorsairLedId PageDown = CorsairLedId.PageDown;
public const CorsairLedId RightShift = CorsairLedId.RightShift;
public const CorsairLedId RightCtrl = CorsairLedId.RightCtrl;
public const CorsairLedId UpArrow = CorsairLedId.UpArrow;
public const CorsairLedId LeftArrow = CorsairLedId.LeftArrow;
public const CorsairLedId DownArrow = CorsairLedId.DownArrow;
public const CorsairLedId RightArrow = CorsairLedId.RightArrow;
public const CorsairLedId WinLock = CorsairLedId.WinLock;
public const CorsairLedId Mute = CorsairLedId.Mute;
public const CorsairLedId Stop = CorsairLedId.Stop;
public const CorsairLedId ScanPreviousTrack = CorsairLedId.ScanPreviousTrack;
public const CorsairLedId PlayPause = CorsairLedId.PlayPause;
public const CorsairLedId ScanNextTrack = CorsairLedId.ScanNextTrack;
public const CorsairLedId NumLock = CorsairLedId.NumLock;
public const CorsairLedId KeypadSlash = CorsairLedId.KeypadSlash;
public const CorsairLedId KeypadAsterisk = CorsairLedId.KeypadAsterisk;
public const CorsairLedId KeypadMinus = CorsairLedId.KeypadMinus;
public const CorsairLedId KeypadPlus = CorsairLedId.KeypadPlus;
public const CorsairLedId KeypadEnter = CorsairLedId.KeypadEnter;
public const CorsairLedId Keypad7 = CorsairLedId.Keypad7;
public const CorsairLedId Keypad8 = CorsairLedId.Keypad8;
public const CorsairLedId Keypad9 = CorsairLedId.Keypad9;
public const CorsairLedId KeypadComma = CorsairLedId.KeypadComma;
public const CorsairLedId Keypad4 = CorsairLedId.Keypad4;
public const CorsairLedId Keypad5 = CorsairLedId.Keypad5;
public const CorsairLedId Keypad6 = CorsairLedId.Keypad6;
public const CorsairLedId Keypad1 = CorsairLedId.Keypad1;
public const CorsairLedId Keypad2 = CorsairLedId.Keypad2;
public const CorsairLedId Keypad3 = CorsairLedId.Keypad3;
public const CorsairLedId Keypad0 = CorsairLedId.Keypad0;
public const CorsairLedId KeypadPeriodAndDelete = CorsairLedId.KeypadPeriodAndDelete;
public const CorsairLedId G1 = CorsairLedId.G1;
public const CorsairLedId G2 = CorsairLedId.G2;
public const CorsairLedId G3 = CorsairLedId.G3;
public const CorsairLedId G4 = CorsairLedId.G4;
public const CorsairLedId G5 = CorsairLedId.G5;
public const CorsairLedId G6 = CorsairLedId.G6;
public const CorsairLedId G7 = CorsairLedId.G7;
public const CorsairLedId G8 = CorsairLedId.G8;
public const CorsairLedId G9 = CorsairLedId.G9;
public const CorsairLedId G10 = CorsairLedId.G10;
public const CorsairLedId VolumeUp = CorsairLedId.VolumeUp;
public const CorsairLedId VolumeDown = CorsairLedId.VolumeDown;
public const CorsairLedId MR = CorsairLedId.MR;
public const CorsairLedId M1 = CorsairLedId.M1;
public const CorsairLedId M2 = CorsairLedId.M2;
public const CorsairLedId M3 = CorsairLedId.M3;
public const CorsairLedId G11 = CorsairLedId.G11;
public const CorsairLedId G12 = CorsairLedId.G12;
public const CorsairLedId G13 = CorsairLedId.G13;
public const CorsairLedId G14 = CorsairLedId.G14;
public const CorsairLedId G15 = CorsairLedId.G15;
public const CorsairLedId G16 = CorsairLedId.G16;
public const CorsairLedId G17 = CorsairLedId.G17;
public const CorsairLedId G18 = CorsairLedId.G18;
public const CorsairLedId International5 = CorsairLedId.International5;
public const CorsairLedId International4 = CorsairLedId.International4;
public const CorsairLedId Fn = CorsairLedId.Fn;
public const CorsairLedId Logo = CorsairLedId.Logo;
public const CorsairLedId Lightbar1 = CorsairLedId.Lightbar1;
public const CorsairLedId Lightbar2 = CorsairLedId.Lightbar2;
public const CorsairLedId Lightbar3 = CorsairLedId.Lightbar3;
public const CorsairLedId Lightbar4 = CorsairLedId.Lightbar4;
public const CorsairLedId Lightbar5 = CorsairLedId.Lightbar5;
public const CorsairLedId Lightbar6 = CorsairLedId.Lightbar6;
public const CorsairLedId Lightbar7 = CorsairLedId.Lightbar7;
public const CorsairLedId Lightbar8 = CorsairLedId.Lightbar8;
public const CorsairLedId Lightbar9 = CorsairLedId.Lightbar9;
public const CorsairLedId Lightbar10 = CorsairLedId.Lightbar10;
public const CorsairLedId Lightbar11 = CorsairLedId.Lightbar11;
public const CorsairLedId Lightbar12 = CorsairLedId.Lightbar12;
public const CorsairLedId Lightbar13 = CorsairLedId.Lightbar13;
public const CorsairLedId Lightbar14 = CorsairLedId.Lightbar14;
public const CorsairLedId Lightbar15 = CorsairLedId.Lightbar15;
public const CorsairLedId Lightbar16 = CorsairLedId.Lightbar16;
public const CorsairLedId Lightbar17 = CorsairLedId.Lightbar17;
public const CorsairLedId Lightbar18 = CorsairLedId.Lightbar18;
public const CorsairLedId Lightbar19 = CorsairLedId.Lightbar19;
}
}

View File

@ -1,6 +1,8 @@
// ReSharper disable InconsistentNaming
// ReSharper disable UnusedMember.Global
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
namespace CUE.NET.Devices.Keyboard.Enums
{
/// <summary>

View File

@ -1,80 +0,0 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System.Linq;
using CUE.NET.Devices.Keyboard.Enums;
using CUE.NET.Devices.Keyboard.Keys;
namespace CUE.NET.Devices.Keyboard.Extensions
{
/// <summary>
/// Offers some extensions and helper-methods for keygroup related things.
/// </summary>
public static class KeyGroupExtension
{
/// <summary>
/// Converts the given <see cref="BaseKeyGroup" /> to a <see cref="ListKeyGroup" />.
/// </summary>
/// <param name="keyGroup">The <see cref="BaseKeyGroup" /> to convert.</param>
/// <returns>The converted <see cref="ListKeyGroup" />.</returns>
public static ListKeyGroup ToSimpleKeyGroup(this BaseKeyGroup keyGroup)
{
ListKeyGroup simpleKeyGroup = keyGroup as ListKeyGroup;
if (simpleKeyGroup == null)
{
bool wasAttached = keyGroup.Detach();
simpleKeyGroup = new ListKeyGroup(keyGroup.Keyboard, wasAttached, keyGroup.Keys.ToArray()) { Brush = keyGroup.Brush };
}
return simpleKeyGroup;
}
/// <summary>
/// Returns a new <see cref="ListKeyGroup" /> which contains all keys from the given keygroup excluding the specified ones.
/// </summary>
/// <param name="keyGroup">The base keygroup.</param>
/// <param name="keyIds">The ids of the keys to exclude.</param>
/// <returns>The new <see cref="ListKeyGroup" />.</returns>
public static ListKeyGroup Exclude(this BaseKeyGroup keyGroup, params CorsairKeyboardKeyId[] keyIds)
{
ListKeyGroup simpleKeyGroup = keyGroup.ToSimpleKeyGroup();
foreach (CorsairKeyboardKeyId keyId in keyIds)
simpleKeyGroup.RemoveKey(keyId);
return simpleKeyGroup;
}
/// <summary>
/// Returns a new <see cref="ListKeyGroup" /> which contains all keys from the given keygroup excluding the specified ones.
/// </summary>
/// <param name="keyGroup">The base keygroup.</param>
/// <param name="keyIds">The keys to exclude.</param>
/// <returns>The new <see cref="ListKeyGroup" />.</returns>
public static ListKeyGroup Exclude(this BaseKeyGroup keyGroup, params CorsairKey[] keyIds)
{
ListKeyGroup simpleKeyGroup = keyGroup.ToSimpleKeyGroup();
foreach (CorsairKey key in keyIds)
simpleKeyGroup.RemoveKey(key);
return simpleKeyGroup;
}
// ReSharper disable once UnusedMethodReturnValue.Global
/// <summary>
/// Attaches the given keygroup to the keyboard.
/// </summary>
/// <param name="keyGroup">The keygroup to attach.</param>
/// <returns><c>true</c> if the keygroup could be attached; otherwise, <c>false</c>.</returns>
public static bool Attach(this BaseKeyGroup keyGroup)
{
return keyGroup.Keyboard?.AttachKeyGroup(keyGroup) ?? false;
}
/// <summary>
/// Detaches the given keygroup from the keyboard.
/// </summary>
/// <param name="keyGroup">The keygroup to attach.</param>
/// <returns><c>true</c> if the keygroup could be detached; otherwise, <c>false</c>.</returns>
public static bool Detach(this BaseKeyGroup keyGroup)
{
return keyGroup.Keyboard?.DetachKeyGroup(keyGroup) ?? false;
}
}
}

View File

@ -1,71 +0,0 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Keyboard.Extensions;
namespace CUE.NET.Devices.Keyboard.Keys
{
/// <summary>
/// Represents a basic keygroup.
/// </summary>
public abstract class BaseKeyGroup : IKeyGroup
{
#region Properties & Fields
/// <summary>
/// Gets the keyboard this keygroup belongs to.
/// </summary>
internal CorsairKeyboard Keyboard { get; }
/// <summary>
/// Gets a read-only collection containing the keys from this group.
/// </summary>
public IEnumerable<CorsairKey> Keys => new ReadOnlyCollection<CorsairKey>(GetGroupKeys());
/// <summary>
/// Gets or sets the brush which should be drawn over this group.
/// </summary>
public IBrush Brush { get; set; }
/// <summary>
/// Gets or sets the z-index of this keygroup to allow ordering them before drawing. (lowest first) (default: 0)
/// </summary>
public int ZIndex { get; set; } = 0;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="BaseKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="autoAttach">Specifies whether this group should be automatically attached or not.</param>
protected BaseKeyGroup(CorsairKeyboard keyboard, bool autoAttach = true)
{
this.Keyboard = keyboard;
if (autoAttach)
this.Attach();
}
#endregion
#region Methods
public IEnumerable<CorsairLed> GetLeds()
{
return GetGroupKeys().Select(x => x.Led);
}
/// <summary>
/// Gets a list containing the keys from this group.
/// </summary>
/// <returns>The list containing the keys.</returns>
protected abstract IList<CorsairKey> GetGroupKeys();
#endregion
}
}

View File

@ -1,51 +0,0 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
using System.Drawing;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Keyboard.Enums;
namespace CUE.NET.Devices.Keyboard.Keys
{
/// <summary>
/// Represents a key of a corsair keyboard.
/// </summary>
public class CorsairKey
{
#region Properties & Fields
/// <summary>
/// Gets the key-ID of the key.
/// </summary>
public CorsairKeyboardKeyId KeyId { get; }
/// <summary>
/// Gets the LED of the key.
/// </summary>
public CorsairLed Led { get; }
/// <summary>
/// Gets a rectangle representing the physical location of the key.
/// </summary>
public RectangleF KeyRectangle { get; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="CorsairKey"/> class.
/// </summary>
/// <param name="keyId">The key-ID of the key.</param>
/// <param name="led">The LED of the key.</param>
/// <param name="keyRectangle">The rectangle representing the physical location of the key.</param>
internal CorsairKey(CorsairKeyboardKeyId keyId, CorsairLed led, RectangleF keyRectangle)
{
this.KeyId = keyId;
this.Led = led;
this.KeyRectangle = keyRectangle;
}
#endregion
}
}

View File

@ -1,246 +0,0 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System.Collections.Generic;
using CUE.NET.Devices.Keyboard.Enums;
namespace CUE.NET.Devices.Keyboard.Keys
{
/// <summary>
/// Represents a keygroup containing arbitrary keys.
/// </summary>
public class ListKeyGroup : BaseKeyGroup
{
#region Properties & Fields
/// <summary>
/// Gets the list containing the keys of this keygroup.
/// </summary>
protected IList<CorsairKey> GroupKeys { get; } = new List<CorsairKey>();
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ListKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="autoAttach">Specifies whether this keygroup should be automatically attached or not.</param>
public ListKeyGroup(CorsairKeyboard keyboard, bool autoAttach = true)
: base(keyboard, autoAttach)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="ListKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="keys">The initial keys of this keygroup.</param>
public ListKeyGroup(CorsairKeyboard keyboard, params CorsairKey[] keys)
: this(keyboard, true, keys)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="ListKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="keys">The initial keys of this keygroup.</param>
public ListKeyGroup(CorsairKeyboard keyboard, IEnumerable<CorsairKey> keys)
: this(keyboard, true, keys)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="ListKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="autoAttach">Specifies whether this keygroup should be automatically attached or not.</param>
/// <param name="keys">The initial keys of this keygroup.</param>
public ListKeyGroup(CorsairKeyboard keyboard, bool autoAttach, IEnumerable<CorsairKey> keys)
: base(keyboard, autoAttach)
{
AddKeys(keys);
}
/// <summary>
/// Initializes a new instance of the <see cref="ListKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="autoAttach">Specifies whether this keygroup should be automatically attached or not.</param>
/// <param name="keys">The initial keys of this keygroup.</param>
public ListKeyGroup(CorsairKeyboard keyboard, bool autoAttach, params CorsairKey[] keys)
: base(keyboard, autoAttach)
{
AddKeys(keys);
}
/// <summary>
/// Initializes a new instance of the <see cref="ListKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="keys">The IDs of the initial keys of this keygroup.</param>
public ListKeyGroup(CorsairKeyboard keyboard, params CorsairKeyboardKeyId[] keys)
: this(keyboard, true, keys)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="ListKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="keys">The IDs of the initial keys of this keygroup.</param>
public ListKeyGroup(CorsairKeyboard keyboard, IEnumerable<CorsairKeyboardKeyId> keys)
: this(keyboard, true, keys)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="ListKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="autoAttach">Specifies whether this keygroup should be automatically attached or not.</param>
/// <param name="keys">The IDs of the initial keys of this keygroup.</param>
public ListKeyGroup(CorsairKeyboard keyboard, bool autoAttach, params CorsairKeyboardKeyId[] keys)
: base(keyboard, autoAttach)
{
AddKeys(keys);
}
/// <summary>
/// Initializes a new instance of the <see cref="ListKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="autoAttach">Specifies whether this keygroup should be automatically attached or not.</param>
/// <param name="keys">The IDs of the initial keys of this keygroup.</param>
public ListKeyGroup(CorsairKeyboard keyboard, bool autoAttach, IEnumerable<CorsairKeyboardKeyId> keys)
: base(keyboard, autoAttach)
{
AddKeys(keys);
}
#endregion
#region Methods
/// <summary>
/// Adds the given key(s) to the keygroup.
/// </summary>
/// <param name="keys">The key(s) to add.</param>
public void AddKey(params CorsairKey[] keys)
{
AddKeys(keys);
}
/// <summary>
/// Adds the given key(s) to the keygroup.
/// </summary>
/// <param name="keyIds">The ID(s) of the key(s) to add.</param>
public void AddKey(params CorsairKeyboardKeyId[] keyIds)
{
AddKeys(keyIds);
}
/// <summary>
/// Adds the given keys to the keygroup.
/// </summary>
/// <param name="keys">The keys to add.</param>
public void AddKeys(IEnumerable<CorsairKey> keys)
{
if (keys != null)
foreach (CorsairKey key in keys)
if (key != null && !ContainsKey(key))
GroupKeys.Add(key);
}
/// <summary>
/// Adds the given keys to the keygroup.
/// </summary>
/// <param name="keyIds">The IDs of the keys to add.</param>
public void AddKeys(IEnumerable<CorsairKeyboardKeyId> keyIds)
{
if (keyIds != null)
foreach (CorsairKeyboardKeyId keyId in keyIds)
AddKey(Keyboard[keyId]);
}
/// <summary>
/// Removes the given key(s) from the keygroup.
/// </summary>
/// <param name="keys">The key(s) to remove.</param>
public void RemoveKey(params CorsairKey[] keys)
{
RemoveKeys(keys);
}
/// <summary>
/// Removes the given key(s) from the keygroup.
/// </summary>
/// <param name="keyIds">The ID(s) of the key(s) to remove.</param>
public void RemoveKey(params CorsairKeyboardKeyId[] keyIds)
{
RemoveKeys(keyIds);
}
/// <summary>
/// Removes the given keys from the keygroup.
/// </summary>
/// <param name="keys">The keys to remove.</param>
public void RemoveKeys(IEnumerable<CorsairKey> keys)
{
if (keys != null)
foreach (CorsairKey key in keys)
if (key != null)
GroupKeys.Remove(key);
}
/// <summary>
/// Removes the given keys from the keygroup.
/// </summary>
/// <param name="keyIds">The IDs of the keys to remove.</param>
public void RemoveKeys(IEnumerable<CorsairKeyboardKeyId> keyIds)
{
if (keyIds != null)
foreach (CorsairKeyboardKeyId keyId in keyIds)
RemoveKey(Keyboard[keyId]);
}
/// <summary>
/// Checks if a given key is contained by this keygroup.
/// </summary>
/// <param name="key">The key which should be checked.</param>
/// <returns><c>true</c> if the key is contained by this keygroup; otherwise, <c>false</c>.</returns>
public bool ContainsKey(CorsairKey key)
{
return key != null && GroupKeys.Contains(key);
}
/// <summary>
/// Checks if a given key is contained by this keygroup.
/// </summary>
/// <param name="keyId">The ID of the key which should be checked.</param>
/// <returns><c>true</c> if the key is contained by this keygroup; otherwise, <c>false</c>.</returns>
public bool ContainsKey(CorsairKeyboardKeyId keyId)
{
return ContainsKey(Keyboard[keyId]);
}
/// <summary>
/// Merges the keys from the given keygroup in this keygroup.
/// </summary>
/// <param name="groupToMerge">The keygroup to merge.</param>
public void MergeKeys(IKeyGroup groupToMerge)
{
foreach (CorsairKey key in groupToMerge.Keys)
if (!GroupKeys.Contains(key))
GroupKeys.Add(key);
}
/// <summary>
/// Gets a list containing the keys from this group.
/// </summary>
/// <returns>The list containing the keys.</returns>
protected override IList<CorsairKey> GetGroupKeys()
{
return GroupKeys;
}
#endregion
}
}

View File

@ -1,110 +0,0 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
// ReSharper disable UnusedMember.Global
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using CUE.NET.Devices.Keyboard.Enums;
using CUE.NET.Helper;
namespace CUE.NET.Devices.Keyboard.Keys
{
/// <summary>
/// Represents a keygroup containing keys which physically lay inside a rectangle.
/// </summary>
public class RectangleKeyGroup : BaseKeyGroup
{
#region Properties & Fields
private IList<CorsairKey> _keyCache;
private RectangleF _rectangle;
/// <summary>
/// Gets or sets the rectangle the keys should be taken from.
/// </summary>
public RectangleF Rectangle
{
get { return _rectangle; }
set
{
_rectangle = value;
_keyCache = null;
}
}
/// <summary>
/// Gets or sets the minimal percentage overlay a key must have with the <see cref="Rectangle" /> to be taken into the keygroup.
/// </summary>
public float MinOverlayPercentage { get; set; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="RectangleKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="fromKey">They ID of the first key to calculate the rectangle of this keygroup from.</param>
/// <param name="toKey">They ID of the second key to calculate the rectangle of this keygroup from.</param>
/// <param name="minOverlayPercentage">(optional) The minimal percentage overlay a key must have with the <see cref="Rectangle" /> to be taken into the keygroup. (default: 0.5f)</param>
/// <param name="autoAttach">(optional) Specifies whether this group should be automatically attached or not. (default: true)</param>
public RectangleKeyGroup(CorsairKeyboard keyboard, CorsairKeyboardKeyId fromKey, CorsairKeyboardKeyId toKey, float minOverlayPercentage = 0.5f, bool autoAttach = true)
: this(keyboard, keyboard[fromKey], keyboard[toKey], minOverlayPercentage, autoAttach)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="RectangleKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="fromKey">They first key to calculate the rectangle of this keygroup from.</param>
/// <param name="toKey">They second key to calculate the rectangle of this keygroup from.</param>
/// <param name="minOverlayPercentage">(optional) The minimal percentage overlay a key must have with the <see cref="Rectangle" /> to be taken into the keygroup. (default: 0.5f)</param>
/// <param name="autoAttach">(optional) Specifies whether this group should be automatically attached or not. (default: true)</param>
public RectangleKeyGroup(CorsairKeyboard keyboard, CorsairKey fromKey, CorsairKey toKey, float minOverlayPercentage = 0.5f, bool autoAttach = true)
: this(keyboard, RectangleHelper.CreateRectangleFromRectangles(fromKey.KeyRectangle, toKey.KeyRectangle), minOverlayPercentage, autoAttach)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="RectangleKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="fromPoint">They first point to calculate the rectangle of this keygroup from.</param>
/// <param name="toPoint">They second point to calculate the rectangle of this keygroup from.</param>
/// <param name="minOverlayPercentage">(optional) The minimal percentage overlay a key must have with the <see cref="Rectangle" /> to be taken into the keygroup. (default: 0.5f)</param>
/// <param name="autoAttach">(optional) Specifies whether this group should be automatically attached or not. (default: true)</param>
public RectangleKeyGroup(CorsairKeyboard keyboard, PointF fromPoint, PointF toPoint, float minOverlayPercentage = 0.5f, bool autoAttach = true)
: this(keyboard, RectangleHelper.CreateRectangleFromPoints(fromPoint, toPoint), minOverlayPercentage, autoAttach)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="RectangleKeyGroup"/> class.
/// </summary>
/// <param name="keyboard">The keyboard this keygroup belongs to.</param>
/// <param name="rectangle">The rectangle of this keygroup.</param>
/// <param name="minOverlayPercentage">(optional) The minimal percentage overlay a key must have with the <see cref="Rectangle" /> to be taken into the keygroup. (default: 0.5f)</param>
/// <param name="autoAttach">(optional) Specifies whether this group should be automatically attached or not. (default: true)</param>
public RectangleKeyGroup(CorsairKeyboard keyboard, RectangleF rectangle, float minOverlayPercentage = 0.5f, bool autoAttach = true)
: base(keyboard, autoAttach)
{
this.Rectangle = rectangle;
this.MinOverlayPercentage = minOverlayPercentage;
}
#endregion
#region Methods
/// <summary>
/// Gets a list containing the keys from this group.
/// </summary>
/// <returns>The list containing the keys.</returns>
protected override IList<CorsairKey> GetGroupKeys()
{
return _keyCache ?? (_keyCache = Keyboard.Where(x => RectangleHelper.CalculateIntersectPercentage(x.KeyRectangle, Rectangle) >= MinOverlayPercentage).ToList());
}
#endregion
}
}

View File

@ -2,58 +2,31 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable UnusedMember.Global
using System.Collections;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Devices.Mouse.Enums;
using CUE.NET.Effects;
using CUE.NET.Exceptions;
using CUE.NET.Native;
namespace CUE.NET.Devices.Mouse
{
/// <summary>
/// Represents the SDK for a corsair mouse.
/// </summary>
public class CorsairMouse : AbstractCueDevice, IEnumerable<CorsairLed>
public class CorsairMouse : AbstractCueDevice
{
#region Properties & Fields
#region Indexer
/// <summary>
/// Gets the <see cref="CorsairLed" /> with the specified ID.
/// </summary>
/// <param name="ledId">The ID of the LED to get.</param>
/// <returns>The LED with the specified ID.</returns>
public CorsairLed this[CorsairMouseLedId ledId]
{
get
{
CorsairLed led;
return base.Leds.TryGetValue((int)ledId, out led) ? led : null;
}
}
#endregion
/// <summary>
/// Gets specific information provided by CUE for the mouse.
/// </summary>
public CorsairMouseDeviceInfo MouseDeviceInfo { get; }
/// <summary>
/// Gets a value indicating if the mouse has an active effect to deal with or not.
/// </summary>
protected override bool HasEffect => false;
/// <summary>
/// Gets a read-only collection containing all LEDs of the mouse.
/// </summary>
public new IEnumerable<CorsairLed> Leds => new ReadOnlyCollection<CorsairLed>(base.Leds.Values.ToList());
#endregion
#region Constructors
@ -66,66 +39,52 @@ namespace CUE.NET.Devices.Mouse
: base(info)
{
this.MouseDeviceInfo = info;
InitializeLeds();
}
#endregion
#region Methods
protected override void ApplyEffect(IEffect effect)
{
//TODO DarthAffe 18.10.2015: How should brushes be applied to mice?
foreach (CorsairLed led in effect.LedList)
led.Color = effect.EffectBrush.GetColorAtPoint(new RectangleF(0, 0, 2, 2), new PointF(1, 1));
}
private void InitializeLeds()
/// <summary>
/// Initializes the mouse.
/// </summary>
public override void Initialize()
{
// Glaive is a special flake that doesn't follow the default layout
if (MouseDeviceInfo.Model == "GLAIVE RGB")
{
InitializeLed(CorsairMouseLedId.B1, new RectangleF(0, 0, 1, 1)); // Logo
InitializeLed(CorsairMouseLedId.B2, new RectangleF(2, 0, 1, 1)); // Front
InitializeLed(CorsairMouseLedId.B5, new RectangleF(3, 0, 1, 1)); // Sides
return;
}
switch (MouseDeviceInfo.PhysicalLayout)
{
case CorsairPhysicalMouseLayout.Zones1:
GetLed((int)CorsairMouseLedId.B1);
InitializeLed(CorsairMouseLedId.B1, new RectangleF(0, 0, 1, 1));
break;
case CorsairPhysicalMouseLayout.Zones2:
GetLed((int)CorsairMouseLedId.B1);
GetLed((int)CorsairMouseLedId.B2);
InitializeLed(CorsairMouseLedId.B1, new RectangleF(0, 0, 1, 1));
InitializeLed(CorsairMouseLedId.B2, new RectangleF(1, 0, 1, 1));
break;
case CorsairPhysicalMouseLayout.Zones3:
GetLed((int)CorsairMouseLedId.B1);
GetLed((int)CorsairMouseLedId.B2);
GetLed((int)CorsairMouseLedId.B3);
InitializeLed(CorsairMouseLedId.B1, new RectangleF(0, 0, 1, 1));
InitializeLed(CorsairMouseLedId.B2, new RectangleF(1, 0, 1, 1));
InitializeLed(CorsairMouseLedId.B3, new RectangleF(2, 0, 1, 1));
break;
case CorsairPhysicalMouseLayout.Zones4:
GetLed((int)CorsairMouseLedId.B1);
GetLed((int)CorsairMouseLedId.B2);
GetLed((int)CorsairMouseLedId.B3);
GetLed((int)CorsairMouseLedId.B4);
InitializeLed(CorsairMouseLedId.B1, new RectangleF(0, 0, 1, 1));
InitializeLed(CorsairMouseLedId.B2, new RectangleF(1, 0, 1, 1));
InitializeLed(CorsairMouseLedId.B3, new RectangleF(2, 0, 1, 1));
InitializeLed(CorsairMouseLedId.B4, new RectangleF(3, 0, 1, 1));
break;
default:
throw new WrapperException($"Can't initial mouse with layout '{MouseDeviceInfo.PhysicalLayout}'");
}
base.Initialize();
}
#region IEnumerable
/// <summary>
/// Returns an enumerator that iterates over all LEDs of the mouse.
/// </summary>
/// <returns>An enumerator for all LDS of the mouse.</returns>
public IEnumerator<CorsairLed> GetEnumerator()
{
return Leds.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#endregion
}
}

View File

@ -1,17 +0,0 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable InconsistentNaming
namespace CUE.NET.Devices.Mouse.Enums
{
/// <summary>
/// Contains list of all LEDs available for corsair mice.
/// </summary>
public enum CorsairMouseLedId
{
Invalid = 0,
B1 = 148,
B2 = 149,
B3 = 150,
B4 = 151
}
}

View File

@ -0,0 +1,30 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable InconsistentNaming
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.Devices.Mouse.Enums
{
/// <summary>
/// Contains list of all LEDs available for corsair mice.
/// </summary>
public static class CorsairMouseKeyId
{
public const CorsairKeyId Invalid = CorsairKeyId.Invalid;
public const CorsairKeyId M1 = CorsairKeyId.M1;
public const CorsairKeyId M2 = CorsairKeyId.M2;
public const CorsairKeyId M3 = CorsairKeyId.M3;
public const CorsairKeyId M4 = CorsairKeyId.M4;
public const CorsairKeyId M5 = CorsairKeyId.M5;
public const CorsairKeyId M6 = CorsairKeyId.M6;
public const CorsairKeyId M7 = CorsairKeyId.M7;
public const CorsairKeyId M8 = CorsairKeyId.M8;
public const CorsairKeyId M9 = CorsairKeyId.M9;
public const CorsairKeyId M10 = CorsairKeyId.M10;
public const CorsairKeyId M11 = CorsairKeyId.M11;
public const CorsairKeyId M12 = CorsairKeyId.M12;
}
}

View File

@ -0,0 +1,23 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable InconsistentNaming
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.Devices.Mouse.Enums
{
/// <summary>
/// Contains list of all LEDs available for corsair mice.
/// </summary>
public static class CorsairMouseLedId
{
public const CorsairLedId Invalid = CorsairLedId.Invalid;
public const CorsairLedId B1 = CorsairLedId.B1;
public const CorsairLedId B2 = CorsairLedId.B2;
public const CorsairLedId B3 = CorsairLedId.B3;
public const CorsairLedId B4 = CorsairLedId.B4;
public const CorsairLedId B5 = CorsairLedId.B5;
public const CorsairLedId B6 = CorsairLedId.B6;
}
}

View File

@ -0,0 +1,91 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Exceptions;
using CUE.NET.Native;
namespace CUE.NET.Devices.Mousemat
{
/// <summary>
/// Represents the SDK for a corsair mousemat.
/// </summary>
public class CorsairMousemat : AbstractCueDevice
{
#region Properties & Fields
/// <summary>
/// Gets specific information provided by CUE for the mousemat.
/// </summary>
public CorsairMousematDeviceInfo MousematDeviceInfo { get; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="CorsairMousemat"/> class.
/// </summary>
/// <param name="info">The specific information provided by CUE for the mousemat</param>
internal CorsairMousemat(CorsairMousematDeviceInfo info)
: base(info)
{
this.MousematDeviceInfo = info;
}
#endregion
#region Methods
/// <summary>
/// Initializes the mousemat.
/// </summary>
public override void Initialize()
{
int deviceCount = _CUESDK.CorsairGetDeviceCount();
// Get mousemat device index
int mousematIndex = -1;
for (int i = 0; i < deviceCount; i++)
{
_CorsairDeviceInfo nativeDeviceInfo = (_CorsairDeviceInfo)Marshal.PtrToStructure(_CUESDK.CorsairGetDeviceInfo(i), typeof(_CorsairDeviceInfo));
GenericDeviceInfo info = new GenericDeviceInfo(nativeDeviceInfo);
if (info.Type != CorsairDeviceType.Mousemat)
continue;
mousematIndex = i;
break;
}
if (mousematIndex < 0)
throw new WrapperException("Can't determine mousemat device index");
_CorsairLedPositions nativeLedPositions = (_CorsairLedPositions)Marshal.PtrToStructure(_CUESDK.CorsairGetLedPositionsByDeviceIndex(mousematIndex), typeof(_CorsairLedPositions));
int structSize = Marshal.SizeOf(typeof(_CorsairLedPosition));
IntPtr ptr = nativeLedPositions.pLedPosition;
// Put the positions in an array for sorting later on
List<_CorsairLedPosition> positions = new List<_CorsairLedPosition>();
for (int i = 0; i < nativeLedPositions.numberOfLed; i++)
{
_CorsairLedPosition ledPosition = (_CorsairLedPosition)Marshal.PtrToStructure(ptr, typeof(_CorsairLedPosition));
ptr = new IntPtr(ptr.ToInt64() + structSize);
positions.Add(ledPosition);
}
// Sort for easy iteration by clients
foreach (_CorsairLedPosition ledPosition in positions.OrderBy(p => p.ledId))
InitializeLed(ledPosition.ledId, new RectangleF((float)ledPosition.left, (float)ledPosition.top, (float)ledPosition.width, (float)ledPosition.height));
base.Initialize();
}
#endregion
}
}

View File

@ -0,0 +1,26 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
using CUE.NET.Devices.Generic;
using CUE.NET.Native;
namespace CUE.NET.Devices.Mousemat
{
/// <summary>
/// Represents specific information for a CUE Mousemat.
/// </summary>
public class CorsairMousematDeviceInfo : GenericDeviceInfo
{
#region Constructors
/// <summary>
/// Internal constructor of managed <see cref="CorsairMousematDeviceInfo" />.
/// </summary>
/// <param name="nativeInfo">The native <see cref="_CorsairDeviceInfo" />-struct</param>
internal CorsairMousematDeviceInfo(_CorsairDeviceInfo nativeInfo)
: base(nativeInfo)
{ }
#endregion
}
}

View File

@ -0,0 +1,32 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable InconsistentNaming
#pragma warning disable 1591 // Missing XML comment for publicly visible type or member
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.Devices.Mousemat.Enums
{
/// <summary>
/// Contains list of all LEDs available for corsair mousemats.
/// </summary>
public static class CorsairMousematLedId
{
public const CorsairLedId Invalid = CorsairLedId.Invalid;
public const CorsairLedId Zone1 = CorsairLedId.Zone1;
public const CorsairLedId Zone2 = CorsairLedId.Zone2;
public const CorsairLedId Zone3 = CorsairLedId.Zone3;
public const CorsairLedId Zone4 = CorsairLedId.Zone4;
public const CorsairLedId Zone5 = CorsairLedId.Zone5;
public const CorsairLedId Zone6 = CorsairLedId.Zone6;
public const CorsairLedId Zone7 = CorsairLedId.Zone7;
public const CorsairLedId Zone8 = CorsairLedId.Zone8;
public const CorsairLedId Zone9 = CorsairLedId.Zone9;
public const CorsairLedId Zone10 = CorsairLedId.Zone10;
public const CorsairLedId Zone11 = CorsairLedId.Zone11;
public const CorsairLedId Zone12 = CorsairLedId.Zone12;
public const CorsairLedId Zone13 = CorsairLedId.Zone13;
public const CorsairLedId Zone14 = CorsairLedId.Zone14;
public const CorsairLedId Zone15 = CorsairLedId.Zone15;
}
}

View File

@ -0,0 +1,71 @@
// ReSharper disable MemberCanBePrivate.Global
using CUE.NET.Brushes;
namespace CUE.NET.Effects
{
/// <summary>
/// Represents a basic effect targeting an <see cref="IBrush"/>.
/// </summary>
public abstract class AbstractBrushEffect<T> : IEffect<IBrush>
where T : IBrush
{
#region Properties & Fields
/// <summary>
/// Gets or sets if this effect has finished all of his work.
/// </summary>
public bool IsDone { get; protected set; }
/// <summary>
/// Gets the <see cref="IBrush"/> this effect is targeting.
/// </summary>
protected T Brush { get; set; }
#endregion
#region Methods
/// <summary>
/// Updates the effect.
/// </summary>
/// <param name="deltaTime">The elapsed time (in seconds) since the last update.</param>
public abstract void Update(float deltaTime);
/// <summary>
/// Checks if the effect can be applied to the target object.
/// </summary>
/// <param name="target">The <see cref="IEffectTarget{T}"/> this effect is attached to.</param>
/// <returns><c>true</c> if the effect can be attached; otherwise, <c>false</c>.</returns>
public virtual bool CanBeAppliedTo(IBrush target)
{
return target is T;
}
/// <summary>
/// Hook which is called when the effect is attached to a device.
/// </summary>
/// <param name="target">The <see cref="IBrush"/> this effect is attached to.</param>
public virtual void OnAttach(IBrush target)
{
Brush = (T)target;
}
/// <summary>
/// Hook which is called when the effect is detached from a device.
/// </summary>
/// <param name="target">The <see cref="IBrush"/> this effect is detached from.</param>
public virtual void OnDetach(IBrush target)
{
Brush = default(T);
}
#endregion
}
/// <summary>
/// Represents a basic effect targeting an <see cref="IBrush"/>.
/// </summary>
public abstract class AbstractBrushEffect : AbstractBrushEffect<IBrush>
{ }
}

View File

@ -1,60 +0,0 @@
// ReSharper disable MemberCanBePrivate.Global
using System.Collections.Generic;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic;
namespace CUE.NET.Effects
{
/// <summary>
/// Represents a basic effect.
/// </summary>
public abstract class AbstractEffect : IEffect
{
#region Properties & Fields
/// <summary>
/// Gets or sets the list of LEDSs to which the effect applies.
/// </summary>
public IEnumerable<CorsairLed> LedList { get; set; }
/// <summary>
/// Gets the brush which is drawn by the effect.
/// </summary>
public abstract IBrush EffectBrush { get; }
/// <summary>
/// Gets or sets the z-index of the brush to allow ordering them before drawing. (lowest first) (default: 0)
/// </summary>
public int ZIndex { get; set; } = 0;
/// <summary>
/// Gets or sets if this effect has finished all of his work.
/// </summary>
public bool IsDone { get; protected set; }
#endregion
#region Methods
/// <summary>
/// Updates the effect.
/// </summary>
/// <param name="deltaTime">The elapsed time (in seconds) since the last update.</param>
public abstract void Update(float deltaTime);
/// <summary>
/// Hook which is called when the effect is attached to a device.
/// </summary>
public virtual void OnAttach()
{ }
/// <summary>
/// Hook which is called when the effect is detached from a device.
/// </summary>
public virtual void OnDetach()
{ }
#endregion
}
}

View File

@ -0,0 +1,99 @@
// ReSharper disable MemberCanBePrivate.Global
using System;
using System.Collections.Generic;
using System.Linq;
using CUE.NET.Exceptions;
namespace CUE.NET.Effects
{
/// <summary>
/// Represents an generic effect-target.
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class AbstractEffectTarget<T> : IEffectTarget<T>
where T : IEffectTarget<T>
{
#region Properties & Fields
/// <summary>
/// Gets a list of <see cref="EffectTimeContainer"/> storing the attached effects.
/// </summary>
protected IList<EffectTimeContainer> EffectTimes { get; } = new List<EffectTimeContainer>();
/// <summary>
/// Gets all <see cref="IEffect{T}" /> attached to this target.
/// </summary>
public IList<IEffect<T>> Effects => EffectTimes.Select(x => x.Effect).Cast<IEffect<T>>().ToList();
/// <summary>
/// Gets the strongly-typed target used for the effect.
/// </summary>
protected abstract T EffectTarget { get; }
#endregion
#region Methods
/// <summary>
/// Updates all effects added to this target.
/// </summary>
public virtual void UpdateEffects()
{
lock (Effects)
{
for (int i = EffectTimes.Count - 1; i >= 0; i--)
{
EffectTimeContainer effectTime = EffectTimes[i];
long currentTicks = DateTime.Now.Ticks;
float deltaTime;
if (effectTime.TicksAtLastUpdate < 0)
{
effectTime.TicksAtLastUpdate = currentTicks;
deltaTime = 0f;
}
else
deltaTime = (currentTicks - effectTime.TicksAtLastUpdate) / 10000000f;
effectTime.TicksAtLastUpdate = currentTicks;
effectTime.Effect.Update(deltaTime);
if (effectTime.Effect.IsDone)
EffectTimes.RemoveAt(i);
}
}
}
/// <summary>
/// Adds an affect.
/// </summary>
/// <param name="effect">The effect to add.</param>
public virtual void AddEffect(IEffect<T> effect)
{
if (EffectTimes.Any(x => x.Effect == effect)) return;
if (!effect.CanBeAppliedTo(EffectTarget))
throw new WrapperException($"Failed to add effect.\r\nThe effect of type '{effect.GetType()}' can't be applied to the target of type '{EffectTarget.GetType()}'.");
effect.OnAttach(EffectTarget);
EffectTimes.Add(new EffectTimeContainer(effect, -1));
}
/// <summary>
/// Removes an effect
/// </summary>
/// <param name="effect">The effect to remove.</param>
public virtual void RemoveEffect(IEffect<T> effect)
{
EffectTimeContainer effectTimeToRemove = EffectTimes.FirstOrDefault(x => x.Effect == effect);
if (effectTimeToRemove == null) return;
effect.OnDetach(EffectTarget);
EffectTimes.Remove(effectTimeToRemove);
}
#endregion
}
}

View File

@ -0,0 +1,73 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable UnusedMember.Global
using CUE.NET.Groups;
namespace CUE.NET.Effects
{
/// <summary>
/// Represents a basic effect targeting an <see cref="ILedGroup"/>.
/// </summary>
public abstract class AbstractLedGroupEffect<T> : IEffect<ILedGroup>
where T : ILedGroup
{
#region Properties & Fields
/// <summary>
/// Gets or sets if this effect has finished all of his work.
/// </summary>
public bool IsDone { get; protected set; }
/// <summary>
/// Gets the <see cref="ILedGroup"/> this effect is targeting.
/// </summary>
protected T LedGroup { get; set; }
#endregion
#region Methods
/// <summary>
/// Updates the effect.
/// </summary>
/// <param name="deltaTime">The elapsed time (in seconds) since the last update.</param>
public abstract void Update(float deltaTime);
/// <summary>
/// Checks if the effect can be applied to the target object.
/// </summary>
/// <param name="target">The <see cref="IEffectTarget{T}"/> this effect is attached to.</param>
/// <returns><c>true</c> if the effect can be attached; otherwise, <c>false</c>.</returns>
public virtual bool CanBeAppliedTo(ILedGroup target)
{
return target is T;
}
/// <summary>
/// Hook which is called when the effect is attached to a device.
/// </summary>
/// <param name="target">The <see cref="ILedGroup"/> this effect is attached to.</param>
public virtual void OnAttach(ILedGroup target)
{
LedGroup = (T)target;
}
/// <summary>
/// Hook which is called when the effect is detached from a device.
/// </summary>
/// <param name="target">The <see cref="ILedGroup"/> this effect is detached from.</param>
public virtual void OnDetach(ILedGroup target)
{
LedGroup = default(T);
}
#endregion
}
/// <summary>
/// Represents a basic effect targeting an <see cref="ILedGroup"/>.
/// </summary>
public abstract class AbstractLedGroupEffect : AbstractLedGroupEffect<ILedGroup>
{ }
}

View File

@ -13,18 +13,13 @@ namespace CUE.NET.Effects
/// <summary>
/// Gets or sets the wrapped effect.
/// </summary>
public IEffect Effect { get; set; }
public IEffect Effect { get; }
/// <summary>
/// Gets or sets the tick-count from the last time the effect was updated.
/// </summary>
public long TicksAtLastUpdate { get; set; }
/// <summary>
/// Gets the z-index of the effect.
/// </summary>
public int ZIndex => Effect?.ZIndex ?? 0;
#endregion
#region Constructors

View File

@ -3,7 +3,6 @@
// ReSharper disable UnusedMember.Global
using System;
using System.Drawing;
using CUE.NET.Brushes;
namespace CUE.NET.Effects
@ -11,37 +10,32 @@ namespace CUE.NET.Effects
/// <summary>
/// Represents an effect which allows to flash an brush by modifying his opacity.
/// </summary>
public class FlashEffect : AbstractEffect
public class FlashEffect : AbstractBrushEffect
{
#region Properties & Fields
/// <summary>
/// Gets the brush which is drawn by the effect.
/// </summary>
public override IBrush EffectBrush { get; }
/// <summary>
/// Gets or sets the attack-time (in seconds) of the effect. (default: 0.2f)<br />
/// This is close to a synthesizer envelope. (See <see cref="http://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope" /> as reference)
/// This is close to a synthesizer envelope. (See <see href="http://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope" /> as reference)
/// </summary>
public float Attack { get; set; } = 0.2f;
/// <summary>
/// Gets or sets the decay-time (in seconds) of the effect. (default: 0f)<br />
/// This is close to a synthesizer envelope. (See <see cref="http://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope" /> as reference)
/// This is close to a synthesizer envelope. (See <see href="http://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope" /> as reference)
/// </summary>
public float Decay { get; set; } = 0f;
/// <summary>
/// Gets or sets the sustain-time (in seconds) of the effect. (default: 0.3f)<br />
/// This is close to a synthesizer envelope. (See <see cref="http://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope" /> as reference)<br />
/// This is close to a synthesizer envelope. (See <see href="http://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope" /> as reference)<br />
/// Note that this value for naming reasons represents the time NOT the level.
/// </summary>
public float Sustain { get; set; } = 0.3f;
/// <summary>
/// Gets or sets the release-time (in seconds) of the effect. (default: 0.2f)<br />
/// This is close to a synthesizer envelope. (See <see cref="http://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope" /> as reference)
/// This is close to a synthesizer envelope. (See <see href="http://en.wikipedia.org/wiki/Synthesizer#ADSR_envelope" /> as reference)
/// </summary>
public float Release { get; set; } = 0.2f;
@ -71,27 +65,6 @@ namespace CUE.NET.Effects
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="FlashEffect"/> class.
/// </summary>
/// <param name="flashColor">The color from which a <see cref="SolidColorBrush" /> should be created and used by this effect.</param>
public FlashEffect(Color flashColor)
: this(new SolidColorBrush(flashColor))
{ }
/// <summary>
/// Initializes a new instance of the <see cref="FlashEffect"/> class.
/// </summary>
/// <param name="effectBrush">The brush which should be used by this effect,</param>
public FlashEffect(IBrush effectBrush)
{
this.EffectBrush = effectBrush;
}
#endregion
#region Methods
/// <summary>
@ -103,10 +76,11 @@ namespace CUE.NET.Effects
_currentPhaseValue -= deltaTime;
// Using ifs instead of a switch allows to skip phases with time 0.
// ReSharper disable InvertIf
if (_currentPhase == ADSRPhase.Attack)
if (_currentPhaseValue > 0f)
EffectBrush.Opacity = Math.Min(1f, (Attack - _currentPhaseValue) / Attack) * AttackValue;
Brush.Opacity = Math.Min(1f, (Attack - _currentPhaseValue) / Attack) * AttackValue;
else
{
_currentPhaseValue = Decay;
@ -115,7 +89,7 @@ namespace CUE.NET.Effects
if (_currentPhase == ADSRPhase.Decay)
if (_currentPhaseValue > 0f)
EffectBrush.Opacity = SustainValue + (Math.Min(1f, _currentPhaseValue / Decay) * (AttackValue - SustainValue));
Brush.Opacity = SustainValue + (Math.Min(1f, _currentPhaseValue / Decay) * (AttackValue - SustainValue));
else
{
_currentPhaseValue = Sustain;
@ -124,7 +98,7 @@ namespace CUE.NET.Effects
if (_currentPhase == ADSRPhase.Sustain)
if (_currentPhaseValue > 0f)
EffectBrush.Opacity = SustainValue;
Brush.Opacity = SustainValue;
else
{
_currentPhaseValue = Release;
@ -133,7 +107,7 @@ namespace CUE.NET.Effects
if (_currentPhase == ADSRPhase.Release)
if (_currentPhaseValue > 0f)
EffectBrush.Opacity = Math.Min(1f, _currentPhaseValue / Release) * SustainValue;
Brush.Opacity = Math.Min(1f, _currentPhaseValue / Release) * SustainValue;
else
{
_currentPhaseValue = Interval;
@ -142,7 +116,7 @@ namespace CUE.NET.Effects
if (_currentPhase == ADSRPhase.Pause)
if (_currentPhaseValue > 0f)
EffectBrush.Opacity = 0f;
Brush.Opacity = 0f;
else
{
if (++_repetitionCount >= Repetitions && Repetitions > 0)
@ -150,19 +124,21 @@ namespace CUE.NET.Effects
_currentPhaseValue = Attack;
_currentPhase = ADSRPhase.Attack;
}
// ReSharper restore InvertIf
}
/// <summary>
/// Resets the effect.
/// </summary>
public override void OnAttach()
public override void OnAttach(IBrush brush)
{
base.OnAttach();
base.OnAttach(brush);
_currentPhase = ADSRPhase.Attack;
_currentPhaseValue = Attack;
_repetitionCount = 0;
EffectBrush.Opacity = 0f;
brush.Opacity = 0f;
}
#endregion

View File

@ -1,9 +1,6 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable UnusedMemberInSuper.Global
using System.Collections.Generic;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic;
// ReSharper disable UnusedParameter.Global
namespace CUE.NET.Effects
{
@ -15,22 +12,7 @@ namespace CUE.NET.Effects
#region Properties & Fields
/// <summary>
/// Gets or sets the list of LEDs to which the effect applies.
/// </summary>
IEnumerable<CorsairLed> LedList { get; set; }
/// <summary>
/// Gets the brush which is drawn by the effect.
/// </summary>
IBrush EffectBrush { get; }
/// <summary>
/// Gets or sets the z-index of the effect to allow ordering them before drawing. (lowest first) (default: 0)
/// </summary>
int ZIndex { get; set; }
/// <summary>
/// Gets or sets if this effect has finished all of his work.
/// Gets if this effect has finished all of his work.
/// </summary>
bool IsDone { get; }
@ -44,15 +26,36 @@ namespace CUE.NET.Effects
/// <param name="deltaTime">The elapsed time (in seconds) since the last update.</param>
void Update(float deltaTime);
#endregion
}
/// <summary>
/// Represents a basic effect.
/// </summary>
/// <typeparam name="T">The type of <see cref="IEffectTarget{T}"/> this effect can be attached to.</typeparam>
public interface IEffect<in T> : IEffect
where T : IEffectTarget<T>
{
#region Methods
/// <summary>
/// Checks if the effect can be applied to the target object.
/// </summary>
/// <param name="target">The <see cref="IEffectTarget{T}"/> this effect is attached to.</param>
/// <returns><c>true</c> if the effect can be attached; otherwise, <c>false</c>.</returns>
bool CanBeAppliedTo(T target);
/// <summary>
/// Hook which is called when the effect is attached to a device.
/// </summary>
void OnAttach();
/// <param name="target">The <see cref="IEffectTarget{T}"/> this effect is attached to.</param>
void OnAttach(T target);
/// <summary>
/// Hook which is called when the effect is detached from a device.
/// </summary>
void OnDetach();
/// <param name="target">The <see cref="IEffectTarget{T}"/> this effect is detached from.</param>
void OnDetach(T target);
#endregion
}

44
Effects/IEffectTarget.cs Normal file
View File

@ -0,0 +1,44 @@
// ReSharper disable UnusedMember.Global
using System.Collections.Generic;
namespace CUE.NET.Effects
{
/// <summary>
/// Represents a basic effect-target.
/// </summary>
/// <typeparam name="T">The type this target represents.</typeparam>
public interface IEffectTarget<T>
where T : IEffectTarget<T>
{
#region Properties & Fields
/// <summary>
/// Gets a list of all active effects of this target.
/// </summary>
IList<IEffect<T>> Effects { get; }
#endregion
#region Methods
/// <summary>
/// Updates all effects added to this target.
/// </summary>
void UpdateEffects();
/// <summary>
/// Adds an affect.
/// </summary>
/// <param name="effect">The effect to add.</param>
void AddEffect(IEffect<T> effect);
/// <summary>
/// Removes an effect
/// </summary>
/// <param name="effect">The effect to remove.</param>
void RemoveEffect(IEffect<T> effect);
#endregion
}
}

View File

@ -0,0 +1,102 @@
using CUE.NET.Brushes;
using CUE.NET.Gradients;
namespace CUE.NET.Effects
{
/// <summary>
/// Represents an effect which allows to move an gradient by modifying his offset.
/// </summary>
public class MoveGradientEffect : AbstractBrushEffect<IGradientBrush>
{
#region Properties & Fields
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
// ReSharper disable MemberCanBePrivate.Global
/// <summary>
/// Gets or sets the direction the gradient is moved.
/// True leads to an offset-increment (normaly moving to the right), false to an offset-decrement (normaly moving to the left).
/// </summary>
public bool Direction { get; set; }
/// <summary>
/// Gets or sets the speed of the movement in units per second.
/// The meaning of units differs for the different gradients, but 360 units will always be one complete cycle:
/// LinearGradient: 360 unit = 1 offset.
/// RainbowGradient: 1 unit = 1 degree.
/// </summary>
public float Speed { get; set; }
// ReSharper restore MemberCanBePrivate.Global
// ReSharper restore AutoPropertyCanBeMadeGetOnly.Global
#endregion
#region Constructors
/// <summary>
///
/// </summary>
/// <param name="speed"></param>
/// <param name="direction"></param>
public MoveGradientEffect(float speed = 180f, bool direction = true)
{
this.Speed = speed;
this.Direction = direction;
}
#endregion
#region Methods
/// <summary>
/// Updates the effect.
/// </summary>
/// <param name="deltaTime">The elapsed time (in seconds) since the last update.</param>
public override void Update(float deltaTime)
{
float movement = Speed * deltaTime;
if (!Direction)
movement = -movement;
// ReSharper disable once CanBeReplacedWithTryCastAndCheckForNull
if (Brush.Gradient is LinearGradient)
{
LinearGradient linearGradient = (LinearGradient)Brush.Gradient;
movement /= 360f;
foreach (GradientStop gradientStop in linearGradient.GradientStops)
{
gradientStop.Offset = gradientStop.Offset + movement;
if (gradientStop.Offset > 1f)
gradientStop.Offset -= 1f;
else if (gradientStop.Offset < 0)
gradientStop.Offset += 1f;
}
}
else if (Brush.Gradient is RainbowGradient)
{
RainbowGradient rainbowGradient = (RainbowGradient)Brush.Gradient;
// RainbowGradient is calculated inverse but the movement should be the same for all.
movement *= -1;
rainbowGradient.StartHue += movement;
rainbowGradient.EndHue += movement;
if (rainbowGradient.StartHue > 360f && rainbowGradient.EndHue > 360f)
{
rainbowGradient.StartHue -= 360f;
rainbowGradient.EndHue -= 360f;
}
else if (rainbowGradient.StartHue < -360f && rainbowGradient.EndHue < -360f)
{
rainbowGradient.StartHue += 360f;
rainbowGradient.EndHue += 360f;
}
}
}
#endregion
}
}

37
Effects/RippleEffect.cs Normal file
View File

@ -0,0 +1,37 @@
using System;
using System.Drawing;
using CUE.NET.Brushes;
namespace CUE.NET.Effects
{
public class RippleEffect : AbstractEffect
{
#region Properties & Fields
private RippleBrush _brush = new RippleBrush();
public override IBrush EffectBrush => _brush;
#endregion
#region Constructors
#endregion
#region Methods
public override void Update(float deltaTime)
{
throw new NotImplementedException();
}
#endregion
private class RippleBrush : AbstractBrush
{
public override Color GetColorAtPoint(RectangleF rectangle, PointF point)
{
return FinalizeColor(Color.Black);
}
}
}
}

View File

@ -0,0 +1,41 @@
// ReSharper disable MemberCanBePrivate.Global
using CUE.NET.Devices.Generic.Enums;
namespace CUE.NET.EventArgs
{
/// <summary>
/// Represents the data provided by the <see cref="CueSDK.KeyPressed"/>-event.
/// </summary>
public class KeyPressedEventArgs : System.EventArgs
{
#region Properties & Fields
/// <summary>
/// Gets the id of the key.
/// </summary>
public CorsairKeyId KeyId { get; }
/// <summary>
/// Gets the current status of the key (true = pressed, flase = released).
/// </summary>
public bool IsPressed { get; }
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="KeyPressedEventArgs"/> class.
/// </summary>
/// <param name="keyId">The id of the key.</param>
/// <param name="isPressed">The current status of the key (true = pressed, flase = released).</param>
public KeyPressedEventArgs(CorsairKeyId keyId, bool isPressed)
{
this.KeyId = keyId;
this.IsPressed = isPressed;
}
#endregion
}
}

View File

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using CUE.NET.Brushes;
using CUE.NET.ColorCorrection;
using CUE.NET.Devices.Generic;
using CUE.NET.Helper;
using Example_Ambilight_full.TakeAsIs;
using Example_Ambilight_full.TakeAsIs.Model;
using Example_Ambilight_full.TakeAsIs.Model.Extensions;
using Example_Ambilight_full.TakeAsIs.ScreenCapturing;
namespace Example_Ambilight_full
{
public abstract class AbstractAmbilightBrush : AbstractBrush
{
#region Properties & Fields
protected readonly IScreenCapture ScreenCapture;
protected readonly AmbilightSettings Settings;
protected byte[] ScreenPixelData;
protected int SourceWidth;
protected int SourceHeight;
protected int OffsetLeft;
protected int OffsetRight;
protected int OffsetTop;
protected int OffsetBottom;
protected int EffectiveSourceWidth;
protected int EffectiveSourceHeight;
protected int Increment;
protected float KeyWidthProportion;
protected float KeyHeightProportion;
#endregion
#region Constructors
public AbstractAmbilightBrush(IScreenCapture screenCapture, AmbilightSettings settings)
{
this.ScreenCapture = screenCapture;
this.Settings = settings;
}
#endregion
#region Methods
public override void PerformRender(RectangleF rectangle, IEnumerable<BrushRenderTarget> renderTargets)
{
ScreenPixelData = ScreenCapture.CaptureScreen();
SourceWidth = ScreenCapture.Width;
SourceHeight = ScreenCapture.Height;
OffsetLeft = Settings.OffsetLeft + (Settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Left)
? ScreenPixelData.DetectBlackBarLeft(SourceWidth, SourceHeight, Settings.OffsetLeft, Settings.OffsetRight, Settings.OffsetTop, Settings.OffsetBottom)
: 0);
OffsetRight = Settings.OffsetRight + (Settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Right)
? ScreenPixelData.DetectBlackBarRight(SourceWidth, SourceHeight, Settings.OffsetLeft, Settings.OffsetRight, Settings.OffsetTop, Settings.OffsetBottom)
: 0);
OffsetTop = Settings.OffsetTop + (Settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Top)
? ScreenPixelData.DetectBlackBarTop(SourceWidth, SourceHeight, Settings.OffsetLeft, Settings.OffsetRight, Settings.OffsetTop, Settings.OffsetBottom)
: 0);
OffsetBottom = Settings.OffsetBottom + (Settings.BlackBarDetectionMode.HasFlag(BlackBarDetectionMode.Bottom)
? ScreenPixelData.DetectBlackBarBottom(SourceWidth, SourceHeight, Settings.OffsetLeft, Settings.OffsetRight, Settings.OffsetTop, Settings.OffsetBottom)
: 0);
EffectiveSourceWidth = SourceWidth - OffsetLeft - OffsetRight;
EffectiveSourceHeight = (int)Math.Round((SourceHeight - OffsetTop - OffsetBottom) * (Settings.MirroredAmount / 100.0));
Increment = Math.Max(1, Math.Min(20, Settings.Downsampling));
KeyWidthProportion = EffectiveSourceWidth / rectangle.Width;
KeyHeightProportion = EffectiveSourceHeight / rectangle.Height;
Opacity = Settings.SmoothMode == SmoothMode.Low ? 0.25f : (Settings.SmoothMode == SmoothMode.Medium ? 0.075f : (Settings.SmoothMode == SmoothMode.High ? 0.025f : 1f /*None*/));
base.PerformRender(rectangle, renderTargets);
}
protected override CorsairColor FinalizeColor(CorsairColor color)
{
// Apply our gamma-correction
((GammaCorrection)Settings.Gamma).ApplyTo(color);
float lightness = (float)Math.Max((Settings.MinLightness / 100.0), (color.GetHSVValue() * ((double)Brightness < 0.0 ? 0.0f : ((double)Brightness > 1.0 ? 1f : Brightness))));
byte alpha = (byte)((double)color.A * ((double)Opacity < 0.0 ? 0.0 : ((double)Opacity > 1.0 ? 1.0 : (double)Opacity)));
return ColorHelper.ColorFromHSV(color.GetHSVHue(), color.GetHSVSaturation(), lightness, alpha);
}
#endregion
}
}

View File

@ -0,0 +1,68 @@
using System.Drawing;
using CUE.NET;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic.Enums;
using Example_Ambilight_full.TakeAsIs;
using Example_Ambilight_full.TakeAsIs.Model;
using Example_Ambilight_full.TakeAsIs.ScreenCapturing;
namespace Example_Ambilight_full
{
public class Ambilight
{
#region Properties & Fields
private readonly IScreenCapture _screenCapture;
private readonly AmbilightSettings _settings;
#endregion
#region Constructors
public Ambilight(IScreenCapture screenCapture, AmbilightSettings settings)
{
this._screenCapture = screenCapture;
this._settings = settings;
}
#endregion
#region Methods
public bool Initialize()
{
try
{
CueSDK.Initialize();
CueSDK.UpdateMode = UpdateMode.Continuous;
CueSDK.UpdateFrequency = 1f / _settings.UpdateRate;
SetAmbilightBrush();
_settings.AmbienceCreatorTypeChanged += (sender, args) => SetAmbilightBrush();
}
catch { return false; }
return true;
}
private void SetAmbilightBrush()
{
IBrush ambilightBrush;
switch (_settings.AmbienceCreatorType)
{
case AmbienceCreatorType.Mirror:
ambilightBrush = new AmbilightMirrorBrush(_screenCapture, _settings);
break;
case AmbienceCreatorType.Extend:
ambilightBrush = new AmbilightExtendBrush(_screenCapture, _settings);
break;
default:
ambilightBrush = new SolidColorBrush(Color.Black);
break;
}
CueSDK.KeyboardSDK.Brush = ambilightBrush;
}
#endregion
}
}

View File

@ -0,0 +1,58 @@
using System;
using System.Drawing;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic;
using Example_Ambilight_full.TakeAsIs;
using Example_Ambilight_full.TakeAsIs.Model;
using Example_Ambilight_full.TakeAsIs.ScreenCapturing;
namespace Example_Ambilight_full
{
public class AmbilightExtendBrush : AbstractAmbilightBrush
{
#region Constructors
public AmbilightExtendBrush(IScreenCapture screenCapture, AmbilightSettings settings)
: base(screenCapture, settings)
{ }
#endregion
#region Methods
protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
float keyWidth = renderTarget.Rectangle.Width;
int widthPixels = Math.Max(1, (int)(KeyWidthProportion * keyWidth));
int r = 0;
int g = 0;
int b = 0;
int counter = 0;
int widthOffset = Settings.FlipMode.HasFlag(FlipMode.Horizontal)
? (int)((SourceWidth - OffsetRight) - (KeyWidthProportion * (renderTarget.Point.X + (keyWidth / 2f))))
: (int)(OffsetLeft + (KeyWidthProportion * (renderTarget.Point.X - (keyWidth / 2f))));
int heightOffset = SourceHeight - OffsetBottom - EffectiveSourceHeight; // DarthAffe 05.11.2016: Vertical flipping doesn't mather in Extend-Mode
// DarthAffe 06.11.2016: Validate offsets - rounding errors might cause problems (heightOffset is safe calculated -> no need to validate)
widthOffset = Math.Max(0, Math.Min(SourceWidth - widthPixels, widthOffset));
for (int y = 0; y < EffectiveSourceHeight; y += Increment)
for (int x = 0; x < widthPixels; x += Increment)
{
int offset = ((((heightOffset + y) * SourceWidth) + widthOffset + x) * 4);
b += ScreenPixelData[offset];
g += ScreenPixelData[offset + 1];
r += ScreenPixelData[offset + 2];
counter++;
}
return new CorsairColor((byte)(r / counter), (byte)(g / counter), (byte)(b / counter));
}
#endregion
}
}

View File

@ -0,0 +1,63 @@
using System;
using System.Drawing;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic;
using Example_Ambilight_full.TakeAsIs;
using Example_Ambilight_full.TakeAsIs.Model;
using Example_Ambilight_full.TakeAsIs.ScreenCapturing;
namespace Example_Ambilight_full
{
public class AmbilightMirrorBrush : AbstractAmbilightBrush
{
#region Constructors
public AmbilightMirrorBrush(IScreenCapture screenCapture, AmbilightSettings settings)
: base(screenCapture, settings)
{ }
#endregion
#region Methods
protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
float keyWidth = renderTarget.Rectangle.Width;
float keyHeight = renderTarget.Rectangle.Height;
int widthPixels = Math.Max(1, (int)(KeyWidthProportion * keyWidth));
int heightPixels = Math.Max(1, (int)(KeyHeightProportion * keyHeight));
int r = 0;
int g = 0;
int b = 0;
int counter = 0;
int widthOffset = Settings.FlipMode.HasFlag(FlipMode.Horizontal)
? ((SourceWidth - OffsetRight) - (int)(KeyWidthProportion * (renderTarget.Point.X + (keyWidth / 2f))))
: (OffsetLeft + (int)(KeyWidthProportion * (renderTarget.Point.X - (keyWidth / 2f))));
int heightOffset = Settings.FlipMode.HasFlag(FlipMode.Vertical)
? ((SourceHeight - OffsetBottom) - (int)(KeyHeightProportion * (renderTarget.Point.Y + (keyHeight / 2f))))
: ((SourceHeight - OffsetBottom - EffectiveSourceHeight) + (int)(KeyHeightProportion * (renderTarget.Point.Y - (keyHeight / 2f))));
// DarthAffe 06.11.2016: Validate offsets - rounding errors might cause problems
widthOffset = Math.Max(0, Math.Min(SourceWidth - widthPixels, widthOffset));
heightOffset = Math.Max(0, Math.Min(SourceHeight - heightPixels, heightOffset));
for (int y = 0; y < heightPixels; y += Increment)
for (int x = 0; x < widthPixels; x += Increment)
{
int offset = ((((heightOffset + y) * SourceWidth) + widthOffset + x) * 4);
b += ScreenPixelData[offset];
g += ScreenPixelData[offset + 1];
r += ScreenPixelData[offset + 2];
counter++;
}
return new CorsairColor((byte)(r / counter), (byte)(g / counter), (byte)(b / counter));
}
#endregion
}
}

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
</configuration>

View File

@ -0,0 +1,17 @@
<Application x:Class="Example_Ambilight_full.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="TakeAsIs/UI/Taskbar.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@ -0,0 +1,67 @@
using System;
using System.Windows;
using Example_Ambilight_full.TakeAsIs;
using Example_Ambilight_full.TakeAsIs.Helper;
using Example_Ambilight_full.TakeAsIs.ScreenCapturing;
using Example_Ambilight_full.TakeAsIs.UI;
using Hardcodet.Wpf.TaskbarNotification;
namespace Example_Ambilight_full
{
public partial class App : Application
{
#region Constants
private const string PATH_SETTINGS = "Settings.xaml";
#endregion
#region Properties & Fields
private TaskbarIcon _taskBar;
private AmbilightSettings _settings;
private Ambilight _ambilight;
#endregion
#region Methods
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
try
{
_settings = SerializationHelper.LoadObjectFromFile<AmbilightSettings>(PATH_SETTINGS) ??
new AmbilightSettings();
IScreenCapture screenCapture = new DX9ScreenCapture();
// DarthAffe 05.11.2016: This could be done way cleaner ...
_taskBar = FindResource("Taskbar") as TaskbarIcon;
FrameworkElement configView = _taskBar?.TrayPopup as ConfigView;
if (configView == null)
Shutdown();
else
configView.DataContext = new ConfigViewModel(_settings);
_ambilight = new Ambilight(screenCapture, _settings);
if (!_ambilight.Initialize())
throw new ApplicationException();
}
catch
{
MessageBox.Show("An error occured while starting the Keyboard-Ambilight.\r\nPlease double check if CUE is running and 'Enable SDK' is checked.", "Can't start Keyboard-Ambilight");
Shutdown();
}
}
protected override void OnExit(ExitEventArgs e)
{
base.OnExit(e);
SerializationHelper.SaveObjectToFile(_settings, PATH_SETTINGS);
}
#endregion
}
}

View File

@ -0,0 +1,169 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{6D7BAF89-A705-4FFA-A3A2-AF93EC3A909C}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Example_Ambilight_full</RootNamespace>
<AssemblyName>Example_Ambilight_full</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>Resources\ambilight.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="CUE.NET, Version=1.1.3.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\CUE.NET.1.1.3.0\lib\net45\CUE.NET.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Hardcodet.Wpf.TaskbarNotification, Version=1.0.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net45\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MahApps.Metro, Version=1.4.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\MahApps.Metro.1.4.0-ALPHA026\lib\net45\MahApps.Metro.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SharpDX, Version=3.1.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\SharpDX.3.1.1\lib\net45\SharpDX.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="SharpDX.Direct3D9, Version=3.1.1.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\SharpDX.Direct3D9.3.1.1\lib\net45\SharpDX.Direct3D9.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\MahApps.Metro.1.4.0-ALPHA026\lib\net45\System.Windows.Interactivity.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Ambilight.cs" />
<Compile Include="AbstractAmbilightBrush.cs" />
<Compile Include="AmbilightExtendBrush.cs" />
<Compile Include="AmbilightMirrorBrush.cs" />
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="TakeAsIs\AmbilightSettings.cs" />
<Compile Include="TakeAsIs\Helper\CheckboxEnumFlagHelper.cs" />
<Compile Include="TakeAsIs\Helper\SerializationHelper.cs" />
<Compile Include="TakeAsIs\Model\AmbienceCreatorType.cs" />
<Compile Include="TakeAsIs\Model\BlackBarDetectionMode.cs" />
<Compile Include="TakeAsIs\Model\Extensions\EnumExtension.cs" />
<Compile Include="TakeAsIs\Model\Extensions\PixelDataExtension.cs" />
<Compile Include="TakeAsIs\Model\FlipMode.cs" />
<Compile Include="TakeAsIs\Model\SmoothMode.cs" />
<Compile Include="TakeAsIs\ScreenCapturing\DX9ScreenCapture.cs" />
<Compile Include="TakeAsIs\ScreenCapturing\IScreenCapture.cs" />
<Compile Include="TakeAsIs\UI\ActionCommand.cs" />
<Compile Include="TakeAsIs\UI\ConfigViewModel.cs" />
<Compile Include="TakeAsIs\UI\ConfigView.xaml.cs">
<DependentUpon>ConfigView.xaml</DependentUpon>
</Compile>
<Compile Include="TakeAsIs\UI\EnumDescriptionConverter.cs" />
<Page Include="TakeAsIs\UI\ConfigView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="TakeAsIs\UI\Taskbar.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<AppDesigner Include="Properties\" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resources\ambilight.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\..\packages\CUE.NET.1.1.3.0\build\net45\CUE.NET.targets" Condition="Exists('..\..\..\packages\CUE.NET.1.1.3.0\build\net45\CUE.NET.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\..\..\packages\CUE.NET.1.1.3.0\build\net45\CUE.NET.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\..\..\packages\CUE.NET.1.1.3.0\build\net45\CUE.NET.targets'))" />
</Target>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View File

@ -0,0 +1,53 @@
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Example_Ambilight_full")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Example_Ambilight_full")]
[assembly: AssemblyCopyright("Copyright © Wyrez 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.1.3")]
[assembly: AssemblyFileVersion("1.0.1.3")]

View File

@ -0,0 +1,63 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Example_Ambilight_full.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Example_Ambilight_full.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Example_Ambilight_full.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,50 @@
using System;
using Example_Ambilight_full.TakeAsIs.Model;
namespace Example_Ambilight_full.TakeAsIs
{
public class AmbilightSettings
{
private AmbienceCreatorType _ambienceCreatorType = AmbienceCreatorType.Mirror;
#region Properties & Fields
public AmbienceCreatorType AmbienceCreatorType
{
get { return _ambienceCreatorType; }
set
{
// ReSharper disable once InvertIf
if (_ambienceCreatorType != value)
{
_ambienceCreatorType = value;
AmbienceCreatorTypeChanged?.Invoke(this, new EventArgs());
}
}
}
public int UpdateRate { get; set; } = 20;
public int OffsetLeft { get; set; } = 0;
public int OffsetRight { get; set; } = 0;
public int OffsetTop { get; set; } = 0;
public int OffsetBottom { get; set; } = 0;
public int Downsampling { get; set; } = 2;
public double MirroredAmount { get; set; } = 10;
public SmoothMode SmoothMode { get; set; } = SmoothMode.Low;
public BlackBarDetectionMode BlackBarDetectionMode { get; set; } = BlackBarDetectionMode.Bottom;
public FlipMode FlipMode { get; set; } = FlipMode.Vertical;
public double MinLightness { get; set; } = 0;
public float Gamma { get; set; } = 1f;
#endregion
#region Events
public event EventHandler AmbienceCreatorTypeChanged;
#endregion
}
}

View File

@ -0,0 +1,93 @@
using System;
using System.Windows;
using System.Windows.Controls;
using Example_Ambilight_full.TakeAsIs.Model.Extensions;
namespace Example_Ambilight_full.TakeAsIs.Helper
{
public class CheckboxEnumFlagHelper
{
#region DependencyProperties
// ReSharper disable InconsistentNaming
public static readonly DependencyProperty FlagsProperty = DependencyProperty.RegisterAttached(
"Flags", typeof(Enum), typeof(CheckboxEnumFlagHelper), new FrameworkPropertyMetadata(default(Enum), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, FlagsChanged));
public static void SetFlags(DependencyObject element, Enum value)
{
element.SetValue(FlagsProperty, value);
}
public static Enum GetFlags(DependencyObject element)
{
return (Enum)element.GetValue(FlagsProperty);
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.RegisterAttached(
"Value", typeof(Enum), typeof(CheckboxEnumFlagHelper), new PropertyMetadata(default(Enum), ValueChanged));
public static void SetValue(DependencyObject element, Enum value)
{
element.SetValue(ValueProperty, value);
}
public static Enum GetValue(DependencyObject element)
{
return (Enum)element.GetValue(ValueProperty);
}
// ReSharper restore InconsistentNaming
#endregion
#region Methods
private static void FlagsChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
UpdateTarget(dependencyObject as CheckBox, dependencyPropertyChangedEventArgs.NewValue as Enum);
}
private static void ValueChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
CheckBox checkbox = dependencyObject as CheckBox;
if (checkbox == null) return;
checkbox.Checked -= UpdateSource;
checkbox.Unchecked -= UpdateSource;
if (dependencyPropertyChangedEventArgs.NewValue != null)
{
checkbox.Checked += UpdateSource;
checkbox.Unchecked += UpdateSource;
}
UpdateTarget(checkbox, GetFlags(checkbox));
}
private static void UpdateTarget(CheckBox checkbox, Enum flags)
{
if (checkbox == null) return;
Enum value = GetValue(checkbox);
checkbox.IsChecked = value != null && (flags?.HasFlag(value) ?? false);
}
private static void UpdateSource(object sender, RoutedEventArgs routedEventArgs)
{
CheckBox checkbox = sender as CheckBox;
if (checkbox == null) return;
Enum flags = GetFlags(checkbox);
Enum value = GetValue(checkbox);
if (value == null) return;
if (checkbox.IsChecked ?? false)
SetFlags(checkbox, flags == null ? value : flags.SetFlag(value, true, flags.GetType()));
else
SetFlags(checkbox, flags?.SetFlag(value, false, flags.GetType()));
}
#endregion
}
}

View File

@ -0,0 +1,50 @@
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace Example_Ambilight_full.TakeAsIs.Helper
{
public static class SerializationHelper
{
public static void SaveObjectToFile<T>(T serializableObject, string path)
{
if (serializableObject == null) return;
try
{
XmlDocument xmlDocument = new XmlDocument();
XmlSerializer serializer = new XmlSerializer(serializableObject.GetType());
using (MemoryStream stream = new MemoryStream())
{
serializer.Serialize(stream, serializableObject);
stream.Seek(0, SeekOrigin.Begin);
xmlDocument.Load(stream);
xmlDocument.Save(path);
}
}
catch {/* Catch'em all */}
}
public static T LoadObjectFromFile<T>(string fileName)
{
if (string.IsNullOrEmpty(fileName)) return default(T);
try
{
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(fileName);
string xmlString = xmlDocument.OuterXml;
using (StringReader sr = new StringReader(xmlString))
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (XmlReader reader = new XmlTextReader(sr))
return (T)serializer.Deserialize(reader);
}
}
catch {/* Catch'em all */}
return default(T);
}
}
}

View File

@ -0,0 +1,13 @@
using System.ComponentModel;
namespace Example_Ambilight_full.TakeAsIs.Model
{
public enum AmbienceCreatorType
{
[Description("Mirror")]
Mirror,
[Description("Extend")]
Extend
}
}

View File

@ -0,0 +1,14 @@
using System;
namespace Example_Ambilight_full.TakeAsIs.Model
{
[Flags]
public enum BlackBarDetectionMode
{
None = 0,
Left = 1 << 0,
Right = 1 << 1,
Top = 1 << 2,
Bottom = 1 << 3,
}
}

View File

@ -0,0 +1,26 @@
using System;
namespace Example_Ambilight_full.TakeAsIs.Model.Extensions
{
public static class EnumExtension
{
#region Methods
public static Enum SetFlag(this Enum e, Enum value, bool set, Type t)
{
if (e == null || value == null || t == null) return e;
int eValue = Convert.ToInt32(e);
int valueValue = Convert.ToInt32(value);
if (set)
eValue |= valueValue;
else
eValue &= ~valueValue;
return (Enum)Enum.ToObject(t, eValue);
}
#endregion
}
}

View File

@ -0,0 +1,89 @@
namespace Example_Ambilight_full.TakeAsIs.Model.Extensions
{
public static class PixelDataExtension
{
#region Methods
public static int DetectBlackBarLeft(this byte[] pixels, int width, int height, int offsetLeft, int offsetRight, int offsetTop, int offsetBottom)
{
int bottomBorder = height - offsetBottom;
int rightBorder = width - offsetRight;
int blackBarWidth = 0;
for (int x = rightBorder - 1; x >= offsetLeft; x--)
{
for (int y = offsetTop; y < bottomBorder; y++)
{
int offset = ((y * width) + x) * 4;
if (pixels[offset] > 15 || pixels[offset + 1] > 15 || pixels[offset + 2] > 15)
return blackBarWidth;
}
blackBarWidth++;
}
return width;
}
public static int DetectBlackBarRight(this byte[] pixels, int width, int height, int offsetLeft, int offsetRight, int offsetTop, int offsetBottom)
{
int bottomBorder = height - offsetBottom;
int rightBorder = width - offsetRight;
int blackBarWidth = 0;
for (int x = offsetLeft; x < rightBorder; x++)
{
for (int y = offsetTop; y < bottomBorder; y++)
{
int offset = ((y * width) + x) * 4;
if (pixels[offset] > 15 || pixels[offset + 1] > 15 || pixels[offset + 2] > 15)
return blackBarWidth;
}
blackBarWidth++;
}
return width;
}
public static int DetectBlackBarTop(this byte[] pixels, int width, int height, int offsetLeft, int offsetRight, int offsetTop, int offsetBottom)
{
int bottomBorder = height - offsetBottom;
int rightBorder = width - offsetRight;
int blackBarHeight = 0;
for (int y = offsetTop; y < bottomBorder; y++)
{
for (int x = offsetLeft; x < rightBorder; x++)
{
int offset = ((y * width) + x) * 4;
if (pixels[offset] > 15 || pixels[offset + 1] > 15 || pixels[offset + 2] > 15)
return blackBarHeight;
}
blackBarHeight++;
}
return height;
}
public static int DetectBlackBarBottom(this byte[] pixels, int width, int height, int offsetLeft, int offsetRight, int offsetTop, int offsetBottom)
{
int bottomBorder = height - offsetBottom;
int rightBorder = width - offsetRight;
int blackBarHeight = 0;
for (int y = bottomBorder - 1; y >= offsetTop; y--)
{
for (int x = offsetLeft; x < rightBorder; x++)
{
int offset = ((y * width) + x) * 4;
if (pixels[offset] > 15 || pixels[offset + 1] > 15 || pixels[offset + 2] > 15)
return blackBarHeight;
}
blackBarHeight++;
}
return height;
}
#endregion
}
}

View File

@ -0,0 +1,12 @@
using System;
namespace Example_Ambilight_full.TakeAsIs.Model
{
[Flags]
public enum FlipMode
{
None = 0,
Vertical = 1 << 0,
Horizontal = 1 << 1
}
}

View File

@ -0,0 +1,19 @@
using System.ComponentModel;
namespace Example_Ambilight_full.TakeAsIs.Model
{
public enum SmoothMode
{
[Description("None")]
None,
[Description("Low")]
Low,
[Description("Medium")]
Medium,
[Description("High")]
High
}
}

View File

@ -0,0 +1,86 @@
using System;
using System.Runtime.InteropServices;
using System.Windows.Media;
using Microsoft.Win32;
using SharpDX;
using SharpDX.Direct3D9;
namespace Example_Ambilight_full.TakeAsIs.ScreenCapturing
{
public class DX9ScreenCapture : IScreenCapture
{
#region Properties & Fields
private Device _device;
private Surface _surface;
private byte[] _buffer;
public int Width { get; }
public int Height { get; }
public PixelFormat PixelFormat => PixelFormats.Bgr24;
#endregion
#region Constructors
public DX9ScreenCapture()
{
Width = (int)System.Windows.SystemParameters.PrimaryScreenWidth;
Height = (int)System.Windows.SystemParameters.PrimaryScreenHeight;
//DarthAffe 08.04.2017: Fix for system using windows-scaling. The primary screen size is reported 'wrong'.
double scaling = GetScaling();
if (Math.Abs(scaling - 1.0) > 0.01)
{
Width = (int)(Width / scaling);
Height = (int)(Height / scaling);
}
PresentParameters presentParams = new PresentParameters(Width, Height)
{
Windowed = true,
SwapEffect = SwapEffect.Discard
};
_device = new Device(new Direct3D(), 0, DeviceType.Hardware, IntPtr.Zero, CreateFlags.SoftwareVertexProcessing, presentParams);
_surface = Surface.CreateOffscreenPlain(_device, Width, Height, Format.A8R8G8B8, Pool.Scratch);
_buffer = new byte[Width * Height * 4];
}
#endregion
#region Methods
private double GetScaling()
{
try
{
int currentDpi = (int)Registry.GetValue("HKEY_CURRENT_USER\\Control Panel\\Desktop", "LogPixels", 96);
return 96.0 / currentDpi;
}
catch
{
return 1.0;
}
}
public byte[] CaptureScreen()
{
_device.GetFrontBufferData(0, _surface);
DataRectangle dr = _surface.LockRectangle(LockFlags.None);
Marshal.Copy(dr.DataPointer, _buffer, 0, _buffer.Length);
_surface.UnlockRectangle();
return _buffer;
}
public void Dispose()
{
_device?.Dispose();
_surface?.Dispose();
}
#endregion
}
}

View File

@ -0,0 +1,18 @@
using System;
using System.Windows.Media;
namespace Example_Ambilight_full.TakeAsIs.ScreenCapturing
{
public interface IScreenCapture : IDisposable
{
int Width { get; }
int Height { get; }
PixelFormat PixelFormat { get; }
/// <summary>
/// As Pixel-Data BGRA
/// </summary>
/// <returns>The Pixel-Data</returns>
byte[] CaptureScreen();
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Windows.Input;
namespace Example_Ambilight_full.TakeAsIs.UI
{
public class ActionCommand : ICommand
{
#region Properties & Fields
private readonly Func<bool> _canExecute;
private readonly Action _command;
#endregion
#region Constructors
public ActionCommand(Action command, Func<bool> canExecute = null)
{
this._command = command;
this._canExecute = canExecute;
}
#endregion
#region Methods
public bool CanExecute(object parameter)
{
return _canExecute?.Invoke() ?? true;
}
public void Execute(object parameter)
{
_command?.Invoke();
}
public void RaiseCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, new EventArgs());
}
#endregion
#region Events
public event EventHandler CanExecuteChanged;
#endregion
}
}

View File

@ -0,0 +1,179 @@
<UserControl x:Class="Example_Ambilight_full.TakeAsIs.UI.ConfigView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:helper="clr-namespace:Example_Ambilight_full.TakeAsIs.Helper"
xmlns:model="clr-namespace:Example_Ambilight_full.TakeAsIs.Model"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:ui="clr-namespace:Example_Ambilight_full.TakeAsIs.UI">
<!-- Quick'n'Dirty - you really shouldn't implement a View like this ... -->
<UserControl.Resources>
<ui:EnumDescriptionConverter x:Key="HEnumDescriptionConverter" />
<ObjectDataProvider x:Key="SmoothModeEnumValues" ObjectType="{x:Type system:Enum}" MethodName="GetValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="model:SmoothMode" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<ObjectDataProvider x:Key="AmbienceCreatorTypeValues" ObjectType="{x:Type system:Enum}" MethodName="GetValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="model:AmbienceCreatorType" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<Style TargetType="ComboBox" BasedOn="{StaticResource {x:Type ComboBox}}">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource HEnumDescriptionConverter}}" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,0,4,0" />
</Style>
<Style TargetType="controls:NumericUpDown" BasedOn="{StaticResource {x:Type controls:NumericUpDown}}">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<Style TargetType="CheckBox" BasedOn="{StaticResource {x:Type CheckBox}}">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</UserControl.Resources>
<Border Padding="16" Background="#CECECE" BorderBrush="#2E2E2E" BorderThickness="2">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="160" />
<ColumnDefinition Width="32" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="160" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
<RowDefinition Height="32" />
</Grid.RowDefinitions>
<!-- Update-Rate-->
<TextBlock Grid.Row="0" Grid.Column="0" Text="Update-Rate (FPS):" />
<controls:NumericUpDown Grid.Row="0" Grid.Column="1"
Minimum="1" Maximum="60"
Value="{Binding Path=UpdateRate, Mode=TwoWay}" />
<!-- AmbienceCreatorType & Downsampling-->
<TextBlock Grid.Row="1" Grid.Column="0" Text="Ambilight-Mode:"/>
<ComboBox Grid.Row="1" Grid.Column="1"
ItemsSource="{Binding Source={StaticResource AmbienceCreatorTypeValues}}"
SelectedItem="{Binding Path=Settings.AmbienceCreatorType}" />
<TextBlock Grid.Row="1" Grid.Column="3" Text="Downsampling:" />
<controls:NumericUpDown Grid.Row="1" Grid.Column="4"
Minimum="1" Maximum="20"
Value="{Binding Path=Settings.Downsampling, Mode=TwoWay}" />
<!-- MirrorAmount & Gamma-->
<TextBlock Grid.Row="2" Grid.Column="0" Text="Mirrored Amount (%):" />
<controls:NumericUpDown Grid.Row="2" Grid.Column="1"
Minimum="0" Maximum="100"
Value="{Binding Path=Settings.MirroredAmount, Mode=TwoWay}" />
<TextBlock Grid.Row="2" Grid.Column="3" Text="Gamma:" />
<controls:NumericUpDown Grid.Row="2" Grid.Column="4"
Minimum="0.1" Maximum="10"
HasDecimals="True" Interval="0.1" StringFormat="F1"
Value="{Binding Path=Settings.Gamma, Mode=TwoWay}" />
<!-- SmoothMode -->
<TextBlock Grid.Row="3" Grid.Column="0" Text="Smoothing:" />
<ComboBox Grid.Row="3" Grid.Column="1"
ItemsSource="{Binding Source={StaticResource SmoothModeEnumValues}}"
SelectedItem="{Binding Path=Settings.SmoothMode}" />
<!-- Min Lightness -->
<TextBlock Grid.Row="3" Grid.Column="3" Text="Min Lightness (%):" />
<controls:NumericUpDown Grid.Row="3" Grid.Column="4"
Minimum="0" Maximum="100"
Value="{Binding Path=Settings.MinLightness, Mode=TwoWay}" />
<!-- FlipMode -->
<TextBlock Grid.Row="4" Grid.Column="0" Text="Flip Horizontal:" />
<CheckBox Grid.Row="4" Grid.Column="1"
helper:CheckboxEnumFlagHelper.Value="{x:Static model:FlipMode.Horizontal}"
helper:CheckboxEnumFlagHelper.Flags="{Binding Path=Settings.FlipMode}" />
<TextBlock Grid.Row="4" Grid.Column="3" Text="Flip Vertical:" />
<CheckBox Grid.Row="4" Grid.Column="4"
helper:CheckboxEnumFlagHelper.Value="{x:Static model:FlipMode.Vertical}"
helper:CheckboxEnumFlagHelper.Flags="{Binding Path=Settings.FlipMode}" />
<!-- Horizontal offsets -->
<TextBlock Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="4" FontWeight="Black" Text="Offset" />
<TextBlock Grid.Row="6" Grid.Column="0" Text="Left:" />
<controls:NumericUpDown Grid.Row="6" Grid.Column="1"
Minimum="0"
Value="{Binding Path=Settings.OffsetLeft, Mode=TwoWay}" />
<TextBlock Grid.Row="6" Grid.Column="3" Text="Right:" />
<controls:NumericUpDown Grid.Row="6" Grid.Column="4"
Minimum="0"
Value="{Binding Path=Settings.OffsetRight, Mode=TwoWay}" />
<!-- Vertical offsets -->
<TextBlock Grid.Row="7" Grid.Column="0" Text="Top:" />
<controls:NumericUpDown Grid.Row="7" Grid.Column="1" Minimum="0"
Value="{Binding Path=Settings.OffsetTop, Mode=TwoWay}" />
<TextBlock Grid.Row="7" Grid.Column="3" Text="Bottom:"/>
<controls:NumericUpDown Grid.Row="7" Grid.Column="4" Minimum="0"
Value="{Binding Path=Settings.OffsetBottom, Mode=TwoWay}" />
<!-- Horizontal BlackBar-detection -->
<TextBlock Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="4" FontWeight="Black" Text="Black-Bar detection" />
<TextBlock Grid.Row="9" Grid.Column="0" Text="Left:" />
<CheckBox Grid.Row="9" Grid.Column="1"
helper:CheckboxEnumFlagHelper.Value="{x:Static model:BlackBarDetectionMode.Left}"
helper:CheckboxEnumFlagHelper.Flags="{Binding Path=Settings.BlackBarDetectionMode}" />
<TextBlock Grid.Row="9" Grid.Column="3" Text="Right:" />
<CheckBox Grid.Row="9" Grid.Column="4"
helper:CheckboxEnumFlagHelper.Value="{x:Static model:BlackBarDetectionMode.Right}"
helper:CheckboxEnumFlagHelper.Flags="{Binding Path=Settings.BlackBarDetectionMode}" />
<!-- Vertical BlackBar-detection -->
<TextBlock Grid.Row="10" Grid.Column="0" Text="Top:" />
<CheckBox Grid.Row="10" Grid.Column="1"
helper:CheckboxEnumFlagHelper.Value="{x:Static model:BlackBarDetectionMode.Top}"
helper:CheckboxEnumFlagHelper.Flags="{Binding Path=Settings.BlackBarDetectionMode}" />
<TextBlock Grid.Row="10" Grid.Column="3" Text="Bottom:" />
<CheckBox Grid.Row="10" Grid.Column="4"
helper:CheckboxEnumFlagHelper.Value="{x:Static model:BlackBarDetectionMode.Bottom}"
helper:CheckboxEnumFlagHelper.Flags="{Binding Path=Settings.BlackBarDetectionMode}" />
<Button Grid.Row="12" Grid.Column="4" Command="{Binding ExitCommand}" Content="Exit" />
</Grid>
</Border>
</UserControl>

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Example_Ambilight_full.TakeAsIs.UI
{
/// <summary>
/// Interaction logic for ConfigView.xaml
/// </summary>
public partial class ConfigView : UserControl
{
public ConfigView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Windows;
using CUE.NET;
namespace Example_Ambilight_full.TakeAsIs.UI
{
public class ConfigViewModel
{
#region Properties & Fields
public AmbilightSettings Settings { get; }
public int UpdateRate
{
get => (int)Math.Round(1f / CueSDK.UpdateFrequency);
set
{
Settings.UpdateRate = value;
CueSDK.UpdateFrequency = 1f / value;
}
}
#endregion
#region Commands
private ActionCommand _exitCommand;
public ActionCommand ExitCommand => _exitCommand ?? (_exitCommand = new ActionCommand(Exit));
#endregion
#region Constructors
public ConfigViewModel(AmbilightSettings settings)
{
this.Settings = settings;
}
#endregion
#region Methods
private void Exit()
{
Application.Current.Shutdown();
}
#endregion
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Windows.Data;
namespace Example_Ambilight_full.TakeAsIs.UI
{
public class EnumDescriptionConverter : IValueConverter
{
#region Methods
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Enum myEnum = (Enum)value;
string description = GetEnumDescription(myEnum);
return description;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.Empty;
}
private string GetEnumDescription(Enum enumObj)
{
FieldInfo fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
object[] attribArray = fieldInfo.GetCustomAttributes(false);
if (attribArray.Length == 0)
return enumObj.ToString();
DescriptionAttribute attrib = attribArray[0] as DescriptionAttribute;
return attrib?.Description;
}
#endregion
}
}

View File

@ -0,0 +1,16 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:ui="clr-namespace:Example_Ambilight_full.TakeAsIs.UI">
<tb:TaskbarIcon x:Key="Taskbar"
ToolTipText="Keyboard-Ambilight"
IconSource="../../Resources/ambilight.ico"
PopupActivation="All">
<tb:TaskbarIcon.TrayPopup>
<ui:ConfigView />
</tb:TaskbarIcon.TrayPopup>
</tb:TaskbarIcon>
</ResourceDictionary>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="CUE.NET" version="1.1.3.0" targetFramework="net45" />
<package id="Hardcodet.NotifyIcon.Wpf" version="1.0.8" targetFramework="net45" />
<package id="MahApps.Metro" version="1.4.0-ALPHA026" targetFramework="net45" />
<package id="SharpDX" version="3.1.1" targetFramework="net45" />
<package id="SharpDX.Direct3D9" version="3.1.1" targetFramework="net45" />
</packages>

View File

@ -3,9 +3,12 @@ using System.Collections.Generic;
using System.Drawing;
using CUE.NET;
using CUE.NET.Brushes;
using CUE.NET.Devices.Generic;
using CUE.NET.Devices.Generic.Enums;
using CUE.NET.Devices.Keyboard;
using CUE.NET.Exceptions;
using CUE.NET.Gradients;
using CUE.NET.Groups;
using Example_AudioAnalyzer_full.TakeAsIs;
namespace Example_AudioAnalyzer_full
@ -60,18 +63,22 @@ namespace Example_AudioAnalyzer_full
public void Run()
{
// Add a lack background. We want this to be semi-transparent to add some sort of fade-effect - this will smooth everything out a bit
CueSDK.UpdateMode = UpdateMode.Continuous;
// Add a black background. We want this to be semi-transparent to add some sort of fade-effect - this will smooth everything out a bit
// Note that this isn't a 'real effect' since it's update-rate dependent. A real effect would do always the same thing not mather how fast the keyboard updates.
_keyboard.Brush = new SolidColorBrush(Color.FromArgb(96, 0, 0, 0));
_keyboard.Brush = new SolidColorBrush(new CorsairColor(96, 0, 0, 0));
// Add our song-beat-effect. Remember to uncomment the update in the spectrum effect if you want to remove this.
_keyboard.AttachEffect(new SongBeatEffect(_soundDataProcessor, Color.FromArgb(127, 164, 164, 164)));
ListLedGroup songBeatGroup = new ListLedGroup(_keyboard, _keyboard);
songBeatGroup.Brush = new SolidColorBrush(new CorsairColor(127, 164, 164, 164));
songBeatGroup.Brush.AddEffect(new SongBeatEffect(_soundDataProcessor));
// Add our spectrum-effect using the soundDataProcessor and a rainbow from purple to red as gradient
_keyboard.AttachEffect(new AudioSpectrumEffect(_soundDataProcessor, new RainbowGradient(300, -14)));
ListLedGroup spectrumGroup = new ListLedGroup(_keyboard, _keyboard);
spectrumGroup.Brush = new AudioSpectrumBrush(_soundDataProcessor, new RainbowGradient(300, -14));
// Hook onto the keyboard update and process data
_keyboard.Updating += (sender, args) => _soundDataProcessor.Process();
// If you don't like rainbows replace the gradient with anything you like. For example:
//_keyboard.AttachEffect(new AudioSpectrumEffect(_soundDataProcessor, new LinearGradient(new GradientStop(0f, Color.Blue), new GradientStop(1f, Color.Red))));

Some files were not shown because too many files have changed in this diff Show More