зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1323521: Prevent Windows touchscreen support from instantiating a11y; r=jimm
MozReview-Commit-ID: 3xV0b97lEre --HG-- extra : rebase_source : 7edcc93d409ffcd50e0fe4307573c2660a274b28 extra : amend_source : 0b8f3fbc292b632b448c135ea55fa6f63d292b35
This commit is contained in:
Родитель
1ce9acc2f9
Коммит
39b609a350
|
@ -329,6 +329,118 @@ private:
|
|||
Maybe<TimeStamp> CurrentWindowsTimeGetter::sBackwardsSkewStamp;
|
||||
DWORD CurrentWindowsTimeGetter::sLastPostTime = 0;
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
/**
|
||||
* Windows touchscreen code works by setting a global WH_GETMESSAGE hook and
|
||||
* injecting tiptsf.dll. The touchscreen process then posts registered messages
|
||||
* to our main thread. The tiptsf hook picks up those registered messages and
|
||||
* uses them as commands, some of which call into UIA, which then calls into
|
||||
* MSAA, which then sends WM_GETOBJECT to us.
|
||||
*
|
||||
* We can get ahead of this by installing our own thread-local WH_GETMESSAGE
|
||||
* hook. Since thread-local hooks are called ahead of global hooks, we will
|
||||
* see these registered messages before tiptsf does. At this point we can then
|
||||
* raise a flag that blocks a11y before invoking CallNextHookEx which will then
|
||||
* invoke the global tiptsf hook. Then when we see WM_GETOBJECT, we check the
|
||||
* flag by calling TIPMessageHandler::IsA11yBlocked().
|
||||
*/
|
||||
class TIPMessageHandler
|
||||
{
|
||||
public:
|
||||
~TIPMessageHandler()
|
||||
{
|
||||
if (mHook) {
|
||||
::UnhookWindowsHookEx(mHook);
|
||||
}
|
||||
}
|
||||
|
||||
static void Initialize()
|
||||
{
|
||||
MOZ_ASSERT(!sInstance);
|
||||
sInstance = new TIPMessageHandler();
|
||||
ClearOnShutdown(&sInstance);
|
||||
}
|
||||
|
||||
static bool IsA11yBlocked()
|
||||
{
|
||||
MOZ_ASSERT(sInstance);
|
||||
if (!sInstance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return sInstance->mA11yBlockCount > 0;
|
||||
}
|
||||
|
||||
private:
|
||||
TIPMessageHandler()
|
||||
: mHook(nullptr)
|
||||
, mA11yBlockCount(0)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Registered messages used by tiptsf
|
||||
mMessages[0] = ::RegisterWindowMessage(L"ImmersiveFocusNotification");
|
||||
mMessages[1] = ::RegisterWindowMessage(L"TipCloseMenus");
|
||||
mMessages[2] = ::RegisterWindowMessage(L"TabletInputPanelOpening");
|
||||
mMessages[3] = ::RegisterWindowMessage(L"IHM Pen or Touch Event noticed");
|
||||
mMessages[4] = ::RegisterWindowMessage(L"ProgrammabilityCaretVisibility");
|
||||
mMessages[5] = ::RegisterWindowMessage(L"CaretTrackingUpdateIPHidden");
|
||||
mMessages[6] = ::RegisterWindowMessage(L"CaretTrackingUpdateIPInfo");
|
||||
|
||||
mHook = ::SetWindowsHookEx(WH_GETMESSAGE, &TIPHook, nullptr,
|
||||
::GetCurrentThreadId());
|
||||
MOZ_ASSERT(mHook);
|
||||
}
|
||||
|
||||
class MOZ_RAII A11yInstantiationBlocker
|
||||
{
|
||||
public:
|
||||
A11yInstantiationBlocker()
|
||||
{
|
||||
MOZ_ASSERT(TIPMessageHandler::sInstance);
|
||||
++TIPMessageHandler::sInstance->mA11yBlockCount;
|
||||
}
|
||||
|
||||
~A11yInstantiationBlocker()
|
||||
{
|
||||
MOZ_ASSERT(TIPMessageHandler::sInstance &&
|
||||
TIPMessageHandler::sInstance->mA11yBlockCount > 0);
|
||||
--TIPMessageHandler::sInstance->mA11yBlockCount;
|
||||
}
|
||||
};
|
||||
|
||||
friend class A11yInstantiationBlocker;
|
||||
|
||||
static LRESULT CALLBACK TIPHook(int aCode, WPARAM aWParam, LPARAM aLParam)
|
||||
{
|
||||
if (aCode < 0 || !sInstance) {
|
||||
return ::CallNextHookEx(nullptr, aCode, aWParam, aLParam);
|
||||
}
|
||||
|
||||
MSG* msg = reinterpret_cast<MSG*>(aLParam);
|
||||
UINT& msgCode = msg->message;
|
||||
|
||||
for (uint32_t i = 0; i < ArrayLength(sInstance->mMessages); ++i) {
|
||||
if (msgCode == sInstance->mMessages[i]) {
|
||||
A11yInstantiationBlocker block;
|
||||
return ::CallNextHookEx(nullptr, aCode, aWParam, aLParam);
|
||||
}
|
||||
}
|
||||
|
||||
return ::CallNextHookEx(nullptr, aCode, aWParam, aLParam);
|
||||
}
|
||||
|
||||
static StaticAutoPtr<TIPMessageHandler> sInstance;
|
||||
|
||||
HHOOK mHook;
|
||||
UINT mMessages[7];
|
||||
uint32_t mA11yBlockCount;
|
||||
};
|
||||
|
||||
StaticAutoPtr<TIPMessageHandler> TIPMessageHandler::sInstance;
|
||||
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
/**************************************************************
|
||||
|
@ -456,6 +568,9 @@ nsWindow::nsWindow()
|
|||
// WinTaskbar.cpp for details.
|
||||
mozilla::widget::WinTaskbar::RegisterAppUserModelID();
|
||||
KeyboardLayout::GetInstance()->OnLayoutChange(::GetKeyboardLayout(0));
|
||||
#if defined(ACCESSIBILITY)
|
||||
mozilla::TIPMessageHandler::Initialize();
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
IMEHandler::Initialize();
|
||||
if (SUCCEEDED(::OleInitialize(nullptr))) {
|
||||
sIsOleInitialized = TRUE;
|
||||
|
@ -3281,9 +3396,9 @@ nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen)
|
|||
if (aFullScreen && !sCurrentWindow) {
|
||||
sCurrentWindow = this;
|
||||
LPARAM pos = sCurrentWindow->lParamToClient(sMouseExitlParamScreen);
|
||||
sCurrentWindow->DispatchMouseEvent(eMouseEnterIntoWidget,
|
||||
sMouseExitwParam, pos, false,
|
||||
WidgetMouseEvent::eLeftButton,
|
||||
sCurrentWindow->DispatchMouseEvent(eMouseEnterIntoWidget,
|
||||
sMouseExitwParam, pos, false,
|
||||
WidgetMouseEvent::eLeftButton,
|
||||
MOUSE_INPUT_SOURCE(), MOUSE_POINTERID());
|
||||
}
|
||||
|
||||
|
@ -5599,7 +5714,7 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
|
|||
// Do explicit casting to make it working on 64bit systems (see bug 649236
|
||||
// for details).
|
||||
int32_t objId = static_cast<DWORD>(lParam);
|
||||
if (objId == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
|
||||
if (!TIPMessageHandler::IsA11yBlocked() && objId == OBJID_CLIENT) { // oleacc.dll will be loaded dynamically
|
||||
a11y::Accessible* rootAccessible = GetAccessible(); // Held by a11y cache
|
||||
if (rootAccessible) {
|
||||
IAccessible *msaaAccessible = nullptr;
|
||||
|
|
Загрузка…
Ссылка в новой задаче