uiautomationcore: Track HWNDs that need WinEvent translation.
Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
parent
2a2c4cd7b9
commit
81caccbf84
4 changed files with 115 additions and 0 deletions
|
@ -1870,6 +1870,9 @@ static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PT
|
|||
&IID_IProxyProviderWinEventHandler, (void **)&winevent_handler)))
|
||||
{
|
||||
FIXME("MSAA to UIA event bridge currently unimplemented\n");
|
||||
hr = uia_event_add_win_event_hwnd(event, prov->hwnd);
|
||||
if (FAILED(hr))
|
||||
WARN("Failed to add hwnd for win_event, hr %#lx\n", hr);
|
||||
IProxyProviderWinEventHandler_Release(winevent_handler);
|
||||
}
|
||||
else if (SUCCEEDED(IRawElementProviderFragmentRoot_QueryInterface(elroot, &IID_IRawElementProviderAdviseEvents,
|
||||
|
@ -1954,6 +1957,7 @@ static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProvid
|
|||
prov->IWineUiaProvider_iface.lpVtbl = &uia_provider_vtbl;
|
||||
prov->elprov = elprov;
|
||||
prov->ref = 1;
|
||||
prov->hwnd = node->hwnd;
|
||||
node->prov[prov_type] = &prov->IWineUiaProvider_iface;
|
||||
if (!node->prov_count)
|
||||
node->creator_prov_type = prov_type;
|
||||
|
|
|
@ -64,6 +64,29 @@ static int win_event_to_uia_event_id(int win_event)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static BOOL CALLBACK uia_win_event_enum_top_level_hwnds(HWND hwnd, LPARAM lparam)
|
||||
{
|
||||
struct rb_tree *hwnd_map = (struct rb_tree *)lparam;
|
||||
HRESULT hr;
|
||||
|
||||
if (!uia_hwnd_is_visible(hwnd))
|
||||
return TRUE;
|
||||
|
||||
hr = uia_hwnd_map_add_hwnd(hwnd_map, hwnd);
|
||||
if (FAILED(hr))
|
||||
WARN("Failed to add hwnd to map, hr %#lx\n", hr);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HRESULT uia_event_add_win_event_hwnd(struct uia_event *event, HWND hwnd)
|
||||
{
|
||||
if (hwnd == GetDesktopWindow())
|
||||
EnumWindows(uia_win_event_enum_top_level_hwnds, (LPARAM)&event->u.clientside.win_event_hwnd_map);
|
||||
|
||||
return uia_hwnd_map_add_hwnd(&event->u.clientside.win_event_hwnd_map, hwnd);
|
||||
}
|
||||
|
||||
/*
|
||||
* UI Automation event map.
|
||||
*/
|
||||
|
@ -658,6 +681,7 @@ static ULONG WINAPI uia_event_Release(IWineUiaEvent *iface)
|
|||
uia_cache_request_destroy(&event->u.clientside.cache_req);
|
||||
if (event->u.clientside.git_cookie)
|
||||
uia_stop_event_thread();
|
||||
uia_hwnd_map_destroy(&event->u.clientside.win_event_hwnd_map);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -834,6 +858,7 @@ static HRESULT create_clientside_uia_event(struct uia_event **out_event, int eve
|
|||
event->scope = scope;
|
||||
event->u.clientside.event_callback = cback;
|
||||
event->u.clientside.callback_data = cback_data;
|
||||
uia_hwnd_map_init(&event->u.clientside.win_event_hwnd_map);
|
||||
|
||||
*out_event = event;
|
||||
return S_OK;
|
||||
|
|
|
@ -95,6 +95,7 @@ struct uia_provider {
|
|||
BOOL return_nested_node;
|
||||
BOOL parent_check_ran;
|
||||
BOOL has_parent;
|
||||
HWND hwnd;
|
||||
};
|
||||
|
||||
static inline struct uia_provider *impl_from_IWineUiaProvider(IWineUiaProvider *iface)
|
||||
|
@ -140,6 +141,7 @@ struct uia_event
|
|||
HRESULT (*event_callback)(struct uia_event *, struct uia_event_args *, SAFEARRAY *, BSTR);
|
||||
void *callback_data;
|
||||
|
||||
struct rb_tree win_event_hwnd_map;
|
||||
DWORD git_cookie;
|
||||
} clientside;
|
||||
struct {
|
||||
|
@ -218,6 +220,7 @@ BOOL uia_condition_matched(HRESULT hr) DECLSPEC_HIDDEN;
|
|||
HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN;
|
||||
|
||||
/* uia_event.c */
|
||||
HRESULT uia_event_add_win_event_hwnd(struct uia_event *event, HWND hwnd) DECLSPEC_HIDDEN;
|
||||
HRESULT create_serverside_uia_event(struct uia_event **out_event, LONG process_id, LONG event_cookie) DECLSPEC_HIDDEN;
|
||||
HRESULT uia_event_add_provider_event_adviser(IRawElementProviderAdviseEvents *advise_events,
|
||||
struct uia_event *event) DECLSPEC_HIDDEN;
|
||||
|
@ -250,3 +253,7 @@ HRESULT uia_cache_request_clone(struct UiaCacheRequest *dst, struct UiaCacheRequ
|
|||
HRESULT get_safearray_dim_bounds(SAFEARRAY *sa, UINT dim, LONG *lbound, LONG *elems) DECLSPEC_HIDDEN;
|
||||
HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems) DECLSPEC_HIDDEN;
|
||||
int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type) DECLSPEC_HIDDEN;
|
||||
BOOL uia_hwnd_is_visible(HWND hwnd) DECLSPEC_HIDDEN;
|
||||
HRESULT uia_hwnd_map_add_hwnd(struct rb_tree *hwnd_map, HWND hwnd) DECLSPEC_HIDDEN;
|
||||
void uia_hwnd_map_init(struct rb_tree *hwnd_map) DECLSPEC_HIDDEN;
|
||||
void uia_hwnd_map_destroy(struct rb_tree *hwnd_map) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -384,3 +384,82 @@ int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* HWND related helper functions.
|
||||
*/
|
||||
BOOL uia_hwnd_is_visible(HWND hwnd)
|
||||
{
|
||||
RECT rect;
|
||||
|
||||
if (!IsWindowVisible(hwnd))
|
||||
return FALSE;
|
||||
|
||||
if (!GetWindowRect(hwnd, &rect))
|
||||
return FALSE;
|
||||
|
||||
if ((rect.right - rect.left) <= 0 || (rect.bottom - rect.top) <= 0)
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* rbtree to efficiently store a collection of HWNDs.
|
||||
*/
|
||||
struct uia_hwnd_map_entry
|
||||
{
|
||||
struct rb_entry entry;
|
||||
HWND hwnd;
|
||||
};
|
||||
|
||||
static int uia_hwnd_map_hwnd_compare(const void *key, const struct rb_entry *entry)
|
||||
{
|
||||
struct uia_hwnd_map_entry *hwnd_entry = RB_ENTRY_VALUE(entry, struct uia_hwnd_map_entry, entry);
|
||||
HWND hwnd = (HWND)key;
|
||||
|
||||
return (hwnd_entry->hwnd > hwnd) - (hwnd_entry->hwnd < hwnd);
|
||||
}
|
||||
|
||||
static void uia_hwnd_map_free(struct rb_entry *entry, void *context)
|
||||
{
|
||||
struct uia_hwnd_map_entry *hwnd_entry = RB_ENTRY_VALUE(entry, struct uia_hwnd_map_entry, entry);
|
||||
|
||||
TRACE("Removing hwnd %p from map %p\n", hwnd_entry->hwnd, context);
|
||||
free(hwnd_entry);
|
||||
}
|
||||
|
||||
static BOOL uia_hwnd_map_check_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
|
||||
{
|
||||
return !!rb_get(hwnd_map, hwnd);
|
||||
}
|
||||
|
||||
HRESULT uia_hwnd_map_add_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
|
||||
{
|
||||
struct uia_hwnd_map_entry *entry;
|
||||
|
||||
if (uia_hwnd_map_check_hwnd(hwnd_map, hwnd))
|
||||
{
|
||||
TRACE("hwnd %p already in map %p\n", hwnd, hwnd_map);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (!(entry = calloc(1, sizeof(*entry))))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
TRACE("Adding hwnd %p to map %p\n", hwnd, hwnd_map);
|
||||
entry->hwnd = hwnd;
|
||||
rb_put(hwnd_map, hwnd, &entry->entry);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void uia_hwnd_map_init(struct rb_tree *hwnd_map)
|
||||
{
|
||||
rb_init(hwnd_map, uia_hwnd_map_hwnd_compare);
|
||||
}
|
||||
|
||||
void uia_hwnd_map_destroy(struct rb_tree *hwnd_map)
|
||||
{
|
||||
rb_destroy(hwnd_map, uia_hwnd_map_free, hwnd_map);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue