Comments (18)
I just run a bit of profiling myself but I'm pretty sure this is a problem in your code.
It seems like you're leaking groups for a reason i just realized isn't documented right now.
If you create a group it's attached to the device by default (that's what the bool parameter is for). But you never detach them so they stack up over time. You can check this in the debugger by breaking in the update method after some runs and checking the "LedGroups"-Property.
If you can confirm this is the problem, there are different ways to solve it. Personally I prefer to only create as much groups/brushes as I need and modify the keys/values inside to get the result I want. But you could of course also create always new groups. Just make sure the old (unused) ones get detached by calling
myLedGroup.Detach(); // using CUE.NET.Groups.Extensions;
// or
CueSDK.KeyboardSDK.DetachLedGroup(myLedGroup);
from cue.net.
Oh that would certainly explain the memory leak then, thanks for making me aware of this.
So I took the ListLedGroup's out of the function scope to access them from the CorsairUpdateLED() function.
The code now looks like this:
private ListLedGroup _CorsairAllKeyboardLED = new ListLedGroup(CueSDK.KeyboardSDK, CueSDK.KeyboardSDK);
private ListLedGroup _CorsairAllMouseLED = new ListLedGroup(CueSDK.MouseSDK, CueSDK.MouseSDK);
private ListLedGroup _CorsairAllHeadsetLED = new ListLedGroup(CueSDK.HeadsetSDK, CueSDK.HeadsetSDK);
private ListLedGroup _CorsairAllMousepadLED = new ListLedGroup(CueSDK.MousematSDK, CueSDK.MousematSDK);
ListLedGroup _CorsairKeyboardIndvLED;
ListLedGroup _CorsairMouseIndvLED;
ListLedGroup _CorsairMousepadIndvLED;
public void CorsairUpdateLED()
{
if (CorsairSDK != false)
{
if (CorsairDeviceHeadset == true) { CueSDK.HeadsetSDK.Update(); }
if (CorsairDeviceKeyboard == true) { CueSDK.KeyboardSDK.Update(); }
if (CorsairDeviceMouse == true) { CueSDK.MouseSDK.Update(); }
if (CorsairDeviceMousepad == true) { CueSDK.MousematSDK.Update(); }
_CorsairAllKeyboardLED.Detach();
_CorsairAllMouseLED.Detach();
_CorsairAllHeadsetLED.Detach();
_CorsairAllMousepadLED.Detach();
_CorsairKeyboardIndvLED.Detach();
_CorsairMouseIndvLED.Detach();
_CorsairMousepadIndvLED.Detach();
}
}
//Update a specific LED on the keyboard
public void CorsairApplyMapKeyLighting(string key, System.Drawing.Color col)
{
if (CorsairSDK != false)
{
//Send Lighting
if (CorsairDeviceKeyboard == true)
{
try
{
if (Corsairkeyids.ContainsKey(key))
{
_CorsairKeyboardIndvLED = new ListLedGroup(CueSDK.KeyboardSDK);
SolidColorBrush _CorsairLEDBrush = new SolidColorBrush(col);
_CorsairKeyboardIndvLED.AddLed(Corsairkeyids[key]);
_CorsairKeyboardIndvLED.ZIndex = 10;
_CorsairKeyboardIndvLED.Brush = _CorsairLEDBrush;
}
}
catch (Exception ex) { }
}
}
}
However I still am getting the same memory issues it seems, with pretty much no notable change?
Basically what I'm doing is trying to set 1 key at a time to a specific color using the CorsairApplyMapKeyLighting() function, is there a better way to do this than creating a new LED group and color brush every time it is called?
from cue.net.
I think you should not create new groups if possible - this makes things quite complex and hard for me to understand without the whole context.
If I run a this program (it should somehow simulate the behavior you want to achieve) I don't see any memory-leaks.
public class Program
{
private static ListLedGroup _singleKeyLedGroup;
private static Random _random = new Random();
public static void Main(string[] args)
{
CueSDK.Initialize();
CueSDK.KeyboardSDK.Brush = (SolidColorBrush)Color.Black;
_singleKeyLedGroup = new ListLedGroup(CueSDK.KeyboardSDK);
// Just do something for a while ~
for (int i = 0; i < 1000; i++)
{
CorsairApplyMapKeyLighting(GetRandomLedId(), ColorHelper.ColorFromHSV(_random.Next(360), 1, 1));
CueSDK.KeyboardSDK.Update();
Thread.Sleep(60);
}
}
private static void CorsairApplyMapKeyLighting(CorsairLedId key, Color col) // I replaced the string since I don't know what logic you're using to get the key but that shouldn't mather.
{
_singleKeyLedGroup.RemoveLeds(_singleKeyLedGroup.GetLeds().ToList()); // It's a bit sad that there is no 'clear'-methodon the group, but this will do the same even if it is some kind of workaround
_singleKeyLedGroup.AddLed(key);
_singleKeyLedGroup.Brush = (SolidColorBrush)col; // this could be replaced too if you keep a reference to the brush but it's not really needed.
}
private static CorsairLedId GetRandomLedId()
{
CorsairLedId[] ids = ((CorsairLedId[])Enum.GetValues(typeof(CorsairLedId)));
return ids[_random.Next(ids.Length - 1)];
}
}
from cue.net.
Thanks for helping me out with these issues, I really appreciate it! >.<;
Okay so I see what you're trying to achieve here, and have attempted to replicate most of it in my code. One problem I can see however is in the logic of how I call the Update(); method.
Basically I have a separate async function which handles all the calls to these functions. This primary function runs every 500 or so milliseconds and essentially calls the relevant functions to draw across the keyboard. The order of this function more or less follows this pattern:
-
Sets a base colour across all of the keys (this gets skipped if nothing has changed from the past iteration) - uses CorsairUpdateAll() function.
-
Sets individual colours on specific keys, using multiple CorsairApplyMapKeyLighting() calls, over the base layer (was utilising the z-index of the LED group).
-
Calls the CueSDK.KeyboardSDK.Update() method.
-
Sleeps for 500ms.
-
Repeats
When I try to implement your code, nothing gets set on step 2. I'm assuming this is because each call to this function overrides the last, before the CueSDK.KeyboardSDK.Update() method can be called.
I'm not sure how much this complicates what I'm trying to achieve. When I first started coding these functions I had the Update() method within each function, however this lead to some weird results where LED's would essentially flash on and off constantly which lead me to having a single Update() call back in the primary async function, which achieved the result I was looking for.
Hopefully that makes sense?
from cue.net.
Will post some sample code to better demonstrate
class TestClass
{
bool CorsairSDK = false;
bool Setbase = false;
Color _BaseColor = System.Drawing.Color.Black;
private ListLedGroup _CorsairAllKeyboardLED;
private ListLedGroup _CorsairAllMouseLED;
private ListLedGroup _CorsairAllHeadsetLED;
private ListLedGroup _CorsairAllMousepadLED;
private ListLedGroup _CorsairKeyboardIndvLED;
private ListLedGroup _CorsairMouseIndvLED;
private ListLedGroup _CorsairMousepadIndvLED;
void Main()
{
//Split off Primary function chain to a Task
new Task(() => { var _call = CallPrimary(); }).Start();
}
//Async function which calls Primary
async Task CallPrimary()
{
await Task.Delay(500); //Sleep for 500 ms
Primary();
}
//The Primary loop function
void Primary()
{
var BaseColor = System.Drawing.Color.DodgerBlue;
var HighlightColor = System.Drawing.Color.Magenta;
//Set Base Keyboard lighting.
//Other LED's are built above this base layer.
if (Setbase == false)
{
_BaseColor = BaseColor;
CorsairUpdateState(_BaseColor);
Setbase = true;
}
//Highlight critical keys
CorsairApplyMapKeyLighting("D1", HighlightColor);
CorsairApplyMapKeyLighting("D2", HighlightColor);
CorsairApplyMapKeyLighting("D3", HighlightColor);
CorsairApplyMapKeyLighting("D4", HighlightColor);
CorsairApplyMapKeyLighting("A", HighlightColor);
CorsairApplyMapKeyLighting("B", HighlightColor);
CorsairApplyMapKeyLighting("C", HighlightColor);
//Update Keyboard
if (CorsairSDK == true)
{
CorsairUpdateLED();
}
}
//Initialise CUE.Net
void InitializeCorsairSDK()
{
CueSDK.Initialize();
CorsairSDK = true;
CueSDK.KeyboardSDK.Brush = (SolidColorBrush)Color.Red;
//Group for All Keys
_CorsairAllKeyboardLED = new ListLedGroup(CueSDK.KeyboardSDK, CueSDK.KeyboardSDK);
_CorsairAllKeyboardLED.ZIndex = 1;
//Group for individual Keys
_CorsairKeyboardIndvLED = new ListLedGroup(CueSDK.KeyboardSDK);
_CorsairKeyboardIndvLED.ZIndex = 10;
}
//Send the update to the device
void CorsairUpdateLED()
{
if (CorsairSDK != false)
{
CueSDK.KeyboardSDK.Update();
}
}
//Update function for ALL keys
void CorsairUpdateState(System.Drawing.Color col)
{
if (CorsairSDK != false)
{
SolidColorBrush _CorsairAllLEDBrush = new SolidColorBrush(col);
_CorsairAllHeadsetLED.Brush = _CorsairAllLEDBrush;
}
}
//Update function for Individual key
void CorsairApplyMapKeyLighting(string key, System.Drawing.Color col)
{
if (CorsairSDK != false)
{
if (Corsairkeyids.ContainsKey(key))
{
SolidColorBrush _CorsairLEDBrush = new SolidColorBrush(col);
_CorsairKeyboardIndvLED.RemoveLeds(_CorsairKeyboardIndvLED.GetLeds().ToList());
_CorsairKeyboardIndvLED.AddLed(Corsairkeyids[key]);
_CorsairKeyboardIndvLED.Brush = (SolidColorBrush)col;
}
}
}
//Dictionary for String -> CorsairLedID lookup
Dictionary<string, CorsairLedId> Corsairkeyids = new Dictionary<string, CorsairLedId>()
{
{"F1", CorsairLedId.F1},
{"F2", CorsairLedId.F2},
{"F3", CorsairLedId.F3},
{"F4", CorsairLedId.F4},
{"F5", CorsairLedId.F5},
{"F6", CorsairLedId.F6},
{"F7", CorsairLedId.F7},
{"F8", CorsairLedId.F8},
{"F9", CorsairLedId.F9},
{"F10", CorsairLedId.F10},
{"F11", CorsairLedId.F11},
{"F12", CorsairLedId.F12},
{"D1", CorsairLedId.D1},
{"D2", CorsairLedId.D2},
{"D3", CorsairLedId.D3},
{"D4", CorsairLedId.D4},
{"D5", CorsairLedId.D5},
{"D6", CorsairLedId.D6},
{"D7", CorsairLedId.D7},
{"D8", CorsairLedId.D8},
{"D9", CorsairLedId.D9},
{"D0", CorsairLedId.D0},
{"A", CorsairLedId.A},
{"B", CorsairLedId.B},
{"C", CorsairLedId.C},
//...
};
}
from cue.net.
This should do what you described above if I understood it right:
public class Program
{
private static Random _random = new Random();
private static ListLedGroup _keyMapLedGroup;
private static KeyMapBrush _keyMapBrush;
public static void Main(string[] args)
{
Console.WriteLine("Press any key to exit ...");
Console.WriteLine();
Task.Factory.StartNew(
() =>
{
Console.ReadKey();
Environment.Exit(0);
});
CueSDK.Initialize();
CueSDK.KeyboardSDK.Brush = (SolidColorBrush)Color.Black; // Set base-color
_keyMapLedGroup = new ListLedGroup(CueSDK.KeyboardSDK, CueSDK.KeyboardSDK);
_keyMapBrush = new KeyMapBrush();
_keyMapLedGroup.Brush = _keyMapBrush;
CueSDK.UpdateMode = UpdateMode.Continuous;
while (true) // this simulates your own task doing the work
{
_keyMapBrush.ClearKeyMap();
int keyCount = _random.Next(30);
for (int i = 0; i < keyCount; i++)
{
_keyMapBrush.CorsairApplyMapKeyLighting(GetRandomLedId(), ColorHelper.ColorFromHSV(_random.Next(360), 1, 1));
}
Thread.Sleep(500);
}
}
private static CorsairLedId GetRandomLedId()
{
CorsairLedId[] ids = ((CorsairLedId[])Enum.GetValues(typeof(CorsairLedId)));
return ids[_random.Next(ids.Length - 1)];
}
}
public class KeyMapBrush : AbstractBrush
{
private Dictionary<CorsairLedId, Color> _keyMap = new Dictionary<CorsairLedId, Color>();
public void ClearKeyMap()
{
_keyMap.Clear();
}
// depending on how you call this method you might need to lock the dictionary in all the methods to prevent weird exceptions due to concurrent accesses from different threads.
public void CorsairApplyMapKeyLighting(CorsairLedId key, Color col)
{
_keyMap[key] = col;
}
// If you're able to include your logic which key to color here this might get easier than working with the dictionary and stuff.
protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
CorsairLedId ledId = renderTarget.LedId;
Color color;
if (_keyMap.TryGetValue(ledId, out color))
return color;
return CorsairColor.Transparent; ;
}
}
from cue.net.
This looks really promising, I am in the process of trying to implement it into my code (See earlier comment as I added a snapshot of my entire code for reference).
Something that I'm a bit unsure about is the line:
CueSDK.UpdateMode = UpdateMode.Continuous;
As whenever I set this value, it throws continuous System.NullReferenceException errors which I can't track down, and blocks all further CUE calls.
from cue.net.
Something that I'm a bit unsure about is the line:
CueSDK.UpdateMode = UpdateMode.Continuous;
Try to replace the line with a 'CueSDK.Update();'
this shouldn't trow the same exception but might give you a better message/stacktrace.
from cue.net.
I'm not sure if I performed it correctly, but it seems to be breaking here:
and it occurs when CueSDK.KeyboardSDK.Update(); gets called.
from cue.net.
Oh shit, brush should be null-checked here.
You set the update mode before applying the brush to the led group which causes the issue here (due to the missing null check in the library). Just make sure you completely set up all the groups/brushes before enabling the auto-update (safest should be to set the brush with the object initializer)
from cue.net.
My initialisation function is:
CueSDK.Initialize();
CorsairSDK = true;
_CorsairKeyboardIndvBrush = new KeyMapBrush();
_CorsairKeyboardIndvLED = new ListLedGroup(CueSDK.KeyboardSDK, CueSDK.KeyboardSDK);
_CorsairAllKeyboardLED = new ListLedGroup(CueSDK.KeyboardSDK, CueSDK.KeyboardSDK);
_CorsairAllKeyboardLED.ZIndex = 1;
_CorsairKeyboardIndvLED.ZIndex = 10;
_CorsairKeyboardIndvLED.Brush = _CorsairKeyboardIndvBrush;
CueSDK.UpdateMode = UpdateMode.Continuous;
However it is still throwing this error. Could the .CorsairApplyMapKeyLighting() method OR CorsairUpdateState() be interfering with it?
void CorsairUpdateState()
{
CueSDK.KeyboardSDK.Brush = (SolidColorBrush)col;
}
Note: Though when i comment out that line it still throws the error.
from cue.net.
_CorsairAllKeyboardLED
has no brush applied.
from cue.net.
Oh, nice catch.
So by adding:
_CorsairAllKeyboardLED.Brush = (SolidColorBrush)System.Drawing.Color.Black;
before setting the UpdateMode, that still doesn't fix the error.. >.>
However if I set the UpdateMode to Manual, call an update from my async function and comment out the following, it does work without throwing any exceptions. Though this still leaves me unable to set the base color of the keyboard after the initialisation however, and UpdateMode.Continuous is still unhappy.
void CorsairUpdateState()
{
//_CorsairAllKeyboardLED.Brush = (SolidColorBrush)col;
}
from cue.net.
Ok, I don't get this. I don't see any reason why you'd need to comment that line to make it work.
Can you post your current code again?
from cue.net.
After hunting out a few silly mistakes, I have got it to "work" with the following code. While it does work, it continues to throw the NullReferenceExceptions every tick and UpdateMode.Continuous does not work at all still.
class TestClass
{
bool CorsairSDK = false;
bool Setbase = false;
Color _BaseColor = System.Drawing.Color.Black;
private ListLedGroup _CorsairAllKeyboardLED;
private ListLedGroup _CorsairKeyboardIndvLED;
private KeyMapBrush _CorsairKeyboardIndvBrush;
void Main()
{
//Split off Primary function chain to a Task
new Task(() => { var _call = CallPrimary(); }).Start();
}
//Async function which calls Primary
async Task CallPrimary()
{
await Task.Delay(500); //Sleep for 500 ms
Primary();
}
//The Primary loop function
void Primary()
{
var BaseColor = System.Drawing.Color.DodgerBlue;
var HighlightColor = System.Drawing.Color.Magenta;
//Set Base Keyboard lighting.
//Other LED's are built above this base layer.
if (Setbase == false)
{
_BaseColor = BaseColor;
CorsairUpdateState(_BaseColor);
Setbase = true;
}
//Highlight critical keys
CorsairApplyMapKeyLighting("D1", HighlightColor);
CorsairApplyMapKeyLighting("D2", HighlightColor);
CorsairApplyMapKeyLighting("D3", HighlightColor);
CorsairApplyMapKeyLighting("D4", HighlightColor);
CorsairApplyMapKeyLighting("A", HighlightColor);
CorsairApplyMapKeyLighting("B", HighlightColor);
CorsairApplyMapKeyLighting("C", HighlightColor);
//Update Keyboard
if (CorsairSDK == true)
{
CorsairUpdateLED();
}
}
//Initialise CUE.Net
void InitializeCorsairSDK()
{
CueSDK.Initialize();
CorsairSDK = true;
_CorsairKeyboardIndvBrush = new KeyMapBrush();
_CorsairKeyboardIndvLED = new ListLedGroup(CueSDK.KeyboardSDK, CueSDK.KeyboardSDK);
_CorsairAllKeyboardLED = new ListLedGroup(CueSDK.KeyboardSDK, CueSDK.KeyboardSDK);
_CorsairAllKeyboardLED.ZIndex = 1;
_CorsairKeyboardIndvLED.ZIndex = 10;
_CorsairKeyboardIndvLED.Brush = _CorsairKeyboardIndvBrush;
_CorsairAllKeyboardLED.Brush = (SolidColorBrush)System.Drawing.Color.Black;
//CueSDK.UpdateMode = UpdateMode.Continuous;
}
//Send the update to the device
void CorsairUpdateLED()
{
if (CorsairSDK != false)
{
CueSDK.KeyboardSDK.Update();
}
}
//Update function for ALL keys
void CorsairUpdateState(System.Drawing.Color col)
{
if (CorsairSDK != false)
{
_CorsairAllKeyboardLED.Brush = (SolidColorBrush)col;
}
}
//Update function for Individual key
void CorsairApplyMapKeyLighting(string key, System.Drawing.Color col)
{
if (CorsairSDK != false)
{
if (Corsairkeyids.ContainsKey(key))
{
_CorsairKeyboardIndvBrush.CorsairApplyMapKeyLighting(Corsairkeyids[key], col);
}
}
}
//Dictionary for String -> CorsairLedID lookup
Dictionary<string, CorsairLedId> Corsairkeyids = new Dictionary<string, CorsairLedId>()
{
{"F1", CorsairLedId.F1},
{"F2", CorsairLedId.F2},
{"F3", CorsairLedId.F3},
{"F4", CorsairLedId.F4},
{"F5", CorsairLedId.F5},
{"F6", CorsairLedId.F6},
{"F7", CorsairLedId.F7},
{"F8", CorsairLedId.F8},
{"F9", CorsairLedId.F9},
{"F10", CorsairLedId.F10},
{"F11", CorsairLedId.F11},
{"F12", CorsairLedId.F12},
{"D1", CorsairLedId.D1},
{"D2", CorsairLedId.D2},
{"D3", CorsairLedId.D3},
{"D4", CorsairLedId.D4},
{"D5", CorsairLedId.D5},
{"D6", CorsairLedId.D6},
{"D7", CorsairLedId.D7},
{"D8", CorsairLedId.D8},
{"D9", CorsairLedId.D9},
{"D0", CorsairLedId.D0},
{"A", CorsairLedId.A},
{"B", CorsairLedId.B},
{"C", CorsairLedId.C},
//...
};
}
public class KeyMapBrush : AbstractBrush
{
private Dictionary<CorsairLedId, Color> _keyMap = new Dictionary<CorsairLedId, Color>();
public void ClearKeyMap()
{
_keyMap.Clear();
}
// depending on how you call this method you might need to lock the dictionary in all the methods to prevent weird exceptions due to concurrent accesses from different threads.
public void CorsairApplyMapKeyLighting(CorsairLedId key, Color col)
{
_keyMap[key] = col;
}
//CorsairApplyAllKeyLighting
public void CorsairApplyAllKeyLighting(CorsairLed[] keys, Color col)
{
foreach (CorsairLed key in keys)
{
_keyMap[key] = col;
}
}
// If you're able to include your logic which key to color here this might get easier than working with the dictionary and stuff.
protected override CorsairColor GetColorAtPoint(RectangleF rectangle, BrushRenderTarget renderTarget)
{
CorsairLedId ledId = renderTarget.LedId;
Color color;
if (_keyMap.TryGetValue(ledId, out color))
return color;
return CorsairColor.Transparent;
}
}
from cue.net.
I just rebuilt CUE.NET from your latest commit and now both UpdateMode.Continuous and UpdateMode.Manual are working without issue.
from cue.net.
Ah i got it. I really don't know why this error doesn't came up earlier ...
The device is a ledgroup on it's own. since you didn't set a brush on it you got the nullreference-exception (which is now gone due to the correct null-check).
from cue.net.
Awesome, that makes sense.
Thanks so much for stepping through this all with me, you have been an amazing help. :D
from cue.net.
Related Issues (20)
- Uninitialize or Shutdown functionality HOT 4
- Test development-changes with all devices HOT 6
- [1.0.0] Keyboard DeviceRectangle size HOT 3
- Using CUE.NET with CUE2 keyboard keys go to white when calling update() HOT 4
- Update Wiki
- Profile-API isn't able to find CUE2 profiles
- CUE.NET Does not initialize for some users HOT 5
- K95 Platinum lightbar support HOT 8
- Load SDK dll from different location HOT 4
- VOID Wireless bug and feature request HOT 2
- Keys which don't exist on a physical device (ie. Macro keys) throws null reference HOT 4
- Locking the PC stops updates (sometimes) HOT 6
- HELP NEEDED: How to keep LED changes active after running application? HOT 2
- UWP Compatibility HOT 12
- CueSDK.Reinitialize never returns HOT 1
- Can't update Key Colors individually unless Brush is applied. HOT 4
- Calling EnableKeypressCallback() more than once causes duplicated events and GC/NRE issues
- Can't read color without device freezing
- Corsair keyboard K70 MK.2 RGB HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cue.net.