uiautomationcore: Implement MSAA accState based property IDs for MSAA providers.
[wine.git] / dlls / uiautomationcore / uia_provider.c
blobdae0187596dd4901f8a86fea57a5f020411026c3
1 /*
2 * Copyright 2022 Connor McAdams for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include "uiautomation.h"
22 #include "ocidl.h"
24 #include "wine/debug.h"
25 #include "wine/heap.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
29 static void variant_init_i4(VARIANT *v, int val)
31 V_VT(v) = VT_I4;
32 V_I4(v) = val;
35 static void variant_init_bool(VARIANT *v, BOOL val)
37 V_VT(v) = VT_BOOL;
38 V_BOOL(v) = val ? VARIANT_TRUE : VARIANT_FALSE;
41 static BOOL msaa_check_acc_state(IAccessible *acc, VARIANT cid, ULONG flag)
43 HRESULT hr;
44 VARIANT v;
46 VariantInit(&v);
47 hr = IAccessible_get_accState(acc, cid, &v);
48 if (SUCCEEDED(hr) && V_VT(&v) == VT_I4 && (V_I4(&v) & flag))
49 return TRUE;
51 return FALSE;
54 static LONG msaa_role_to_uia_control_type(LONG role)
56 switch (role)
58 case ROLE_SYSTEM_TITLEBAR: return UIA_TitleBarControlTypeId;
59 case ROLE_SYSTEM_MENUBAR: return UIA_MenuBarControlTypeId;
60 case ROLE_SYSTEM_SCROLLBAR: return UIA_ScrollBarControlTypeId;
61 case ROLE_SYSTEM_INDICATOR:
62 case ROLE_SYSTEM_GRIP: return UIA_ThumbControlTypeId;
63 case ROLE_SYSTEM_APPLICATION:
64 case ROLE_SYSTEM_WINDOW: return UIA_WindowControlTypeId;
65 case ROLE_SYSTEM_MENUPOPUP: return UIA_MenuControlTypeId;
66 case ROLE_SYSTEM_TOOLTIP: return UIA_ToolTipControlTypeId;
67 case ROLE_SYSTEM_DOCUMENT: return UIA_DocumentControlTypeId;
68 case ROLE_SYSTEM_PANE: return UIA_PaneControlTypeId;
69 case ROLE_SYSTEM_GROUPING: return UIA_GroupControlTypeId;
70 case ROLE_SYSTEM_SEPARATOR: return UIA_SeparatorControlTypeId;
71 case ROLE_SYSTEM_TOOLBAR: return UIA_ToolBarControlTypeId;
72 case ROLE_SYSTEM_STATUSBAR: return UIA_StatusBarControlTypeId;
73 case ROLE_SYSTEM_TABLE: return UIA_TableControlTypeId;
74 case ROLE_SYSTEM_COLUMNHEADER:
75 case ROLE_SYSTEM_ROWHEADER: return UIA_HeaderControlTypeId;
76 case ROLE_SYSTEM_CELL: return UIA_DataItemControlTypeId;
77 case ROLE_SYSTEM_LINK: return UIA_HyperlinkControlTypeId;
78 case ROLE_SYSTEM_LIST: return UIA_ListControlTypeId;
79 case ROLE_SYSTEM_LISTITEM: return UIA_ListItemControlTypeId;
80 case ROLE_SYSTEM_OUTLINE: return UIA_TreeControlTypeId;
81 case ROLE_SYSTEM_OUTLINEITEM: return UIA_TreeItemControlTypeId;
82 case ROLE_SYSTEM_PAGETAB: return UIA_TabItemControlTypeId;
83 case ROLE_SYSTEM_GRAPHIC: return UIA_ImageControlTypeId;
84 case ROLE_SYSTEM_STATICTEXT: return UIA_TextControlTypeId;
85 case ROLE_SYSTEM_TEXT: return UIA_EditControlTypeId;
86 case ROLE_SYSTEM_CLOCK:
87 case ROLE_SYSTEM_BUTTONDROPDOWNGRID:
88 case ROLE_SYSTEM_PUSHBUTTON: return UIA_ButtonControlTypeId;
89 case ROLE_SYSTEM_CHECKBUTTON: return UIA_CheckBoxControlTypeId;
90 case ROLE_SYSTEM_RADIOBUTTON: return UIA_RadioButtonControlTypeId;
91 case ROLE_SYSTEM_COMBOBOX: return UIA_ComboBoxControlTypeId;
92 case ROLE_SYSTEM_PROGRESSBAR: return UIA_ProgressBarControlTypeId;
93 case ROLE_SYSTEM_SLIDER: return UIA_SliderControlTypeId;
94 case ROLE_SYSTEM_SPINBUTTON: return UIA_SpinnerControlTypeId;
95 case ROLE_SYSTEM_BUTTONMENU:
96 case ROLE_SYSTEM_MENUITEM: return UIA_MenuItemControlTypeId;
97 case ROLE_SYSTEM_PAGETABLIST: return UIA_TabControlTypeId;
98 case ROLE_SYSTEM_BUTTONDROPDOWN:
99 case ROLE_SYSTEM_SPLITBUTTON: return UIA_SplitButtonControlTypeId;
100 case ROLE_SYSTEM_SOUND:
101 case ROLE_SYSTEM_CURSOR:
102 case ROLE_SYSTEM_CARET:
103 case ROLE_SYSTEM_ALERT:
104 case ROLE_SYSTEM_CLIENT:
105 case ROLE_SYSTEM_CHART:
106 case ROLE_SYSTEM_DIALOG:
107 case ROLE_SYSTEM_BORDER:
108 case ROLE_SYSTEM_COLUMN:
109 case ROLE_SYSTEM_ROW:
110 case ROLE_SYSTEM_HELPBALLOON:
111 case ROLE_SYSTEM_CHARACTER:
112 case ROLE_SYSTEM_PROPERTYPAGE:
113 case ROLE_SYSTEM_DROPLIST:
114 case ROLE_SYSTEM_DIAL:
115 case ROLE_SYSTEM_HOTKEYFIELD:
116 case ROLE_SYSTEM_DIAGRAM:
117 case ROLE_SYSTEM_ANIMATION:
118 case ROLE_SYSTEM_EQUATION:
119 case ROLE_SYSTEM_WHITESPACE:
120 case ROLE_SYSTEM_IPADDRESS:
121 case ROLE_SYSTEM_OUTLINEBUTTON:
122 WARN("No UIA control type mapping for MSAA role %ld\n", role);
123 break;
125 default:
126 FIXME("UIA control type mapping unimplemented for MSAA role %ld\n", role);
127 break;
130 return 0;
134 * UiaProviderFromIAccessible IRawElementProviderSimple interface.
136 struct msaa_provider {
137 IRawElementProviderSimple IRawElementProviderSimple_iface;
138 LONG refcount;
140 IAccessible *acc;
141 VARIANT cid;
142 HWND hwnd;
143 LONG control_type;
146 static inline struct msaa_provider *impl_from_msaa_provider(IRawElementProviderSimple *iface)
148 return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderSimple_iface);
151 HRESULT WINAPI msaa_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv)
153 *ppv = NULL;
154 if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown))
155 *ppv = iface;
156 else
157 return E_NOINTERFACE;
159 IRawElementProviderSimple_AddRef(iface);
160 return S_OK;
163 ULONG WINAPI msaa_provider_AddRef(IRawElementProviderSimple *iface)
165 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
166 ULONG refcount = InterlockedIncrement(&msaa_prov->refcount);
168 TRACE("%p, refcount %ld\n", iface, refcount);
170 return refcount;
173 ULONG WINAPI msaa_provider_Release(IRawElementProviderSimple *iface)
175 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
176 ULONG refcount = InterlockedDecrement(&msaa_prov->refcount);
178 TRACE("%p, refcount %ld\n", iface, refcount);
180 if (!refcount)
182 IAccessible_Release(msaa_prov->acc);
183 heap_free(msaa_prov);
186 return refcount;
189 HRESULT WINAPI msaa_provider_get_ProviderOptions(IRawElementProviderSimple *iface,
190 enum ProviderOptions *ret_val)
192 TRACE("%p, %p\n", iface, ret_val);
193 *ret_val = ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading;
194 return S_OK;
197 HRESULT WINAPI msaa_provider_GetPatternProvider(IRawElementProviderSimple *iface,
198 PATTERNID pattern_id, IUnknown **ret_val)
200 FIXME("%p, %d, %p: stub!\n", iface, pattern_id, ret_val);
201 *ret_val = NULL;
202 return E_NOTIMPL;
205 HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface,
206 PROPERTYID prop_id, VARIANT *ret_val)
208 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
209 HRESULT hr;
210 VARIANT v;
212 TRACE("%p, %d, %p\n", iface, prop_id, ret_val);
214 VariantInit(ret_val);
215 VariantInit(&v);
216 switch (prop_id)
218 case UIA_ProviderDescriptionPropertyId:
219 V_VT(ret_val) = VT_BSTR;
220 V_BSTR(ret_val) = SysAllocString(L"Wine: MSAA Proxy");
221 break;
223 case UIA_ControlTypePropertyId:
224 if (!msaa_prov->control_type)
226 hr = IAccessible_get_accRole(msaa_prov->acc, msaa_prov->cid, &v);
227 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
228 msaa_prov->control_type = msaa_role_to_uia_control_type(V_I4(&v));
231 if (msaa_prov->control_type)
232 variant_init_i4(ret_val, msaa_prov->control_type);
234 break;
236 case UIA_HasKeyboardFocusPropertyId:
237 variant_init_bool(ret_val, msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
238 STATE_SYSTEM_FOCUSED));
239 break;
241 case UIA_IsKeyboardFocusablePropertyId:
242 variant_init_bool(ret_val, msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
243 STATE_SYSTEM_FOCUSABLE));
244 break;
246 case UIA_IsEnabledPropertyId:
247 variant_init_bool(ret_val, !msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
248 STATE_SYSTEM_UNAVAILABLE));
249 break;
251 case UIA_IsPasswordPropertyId:
252 variant_init_bool(ret_val, msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
253 STATE_SYSTEM_PROTECTED));
254 break;
256 default:
257 FIXME("Unimplemented propertyId %d\n", prop_id);
258 break;
261 return S_OK;
264 HRESULT WINAPI msaa_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface,
265 IRawElementProviderSimple **ret_val)
267 FIXME("%p, %p: stub!\n", iface, ret_val);
268 *ret_val = NULL;
269 return E_NOTIMPL;
272 static const IRawElementProviderSimpleVtbl msaa_provider_vtbl = {
273 msaa_provider_QueryInterface,
274 msaa_provider_AddRef,
275 msaa_provider_Release,
276 msaa_provider_get_ProviderOptions,
277 msaa_provider_GetPatternProvider,
278 msaa_provider_GetPropertyValue,
279 msaa_provider_get_HostRawElementProvider,
282 /***********************************************************************
283 * UiaProviderFromIAccessible (uiautomationcore.@)
285 HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD flags,
286 IRawElementProviderSimple **elprov)
288 struct msaa_provider *msaa_prov;
289 IServiceProvider *serv_prov;
290 HWND hwnd = NULL;
291 HRESULT hr;
293 TRACE("(%p, %ld, %#lx, %p)\n", acc, child_id, flags, elprov);
295 if (elprov)
296 *elprov = NULL;
298 if (!elprov)
299 return E_POINTER;
300 if (!acc)
301 return E_INVALIDARG;
303 if (flags != UIA_PFIA_DEFAULT)
305 FIXME("unsupported flags %#lx\n", flags);
306 return E_NOTIMPL;
309 hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&serv_prov);
310 if (SUCCEEDED(hr))
312 IUnknown *unk;
314 hr = IServiceProvider_QueryService(serv_prov, &IIS_IsOleaccProxy, &IID_IUnknown, (void **)&unk);
315 if (SUCCEEDED(hr))
317 WARN("Cannot wrap an oleacc proxy IAccessible!\n");
318 IUnknown_Release(unk);
319 IServiceProvider_Release(serv_prov);
320 return E_INVALIDARG;
323 IServiceProvider_Release(serv_prov);
326 hr = WindowFromAccessibleObject(acc, &hwnd);
327 if (FAILED(hr))
328 return hr;
329 if (!hwnd)
330 return E_FAIL;
332 msaa_prov = heap_alloc_zero(sizeof(*msaa_prov));
333 if (!msaa_prov)
334 return E_OUTOFMEMORY;
336 msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl;
337 msaa_prov->refcount = 1;
338 msaa_prov->hwnd = hwnd;
339 variant_init_i4(&msaa_prov->cid, child_id);
340 msaa_prov->acc = acc;
341 IAccessible_AddRef(acc);
342 *elprov = &msaa_prov->IRawElementProviderSimple_iface;
344 return S_OK;