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:
Aaron Klotz 2016-12-14 12:20:48 -07:00
Родитель 1ce9acc2f9
Коммит 39b609a350
1 изменённых файлов: 119 добавлений и 4 удалений

Просмотреть файл

@ -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;