[KBM] Fixing text replacement bug (#46069)

There is a bug now where text replacement is causing the app to crash.
Wrapping those blocks in try catch so the worker stays alive.
This commit is contained in:
Jaylyn Barbee
2026-03-11 14:02:46 -04:00
committed by GitHub
parent 4620f6f381
commit 39bbf0593e
2 changed files with 35 additions and 24 deletions

View File

@@ -428,20 +428,20 @@ namespace Helpers
{ {
while (true) while (true)
{ {
std::wstring text;
{
std::unique_lock<std::mutex> lock(s_queueMutex);
s_queueCV.wait(lock, [] { return !s_clipboardQueue.empty() || s_shutdown.load(); });
if (s_shutdown.load())
{
break;
}
text = std::move(s_clipboardQueue.front());
s_clipboardQueue.pop();
}
try try
{ {
std::wstring text;
{
std::unique_lock<std::mutex> lock(s_queueMutex);
s_queueCV.wait(lock, [] { return !s_clipboardQueue.empty() || s_shutdown.load(); });
if (s_shutdown.load())
{
break;
}
text = std::move(s_clipboardQueue.front());
s_clipboardQueue.pop();
}
// Snapshot current clipboard state // Snapshot current clipboard state
bool hadOriginalText = false; bool hadOriginalText = false;
std::wstring originalClipboardText; std::wstring originalClipboardText;
@@ -490,22 +490,15 @@ namespace Helpers
} }
} }
} }
catch (const std::exception& ex)
{
OutputDebugStringA("KBM ClipboardWorker exception: ");
OutputDebugStringA(ex.what());
OutputDebugStringA("\n");
}
catch (...) catch (...)
{ {
OutputDebugStringA("KBM ClipboardWorker unknown exception\n"); OutputDebugStringA("KBM ClipboardWorker exception caught, continuing\n");
} }
} }
} }
// Function to send text via clipboard paste (Ctrl+V). // Inner implementation that may throw C++ exceptions.
// Saves the previous clipboard content and restores it asynchronously. static bool SendTextViaClipboardImpl(const std::wstring& text)
bool SendTextViaClipboard(const std::wstring& text)
{ {
// Lazily start the worker on first use. // Lazily start the worker on first use.
std::call_once(s_workerInitFlag, [] { std::call_once(s_workerInitFlag, [] {
@@ -524,7 +517,7 @@ namespace Helpers
}); });
// Enqueue the text and return immediately so we never block the // Enqueue the text and return immediately so we never block the
// low-level keyboard hook (WH_KEYBOARD_LL). // low-level keyboard hook (WH_KEYBOARD_LL).
{ {
std::lock_guard<std::mutex> lock(s_queueMutex); std::lock_guard<std::mutex> lock(s_queueMutex);
if (!s_clipboardQueue.empty()) if (!s_clipboardQueue.empty())
@@ -538,6 +531,24 @@ namespace Helpers
return true; return true;
} }
// Function to send text via clipboard paste (Ctrl+V).
// Saves the previous clipboard content and restores it asynchronously.
// This function MUST NOT throw — it's called from noexcept hook handlers.
// We use __try/__except (SEH) because C++ try/catch may be optimized away
// in Release builds when the caller is noexcept.
bool SendTextViaClipboard(const std::wstring& text) noexcept
{
__try
{
return SendTextViaClipboardImpl(text);
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
OutputDebugStringA("KBM SendTextViaClipboard SEH exception caught\n");
return false;
}
}
// Function to filter the key codes for artificial key codes // Function to filter the key codes for artificial key codes
int32_t FilterArtificialKeys(const int32_t& key) int32_t FilterArtificialKeys(const int32_t& key)
{ {

View File

@@ -42,7 +42,7 @@ namespace Helpers
void SetTextKeyEvents(std::vector<INPUT>& keyEventArray, const std::wstring& remapping); void SetTextKeyEvents(std::vector<INPUT>& keyEventArray, const std::wstring& remapping);
// Function to send text via clipboard paste (Ctrl+V). Saves and restores previous clipboard content. // Function to send text via clipboard paste (Ctrl+V). Saves and restores previous clipboard content.
bool SendTextViaClipboard(const std::wstring& text); bool SendTextViaClipboard(const std::wstring& text) noexcept;
// Function to return window handle for a full screen UWP app // Function to return window handle for a full screen UWP app
HWND GetFullscreenUWPWindowHandle(); HWND GetFullscreenUWPWindowHandle();