Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wine-cw
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wine
wine-cw
Commits
e070e9b4
Commit
e070e9b4
authored
Apr 25, 2023
by
Connor McAdams
Committed by
Alexandre Julliard
Apr 28, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
uiautomationcore: Implement UiaNodeFromFocus.
Signed-off-by:
Connor McAdams
<
cmcadams@codeweavers.com
>
parent
ba927e50
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
158 additions
and
14 deletions
+158
-14
uiautomation.c
dlls/uiautomationcore/tests/uiautomation.c
+11
-12
uia_classes.idl
dlls/uiautomationcore/uia_classes.idl
+1
-0
uia_client.c
dlls/uiautomationcore/uia_client.c
+146
-2
No files found.
dlls/uiautomationcore/tests/uiautomation.c
View file @
e070e9b4
...
...
@@ -13166,21 +13166,20 @@ static void test_node_from_focus_(struct UiaCacheRequest *cache_req, struct node
SET_EXPECT_MULTI
(
winproc_GETOBJECT_UiaRoot
,
win_get_obj_count
);
SET_EXPECT_MULTI
(
child_winproc_GETOBJECT_UiaRoot
,
child_win_get_obj_count
);
hr
=
UiaNodeFromFocus
(
cache_req
,
&
out_req
,
&
tree_struct
);
todo_wine
ok_
(
file
,
line
)(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
ok_
(
file
,
line
)(
hr
==
S_OK
,
"Unexpected hr %#lx.
\n
"
,
hr
);
if
(
exp_node_desc
->
prov_count
)
todo_wine
ok_
(
file
,
line
)(
!!
out_req
,
"out_req == NULL
\n
"
);
ok_
(
file
,
line
)(
!!
out_req
,
"out_req == NULL
\n
"
);
else
ok_
(
file
,
line
)(
!
out_req
,
"out_req != NULL
\n
"
);
todo_wine
ok_
(
file
,
line
)(
!!
tree_struct
,
"tree_struct == NULL
\n
"
);
ok_
(
file
,
line
)(
!!
tree_struct
,
"tree_struct == NULL
\n
"
);
todo_wine_if
(
base_hwnd_cback_todo
)
CHECK_CALLED_MULTI
(
prov_callback_base_hwnd
,
base_hwnd_cback_count
);
todo_wine_if
(
proxy_cback_todo
)
CHECK_CALLED_MULTI
(
prov_callback_proxy
,
proxy_cback_count
);
todo_wine_if
(
nc_cback_todo
)
CHECK_CALLED_MULTI
(
prov_callback_nonclient
,
nc_cback_count
);
todo_wine_if
(
win_get_obj_todo
)
CHECK_CALLED_MULTI
(
winproc_GETOBJECT_UiaRoot
,
win_get_obj_count
);
todo_wine_if
(
child_win_get_obj_todo
)
CHECK_CALLED_MULTI
(
child_winproc_GETOBJECT_UiaRoot
,
child_win_get_obj_count
);
if
(
tree_struct
)
ok_
(
file
,
line
)(
!
wcscmp
(
tree_struct
,
exp_tree_struct
),
"unexpected tree structure %s
\n
"
,
debugstr_w
(
tree_struct
));
if
(
exp_node_desc
->
prov_count
&&
SUCCEEDED
(
hr
))
ok_
(
file
,
line
)(
!
wcscmp
(
tree_struct
,
exp_tree_struct
),
"unexpected tree structure %s
\n
"
,
debugstr_w
(
tree_struct
));
if
(
exp_node_desc
->
prov_count
)
{
exp_lbound
[
0
]
=
exp_lbound
[
1
]
=
0
;
exp_elems
[
0
]
=
1
;
...
...
@@ -13250,7 +13249,7 @@ static void test_UiaNodeFromFocus(void)
add_provider_desc
(
&
exp_node_desc
,
L"Nonclient"
,
L"Provider_nc"
,
FALSE
);
add_provider_desc
(
&
exp_node_desc
,
L"Hwnd"
,
L"Provider_hwnd"
,
FALSE
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
1
,
1
,
1
,
0
,
0
,
TRUE
,
TRUE
,
TRU
E
,
FALSE
,
FALSE
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
1
,
1
,
1
,
0
,
0
,
FALSE
,
FALSE
,
FALS
E
,
FALSE
,
FALSE
);
/* Provider_hwnd returns Provider_hwnd2 from GetFocus. */
Provider_hwnd
.
focus_prov
=
&
Provider_hwnd2
.
IRawElementProviderFragment_iface
;
...
...
@@ -13260,7 +13259,7 @@ static void test_UiaNodeFromFocus(void)
add_provider_desc
(
&
exp_node_desc
,
L"Nonclient"
,
L"Provider_nc2"
,
FALSE
);
add_provider_desc
(
&
exp_node_desc
,
L"Hwnd"
,
L"Provider_hwnd2"
,
FALSE
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
2
,
1
,
2
,
1
,
0
,
TRUE
,
TRUE
,
TRUE
,
TRU
E
,
FALSE
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
2
,
1
,
2
,
1
,
0
,
TRUE
,
FALSE
,
FALSE
,
FALS
E
,
FALSE
);
/*
* Provider_proxy returns Provider from GetFocus. The provider that
...
...
@@ -13277,7 +13276,7 @@ static void test_UiaNodeFromFocus(void)
add_provider_desc
(
&
exp_node_desc
,
L"Nonclient"
,
L"Provider_nc2"
,
FALSE
);
add_provider_desc
(
&
exp_node_desc
,
L"Hwnd"
,
L"Provider_hwnd2"
,
FALSE
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
2
,
2
,
2
,
1
,
0
,
TRUE
,
TRUE
,
TRUE
,
TRU
E
,
FALSE
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
2
,
2
,
2
,
1
,
0
,
TRUE
,
FALSE
,
FALSE
,
FALS
E
,
FALSE
);
/*
* Provider_nc returns Provider_nc2 from GetFocus, Provider returns
...
...
@@ -13292,7 +13291,7 @@ static void test_UiaNodeFromFocus(void)
init_node_provider_desc
(
&
exp_node_desc
,
GetCurrentProcessId
(),
NULL
);
add_provider_desc
(
&
exp_node_desc
,
L"Main"
,
L"Provider_child"
,
TRUE
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
2
,
3
,
2
,
2
,
1
,
TRUE
,
TRUE
,
TRUE
,
TRUE
,
TRU
E
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
2
,
3
,
2
,
2
,
1
,
TRUE
,
FALSE
,
FALSE
,
TRUE
,
FALS
E
);
/*
* Provider_proxy returns Provider_child_child from GetFocus. The focus
...
...
@@ -13314,7 +13313,7 @@ static void test_UiaNodeFromFocus(void)
set_provider_prop_override
(
&
Provider
,
&
prop_override
,
1
);
init_node_provider_desc
(
&
exp_node_desc
,
0
,
NULL
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
2
,
2
,
2
,
1
,
0
,
TRUE
,
TRUE
,
TRUE
,
TRU
E
,
FALSE
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
2
,
2
,
2
,
1
,
0
,
TRUE
,
FALSE
,
FALSE
,
FALS
E
,
FALSE
);
/* This time, Provider_child matches our view condition. */
set_provider_prop_override
(
&
Provider_child
,
NULL
,
0
);
...
...
@@ -13322,7 +13321,7 @@ static void test_UiaNodeFromFocus(void)
init_node_provider_desc
(
&
exp_node_desc
,
GetCurrentProcessId
(),
NULL
);
add_provider_desc
(
&
exp_node_desc
,
L"Main"
,
L"Provider_child"
,
TRUE
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
1
,
1
,
1
,
0
,
0
,
TRUE
,
TRUE
,
TRU
E
,
FALSE
,
FALSE
);
test_node_from_focus
(
&
cache_req
,
&
exp_node_desc
,
1
,
1
,
1
,
0
,
0
,
FALSE
,
FALSE
,
FALS
E
,
FALSE
,
FALSE
);
method_sequences_enabled
=
TRUE
;
initialize_provider
(
&
Provider
,
ProviderOptions_ServerSideProvider
,
NULL
,
TRUE
);
...
...
dlls/uiautomationcore/uia_classes.idl
View file @
e070e9b4
...
...
@@ -66,6 +66,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
)
;
}
[
...
...
dlls/uiautomationcore/uia_client.c
View file @
e070e9b4
...
...
@@ -446,6 +446,22 @@ 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
)
{
IWineUiaProvider
*
prov
;
HRESULT
hr
;
VariantInit
(
ret_val
);
hr
=
IWineUiaNode_get_provider
(
node
,
idx
,
&
prov
);
if
(
FAILED
(
hr
))
return
hr
;
hr
=
IWineUiaProvider_get_focus
(
prov
,
ret_val
);
IWineUiaProvider_Release
(
prov
);
return
hr
;
}
/*
* IWineUiaNode interface.
*/
...
...
@@ -1762,6 +1778,38 @@ 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
)
{
struct
uia_provider
*
prov
=
impl_from_IWineUiaProvider
(
iface
);
IRawElementProviderFragmentRoot
*
elroot
;
IRawElementProviderFragment
*
elfrag
;
IRawElementProviderSimple
*
elprov
;
HRESULT
hr
;
TRACE
(
"%p, %p
\n
"
,
iface
,
out_val
);
VariantInit
(
out_val
);
hr
=
IRawElementProviderSimple_QueryInterface
(
prov
->
elprov
,
&
IID_IRawElementProviderFragmentRoot
,
(
void
**
)
&
elroot
);
if
(
FAILED
(
hr
))
return
S_OK
;
hr
=
IRawElementProviderFragmentRoot_GetFocus
(
elroot
,
&
elfrag
);
IRawElementProviderFragmentRoot_Release
(
elroot
);
if
(
FAILED
(
hr
)
||
!
elfrag
)
return
hr
;
hr
=
IRawElementProviderFragment_QueryInterface
(
elfrag
,
&
IID_IRawElementProviderSimple
,
(
void
**
)
&
elprov
);
IRawElementProviderFragment_Release
(
elfrag
);
if
(
SUCCEEDED
(
hr
))
{
hr
=
get_variant_for_elprov_node
(
elprov
,
prov
->
return_nested_node
,
out_val
);
if
(
FAILED
(
hr
))
VariantClear
(
out_val
);
}
return
hr
;
}
static
const
IWineUiaProviderVtbl
uia_provider_vtbl
=
{
uia_provider_QueryInterface
,
uia_provider_AddRef
,
...
...
@@ -1770,6 +1818,7 @@ static const IWineUiaProviderVtbl uia_provider_vtbl = {
uia_provider_get_prov_opts
,
uia_provider_has_parent
,
uia_provider_navigate
,
uia_provider_get_focus
,
};
static
HRESULT
create_wine_uia_provider
(
struct
uia_node
*
node
,
IRawElementProviderSimple
*
elprov
,
...
...
@@ -2170,6 +2219,30 @@ 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
)
{
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
);
VariantInit
(
out_val
);
hr
=
get_focus_from_node_provider
(
prov
->
nested_node
,
0
,
&
v
);
if
(
FAILED
(
hr
)
||
V_VT
(
&
v
)
==
VT_EMPTY
)
return
hr
;
hr
=
uia_node_from_lresult
((
LRESULT
)
V_I4
(
&
v
),
&
node
);
if
(
FAILED
(
hr
))
return
hr
;
get_variant_for_node
(
node
,
out_val
);
VariantClear
(
&
v
);
return
S_OK
;
}
static
const
IWineUiaProviderVtbl
uia_nested_node_provider_vtbl
=
{
uia_nested_node_provider_QueryInterface
,
uia_nested_node_provider_AddRef
,
...
...
@@ -2178,6 +2251,7 @@ static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = {
uia_nested_node_provider_get_prov_opts
,
uia_nested_node_provider_has_parent
,
uia_nested_node_provider_navigate
,
uia_nested_node_provider_get_focus
,
};
static
BOOL
is_nested_node_provider
(
IWineUiaProvider
*
iface
)
...
...
@@ -2435,13 +2509,83 @@ HRESULT WINAPI UiaGetRootNode(HUIANODE *huianode)
return
UiaNodeFromHandle
(
GetDesktopWindow
(),
huianode
);
}
static
HRESULT
get_focused_uia_node
(
HUIANODE
in_node
,
HUIANODE
*
out_node
)
{
struct
uia_node
*
node
=
unsafe_impl_from_IWineUiaNode
((
IWineUiaNode
*
)
in_node
);
const
BOOL
desktop_node
=
(
node
->
hwnd
==
GetDesktopWindow
());
HRESULT
hr
=
S_OK
;
VARIANT
v
;
int
i
;
*
out_node
=
NULL
;
VariantInit
(
&
v
);
for
(
i
=
0
;
i
<
node
->
prov_count
;
i
++
)
{
/*
* When getting focus from nodes other than the desktop, we ignore
* both the node's creator provider and its HWND provider. This avoids
* the problem of returning the same provider twice from GetFocus.
*/
if
(
!
desktop_node
&&
((
i
==
node
->
creator_prov_idx
)
||
(
get_node_provider_type_at_idx
(
node
,
i
)
==
PROV_TYPE_HWND
)))
continue
;
hr
=
get_focus_from_node_provider
(
&
node
->
IWineUiaNode_iface
,
i
,
&
v
);
if
(
FAILED
(
hr
))
break
;
if
(
V_VT
(
&
v
)
!=
VT_EMPTY
)
{
hr
=
UiaHUiaNodeFromVariant
(
&
v
,
out_node
);
if
(
FAILED
(
hr
))
*
out_node
=
NULL
;
break
;
}
}
return
hr
;
}
/***********************************************************************
* UiaNodeFromFocus (uiautomationcore.@)
*/
HRESULT
WINAPI
UiaNodeFromFocus
(
struct
UiaCacheRequest
*
cache_req
,
SAFEARRAY
**
out_req
,
BSTR
*
tree_struct
)
{
FIXME
(
"(%p, %p, %p): stub
\n
"
,
cache_req
,
out_req
,
tree_struct
);
return
E_NOTIMPL
;
HUIANODE
node
,
node2
;
HRESULT
hr
;
TRACE
(
"(%p, %p, %p)
\n
"
,
cache_req
,
out_req
,
tree_struct
);
if
(
!
cache_req
||
!
out_req
||
!
tree_struct
)
return
E_INVALIDARG
;
*
out_req
=
NULL
;
*
tree_struct
=
NULL
;
hr
=
UiaGetRootNode
(
&
node
);
if
(
FAILED
(
hr
))
return
hr
;
while
(
1
)
{
hr
=
get_focused_uia_node
(
node
,
&
node2
);
if
(
FAILED
(
hr
))
goto
exit
;
if
(
!
node2
)
break
;
UiaNodeRelease
(
node
);
node
=
node2
;
}
hr
=
UiaGetUpdatedCache
(
node
,
cache_req
,
NormalizeState_View
,
NULL
,
out_req
,
tree_struct
);
if
(
FAILED
(
hr
))
WARN
(
"UiaGetUpdatedCache failed with hr %#lx
\n
"
,
hr
);
exit:
UiaNodeRelease
(
node
);
return
hr
;
}
/***********************************************************************
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment