// ReSharper disable MemberCanBePrivate.Global // ReSharper disable UnusedAutoPropertyAccessor.Global // 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.Native; namespace CUE.NET.Devices.Keyboard { /// /// Represents the SDK for a corsair keyboard. /// public class CorsairKeyboard : AbstractCueDevice, IEnumerable, IKeyGroup { #region Properties & Fields #region Indexer /// /// Gets the with the specified ID. /// /// The ID of the key to get. /// The key with the specified ID or null if no key is found. public CorsairKey this[CorsairKeyboardKeyId keyId] { get { CorsairKey key; return _keys.TryGetValue(keyId, out key) ? key : null; } } /// /// Gets the representing the given character by calling the SDK-method 'CorsairGetLedIdForKeyName'.
/// Note that this currently only works for letters. ///
/// The character of the key. /// The key representing the given character or null if no key is found. public CorsairKey this[char key] { get { CorsairKeyboardKeyId keyId = _CUESDK.CorsairGetLedIdForKeyName(key); CorsairKey cKey; return _keys.TryGetValue(keyId, out cKey) ? cKey : null; } } /// /// Gets the at the given physical location. /// /// The point to get the key from. /// The key at the given point or null if no key is found. public CorsairKey this[PointF location] => _keys.Values.FirstOrDefault(x => x.KeyRectangle.Contains(location)); /// /// Gets a list of inside the given rectangle. /// /// The rectangle to check. /// The minimal percentage overlay a key must have with the to be taken into the list. /// public IEnumerable this[RectangleF referenceRect, float minOverlayPercentage = 0.5f] => _keys.Values.Where(x => RectangleHelper.CalculateIntersectPercentage(x.KeyRectangle, referenceRect) >= minOverlayPercentage); #endregion private readonly LinkedList _keyGroups = new LinkedList(); private Dictionary _keys = new Dictionary(); /// /// Gets a read-only collection containing the keys of the keyboard. /// public IEnumerable Keys => new ReadOnlyCollection(_keys.Values.ToList()); /// /// Gets specific information provided by CUE for the keyboard. /// public CorsairKeyboardDeviceInfo KeyboardDeviceInfo { get; } /// /// Gets the rectangle containing all keys of the keyboard. /// public RectangleF KeyboardRectangle { get; private set; } /// /// Gets or sets the background brush of the keyboard. /// public IBrush Brush { get; set; } /// /// Gets or sets the z-index of the background brush of the keyboard.
/// This value has absolutely no effect. ///
public int ZIndex { get; set; } = 0; /// /// Gets a value indicating if the keyboard has an active effect to deal with or not. /// protected override bool HasEffect { get { lock (Effects) return Effects.Any(); } } #endregion #region Constructors /// /// Initializes a new instance of the class. /// /// The specific information provided by CUE for the keyboard internal CorsairKeyboard(CorsairKeyboardDeviceInfo info) : base(info) { this.KeyboardDeviceInfo = info; InitializeKeys(); KeyboardRectangle = RectangleHelper.CreateRectangleFromRectangles(this.Select(x => x.KeyRectangle)); } #endregion #region Methods #region Update /// /// Updates all groups and effects and perform an update for all dirty keys, or all keys if flushLeds is set to true. /// /// Specifies whether all keys (including clean ones) should be updated. public override void Update(bool flushLeds = false) { UpdateKeyGroups(); // Perform 'real' update base.Update(flushLeds); } private void UpdateKeyGroups() { 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 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 keys, IBrush brush) { try { RectangleF brushRectangle = RectangleHelper.CreateRectangleFromRectangles(keys.Select(x => x.KeyRectangle)); foreach (CorsairKey key in keys) key.Led.Color = brush.GetColorAtPoint(brushRectangle, key.KeyRectangle.GetCenter()); } // ReSharper disable once CatchAllClause catch (Exception ex) { ManageException(ex); } } public IEnumerable GetLeds() { return this.Select(x => x.Led); } #endregion /// /// Attaches the given keygroup. /// /// The keygroup to attach. /// true if the keygroup could be attached; otherwise, false. public bool AttachKeyGroup(IKeyGroup keyGroup) { lock (_keyGroups) { if (keyGroup == null || _keyGroups.Contains(keyGroup)) return false; _keyGroups.AddLast(keyGroup); return true; } } /// /// Detaches the given keygroup. /// /// The keygroup to detached. /// true if the keygroup could be detached; otherwise, false. public bool DetachKeyGroup(IKeyGroup keyGroup) { lock (_keyGroups) { if (keyGroup == null) return false; LinkedListNode node = _keyGroups.Find(keyGroup); if (node == null) return false; _keyGroups.Remove(node); return true; } } private void InitializeKeys() { _CorsairLedPositions nativeLedPositions = (_CorsairLedPositions)Marshal.PtrToStructure(_CUESDK.CorsairGetLedPositions(), typeof(_CorsairLedPositions)); int structSize = Marshal.SizeOf(typeof(_CorsairLedPosition)); IntPtr ptr = nativeLedPositions.pLedPosition; 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))); ptr = new IntPtr(ptr.ToInt64() + structSize); } } #region IEnumerable /// /// Returns an enumerator that iterates over all keys of the keyboard. /// /// An enumerator for all keys of the keyboard. public IEnumerator GetEnumerator() { return _keys.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion #endregion } }