uiautomationcore: Potentially raise focus event on the currently focused serverside provider in response to EVENT_OBJECT_FOCUS.
Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
parent
2be7de9898
commit
f26d470920
6 changed files with 131 additions and 22 deletions
|
@ -14681,6 +14681,12 @@ static void set_com_event_data(struct node_provider_desc *exp_node_desc)
|
|||
SET_EXPECT(uia_com_event_callback);
|
||||
}
|
||||
|
||||
static void push_expected_com_event(struct node_provider_desc *exp_node_desc)
|
||||
{
|
||||
push_event_queue_event(&ComEventData.exp_events, exp_node_desc);
|
||||
SET_EXPECT_MULTI(uia_com_event_callback, ComEventData.exp_events.exp_event_count);
|
||||
}
|
||||
|
||||
#define test_com_event_data( sender ) \
|
||||
test_com_event_data_( (sender), __FILE__, __LINE__)
|
||||
static void test_com_event_data_(IUIAutomationElement *sender, const char *file, int line)
|
||||
|
@ -15560,6 +15566,12 @@ static void set_multi_event_data(struct node_provider_desc *exp_node_desc)
|
|||
SET_EXPECT(uia_event_callback);
|
||||
}
|
||||
|
||||
static void push_expected_event(struct node_provider_desc *exp_node_desc)
|
||||
{
|
||||
push_event_queue_event(&MultiEventData.exp_events, exp_node_desc);
|
||||
SET_EXPECT_MULTI(uia_event_callback, MultiEventData.exp_events.exp_event_count);
|
||||
}
|
||||
|
||||
static void WINAPI multi_uia_event_callback(struct UiaEventArgs *args, SAFEARRAY *req_data, BSTR tree_struct)
|
||||
{
|
||||
struct node_provider_desc *exp_desc;
|
||||
|
@ -15696,6 +15708,72 @@ static void test_uia_com_focus_change_event_handler_win_event_handling(IUIAutoma
|
|||
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
|
||||
set_provider_prop_override(&Provider, NULL, 0);
|
||||
|
||||
/*
|
||||
* The first time EVENT_OBJECT_FOCUS is raised for an HWND with a
|
||||
* serverside provider UIA will query for the currently focused provider
|
||||
* and raise a focus change event for it, alongside advising the root
|
||||
* provider of focus change events being listened for. All subsequent
|
||||
* EVENT_OBJECT_FOCUS events on the same HWND only query the root
|
||||
* provider.
|
||||
*/
|
||||
initialize_provider(&Provider_child2, ProviderOptions_ServerSideProvider, NULL, TRUE);
|
||||
Provider_child2.parent = &Provider2.IRawElementProviderFragment_iface;
|
||||
Provider_child2.frag_root = &Provider2.IRawElementProviderFragmentRoot_iface;
|
||||
Provider2.focus_prov = &Provider_child2.IRawElementProviderFragment_iface;
|
||||
set_provider_runtime_id(&Provider_child2, UiaAppendRuntimeId, 2);
|
||||
initialize_provider_advise_events_ids(&Provider2);
|
||||
|
||||
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), NULL);
|
||||
add_provider_desc(&exp_node_desc, L"Main", L"Provider_child2", TRUE);
|
||||
|
||||
set_multi_event_data(&exp_node_desc);
|
||||
set_com_event_data(&exp_node_desc);
|
||||
|
||||
/* Second event. */
|
||||
init_node_provider_desc(&exp_nested_node_desc, GetCurrentProcessId(), test_child_hwnd);
|
||||
add_provider_desc(&exp_nested_node_desc, L"Main", L"Provider2", TRUE);
|
||||
|
||||
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), test_child_hwnd);
|
||||
add_provider_desc(&exp_node_desc, L"Hwnd", L"Provider_hwnd3", TRUE);
|
||||
add_provider_desc(&exp_node_desc, L"Nonclient", L"Provider_nc3", FALSE);
|
||||
add_nested_provider_desc(&exp_node_desc, L"Main", NULL, FALSE, &exp_nested_node_desc);
|
||||
|
||||
push_expected_event(&exp_node_desc);
|
||||
push_expected_com_event(&exp_node_desc);
|
||||
set_uia_hwnd_expects(0, 2, 2, 3, 0); /* Win11 sends 3 WM_GETOBJECT messages, normally only 2. */
|
||||
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 4); /* Win11 sends 4 WM_GETOBJECT messages, normally only 3. */
|
||||
NotifyWinEvent(EVENT_OBJECT_FOCUS, test_child_hwnd, OBJID_CLIENT, CHILDID_SELF);
|
||||
ok(msg_wait_for_all_events(event_handles, 2, 5000) != WAIT_TIMEOUT, "Wait for event_handle(s) timed out.\n");
|
||||
if (wait_for_clientside_callbacks(2000)) trace("Kept getting callbacks up until timeout\n");
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 2, FALSE, 2, FALSE, 2, TRUE, 0, FALSE);
|
||||
CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 3);
|
||||
CHECK_CALLED_MULTI(uia_com_event_callback, 2);
|
||||
CHECK_CALLED_MULTI(uia_event_callback, 2);
|
||||
|
||||
/*
|
||||
* Second time EVENT_OBJECT_FOCUS is raised for this HWND, only the root
|
||||
* provider will have an event raised.
|
||||
*/
|
||||
init_node_provider_desc(&exp_nested_node_desc, GetCurrentProcessId(), test_child_hwnd);
|
||||
add_provider_desc(&exp_nested_node_desc, L"Main", L"Provider2", TRUE);
|
||||
|
||||
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), test_child_hwnd);
|
||||
add_provider_desc(&exp_node_desc, L"Hwnd", L"Provider_hwnd3", TRUE);
|
||||
add_provider_desc(&exp_node_desc, L"Nonclient", L"Provider_nc3", FALSE);
|
||||
add_nested_provider_desc(&exp_node_desc, L"Main", NULL, FALSE, &exp_nested_node_desc);
|
||||
|
||||
set_multi_event_data(&exp_node_desc);
|
||||
set_com_event_data(&exp_node_desc);
|
||||
set_uia_hwnd_expects(0, 2, 2, 3, 0); /* Win11 sends 3 WM_GETOBJECT messages, normally only 2. */
|
||||
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 4); /* Win11 sends 4 WM_GETOBJECT messages, normally only 3. */
|
||||
NotifyWinEvent(EVENT_OBJECT_FOCUS, test_child_hwnd, OBJID_CLIENT, CHILDID_SELF);
|
||||
ok(msg_wait_for_all_events(event_handles, 2, 5000) != WAIT_TIMEOUT, "Wait for event_handle(s) timed out.\n");
|
||||
if (wait_for_clientside_callbacks(2000)) trace("Kept getting callbacks up until timeout\n");
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 2, FALSE, 2, FALSE, 2, TRUE, 0, FALSE);
|
||||
CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 3);
|
||||
CHECK_CALLED(uia_com_event_callback);
|
||||
CHECK_CALLED(uia_event_callback);
|
||||
|
||||
set_uia_hwnd_expects(0, 1, 1, 0, 0);
|
||||
hr = IUIAutomation_RemoveFocusChangedEventHandler(uia_iface,
|
||||
&FocusChangedHandler.IUIAutomationFocusChangedEventHandler_iface);
|
||||
|
|
|
@ -91,7 +91,7 @@ library UIA_wine_private
|
|||
HRESULT get_prov_opts([out, retval]int *out_opts);
|
||||
HRESULT has_parent([out, retval]BOOL *out_val);
|
||||
HRESULT navigate([in]int nav_dir, [out, retval]VARIANT *ret_val);
|
||||
HRESULT get_focus([out, retval]VARIANT *ret_val);
|
||||
HRESULT get_focus([in]long flags, [out, retval]VARIANT *ret_val);
|
||||
HRESULT attach_event([in]LONG_PTR huiaevent);
|
||||
HRESULT respond_to_win_event([in]DWORD win_event, [in]ULONG hwnd, [in]LONG obj_id, [in]LONG child_id,
|
||||
[in]IProxyProviderWinEventSink *sink);
|
||||
|
|
|
@ -347,7 +347,7 @@ static HRESULT get_navigate_from_node_provider(IWineUiaNode *node, int idx, int
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT get_focus_from_node_provider(IWineUiaNode *node, int idx, VARIANT *ret_val)
|
||||
HRESULT get_focus_from_node_provider(IWineUiaNode *node, int idx, LONG flags, VARIANT *ret_val)
|
||||
{
|
||||
IWineUiaProvider *prov;
|
||||
HRESULT hr;
|
||||
|
@ -357,7 +357,7 @@ static HRESULT get_focus_from_node_provider(IWineUiaNode *node, int idx, VARIANT
|
|||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = IWineUiaProvider_get_focus(prov, ret_val);
|
||||
hr = IWineUiaProvider_get_focus(prov, flags, ret_val);
|
||||
IWineUiaProvider_Release(prov);
|
||||
|
||||
return hr;
|
||||
|
@ -1836,7 +1836,7 @@ static HRESULT WINAPI uia_provider_navigate(IWineUiaProvider *iface, int nav_dir
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI uia_provider_get_focus(IWineUiaProvider *iface, VARIANT *out_val)
|
||||
static HRESULT WINAPI uia_provider_get_focus(IWineUiaProvider *iface, LONG flags, VARIANT *out_val)
|
||||
{
|
||||
struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
|
||||
IRawElementProviderFragmentRoot *elroot;
|
||||
|
@ -1844,7 +1844,10 @@ static HRESULT WINAPI uia_provider_get_focus(IWineUiaProvider *iface, VARIANT *o
|
|||
IRawElementProviderSimple *elprov;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("%p, %p\n", iface, out_val);
|
||||
TRACE("%p, %#lx, %p\n", iface, flags, out_val);
|
||||
|
||||
if (flags & PROV_METHOD_FLAG_RETURN_NODE_LRES)
|
||||
FIXME("PROV_METHOD_FLAG_RETURN_NODE_LRES ignored for normal providers.\n");
|
||||
|
||||
VariantInit(out_val);
|
||||
hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragmentRoot, (void **)&elroot);
|
||||
|
@ -2357,7 +2360,7 @@ static HRESULT WINAPI uia_nested_node_provider_get_prop_val(IWineUiaProvider *if
|
|||
{
|
||||
HUIANODE node;
|
||||
|
||||
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node);
|
||||
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node, 0);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
|
@ -2406,7 +2409,7 @@ static HRESULT WINAPI uia_nested_node_provider_navigate(IWineUiaProvider *iface,
|
|||
if (FAILED(hr) || V_VT(&v) == VT_EMPTY)
|
||||
return hr;
|
||||
|
||||
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node);
|
||||
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node, 0);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
|
@ -2416,21 +2419,27 @@ static HRESULT WINAPI uia_nested_node_provider_navigate(IWineUiaProvider *iface,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI uia_nested_node_provider_get_focus(IWineUiaProvider *iface, VARIANT *out_val)
|
||||
static HRESULT WINAPI uia_nested_node_provider_get_focus(IWineUiaProvider *iface, LONG flags, VARIANT *out_val)
|
||||
{
|
||||
struct uia_nested_node_provider *prov = impl_from_nested_node_IWineUiaProvider(iface);
|
||||
HUIANODE node;
|
||||
HRESULT hr;
|
||||
VARIANT v;
|
||||
|
||||
TRACE("%p, %p\n", iface, out_val);
|
||||
TRACE("%p, %#lx, %p\n", iface, flags, out_val);
|
||||
|
||||
VariantInit(out_val);
|
||||
hr = get_focus_from_node_provider(prov->nested_node, 0, &v);
|
||||
hr = get_focus_from_node_provider(prov->nested_node, 0, 0, &v);
|
||||
if (FAILED(hr) || V_VT(&v) == VT_EMPTY)
|
||||
return hr;
|
||||
|
||||
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node);
|
||||
if (flags & PROV_METHOD_FLAG_RETURN_NODE_LRES)
|
||||
{
|
||||
*out_val = v;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node, 0);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
|
@ -2488,7 +2497,7 @@ static HRESULT WINAPI uia_nested_node_provider_create_node_from_prov(IWineUiaPro
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node);
|
||||
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node, 0);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
|
@ -2631,14 +2640,14 @@ static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESU
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode)
|
||||
HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode, int node_flags)
|
||||
{
|
||||
struct uia_node *node;
|
||||
HRESULT hr;
|
||||
|
||||
*huianode = NULL;
|
||||
|
||||
hr = create_uia_node(&node, 0);
|
||||
hr = create_uia_node(&node, node_flags);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
uia_node_lresult_release(lr);
|
||||
|
@ -2804,7 +2813,7 @@ static HRESULT get_focused_uia_node(HUIANODE in_node, HUIANODE *out_node)
|
|||
(get_node_provider_type_at_idx(node, i) == PROV_TYPE_HWND)))
|
||||
continue;
|
||||
|
||||
hr = get_focus_from_node_provider(&node->IWineUiaNode_iface, i, &v);
|
||||
hr = get_focus_from_node_provider(&node->IWineUiaNode_iface, i, 0, &v);
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
|
||||
|
|
|
@ -1013,7 +1013,7 @@ static HRESULT uia_com_focus_win_event_callback(struct uia_event *event, void *u
|
|||
return hr;
|
||||
}
|
||||
|
||||
static void uia_com_focus_handler_advise_node(struct uia_com_event *event, HUIANODE node, HWND hwnd)
|
||||
static BOOL uia_com_focus_handler_advise_node(struct uia_com_event *event, HUIANODE node, HWND hwnd)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
||||
|
@ -1021,12 +1021,15 @@ static void uia_com_focus_handler_advise_node(struct uia_com_event *event, HUIAN
|
|||
if (FAILED(hr))
|
||||
{
|
||||
WARN("uia_event_advise_node failed with hr %#lx\n", hr);
|
||||
return;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
hr = uia_hwnd_map_add_hwnd(&event->focus_hwnd_map, hwnd);
|
||||
if (FAILED(hr))
|
||||
WARN("Failed to add hwnd for focus winevent, hr %#lx\n", hr);
|
||||
|
||||
exit:
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
static void uia_com_focus_win_event_handler(HUIANODE node, HWND hwnd, struct uia_event_handler_event_id_map_entry *event_id_map)
|
||||
|
@ -1041,8 +1044,26 @@ static void uia_com_focus_win_event_handler(HUIANODE node, HWND hwnd, struct uia
|
|||
|
||||
LIST_FOR_EACH_ENTRY(event, &entry->handlers_list, struct uia_com_event, event_handler_map_list_entry)
|
||||
{
|
||||
if (!uia_hwnd_map_check_hwnd(&event->focus_hwnd_map, hwnd))
|
||||
uia_com_focus_handler_advise_node(event, node, hwnd);
|
||||
if (uia_hwnd_map_check_hwnd(&event->focus_hwnd_map, hwnd) ||
|
||||
!uia_com_focus_handler_advise_node(event, node, hwnd))
|
||||
continue;
|
||||
|
||||
hr = get_focus_from_node_provider((IWineUiaNode *)node, 0, PROV_METHOD_FLAG_RETURN_NODE_LRES, &v);
|
||||
if (V_VT(&v) == VT_I4)
|
||||
{
|
||||
HUIANODE focus_node = NULL;
|
||||
|
||||
hr = uia_node_from_lresult(V_I4(&v), &focus_node, NODE_FLAG_IGNORE_CLIENTSIDE_HWND_PROVS);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = uia_event_for_each(UIA_AutomationFocusChangedEventId, uia_com_focus_win_event_callback,
|
||||
(void *)focus_node, TRUE);
|
||||
if (FAILED(hr))
|
||||
WARN("uia_event_for_each on focus_node failed with hr %#lx\n", hr);
|
||||
}
|
||||
UiaNodeRelease(focus_node);
|
||||
}
|
||||
VariantClear(&v);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -595,7 +595,7 @@ static HRESULT uia_raise_clientside_event(struct uia_queue_uia_event *event)
|
|||
HRESULT hr;
|
||||
|
||||
node = nav_start_node = NULL;
|
||||
hr = uia_node_from_lresult(event->u.clientside.node, &node);
|
||||
hr = uia_node_from_lresult(event->u.clientside.node, &node, 0);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN("Failed to create node from lresult, hr %#lx\n", hr);
|
||||
|
@ -605,7 +605,7 @@ static HRESULT uia_raise_clientside_event(struct uia_queue_uia_event *event)
|
|||
|
||||
if (event->u.clientside.nav_start_node)
|
||||
{
|
||||
hr = uia_node_from_lresult(event->u.clientside.nav_start_node, &nav_start_node);
|
||||
hr = uia_node_from_lresult(event->u.clientside.nav_start_node, &nav_start_node, 0);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN("Failed to create nav_start_node from lresult, hr %#lx\n", hr);
|
||||
|
|
|
@ -216,6 +216,7 @@ enum provider_method_flags {
|
|||
|
||||
/* uia_client.c */
|
||||
int get_node_provider_type_at_idx(struct uia_node *node, int idx) DECLSPEC_HIDDEN;
|
||||
HRESULT get_focus_from_node_provider(IWineUiaNode *node, int idx, LONG flags, VARIANT *ret_val) DECLSPEC_HIDDEN;
|
||||
HRESULT respond_to_win_event_on_node_provider(IWineUiaNode *node, int idx, DWORD win_event, HWND hwnd, LONG obj_id,
|
||||
LONG child_id, IProxyProviderWinEventSink *sink) DECLSPEC_HIDDEN;
|
||||
HRESULT create_node_from_node_provider(IWineUiaNode *node, int idx, LONG flags, VARIANT *ret_val) DECLSPEC_HIDDEN;
|
||||
|
@ -224,7 +225,7 @@ HRESULT clone_uia_node(HUIANODE in_node, HUIANODE *out_node) DECLSPEC_HIDDEN;
|
|||
HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node) DECLSPEC_HIDDEN;
|
||||
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 uia_node_from_lresult(LRESULT lr, HUIANODE *huianode, int node_flags) DECLSPEC_HIDDEN;
|
||||
void uia_node_lresult_release(LRESULT lr) 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;
|
||||
|
|
Loading…
Add table
Reference in a new issue