uiautomationcore: Query EVENT_OBJECT_FOCUS HWND for a serverside provider if there is a registered focus change event handler.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
Connor McAdams 2023-09-15 15:19:53 -04:00 committed by Alexandre Julliard
parent 7886e4d08b
commit 6b972a68b8
3 changed files with 89 additions and 1 deletions

View file

@ -2631,7 +2631,7 @@ static HRESULT uia_get_provider_from_hwnd(struct uia_node *node)
return SendMessageW(client_thread.hwnd, WM_UIA_CLIENT_GET_NODE_PROV, (WPARAM)&args, (LPARAM)node);
}
static HRESULT create_uia_node_from_hwnd(HWND hwnd, HUIANODE *out_node, int node_flags)
HRESULT create_uia_node_from_hwnd(HWND hwnd, HUIANODE *out_node, int node_flags)
{
struct uia_node *node;
HRESULT hr;

View file

@ -903,6 +903,7 @@ static HRESULT get_uia_cache_request_struct_from_iface(IUIAutomationCacheRequest
*/
static struct uia_com_event_handlers
{
struct rb_tree handler_event_id_map;
struct rb_tree handler_map;
LONG handler_count;
@ -917,6 +918,22 @@ static CRITICAL_SECTION_DEBUG com_event_handlers_cs_debug =
};
static CRITICAL_SECTION com_event_handlers_cs = { &com_event_handlers_cs_debug, -1, 0, 0, 0, 0 };
struct uia_event_handler_event_id_map_entry
{
struct rb_entry entry;
int event_id;
struct list handlers_list;
};
static int uia_com_event_handler_event_id_compare(const void *key, const struct rb_entry *entry)
{
struct uia_event_handler_event_id_map_entry *event_entry = RB_ENTRY_VALUE(entry, struct uia_event_handler_event_id_map_entry, entry);
int event_id = *((int *)key);
return (event_entry->event_id > event_id) - (event_entry->event_id < event_id);
}
struct uia_event_handler_identifier {
IUnknown *handler_iface;
SAFEARRAY *runtime_id;
@ -932,6 +949,9 @@ struct uia_event_handler_map_entry
int event_id;
struct list handlers_list;
struct uia_event_handler_event_id_map_entry *handler_event_id_map;
struct list handler_event_id_map_list_entry;
};
static int uia_com_event_handler_id_compare(const void *key, const struct rb_entry *entry)
@ -1027,6 +1047,32 @@ HRESULT uia_com_win_event_callback(DWORD event_id, HWND hwnd, LONG obj_id, LONG
break;
}
case EVENT_OBJECT_FOCUS:
{
static const int uia_event_id = UIA_AutomationFocusChangedEventId;
struct rb_entry *rb_entry;
HRESULT hr;
if (obj_id != OBJID_CLIENT)
break;
EnterCriticalSection(&com_event_handlers_cs);
if ((rb_entry = rb_get(&com_event_handlers.handler_event_id_map, &uia_event_id)))
{
HUIANODE node = NULL;
hr = create_uia_node_from_hwnd(hwnd, &node, NODE_FLAG_IGNORE_CLIENTSIDE_HWND_PROVS);
if (SUCCEEDED(hr))
FIXME("EVENT_OBJECT_FOCUS event advisement currently unimplemented\n");
UiaNodeRelease(node);
}
LeaveCriticalSection(&com_event_handlers_cs);
break;
}
default:
break;
}
@ -1034,6 +1080,29 @@ HRESULT uia_com_win_event_callback(DWORD event_id, HWND hwnd, LONG obj_id, LONG
return S_OK;
}
static HRESULT uia_event_handlers_add_handler_to_event_id_map(struct uia_event_handler_map_entry *event_map)
{
struct uia_event_handler_event_id_map_entry *event_id_map;
struct rb_entry *rb_entry;
if ((rb_entry = rb_get(&com_event_handlers.handler_event_id_map, &event_map->event_id)))
event_id_map = RB_ENTRY_VALUE(rb_entry, struct uia_event_handler_event_id_map_entry, entry);
else
{
if (!(event_id_map = calloc(1, sizeof(*event_id_map))))
return E_OUTOFMEMORY;
event_id_map->event_id = event_map->event_id;
list_init(&event_id_map->handlers_list);
rb_put(&com_event_handlers.handler_event_id_map, &event_map->event_id, &event_id_map->entry);
}
list_add_tail(&event_id_map->handlers_list, &event_map->handler_event_id_map_list_entry);
event_map->handler_event_id_map = event_id_map;
return S_OK;
}
static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, SAFEARRAY *runtime_id, int event_id,
struct uia_com_event *event)
{
@ -1045,7 +1114,10 @@ static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, SAFEARRAY
EnterCriticalSection(&com_event_handlers_cs);
if (!com_event_handlers.handler_count)
{
rb_init(&com_event_handlers.handler_map, uia_com_event_handler_id_compare);
rb_init(&com_event_handlers.handler_event_id_map, uia_com_event_handler_event_id_compare);
}
if ((rb_entry = rb_get(&com_event_handlers.handler_map, &event_ident)))
event_map = RB_ENTRY_VALUE(rb_entry, struct uia_event_handler_map_entry, entry);
@ -1065,6 +1137,14 @@ static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, SAFEARRAY
}
event_map->event_id = event_id;
hr = uia_event_handlers_add_handler_to_event_id_map(event_map);
if (FAILED(hr))
{
SafeArrayDestroy(event_map->runtime_id);
free(event_map);
goto exit;
}
event_map->handler_iface = handler_iface;
IUnknown_AddRef(event_map->handler_iface);
@ -1102,6 +1182,13 @@ static void uia_event_handler_map_entry_destroy(struct uia_event_handler_map_ent
com_event_handlers.handler_count--;
}
list_remove(&entry->handler_event_id_map_list_entry);
if (list_empty(&entry->handler_event_id_map->handlers_list))
{
rb_remove(&com_event_handlers.handler_event_id_map, &entry->handler_event_id_map->entry);
free(entry->handler_event_id_map);
}
rb_remove(&com_event_handlers.handler_map, &entry->entry);
IUnknown_Release(entry->handler_iface);
SafeArrayDestroy(entry->runtime_id);

View file

@ -219,6 +219,7 @@ HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node
HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node,
BOOL get_hwnd_providers, int node_flags) DECLSPEC_HIDDEN;
HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode) DECLSPEC_HIDDEN;
HRESULT create_uia_node_from_hwnd(HWND hwnd, HUIANODE *out_node, int node_flags) DECLSPEC_HIDDEN;
HRESULT uia_condition_check(HUIANODE node, struct UiaCondition *condition) DECLSPEC_HIDDEN;
BOOL uia_condition_matched(HRESULT hr) DECLSPEC_HIDDEN;