// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_VIEWS_ACCESSIBILITY_UIA_ACCESSIBILITY_EVENT_WAITER_H_
#define CHROME_BROWSER_UI_VIEWS_ACCESSIBILITY_UIA_ACCESSIBILITY_EVENT_WAITER_H_
#include <ole2.h>
#include <stdint.h>
#include <wrl/client.h>
#include <map>
#include <string>
#include <vector>
#include "base/memory/raw_ptr.h"
#include "base/process/process_handle.h"
#include "base/run_loop.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "base/win/atl.h"
#include "ui/views/accessibility/view_accessibility.h"
#include <uiautomation.h>
struct UiaAccessibilityWaiterInfo {
HWND hwnd;
std::wstring role;
std::wstring name;
ax::mojom::Event event;
};
class UiaAccessibilityEventWaiter {
public:
explicit UiaAccessibilityEventWaiter(UiaAccessibilityWaiterInfo info);
~UiaAccessibilityEventWaiter();
void Wait();
void WaitWithTimeout(base::TimeDelta timeout);
private:
// All UIA calls need to be made on a secondary MTA thread to avoid sporadic
// test hangs / timeouts.
class Thread : public base::PlatformThread::Delegate {
public:
Thread();
~Thread() override;
void Init(UiaAccessibilityEventWaiter* owner,
const UiaAccessibilityWaiterInfo& info,
base::OnceClosure initialization_loop,
base::OnceClosure shutdown_loop);
void SendShutdownSignal();
void ThreadMain() override;
protected:
UiaAccessibilityWaiterInfo info_;
private:
raw_ptr<UiaAccessibilityEventWaiter> owner_ = nullptr;
Microsoft::WRL::ComPtr<IUIAutomation> uia_;
Microsoft::WRL::ComPtr<IUIAutomationElement> root_;
Microsoft::WRL::ComPtr<IUIAutomationCacheRequest> cache_request_;
// Thread synchronization members.
base::OnceClosure initialization_complete_;
base::OnceClosure shutdown_complete_;
base::WaitableEvent shutdown_signal_;
// An implementation of various UIA interfaces that forward event
// notifications to the waiter.
class EventHandler : public CComObjectRootEx<CComMultiThreadModel>,
public IUIAutomationFocusChangedEventHandler,
public IUIAutomationPropertyChangedEventHandler,
public IUIAutomationStructureChangedEventHandler,
public IUIAutomationEventHandler {
public:
EventHandler();
EventHandler(const EventHandler&) = delete;
EventHandler& operator=(const EventHandler&) = delete;
virtual ~EventHandler();
void Init(UiaAccessibilityEventWaiter::Thread* owner,
Microsoft::WRL::ComPtr<IUIAutomationElement> root);
void CleanUp();
BEGIN_COM_MAP(EventHandler)
COM_INTERFACE_ENTRY(IUIAutomationFocusChangedEventHandler)
COM_INTERFACE_ENTRY(IUIAutomationPropertyChangedEventHandler)
COM_INTERFACE_ENTRY(IUIAutomationStructureChangedEventHandler)
COM_INTERFACE_ENTRY(IUIAutomationEventHandler)
END_COM_MAP()
// IUIAutomationFocusChangedEventHandler interface.
IFACEMETHODIMP HandleFocusChangedEvent(
IUIAutomationElement* sender) override;
// IUIAutomationPropertyChangedEventHandler interface.
IFACEMETHODIMP HandlePropertyChangedEvent(IUIAutomationElement* sender,
PROPERTYID property_id,
VARIANT new_value) override;
// IUIAutomationStructureChangedEventHandler interface.
IFACEMETHODIMP HandleStructureChangedEvent(
IUIAutomationElement* sender,
StructureChangeType change_type,
SAFEARRAY* runtime_id) override;
// IUIAutomationEventHandler interface.
IFACEMETHODIMP HandleAutomationEvent(IUIAutomationElement* sender,
EVENTID event_id) override;
// Points to the waiter to receive notifications.
raw_ptr<UiaAccessibilityEventWaiter::Thread> owner_ = nullptr;
private:
bool MatchesNameRole(IUIAutomationElement* sender);
Microsoft::WRL::ComPtr<IUIAutomationElement> root_;
};
Microsoft::WRL::ComPtr<CComObject<EventHandler>> uia_event_handler_;
};
Thread thread_;
base::RunLoop shutdown_loop_;
base::PlatformThreadHandle thread_handle_;
};
#endif // CHROME_BROWSER_UI_VIEWS_ACCESSIBILITY_UIA_ACCESSIBILITY_EVENT_WAITER_H_