/// <summary> /// Creates a new console app given a set of boundaries /// </summary> /// <param name="w">The width of the app</param> /// <param name="h">The height of the app</param> public ConsoleApp(int w, int h) { this.Name = GetType().Name; this.console = ConsoleProvider.Current; consoleWriter = Console.Out; this.lastConsoleWidth = this.console.BufferWidth; this.lastConsoleHeight = this.console.WindowHeight; this.observable = new ObservableObject(this); cycleRateMeter = new FrameRateMeter(); this.EndOfCycle.SubscribeForLifetime(Cycle, this); SetFocusOnStart = true; LayoutRoot = new ConsolePanel(w, h); FocusManager = new FocusManager(); LayoutRoot.Application = this; isFullScreen = false; FocusManager.SubscribeForLifetime(nameof(FocusManager.FocusedControl), () => RequestPaintAsync(), this); LayoutRoot.Controls.BeforeAdded.SubscribeForLifetime((c) => { c.Application = this; c.BeforeAddedToVisualTreeInternal(); }, this); LayoutRoot.Controls.BeforeRemoved.SubscribeForLifetime((c) => { c.BeforeRemovedFromVisualTreeInternal(); }, this); LayoutRoot.Controls.Added.SubscribeForLifetime(ControlAddedToVisualTree, this); LayoutRoot.Controls.Removed.SubscribeForLifetime(ControlRemovedFromVisualTree, this); WindowResized.SubscribeForLifetime(HandleDebouncedResize, this); this.LoopStarted.SubscribeOnce(() => _current = this); this.EndOfCycle.SubscribeForLifetime(DrainPaints, this); }
private void Pump() { try { bool stopRequested = false; frameRateMeter = new FrameRateMeter(); paintRateMeter = new FrameRateMeter(); while (true) { if ((lastConsoleWidth != this.console.BufferWidth || lastConsoleHeight != this.console.WindowHeight)) { DebounceResize(); WindowResized.Fire(); } bool idle = true; List <PumpMessage> iterationQueue; PaintMessage iterationPaintMessage = null; lock (pumpMessageQueue) { iterationQueue = new List <PumpMessage>(pumpMessageQueue); pumpMessageQueue.Clear(); } foreach (var message in iterationQueue) { idle = false; if (message is StopPumpMessage) { stopRequested = true; break; } else if (message is PaintMessage) { iterationPaintMessage = message as PaintMessage; } else { TryWork(message); } } if (iterationPaintMessage != null) { TryWork(iterationPaintMessage); paintRateMeter.Increment(); #if PROFILING CliProfiler.Instance.PaintMessagesProcessed++; #endif } if (stopRequested) { break; } if (this.console.KeyAvailable) { idle = false; var info = this.console.ReadKey(true); QueueAction(() => { HandleKeyInput(info); }); } frameRateMeter.Increment(); if (idle) { Thread.Sleep(0); } #if PROFILING else { CliProfiler.Instance.TotalNonIdleIterations++; } #endif } runDeferred.Resolve(); } catch (Exception ex) { runDeferred.Reject(ex); } finally { IsRunning = false; runDeferred = null; } }
private void Pump() { try { OnThredStart(); SynchronizationContext.SetSynchronizationContext(new CustomSyncContext(this)); bool stopRequested = false; cycleRateMeter = new FrameRateMeter(); paintRateMeter = new FrameRateMeter(); while (true) { cycleRateMeter.Increment(); if ((lastConsoleWidth != this.console.BufferWidth || lastConsoleHeight != this.console.WindowHeight)) { DebounceResize(); WindowResized.Fire(); } bool idle = true; List <PumpMessage> iterationQueue; PaintMessage iterationPaintMessage = null; var paintDeferreds = new List <Deferred>(); lock (pumpMessageQueue) { iterationQueue = new List <PumpMessage>(pumpMessageQueue); pumpMessageQueue.Clear(); } foreach (var message in iterationQueue) { idle = false; if (message is StopPumpMessage) { stopRequested = true; break; } else if (message is PaintMessage) { if (message.Deferred != null) { paintDeferreds.Add(message.Deferred); } iterationPaintMessage = message as PaintMessage; } else { TryWork(message); } } if (iterationPaintMessage != null) { TryWork(iterationPaintMessage); // since we debounce paints, make sure the paints // that got debounced get resolved foreach (var deferred in paintDeferreds) { if (deferred != iterationPaintMessage.Deferred) { deferred.Resolve(); } } paintRateMeter.Increment(); } if (stopRequested) { break; } if (this.console.KeyAvailable) { idle = false; var info = this.console.ReadKey(true); var effectiveMinTimeBetweenKeyPresses = MinTimeBetweenKeyPresses; if (KeyThrottlingEnabled && info.Key == lastKey && DateTime.UtcNow - lastKeyPressTime < effectiveMinTimeBetweenKeyPresses) { // the user is holding the key down and throttling is enabled } else { lastKeyPressTime = DateTime.UtcNow; lastKey = info.Key; QueueAction(() => HandleKeyInput(info)); } } else if (sendKeys.Count > 0) { idle = false; var info = sendKeys.Dequeue(); QueueAction(() => HandleKeyInput(info)); } if (idle) { Thread.Sleep(1); } } runDeferred.Resolve(); } catch (Exception ex) { runDeferred.Reject(ex); } finally { IsRunning = false; runDeferred = null; } }