uiautomationcore: Potentially raise focus event for serverside providers in response to EVENT_OBJECT_FOCUS.
Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
parent
5a987d48b2
commit
2be7de9898
6 changed files with 133 additions and 10 deletions
|
@ -15659,11 +15659,11 @@ static void test_uia_com_focus_change_event_handler_win_event_handling(IUIAutoma
|
|||
|
||||
set_uia_hwnd_expects(0, 2, 2, 4, 0); /* Win11 sends 4 WM_GETOBJECT messages, normally only 3. */
|
||||
NotifyWinEvent(EVENT_OBJECT_FOCUS, test_hwnd, OBJID_CLIENT, CHILDID_SELF);
|
||||
todo_wine ok(msg_wait_for_all_events(event_handles, 2, 5000) != WAIT_TIMEOUT, "Wait for event_handle(s) timed out.\n");
|
||||
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, TRUE, 2, TRUE, 3, TRUE, 0, FALSE);
|
||||
todo_wine CHECK_CALLED(uia_com_event_callback);
|
||||
todo_wine CHECK_CALLED(uia_event_callback);
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 2, FALSE, 2, FALSE, 3, FALSE, 0, FALSE);
|
||||
CHECK_CALLED(uia_com_event_callback);
|
||||
CHECK_CALLED(uia_event_callback);
|
||||
|
||||
/*
|
||||
* Child ID is ignored when translating EVENT_OBJECT_FOCUS events into
|
||||
|
@ -15674,11 +15674,11 @@ static void test_uia_com_focus_change_event_handler_win_event_handling(IUIAutoma
|
|||
set_uia_hwnd_expects(0, 2, 2, 4, 0); /* Win11 sends 4 WM_GETOBJECT messages, normally only 3. */
|
||||
|
||||
NotifyWinEvent(EVENT_OBJECT_FOCUS, test_hwnd, OBJID_CLIENT, -1);
|
||||
todo_wine ok(msg_wait_for_all_events(event_handles, 2, 5000) != WAIT_TIMEOUT, "Wait for event_handle(s) timed out.\n");
|
||||
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, TRUE, 2, TRUE, 3, TRUE, 0, FALSE);
|
||||
todo_wine CHECK_CALLED(uia_com_event_callback);
|
||||
todo_wine CHECK_CALLED(uia_event_callback);
|
||||
check_uia_hwnd_expects_at_least(0, FALSE, 2, FALSE, 2, FALSE, 3, FALSE, 0, FALSE);
|
||||
CHECK_CALLED(uia_com_event_callback);
|
||||
CHECK_CALLED(uia_event_callback);
|
||||
|
||||
/*
|
||||
* UIA queries the serverside provider for UIA_HasKeyboardFocusPropertyId.
|
||||
|
|
|
@ -95,6 +95,7 @@ library UIA_wine_private
|
|||
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);
|
||||
HRESULT create_node_from_prov([in]long flags, [out, retval]VARIANT *ret_val);
|
||||
}
|
||||
|
||||
[
|
||||
|
|
|
@ -394,6 +394,22 @@ HRESULT respond_to_win_event_on_node_provider(IWineUiaNode *node, int idx, DWORD
|
|||
return hr;
|
||||
}
|
||||
|
||||
HRESULT create_node_from_node_provider(IWineUiaNode *node, int idx, LONG flags, VARIANT *ret_val)
|
||||
{
|
||||
IWineUiaProvider *prov;
|
||||
HRESULT hr;
|
||||
|
||||
VariantInit(ret_val);
|
||||
hr = IWineUiaNode_get_provider(node, idx, &prov);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
hr = IWineUiaProvider_create_node_from_prov(prov, flags, ret_val);
|
||||
IWineUiaProvider_Release(prov);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/*
|
||||
* IWineUiaNode interface.
|
||||
*/
|
||||
|
@ -1972,6 +1988,26 @@ static HRESULT WINAPI uia_provider_respond_to_win_event(IWineUiaProvider *iface,
|
|||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI uia_provider_create_node_from_prov(IWineUiaProvider *iface, LONG flags, VARIANT *ret_val)
|
||||
{
|
||||
struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
|
||||
IRawElementProviderSimple *elprov;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("%p, %#lx, %p\n", iface, flags, ret_val);
|
||||
|
||||
if (flags & PROV_METHOD_FLAG_RETURN_NODE_LRES)
|
||||
FIXME("PROV_METHOD_FLAG_RETURN_NODE_LRES ignored for normal providers.\n");
|
||||
|
||||
VariantInit(ret_val);
|
||||
hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderSimple, (void **)&elprov);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
/* get_variant_for_elprov_node will release our provider upon failure. */
|
||||
return get_variant_for_elprov_node(elprov, prov->return_nested_node, prov->refuse_hwnd_node_providers, ret_val);
|
||||
}
|
||||
|
||||
static const IWineUiaProviderVtbl uia_provider_vtbl = {
|
||||
uia_provider_QueryInterface,
|
||||
uia_provider_AddRef,
|
||||
|
@ -1983,6 +2019,7 @@ static const IWineUiaProviderVtbl uia_provider_vtbl = {
|
|||
uia_provider_get_focus,
|
||||
uia_provider_attach_event,
|
||||
uia_provider_respond_to_win_event,
|
||||
uia_provider_create_node_from_prov,
|
||||
};
|
||||
|
||||
static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov,
|
||||
|
@ -2431,6 +2468,36 @@ static HRESULT WINAPI uia_nested_node_provider_respond_to_win_event(IWineUiaProv
|
|||
return E_FAIL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI uia_nested_node_provider_create_node_from_prov(IWineUiaProvider *iface, LONG flags, VARIANT *ret_val)
|
||||
{
|
||||
struct uia_nested_node_provider *prov = impl_from_nested_node_IWineUiaProvider(iface);
|
||||
HUIANODE node;
|
||||
HRESULT hr;
|
||||
VARIANT v;
|
||||
|
||||
TRACE("%p, %#lx, %p\n", iface, flags, ret_val);
|
||||
|
||||
VariantInit(ret_val);
|
||||
hr = create_node_from_node_provider(prov->nested_node, 0, 0, &v);
|
||||
if (FAILED(hr) || V_VT(&v) == VT_EMPTY)
|
||||
return hr;
|
||||
|
||||
if (flags & PROV_METHOD_FLAG_RETURN_NODE_LRES)
|
||||
{
|
||||
*ret_val = v;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node);
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
get_variant_for_node(node, ret_val);
|
||||
VariantClear(&v);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = {
|
||||
uia_nested_node_provider_QueryInterface,
|
||||
uia_nested_node_provider_AddRef,
|
||||
|
@ -2442,6 +2509,7 @@ static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = {
|
|||
uia_nested_node_provider_get_focus,
|
||||
uia_nested_node_provider_attach_event,
|
||||
uia_nested_node_provider_respond_to_win_event,
|
||||
uia_nested_node_provider_create_node_from_prov,
|
||||
};
|
||||
|
||||
static BOOL is_nested_node_provider(IWineUiaProvider *iface)
|
||||
|
|
|
@ -979,6 +979,40 @@ struct uia_com_event {
|
|||
struct uia_event_handler_map_entry *handler_map;
|
||||
};
|
||||
|
||||
static HRESULT uia_com_focus_win_event_callback(struct uia_event *event, void *user_data)
|
||||
{
|
||||
struct uia_node *node = impl_from_IWineUiaNode((IWineUiaNode *)user_data);
|
||||
VARIANT v, v2;
|
||||
HRESULT hr;
|
||||
|
||||
/* Only match desktop events. */
|
||||
if (!event->desktop_subtree_event)
|
||||
return S_OK;
|
||||
|
||||
VariantInit(&v);
|
||||
VariantInit(&v2);
|
||||
|
||||
hr = create_node_from_node_provider(&node->IWineUiaNode_iface, 0, PROV_METHOD_FLAG_RETURN_NODE_LRES, &v);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN("Failed to create new node lres with hr %#lx\n", hr);
|
||||
return hr;
|
||||
}
|
||||
|
||||
if (V_VT(&v) == VT_I4)
|
||||
{
|
||||
hr = IWineUiaEvent_raise_event(&event->IWineUiaEvent_iface, v, v2);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
WARN("raise_event failed with hr %#lx\n", hr);
|
||||
uia_node_lresult_release(V_I4(&v));
|
||||
}
|
||||
}
|
||||
VariantClear(&v);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void uia_com_focus_handler_advise_node(struct uia_com_event *event, HUIANODE node, HWND hwnd)
|
||||
{
|
||||
HRESULT hr;
|
||||
|
@ -998,6 +1032,8 @@ static void uia_com_focus_handler_advise_node(struct uia_com_event *event, HUIAN
|
|||
static void uia_com_focus_win_event_handler(HUIANODE node, HWND hwnd, struct uia_event_handler_event_id_map_entry *event_id_map)
|
||||
{
|
||||
struct uia_event_handler_map_entry *entry;
|
||||
HRESULT hr;
|
||||
VARIANT v;
|
||||
|
||||
LIST_FOR_EACH_ENTRY(entry, &event_id_map->handlers_list, struct uia_event_handler_map_entry, handler_event_id_map_list_entry)
|
||||
{
|
||||
|
@ -1009,6 +1045,17 @@ static void uia_com_focus_win_event_handler(HUIANODE node, HWND hwnd, struct uia
|
|||
uia_com_focus_handler_advise_node(event, node, hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
VariantInit(&v);
|
||||
hr = UiaGetPropertyValue(node, UIA_HasKeyboardFocusPropertyId, &v);
|
||||
if (SUCCEEDED(hr) && (V_VT(&v) == VT_BOOL && V_BOOL(&v) == VARIANT_TRUE))
|
||||
{
|
||||
hr = uia_event_for_each(UIA_AutomationFocusChangedEventId, uia_com_focus_win_event_callback, (void *)node, TRUE);
|
||||
if (FAILED(hr))
|
||||
WARN("uia_event_for_each failed with hr %#lx\n", hr);
|
||||
}
|
||||
|
||||
VariantClear(&v);
|
||||
}
|
||||
|
||||
HRESULT uia_com_win_event_callback(DWORD event_id, HWND hwnd, LONG obj_id, LONG child_id, DWORD thread_id, DWORD event_time)
|
||||
|
|
|
@ -252,8 +252,7 @@ static void uia_event_map_entry_release(struct uia_event_map_entry *entry)
|
|||
}
|
||||
}
|
||||
|
||||
typedef HRESULT UiaWineEventForEachCallback(struct uia_event *, void *);
|
||||
static HRESULT uia_event_for_each(int event_id, UiaWineEventForEachCallback *callback, void *user_data,
|
||||
HRESULT uia_event_for_each(int event_id, UiaWineEventForEachCallback *callback, void *user_data,
|
||||
BOOL clientside_only)
|
||||
{
|
||||
struct uia_event_map_entry *event_entry;
|
||||
|
|
|
@ -158,6 +158,7 @@ struct uia_event
|
|||
};
|
||||
|
||||
typedef HRESULT UiaWineEventCallback(struct uia_event *, struct uia_event_args *, SAFEARRAY *, BSTR);
|
||||
typedef HRESULT UiaWineEventForEachCallback(struct uia_event *, void *);
|
||||
|
||||
static inline void variant_init_bool(VARIANT *v, BOOL val)
|
||||
{
|
||||
|
@ -209,10 +210,15 @@ static inline BOOL uia_array_reserve(void **elements, SIZE_T *capacity, SIZE_T c
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
enum provider_method_flags {
|
||||
PROV_METHOD_FLAG_RETURN_NODE_LRES = 0x0001,
|
||||
};
|
||||
|
||||
/* uia_client.c */
|
||||
int get_node_provider_type_at_idx(struct uia_node *node, int idx) 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;
|
||||
HRESULT attach_event_to_uia_node(HUIANODE node, struct uia_event *event) DECLSPEC_HIDDEN;
|
||||
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;
|
||||
|
@ -231,6 +237,8 @@ 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 uia_event_for_each(int event_id, UiaWineEventForEachCallback *callback, void *user_data,
|
||||
BOOL clientside_only) DECLSPEC_HIDDEN;
|
||||
BOOL uia_clientside_event_start_event_thread(struct uia_event *event) 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,
|
||||
|
|
Loading…
Add table
Reference in a new issue