1
1
using System ;
2
2
using System . IO ;
3
3
using System . Linq ;
4
+ using System . Text ;
4
5
using System . Threading ;
5
6
using System . Drawing ;
6
7
using System . Drawing . Imaging ;
12
13
using System . Runtime . CompilerServices ;
13
14
using System . Runtime . InteropServices ;
14
15
using System . Numerics ;
16
+ using System . Text . Unicode ;
15
17
16
18
namespace KeyboardLighting
17
19
{
@@ -20,14 +22,12 @@ namespace KeyboardLighting
20
22
21
23
class Program
22
24
{
23
-
25
+ static readonly byte [ ] debugBuffer = new byte [ 1024 ] ;
24
26
static readonly object colorsLock = new object ( ) ;
25
27
static ORGBColor [ ] ? prevColors ;
26
28
static DateTime lastUpdate = DateTime . MinValue ;
27
29
static DateTime lastDebugImageSave = DateTime . MinValue ;
28
30
29
- // Remove fade progress tracking
30
- // static float[] fadeProgress;
31
31
static ORGBColor [ ] targetColors ;
32
32
33
33
const int MIN_CAPTURE_INTERVAL_MS = 16 ;
@@ -75,7 +75,7 @@ static void Main(string[] args)
75
75
76
76
prevColors = new ORGBColor [ ledCount ] ;
77
77
ledColorsBuffer = new ORGBColor [ ledCount ] ;
78
- // Removed fadeProgress
78
+
79
79
targetColors = new ORGBColor [ ledCount ] ;
80
80
81
81
var processor = new CPUImageProcessor ( config ) ;
@@ -183,7 +183,30 @@ static void ProcessFrame(ScreenCapturer capturer, CPUImageProcessor processor, O
183
183
184
184
if ( config . DebugStringUpdates )
185
185
{
186
- Console . WriteLine ( $ "CPU colors: { string . Join ( ", " , columnColors . Take ( 5 ) . Select ( c => $ "R{ c . R } ,G{ c . G } ,B{ c . B } ") ) } ") ;
186
+
187
+ var span = debugBuffer . AsSpan ( ) ;
188
+ bool success = false ;
189
+ int written = 0 ;
190
+
191
+ if ( Utf8 . TryWrite ( span , $ "CPU colors: ", out written ) )
192
+ {
193
+ span = span . Slice ( written ) ;
194
+ for ( int i = 0 ; i < Math . Min ( 5 , columnColors . Length ) ; i ++ )
195
+ {
196
+ var c = columnColors [ i ] ;
197
+ if ( i > 0 && Utf8 . TryWrite ( span , $ ", ", out int commaWritten ) )
198
+ {
199
+ span = span . Slice ( commaWritten ) ;
200
+ }
201
+ if ( Utf8 . TryWrite ( span , $ "R{ c . R } ,G{ c . G } ,B{ c . B } ", out int colorWritten ) )
202
+ {
203
+ span = span . Slice ( colorWritten ) ;
204
+ written += colorWritten ;
205
+ }
206
+ else break ;
207
+ }
208
+ Console . WriteLine ( Encoding . UTF8 . GetString ( debugBuffer , 0 , debugBuffer . Length - span . Length ) ) ;
209
+ }
187
210
}
188
211
189
212
UpdateLedColors ( columnColors , config , ledCount ) ;
@@ -192,7 +215,12 @@ static void ProcessFrame(ScreenCapturer capturer, CPUImageProcessor processor, O
192
215
193
216
if ( config . DebugStringUpdates )
194
217
{
195
- Console . WriteLine ( $ "Updated LEDs, first LED: R{ ledColorsBuffer [ 0 ] . R } G{ ledColorsBuffer [ 0 ] . G } B{ ledColorsBuffer [ 0 ] . B } ") ;
218
+
219
+ var span = debugBuffer . AsSpan ( ) ;
220
+ if ( Utf8 . TryWrite ( span , $ "Updated LEDs, first LED: R{ ledColorsBuffer [ 0 ] . R } G{ ledColorsBuffer [ 0 ] . G } B{ ledColorsBuffer [ 0 ] . B } ", out int written ) )
221
+ {
222
+ Console . WriteLine ( Encoding . UTF8 . GetString ( debugBuffer , 0 , written ) ) ;
223
+ }
196
224
}
197
225
198
226
if ( config . SaveDebugImages &&
@@ -217,7 +245,7 @@ static void ProcessFrame(ScreenCapturer capturer, CPUImageProcessor processor, O
217
245
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
218
246
static void UpdateLedColors ( ORGBColor [ ] columnColors , LightingConfig config , int ledCount )
219
247
{
220
- // Check if we want instant transitions (fadeSpeed at or very near 1.0)
248
+
221
249
bool instantTransition = config . FadeFactor >= 0.99 ;
222
250
223
251
var wasdEnabled = config . WASDEnabled ;
@@ -238,27 +266,26 @@ static void UpdateLedColors(ORGBColor[] columnColors, LightingConfig config, int
238
266
{
239
267
if ( wasdEnabled && Array . IndexOf ( wasdKeys , i ) >= 0 )
240
268
{
241
- // Handle WASD keys with special color
269
+
242
270
ledColorsBuffer [ i ] = new ORGBColor ( wasdR , wasdG , wasdB ) ;
243
271
}
244
272
else
245
273
{
246
- // Apply column colors to the keyboard
274
+
247
275
int columnIndex = Math . Min ( i , columnLength - 1 ) ;
248
276
249
277
if ( instantTransition )
250
278
{
251
- // With instantTransition, directly apply the column color
279
+
252
280
ledColorsBuffer [ i ] = columnColors [ columnIndex ] ;
253
281
}
254
282
else
255
283
{
256
- // For backward compatibility, keep some very minimal smoothing
284
+
257
285
ORGBColor prev = prevColors [ i ] ;
258
286
ORGBColor target = columnColors [ columnIndex ] ;
259
287
260
- // Simple lerp with very high weight toward target color
261
- float t = 0.8f ; // High value for quick transition but not instant
288
+ float t = 0.8f ;
262
289
263
290
byte r = ( byte ) Math . Round ( prev . R * ( 1 - t ) + target . R * t ) ;
264
291
byte g = ( byte ) Math . Round ( prev . G * ( 1 - t ) + target . G * t ) ;
@@ -267,57 +294,61 @@ static void UpdateLedColors(ORGBColor[] columnColors, LightingConfig config, int
267
294
ledColorsBuffer [ i ] = new ORGBColor ( r , g , b ) ;
268
295
}
269
296
270
- // Store current color for next frame
271
297
prevColors [ i ] = ledColorsBuffer [ i ] ;
272
298
}
273
299
}
274
300
}
301
+ [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
302
+ static void WriteFormattedToConsole < T > ( T value ) where T : IUtf8SpanFormattable
303
+ {
304
+ Span < byte > buffer = stackalloc byte [ 512 ] ;
305
+ if ( value . TryFormat ( buffer , out int written , default , null ) )
306
+ {
307
+ Console . WriteLine ( Encoding . UTF8 . GetString ( buffer . Slice ( 0 , written ) ) ) ;
308
+ }
309
+ }
310
+ static class Utf8BufferPool
311
+ {
312
+ private static readonly ThreadLocal < byte [ ] > _threadLocalBuffer =
313
+ new ThreadLocal < byte [ ] > ( ( ) => new byte [ 2048 ] ) ;
275
314
315
+ public static byte [ ] GetBuffer ( ) => _threadLocalBuffer . Value ;
316
+ }
276
317
static void SaveDebugImages ( Bitmap frame , ORGBColor [ ] columnColors , LightingConfig config )
277
318
{
278
319
try
279
320
{
280
321
string folder = "images" ;
281
322
Directory . CreateDirectory ( folder ) ;
282
323
283
- using ( var debugBmp = new Bitmap ( columnColors . Length , 50 ) )
284
- {
324
+ Span < byte > filenameBuffer = stackalloc byte [ 256 ] ;
325
+ DateTime now = DateTime . Now ;
285
326
286
- var bmpData = debugBmp . LockBits (
287
- new Rectangle ( 0 , 0 , debugBmp . Width , debugBmp . Height ) ,
288
- ImageLockMode . WriteOnly ,
289
- PixelFormat . Format32bppArgb ) ;
290
-
291
- IntPtr ptr = bmpData . Scan0 ;
292
- int bytes = Math . Abs ( bmpData . Stride ) * debugBmp . Height ;
293
- byte [ ] rgbValues = new byte [ bytes ] ;
327
+ if ( Utf8 . TryWrite ( filenameBuffer , $ "{ folder } /debug_frame_{ now : yyyyMMdd_HHmmss_fff} .png", out int debugWritten ) )
328
+ {
329
+ string debugFilename = Encoding . UTF8 . GetString ( filenameBuffer . Slice ( 0 , debugWritten ) ) ;
294
330
295
- for ( int x = 0 ; x < columnColors . Length ; x ++ )
331
+ using ( var debugBmp = new Bitmap ( columnColors . Length , 50 ) )
296
332
{
297
- var color = columnColors [ x ] ;
298
- for ( int y = 0 ; y < 50 ; y ++ )
299
- {
300
- int offset = y * bmpData . Stride + x * 4 ;
301
- rgbValues [ offset ] = color . B ;
302
- rgbValues [ offset + 1 ] = color . G ;
303
- rgbValues [ offset + 2 ] = color . R ;
304
- rgbValues [ offset + 3 ] = 255 ;
305
- }
306
- }
307
-
308
- Marshal . Copy ( rgbValues , 0 , ptr , bytes ) ;
309
- debugBmp . UnlockBits ( bmpData ) ;
310
333
311
- string filename = $ " { folder } /debug_frame_ { DateTime . Now : yyyyMMdd_HHmmss_fff } .png" ;
312
- debugBmp . Save ( filename , ImageFormat . Png ) ;
334
+ debugBmp . Save ( debugFilename , ImageFormat . Png ) ;
335
+ }
313
336
}
314
337
315
- string frameFilename = $ "{ folder } /captured_frame_{ DateTime . Now : yyyyMMdd_HHmmss_fff} .png";
316
- frame . Save ( frameFilename , ImageFormat . Png ) ;
338
+ if ( Utf8 . TryWrite ( filenameBuffer , $ "{ folder } /captured_frame_{ now : yyyyMMdd_HHmmss_fff} .png", out int frameWritten ) )
339
+ {
340
+ string frameFilename = Encoding . UTF8 . GetString ( filenameBuffer . Slice ( 0 , frameWritten ) ) ;
341
+ frame . Save ( frameFilename , ImageFormat . Png ) ;
342
+ }
317
343
}
318
344
catch ( Exception ex )
319
345
{
320
- Console . WriteLine ( $ "Error saving debug images: { ex . Message } ") ;
346
+
347
+ var span = debugBuffer . AsSpan ( ) ;
348
+ if ( Utf8 . TryWrite ( span , $ "Error saving debug images: { ex . Message } ", out int written ) )
349
+ {
350
+ Console . WriteLine ( Encoding . UTF8 . GetString ( debugBuffer , 0 , written ) ) ;
351
+ }
321
352
}
322
353
}
323
354
}
0 commit comments