11using System ;
22using System . IO ;
33using System . Linq ;
4+ using System . Text ;
45using System . Threading ;
56using System . Drawing ;
67using System . Drawing . Imaging ;
1213using System . Runtime . CompilerServices ;
1314using System . Runtime . InteropServices ;
1415using System . Numerics ;
16+ using System . Text . Unicode ;
1517
1618namespace KeyboardLighting
1719{
@@ -20,14 +22,12 @@ namespace KeyboardLighting
2022
2123 class Program
2224 {
23-
25+ static readonly byte [ ] debugBuffer = new byte [ 1024 ] ;
2426 static readonly object colorsLock = new object ( ) ;
2527 static ORGBColor [ ] ? prevColors ;
2628 static DateTime lastUpdate = DateTime . MinValue ;
2729 static DateTime lastDebugImageSave = DateTime . MinValue ;
2830
29- // Remove fade progress tracking
30- // static float[] fadeProgress;
3131 static ORGBColor [ ] targetColors ;
3232
3333 const int MIN_CAPTURE_INTERVAL_MS = 16 ;
@@ -75,7 +75,7 @@ static void Main(string[] args)
7575
7676 prevColors = new ORGBColor [ ledCount ] ;
7777 ledColorsBuffer = new ORGBColor [ ledCount ] ;
78- // Removed fadeProgress
78+
7979 targetColors = new ORGBColor [ ledCount ] ;
8080
8181 var processor = new CPUImageProcessor ( config ) ;
@@ -183,7 +183,30 @@ static void ProcessFrame(ScreenCapturer capturer, CPUImageProcessor processor, O
183183
184184 if ( config . DebugStringUpdates )
185185 {
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+ }
187210 }
188211
189212 UpdateLedColors ( columnColors , config , ledCount ) ;
@@ -192,7 +215,12 @@ static void ProcessFrame(ScreenCapturer capturer, CPUImageProcessor processor, O
192215
193216 if ( config . DebugStringUpdates )
194217 {
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+ }
196224 }
197225
198226 if ( config . SaveDebugImages &&
@@ -217,7 +245,7 @@ static void ProcessFrame(ScreenCapturer capturer, CPUImageProcessor processor, O
217245 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
218246 static void UpdateLedColors ( ORGBColor [ ] columnColors , LightingConfig config , int ledCount )
219247 {
220- // Check if we want instant transitions (fadeSpeed at or very near 1.0)
248+
221249 bool instantTransition = config . FadeFactor >= 0.99 ;
222250
223251 var wasdEnabled = config . WASDEnabled ;
@@ -238,27 +266,26 @@ static void UpdateLedColors(ORGBColor[] columnColors, LightingConfig config, int
238266 {
239267 if ( wasdEnabled && Array . IndexOf ( wasdKeys , i ) >= 0 )
240268 {
241- // Handle WASD keys with special color
269+
242270 ledColorsBuffer [ i ] = new ORGBColor ( wasdR , wasdG , wasdB ) ;
243271 }
244272 else
245273 {
246- // Apply column colors to the keyboard
274+
247275 int columnIndex = Math . Min ( i , columnLength - 1 ) ;
248276
249277 if ( instantTransition )
250278 {
251- // With instantTransition, directly apply the column color
279+
252280 ledColorsBuffer [ i ] = columnColors [ columnIndex ] ;
253281 }
254282 else
255283 {
256- // For backward compatibility, keep some very minimal smoothing
284+
257285 ORGBColor prev = prevColors [ i ] ;
258286 ORGBColor target = columnColors [ columnIndex ] ;
259287
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 ;
262289
263290 byte r = ( byte ) Math . Round ( prev . R * ( 1 - t ) + target . R * t ) ;
264291 byte g = ( byte ) Math . Round ( prev . G * ( 1 - t ) + target . G * t ) ;
@@ -267,57 +294,61 @@ static void UpdateLedColors(ORGBColor[] columnColors, LightingConfig config, int
267294 ledColorsBuffer [ i ] = new ORGBColor ( r , g , b ) ;
268295 }
269296
270- // Store current color for next frame
271297 prevColors [ i ] = ledColorsBuffer [ i ] ;
272298 }
273299 }
274300 }
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 ] ) ;
275314
315+ public static byte [ ] GetBuffer ( ) => _threadLocalBuffer . Value ;
316+ }
276317 static void SaveDebugImages ( Bitmap frame , ORGBColor [ ] columnColors , LightingConfig config )
277318 {
278319 try
279320 {
280321 string folder = "images" ;
281322 Directory . CreateDirectory ( folder ) ;
282323
283- using ( var debugBmp = new Bitmap ( columnColors . Length , 50 ) )
284- {
324+ Span < byte > filenameBuffer = stackalloc byte [ 256 ] ;
325+ DateTime now = DateTime . Now ;
285326
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 ) ) ;
294330
295- for ( int x = 0 ; x < columnColors . Length ; x ++ )
331+ using ( var debugBmp = new Bitmap ( columnColors . Length , 50 ) )
296332 {
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 ) ;
310333
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+ }
313336 }
314337
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+ }
317343 }
318344 catch ( Exception ex )
319345 {
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+ }
321352 }
322353 }
323354 }
0 commit comments