From 6e4acceb5e8edb4c644283475bcc62df2a716963 Mon Sep 17 00:00:00 2001 From: Akash Chaudhary <45934600+akash1306@users.noreply.github.com> Date: Wed, 1 Apr 2026 13:57:46 +0000 Subject: [PATCH 1/2] fix: run flash operations on background thread to avoid UI message pump dependency Flash/reset/EEPROM operations used async/await without ConfigureAwait(false), causing continuations between sequential process calls to be posted back to the UI thread via WindowsFormsSynchronizationContext. When the window received no input events, the message loop would not wake to process these continuations, stalling firmware updates for hours until a stray WM_MOUSEMOVE arrived. Wrap bootloader operation loops in Task.Run() so continuations execute on threadpool threads with no dependency on the Windows message pump. --- windows/QMK Toolbox/MainWindow.cs | 74 +++++++++++++++++++------------ 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/windows/QMK Toolbox/MainWindow.cs b/windows/QMK Toolbox/MainWindow.cs index 4ca7b4361f..79b8f9dfc5 100644 --- a/windows/QMK Toolbox/MainWindow.cs +++ b/windows/QMK Toolbox/MainWindow.cs @@ -293,19 +293,23 @@ private async void FlashAllAsync() if (!windowState.AutoFlashEnabled) { - Invoke(new Action(DisableUI)); + DisableUI(); } - foreach (BootloaderDevice b in FindBootloaders()) + var bootloaders = FindBootloaders(); + await Task.Run(async () => { - logTextBox.LogBootloader("Attempting to flash, please don't remove device"); - await b.Flash(selectedMcu, filePath); - logTextBox.LogBootloader("Flash complete"); - } + foreach (BootloaderDevice b in bootloaders) + { + Invoke(new Action(() => logTextBox.LogBootloader("Attempting to flash, please don't remove device"))); + await b.Flash(selectedMcu, filePath); + Invoke(new Action(() => logTextBox.LogBootloader("Flash complete"))); + } + }); if (!windowState.AutoFlashEnabled) { - Invoke(new Action(EnableUI)); + EnableUI(); } } @@ -315,20 +319,24 @@ private async void ResetAllAsync() if (!windowState.AutoFlashEnabled) { - Invoke(new Action(DisableUI)); + DisableUI(); } - foreach (BootloaderDevice b in FindBootloaders()) + var bootloaders = FindBootloaders(); + await Task.Run(async () => { - if (b.IsResettable) + foreach (BootloaderDevice b in bootloaders) { - await b.Reset(selectedMcu); + if (b.IsResettable) + { + await b.Reset(selectedMcu); + } } - } + }); if (!windowState.AutoFlashEnabled) { - Invoke(new Action(EnableUI)); + EnableUI(); } } @@ -338,22 +346,26 @@ private async void ClearEepromAllAsync() if (!windowState.AutoFlashEnabled) { - Invoke(new Action(DisableUI)); + DisableUI(); } - foreach (BootloaderDevice b in FindBootloaders()) + var bootloaders = FindBootloaders(); + await Task.Run(async () => { - if (b.IsEepromFlashable) + foreach (BootloaderDevice b in bootloaders) { - logTextBox.LogBootloader("Attempting to clear EEPROM, please don't remove device"); - await b.FlashEeprom(selectedMcu, "reset.eep"); - logTextBox.LogBootloader("EEPROM clear complete"); + if (b.IsEepromFlashable) + { + Invoke(new Action(() => logTextBox.LogBootloader("Attempting to clear EEPROM, please don't remove device"))); + await b.FlashEeprom(selectedMcu, "reset.eep"); + Invoke(new Action(() => logTextBox.LogBootloader("EEPROM clear complete"))); + } } - } + }); if (!windowState.AutoFlashEnabled) { - Invoke(new Action(EnableUI)); + EnableUI(); } } @@ -364,22 +376,26 @@ private async void SetHandednessAllAsync(bool left) if (!windowState.AutoFlashEnabled) { - Invoke(new Action(DisableUI)); + DisableUI(); } - foreach (BootloaderDevice b in FindBootloaders()) + var bootloaders = FindBootloaders(); + await Task.Run(async () => { - if (b.IsEepromFlashable) + foreach (BootloaderDevice b in bootloaders) { - logTextBox.LogBootloader("Attempting to set handedness, please don't remove device"); - await b.FlashEeprom(selectedMcu, file); - logTextBox.LogBootloader("EEPROM write complete"); + if (b.IsEepromFlashable) + { + Invoke(new Action(() => logTextBox.LogBootloader("Attempting to set handedness, please don't remove device"))); + await b.FlashEeprom(selectedMcu, file); + Invoke(new Action(() => logTextBox.LogBootloader("EEPROM write complete"))); + } } - } + }); if (!windowState.AutoFlashEnabled) { - Invoke(new Action(EnableUI)); + EnableUI(); } } From 38b86f534ec96c75aa487ad3368cad3e4ae522f7 Mon Sep 17 00:00:00 2001 From: Akash Chaudhary <45934600+akash1306@users.noreply.github.com> Date: Thu, 2 Apr 2026 00:24:07 +0200 Subject: [PATCH 2/2] Added Tasks import --- windows/QMK Toolbox/MainWindow.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/windows/QMK Toolbox/MainWindow.cs b/windows/QMK Toolbox/MainWindow.cs index 79b8f9dfc5..98b9532b14 100644 --- a/windows/QMK Toolbox/MainWindow.cs +++ b/windows/QMK Toolbox/MainWindow.cs @@ -14,6 +14,7 @@ using System.Net.Http; using System.Runtime.InteropServices; using System.Windows.Forms; +using System.Threading.Tasks; namespace QMK_Toolbox {