diff --git a/accessible/windows/msaa/Compatibility.cpp b/accessible/windows/msaa/Compatibility.cpp index ce4e858d38ce916006a426dcd4ac915df45d6315..3fdda8f866c62f4799f08fe5d712aec477529c1d 100644 --- a/accessible/windows/msaa/Compatibility.cpp +++ b/accessible/windows/msaa/Compatibility.cpp @@ -243,3 +243,40 @@ void Compatibility::GetHumanReadableConsumersStr(nsAString& aResult) { } } } + +// Time when SuppressA11yForClipboardCopy() was called, as returned by +// ::GetTickCount(). +static DWORD sA11yClipboardCopySuppressionStartTime = 0; + +/* static */ +void Compatibility::SuppressA11yForClipboardCopy() { + // Bug 1774285: Windows Suggested Actions (introduced in Windows 11 22H2) + // might walk the a11y tree using UIA whenever anything is copied to the + // clipboard. This causes an unacceptable hang, particularly when the cache + // is disabled. + bool doSuppress = [&] { + switch ( + StaticPrefs::accessibility_windows_suppress_after_clipboard_copy()) { + case 0: + return false; + case 1: + return true; + default: + return NeedsWindows11SuggestedActionsWorkaround(); + } + }(); + + if (doSuppress) { + sA11yClipboardCopySuppressionStartTime = ::GetTickCount(); + } +} + +/* static */ +bool Compatibility::IsA11ySuppressedForClipboardCopy() { + constexpr DWORD kSuppressTimeout = 1000; // ms + if (!sA11yClipboardCopySuppressionStartTime) { + return false; + } + return ::GetTickCount() - sA11yClipboardCopySuppressionStartTime < + kSuppressTimeout; +} diff --git a/accessible/windows/msaa/Compatibility.h b/accessible/windows/msaa/Compatibility.h index b9684db70e82a92c5dbe2c4201164fd9425241fc..072ecb4e0a05212b50db39da3622f48b3f7d468c 100644 --- a/accessible/windows/msaa/Compatibility.h +++ b/accessible/windows/msaa/Compatibility.h @@ -77,6 +77,9 @@ class Compatibility { static bool IsModuleVersionLessThan(HMODULE aModuleHandle, unsigned long long aVersion); + static void SuppressA11yForClipboardCopy(); + static bool IsA11ySuppressedForClipboardCopy(); + private: Compatibility(); Compatibility(const Compatibility&); diff --git a/accessible/windows/msaa/LazyInstantiator.cpp b/accessible/windows/msaa/LazyInstantiator.cpp index 9bc2190ef82fcfa05491296881d850e78e01a3ad..b637c0bb9b9c29ca7e086c7caa11b1393641018e 100644 --- a/accessible/windows/msaa/LazyInstantiator.cpp +++ b/accessible/windows/msaa/LazyInstantiator.cpp @@ -214,6 +214,14 @@ bool LazyInstantiator::IsBlockedInjection() { * @return true if we should instantiate a11y */ bool LazyInstantiator::ShouldInstantiate(const DWORD aClientTid) { + if (Compatibility::IsA11ySuppressedForClipboardCopy()) { + // Bug 1774285: Windows Suggested Actions (introduced in Windows 11 22H2) + // walks the entire a11y tree using UIA whenever anything is copied to the + // clipboard. This causes an unacceptable hang, particularly when the cache + // is disabled. Don't allow a11y to be instantiated by this. + return false; + } + if (!aClientTid) { // aClientTid == 0 implies that this is either an in-process call, or else // we failed to retrieve information about the remote caller. diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index b7c239fd080b3d8acb53d8e335a3c3a10f4c658a..72ae8d3af80dfc970f5996a9bc346adb209bb1b5 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -228,6 +228,18 @@ #endif mirror: once +# Whether to avoid accessibility activation on Windows shortly after clipboard +# copy. +# +# Possible values are: +# * 0: never +# * 1: always +# * 2 (or others): when needed +- name: accessibility.windows.suppress-after-clipboard-copy + type: uint32_t + value: 2 + mirror: always + #--------------------------------------------------------------------------- # Prefs starting with "alerts." #--------------------------------------------------------------------------- diff --git a/widget/nsClipboardProxy.cpp b/widget/nsClipboardProxy.cpp index c375ac8e57a0a0551afcdcfa300bc3c2b76b515d..8bea74f2b4649bf2c412645cca69f652661aecf4 100644 --- a/widget/nsClipboardProxy.cpp +++ b/widget/nsClipboardProxy.cpp @@ -2,6 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#if defined(ACCESSIBILITY) && defined(XP_WIN) +# include "mozilla/a11y/Compatibility.h" +#endif #include "mozilla/dom/ContentChild.h" #include "mozilla/Unused.h" #include "nsArrayUtils.h" @@ -23,6 +26,10 @@ nsClipboardProxy::nsClipboardProxy() : mClipboardCaps(false, false) {} NS_IMETHODIMP nsClipboardProxy::SetData(nsITransferable* aTransferable, nsIClipboardOwner* anOwner, int32_t aWhichClipboard) { +#if defined(ACCESSIBILITY) && defined(XP_WIN) + a11y::Compatibility::SuppressA11yForClipboardCopy(); +#endif + ContentChild* child = ContentChild::GetSingleton(); IPCDataTransfer ipcDataTransfer; diff --git a/widget/windows/nsClipboard.cpp b/widget/windows/nsClipboard.cpp index 2007bd9bdb83b8179ef1978e01f1c8543c7ae6b3..87c3eac895d7073d7712b31ea8c96f1a82039a59 100644 --- a/widget/windows/nsClipboard.cpp +++ b/widget/windows/nsClipboard.cpp @@ -15,6 +15,9 @@ #include <thread> #include <chrono> +#ifdef ACCESSIBILITY +# include "mozilla/a11y/Compatibility.h" +#endif #include "mozilla/Logging.h" #include "mozilla/StaticPrefs_clipboard.h" #include "nsArrayUtils.h" @@ -482,6 +485,10 @@ NS_IMETHODIMP nsClipboard::SetNativeClipboardData(int32_t aWhichClipboard) { return NS_ERROR_FAILURE; } +#ifdef ACCESSIBILITY + a11y::Compatibility::SuppressA11yForClipboardCopy(); +#endif + IDataObject* dataObj; if (NS_SUCCEEDED(CreateNativeDataObject(mTransferable, &dataObj, nullptr))) { // this add refs dataObj