From: Piotr Caban piotr@codeweavers.com
--- dlls/oleacc/client.c | 36 ++++++++++++++++ dlls/oleacc/main.c | 82 +++++------------------------------- dlls/oleacc/oleacc_private.h | 7 +++ 3 files changed, 53 insertions(+), 72 deletions(-)
diff --git a/dlls/oleacc/client.c b/dlls/oleacc/client.c index 93f6b590f78..333a95dc388 100644 --- a/dlls/oleacc/client.c +++ b/dlls/oleacc/client.c @@ -19,6 +19,7 @@ #define COBJMACROS
#include "oleacc_private.h" +#include "commctrl.h"
#include "wine/debug.h" #include "wine/heap.h" @@ -650,6 +651,39 @@ static const IEnumVARIANTVtbl ClientEnumVARIANTVtbl = { Client_EnumVARIANT_Clone };
+static const struct win_class_data classes[] = { + {WC_LISTBOXW, 0x10000, TRUE}, + {L"#32768", 0x10001, TRUE}, /* menu */ + {WC_BUTTONW, 0x10002, TRUE}, + {WC_STATICW, 0x10003, TRUE}, + {WC_EDITW, 0x10004, TRUE}, + {WC_COMBOBOXW, 0x10005, TRUE}, + {L"#32770", 0x10006, TRUE}, /* dialog */ + {L"#32771", 0x10007, TRUE}, /* winswitcher */ + {L"MDIClient", 0x10008, TRUE}, + {L"#32769", 0x10009, TRUE}, /* desktop */ + {WC_SCROLLBARW, 0x1000a, TRUE}, + {STATUSCLASSNAMEW, 0x1000b, TRUE}, + {TOOLBARCLASSNAMEW, 0x1000c, TRUE}, + {PROGRESS_CLASSW, 0x1000d, TRUE}, + {ANIMATE_CLASSW, 0x1000e, TRUE}, + {WC_TABCONTROLW, 0x1000f, TRUE}, + {HOTKEY_CLASSW, 0x10010, TRUE}, + {WC_HEADERW, 0x10011, TRUE}, + {TRACKBAR_CLASSW, 0x10012, TRUE}, + {WC_LISTVIEWW, 0x10013, TRUE}, + {UPDOWN_CLASSW, 0x10016, TRUE}, + {TOOLTIPS_CLASSW, 0x10018, TRUE}, + {WC_TREEVIEWW, 0x10019, TRUE}, + {MONTHCAL_CLASSW, 0, TRUE}, + {DATETIMEPICK_CLASSW, 0, TRUE}, + {WC_IPADDRESSW, 0, TRUE}, + {L"RICHEDIT", 0x1001c, TRUE}, + {L"RichEdit20A", 0, TRUE}, + {L"RichEdit20W", 0, TRUE}, + {NULL} +}; + HRESULT create_client_object(HWND hwnd, const IID *iid, void **obj) { Client *client; @@ -662,6 +696,8 @@ HRESULT create_client_object(HWND hwnd, const IID *iid, void **obj) if(!client) return E_OUTOFMEMORY;
+ find_class_data(hwnd, classes); + client->IAccessible_iface.lpVtbl = &ClientVtbl; client->IOleWindow_iface.lpVtbl = &ClientOleWindowVtbl; client->IEnumVARIANT_iface.lpVtbl = &ClientEnumVARIANTVtbl; diff --git a/dlls/oleacc/main.c b/dlls/oleacc/main.c index db9f646988c..3ce616ae0c1 100644 --- a/dlls/oleacc/main.c +++ b/dlls/oleacc/main.c @@ -20,13 +20,6 @@
#define COBJMACROS
-#include <stdarg.h> -#include "windef.h" -#include "winbase.h" -#include "ole2.h" -#include "commctrl.h" -#include "rpcproxy.h" - #include "initguid.h" #include "oleacc_private.h" #include "resource.h" @@ -37,50 +30,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(oleacc);
static const WCHAR lresult_atom_prefix[] = {'w','i','n','e','_','o','l','e','a','c','c',':'};
-typedef HRESULT (*accessible_create)(HWND, const IID*, void**); - extern HRESULT WINAPI OLEACC_DllGetClassObject(REFCLSID, REFIID, void**) DECLSPEC_HIDDEN; extern BOOL WINAPI OLEACC_DllMain(HINSTANCE, DWORD, void*) DECLSPEC_HIDDEN; extern HRESULT WINAPI OLEACC_DllRegisterServer(void) DECLSPEC_HIDDEN; extern HRESULT WINAPI OLEACC_DllUnregisterServer(void) DECLSPEC_HIDDEN;
-static struct { - const WCHAR *name; - DWORD idx; - accessible_create create_client; - accessible_create create_window; -} builtin_classes[] = { - {WC_LISTBOXW, 0x10000, NULL, NULL}, - {L"#32768", 0x10001, NULL, NULL}, /* menu */ - {WC_BUTTONW, 0x10002, NULL, NULL}, - {WC_STATICW, 0x10003, NULL, NULL}, - {WC_EDITW, 0x10004, NULL, NULL}, - {WC_COMBOBOXW, 0x10005, NULL, NULL}, - {L"#32770", 0x10006, NULL, NULL}, /* dialog */ - {L"#32771", 0x10007, NULL, NULL}, /* winswitcher */ - {L"MDIClient", 0x10008, NULL, NULL}, - {L"#32769", 0x10009, NULL, NULL}, /* desktop */ - {WC_SCROLLBARW, 0x1000a, NULL, NULL}, - {STATUSCLASSNAMEW, 0x1000b, NULL, NULL}, - {TOOLBARCLASSNAMEW, 0x1000c, NULL, NULL}, - {PROGRESS_CLASSW, 0x1000d, NULL, NULL}, - {ANIMATE_CLASSW, 0x1000e, NULL, NULL}, - {WC_TABCONTROLW, 0x1000f, NULL, NULL}, - {HOTKEY_CLASSW, 0x10010, NULL, NULL}, - {WC_HEADERW, 0x10011, NULL, NULL}, - {TRACKBAR_CLASSW, 0x10012, NULL, NULL}, - {WC_LISTVIEWW, 0x10013, NULL, NULL}, - {UPDOWN_CLASSW, 0x10016, NULL, NULL}, - {TOOLTIPS_CLASSW, 0x10018, NULL, NULL}, - {WC_TREEVIEWW, 0x10019, NULL, NULL}, - {MONTHCAL_CLASSW, 0, NULL, NULL}, - {DATETIMEPICK_CLASSW, 0, NULL, NULL}, - {WC_IPADDRESSW, 0, NULL, NULL}, - {L"RICHEDIT", 0x1001c, NULL, NULL}, - {L"RichEdit20A", 0, NULL, NULL}, - {L"RichEdit20W", 0, NULL, NULL}, -}; - static HINSTANCE oleacc_handle = 0;
int convert_child_id(VARIANT *v) @@ -94,7 +48,7 @@ int convert_child_id(VARIANT *v) } }
-static accessible_create get_builtin_accessible_obj(HWND hwnd, LONG objid) +const struct win_class_data* find_class_data(HWND hwnd, const struct win_class_data *classes) { WCHAR class_name[64]; int i, idx; @@ -103,31 +57,21 @@ static accessible_create get_builtin_accessible_obj(HWND hwnd, LONG objid) return NULL; TRACE("got window class: %s\n", debugstr_w(class_name));
- for(i=0; i<ARRAY_SIZE(builtin_classes); i++) { - if(!wcsicmp(class_name, builtin_classes[i].name)) { - accessible_create ret; - - ret = (objid==OBJID_CLIENT ? - builtin_classes[i].create_client : - builtin_classes[i].create_window); - if(!ret) + for(i=0; classes[i].name; i++) { + if(!wcsicmp(class_name, classes[i].name)) { + if(classes[i].stub) FIXME("unhandled window class: %s\n", debugstr_w(class_name)); - return ret; + return &classes[i]; } }
idx = SendMessageW(hwnd, WM_GETOBJECT, 0, OBJID_QUERYCLASSNAMEIDX); if(idx) { - for(i=0; i<ARRAY_SIZE(builtin_classes); i++) { - if(idx == builtin_classes[i].idx) { - accessible_create ret; - - ret = (objid==OBJID_CLIENT ? - builtin_classes[i].create_client : - builtin_classes[i].create_window); - if(!ret) - FIXME("unhandled class name idx: %x\n", idx); - return ret; + for(i=0; classes[i].name; i++) { + if(idx == classes[i].idx) { + if(classes[i].stub) + FIXME("unhandled window class: %s\n", debugstr_w(class_name)); + return &classes[i]; } }
@@ -140,19 +84,13 @@ static accessible_create get_builtin_accessible_obj(HWND hwnd, LONG objid) HRESULT WINAPI CreateStdAccessibleObject( HWND hwnd, LONG idObject, REFIID riidInterface, void** ppvObject ) { - accessible_create create; - TRACE("%p %d %s %p\n", hwnd, idObject, debugstr_guid( riidInterface ), ppvObject );
switch(idObject) { case OBJID_CLIENT: - create = get_builtin_accessible_obj(hwnd, idObject); - if(create) return create(hwnd, riidInterface, ppvObject); return create_client_object(hwnd, riidInterface, ppvObject); case OBJID_WINDOW: - create = get_builtin_accessible_obj(hwnd, idObject); - if(create) return create(hwnd, riidInterface, ppvObject); return create_window_object(hwnd, riidInterface, ppvObject); default: FIXME("unhandled object id: %d\n", idObject); diff --git a/dlls/oleacc/oleacc_private.h b/dlls/oleacc/oleacc_private.h index 32561ef3d2f..64926b6abb7 100644 --- a/dlls/oleacc/oleacc_private.h +++ b/dlls/oleacc/oleacc_private.h @@ -18,6 +18,13 @@
#include "oleacc_classes.h"
+struct win_class_data { + const WCHAR *name; + DWORD idx; + BOOL stub; +}; +const struct win_class_data* find_class_data(HWND, const struct win_class_data*) DECLSPEC_HIDDEN; + HRESULT create_client_object(HWND, const IID*, void**) DECLSPEC_HIDDEN; HRESULT create_window_object(HWND, const IID*, void**) DECLSPEC_HIDDEN; HRESULT get_accpropservices_factory(REFIID, void**) DECLSPEC_HIDDEN;
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/client.c | 32 ++++++++++++++++++++++++++++---- dlls/oleacc/oleacc_private.h | 1 + 2 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/dlls/oleacc/client.c b/dlls/oleacc/client.c index 333a95dc388..1f24daf1a47 100644 --- a/dlls/oleacc/client.c +++ b/dlls/oleacc/client.c @@ -26,6 +26,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(oleacc);
+typedef struct win_class_vtbl win_class_vtbl; typedef struct { IAccessible IAccessible_iface; IOleWindow IOleWindow_iface; @@ -35,8 +36,15 @@ typedef struct {
HWND hwnd; HWND enum_pos; + INT role; + + const win_class_vtbl *vtbl; } Client;
+struct win_class_vtbl { + void (*init)(Client*); +}; + static inline Client* impl_from_Client(IAccessible *iface) { return CONTAINING_RECORD(iface, Client, IAccessible_iface); @@ -221,7 +229,7 @@ static HRESULT WINAPI Client_get_accRole(IAccessible *iface, VARIANT varID, VARI }
V_VT(pvarRole) = VT_I4; - V_I4(pvarRole) = ROLE_SYSTEM_CLIENT; + V_I4(pvarRole) = This->role; return S_OK; }
@@ -651,12 +659,21 @@ static const IEnumVARIANTVtbl ClientEnumVARIANTVtbl = { Client_EnumVARIANT_Clone };
+static void edit_init(Client *client) +{ + client->role = ROLE_SYSTEM_TEXT; +} + +static const win_class_vtbl edit_vtbl = { + edit_init, +}; + static const struct win_class_data classes[] = { {WC_LISTBOXW, 0x10000, TRUE}, {L"#32768", 0x10001, TRUE}, /* menu */ {WC_BUTTONW, 0x10002, TRUE}, {WC_STATICW, 0x10003, TRUE}, - {WC_EDITW, 0x10004, TRUE}, + {WC_EDITW, 0x10004, FALSE, &edit_vtbl}, {WC_COMBOBOXW, 0x10005, TRUE}, {L"#32770", 0x10006, TRUE}, /* dialog */ {L"#32771", 0x10007, TRUE}, /* winswitcher */ @@ -686,8 +703,9 @@ static const struct win_class_data classes[] = {
HRESULT create_client_object(HWND hwnd, const IID *iid, void **obj) { + const struct win_class_data *data; Client *client; - HRESULT hres; + HRESULT hres = S_OK;
if(!IsWindow(hwnd)) return E_FAIL; @@ -696,7 +714,7 @@ HRESULT create_client_object(HWND hwnd, const IID *iid, void **obj) if(!client) return E_OUTOFMEMORY;
- find_class_data(hwnd, classes); + data = find_class_data(hwnd, classes);
client->IAccessible_iface.lpVtbl = &ClientVtbl; client->IOleWindow_iface.lpVtbl = &ClientOleWindowVtbl; @@ -704,6 +722,12 @@ HRESULT create_client_object(HWND hwnd, const IID *iid, void **obj) client->ref = 1; client->hwnd = hwnd; client->enum_pos = 0; + client->role = ROLE_SYSTEM_CLIENT; + + if(data) + client->vtbl = data->vtbl; + if(client->vtbl && client->vtbl->init) + client->vtbl->init(client);
hres = IAccessible_QueryInterface(&client->IAccessible_iface, iid, obj); IAccessible_Release(&client->IAccessible_iface); diff --git a/dlls/oleacc/oleacc_private.h b/dlls/oleacc/oleacc_private.h index 64926b6abb7..a01fc3615fe 100644 --- a/dlls/oleacc/oleacc_private.h +++ b/dlls/oleacc/oleacc_private.h @@ -22,6 +22,7 @@ struct win_class_data { const WCHAR *name; DWORD idx; BOOL stub; + const void *vtbl; }; const struct win_class_data* find_class_data(HWND, const struct win_class_data*) DECLSPEC_HIDDEN;
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/client.c | 60 +++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 15 deletions(-)
diff --git a/dlls/oleacc/client.c b/dlls/oleacc/client.c index 1f24daf1a47..2a8c58d79a4 100644 --- a/dlls/oleacc/client.c +++ b/dlls/oleacc/client.c @@ -18,6 +18,7 @@
#define COBJMACROS
+#include <assert.h> #include "oleacc_private.h" #include "commctrl.h"
@@ -43,6 +44,7 @@ typedef struct {
struct win_class_vtbl { void (*init)(Client*); + HRESULT (*get_state)(Client*, VARIANT, VARIANT*); };
static inline Client* impl_from_Client(IAccessible *iface) @@ -233,36 +235,44 @@ static HRESULT WINAPI Client_get_accRole(IAccessible *iface, VARIANT varID, VARI return S_OK; }
-static HRESULT WINAPI Client_get_accState(IAccessible *iface, VARIANT varID, VARIANT *pvarState) +static HRESULT client_get_state(Client *client, VARIANT id, VARIANT *state) { - Client *This = impl_from_Client(iface); GUITHREADINFO info; LONG style;
- TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pvarState); - - if(convert_child_id(&varID) != CHILDID_SELF) { - V_VT(pvarState) = VT_EMPTY; + if(convert_child_id(&id) != CHILDID_SELF) { + V_VT(state) = VT_EMPTY; return E_INVALIDARG; }
- V_VT(pvarState) = VT_I4; - V_I4(pvarState) = 0; + V_VT(state) = VT_I4; + V_I4(state) = 0;
- style = GetWindowLongW(This->hwnd, GWL_STYLE); + style = GetWindowLongW(client->hwnd, GWL_STYLE); if(style & WS_DISABLED) - V_I4(pvarState) |= STATE_SYSTEM_UNAVAILABLE; - else if(IsWindow(This->hwnd)) - V_I4(pvarState) |= STATE_SYSTEM_FOCUSABLE; + V_I4(state) |= STATE_SYSTEM_UNAVAILABLE; + else if(IsWindow(client->hwnd)) + V_I4(state) |= STATE_SYSTEM_FOCUSABLE;
info.cbSize = sizeof(info); - if(GetGUIThreadInfo(0, &info) && info.hwndFocus == This->hwnd) - V_I4(pvarState) |= STATE_SYSTEM_FOCUSED; + if(GetGUIThreadInfo(0, &info) && info.hwndFocus == client->hwnd) + V_I4(state) |= STATE_SYSTEM_FOCUSED; if(!(style & WS_VISIBLE)) - V_I4(pvarState) |= STATE_SYSTEM_INVISIBLE; + V_I4(state) |= STATE_SYSTEM_INVISIBLE; return S_OK; }
+static HRESULT WINAPI Client_get_accState(IAccessible *iface, VARIANT id, VARIANT *state) +{ + Client *This = impl_from_Client(iface); + + TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&id), state); + + if(This->vtbl && This->vtbl->get_state) + return This->vtbl->get_state(This, id, state); + return client_get_state(This, id, state); +} + static HRESULT WINAPI Client_get_accHelp(IAccessible *iface, VARIANT varID, BSTR *pszHelp) { Client *This = impl_from_Client(iface); @@ -664,8 +674,28 @@ static void edit_init(Client *client) client->role = ROLE_SYSTEM_TEXT; }
+static HRESULT edit_get_state(Client *client, VARIANT id, VARIANT *state) +{ + HRESULT hres; + LONG style; + + hres = client_get_state(client, id, state); + if(FAILED(hres)) + return hres; + + assert(V_VT(state) == VT_I4); + + style = GetWindowLongW(client->hwnd, GWL_STYLE); + if(style & ES_READONLY) + V_I4(state) |= STATE_SYSTEM_READONLY; + if(style & ES_PASSWORD) + V_I4(state) |= STATE_SYSTEM_PROTECTED; + return S_OK; +} + static const win_class_vtbl edit_vtbl = { edit_init, + edit_get_state, };
static const struct win_class_data classes[] = {
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/client.c | 92 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 74 insertions(+), 18 deletions(-)
diff --git a/dlls/oleacc/client.c b/dlls/oleacc/client.c index 2a8c58d79a4..c01f060f3a5 100644 --- a/dlls/oleacc/client.c +++ b/dlls/oleacc/client.c @@ -45,8 +45,28 @@ typedef struct { struct win_class_vtbl { void (*init)(Client*); HRESULT (*get_state)(Client*, VARIANT, VARIANT*); + HRESULT (*get_name)(Client*, VARIANT, BSTR*); };
+static HRESULT acc_client_get_name_str(WCHAR *name, UINT len, BSTR *name_out) +{ + UINT i; + + if(!len) + return S_FALSE; + + for(i=0; i<len; i++) { + if(name[i] == '&') { + len--; + memmove(name+i, name+i+1, (len-i)*sizeof(WCHAR)); + break; + } + } + + *name_out = SysAllocStringLen(name, len); + return *name_out ? S_OK : E_OUTOFMEMORY; +} + static inline Client* impl_from_Client(IAccessible *iface) { return CONTAINING_RECORD(iface, Client, IAccessible_iface); @@ -166,32 +186,23 @@ static HRESULT WINAPI Client_get_accChild(IAccessible *iface, return E_INVALIDARG; }
-static HRESULT WINAPI Client_get_accName(IAccessible *iface, VARIANT varID, BSTR *pszName) +static HRESULT WINAPI Client_get_accName(IAccessible *iface, VARIANT id, BSTR *name_out) { Client *This = impl_from_Client(iface); WCHAR name[1024]; - UINT i, len; + UINT len;
- TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszName); + TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&id), name_out);
- *pszName = NULL; - if(convert_child_id(&varID) != CHILDID_SELF || !IsWindow(This->hwnd)) + *name_out = NULL; + if (This->vtbl && This->vtbl->get_name) + return This->vtbl->get_name(This, id, name_out); + + if(convert_child_id(&id) != CHILDID_SELF || !IsWindow(This->hwnd)) return E_INVALIDARG;
len = SendMessageW(This->hwnd, WM_GETTEXT, ARRAY_SIZE(name), (LPARAM)name); - if(!len) - return S_FALSE; - - for(i=0; i<len; i++) { - if(name[i] == '&') { - len--; - memmove(name+i, name+i+1, (len-i)*sizeof(WCHAR)); - break; - } - } - - *pszName = SysAllocStringLen(name, len); - return *pszName ? S_OK : E_OUTOFMEMORY; + return acc_client_get_name_str(name, len, name_out); }
static HRESULT WINAPI Client_get_accValue(IAccessible *iface, VARIANT varID, BSTR *pszValue) @@ -693,9 +704,54 @@ static HRESULT edit_get_state(Client *client, VARIANT id, VARIANT *state) return S_OK; }
+/* + * Edit control objects have their name property defined by the first static + * text control preceding them in the order of window creation. If one is not + * found, the edit has no name property. In the case of the keyboard shortcut + * property, the first preceding visible static text control is used. + */ +static HWND acc_edit_find_label(HWND hwnd, BOOL visible) +{ + HWND cur; + + for(cur = hwnd; cur; cur = GetWindow(cur, GW_HWNDPREV)) { + WCHAR class_name[64]; + + if(!RealGetWindowClassW(cur, class_name, ARRAY_SIZE(class_name))) + continue; + + if(!wcsicmp(class_name, WC_STATICW)) { + if (visible && !(GetWindowLongW(cur, GWL_STYLE) & WS_VISIBLE)) + continue; + else + break; + } + } + + return cur; +} + +static HRESULT edit_get_name(Client *client, VARIANT id, BSTR *name_out) +{ + WCHAR name[1024]; + HWND label; + UINT len; + + if(convert_child_id(&id) != CHILDID_SELF || !IsWindow(client->hwnd)) + return E_INVALIDARG; + + label = acc_edit_find_label(client->hwnd, FALSE); + if(!label) + return S_FALSE; + + len = SendMessageW(label, WM_GETTEXT, ARRAY_SIZE(name), (LPARAM)name); + return acc_client_get_name_str(name, len, name_out); +} + static const win_class_vtbl edit_vtbl = { edit_init, edit_get_state, + edit_get_name, };
static const struct win_class_data classes[] = {
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/client.c | 66 ++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 18 deletions(-)
diff --git a/dlls/oleacc/client.c b/dlls/oleacc/client.c index c01f060f3a5..ed7dd86b13b 100644 --- a/dlls/oleacc/client.c +++ b/dlls/oleacc/client.c @@ -46,6 +46,7 @@ struct win_class_vtbl { void (*init)(Client*); HRESULT (*get_state)(Client*, VARIANT, VARIANT*); HRESULT (*get_name)(Client*, VARIANT, BSTR*); + HRESULT (*get_kbd_shortcut)(Client*, VARIANT, BSTR*); };
static HRESULT acc_client_get_name_str(WCHAR *name, UINT len, BSTR *name_out) @@ -67,6 +68,26 @@ static HRESULT acc_client_get_name_str(WCHAR *name, UINT len, BSTR *name_out) return *name_out ? S_OK : E_OUTOFMEMORY; }
+static HRESULT acc_client_get_kbd_shortcut_str(WCHAR *name, UINT len, + BSTR *kbd_shortcut_out) +{ + UINT i; + + for(i=0; i<len; i++) { + if(name[i] == '&') + break; + } + if(i+1 >= len) + return S_FALSE; + + *kbd_shortcut_out = SysAllocString(L"Alt+!"); + if(!*kbd_shortcut_out) + return E_OUTOFMEMORY; + + (*kbd_shortcut_out)[4] = name[i+1]; + return S_OK; +} + static inline Client* impl_from_Client(IAccessible *iface) { return CONTAINING_RECORD(iface, Client, IAccessible_iface); @@ -305,32 +326,23 @@ static HRESULT WINAPI Client_get_accHelpTopic(IAccessible *iface, }
static HRESULT WINAPI Client_get_accKeyboardShortcut(IAccessible *iface, - VARIANT varID, BSTR *pszKeyboardShortcut) + VARIANT id, BSTR *kbd_shortcut_out) { Client *This = impl_from_Client(iface); WCHAR name[1024]; - UINT i, len; + UINT len;
- TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszKeyboardShortcut); + TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&id), kbd_shortcut_out);
- *pszKeyboardShortcut = NULL; - if(convert_child_id(&varID) != CHILDID_SELF) + *kbd_shortcut_out = NULL; + if (This->vtbl && This->vtbl->get_kbd_shortcut) + return This->vtbl->get_kbd_shortcut(This, id, kbd_shortcut_out); + + if(convert_child_id(&id) != CHILDID_SELF) return E_INVALIDARG;
len = SendMessageW(This->hwnd, WM_GETTEXT, ARRAY_SIZE(name), (LPARAM)name); - for(i=0; i<len; i++) { - if(name[i] == '&') - break; - } - if(i+1 >= len) - return S_FALSE; - - *pszKeyboardShortcut = SysAllocString(L"Alt+!"); - if(!*pszKeyboardShortcut) - return E_OUTOFMEMORY; - - (*pszKeyboardShortcut)[4] = name[i+1]; - return S_OK; + return acc_client_get_kbd_shortcut_str(name, len, kbd_shortcut_out); }
static HRESULT WINAPI Client_get_accFocus(IAccessible *iface, VARIANT *focus) @@ -748,10 +760,28 @@ static HRESULT edit_get_name(Client *client, VARIANT id, BSTR *name_out) return acc_client_get_name_str(name, len, name_out); }
+static HRESULT edit_get_kbd_shortcut(Client *client, VARIANT id, BSTR *kbd_shortcut_out) +{ + WCHAR name[1024]; + HWND label; + UINT len; + + if(convert_child_id(&id) != CHILDID_SELF) + return E_INVALIDARG; + + label = acc_edit_find_label(client->hwnd, TRUE); + if(!label) + return S_FALSE; + + len = SendMessageW(label, WM_GETTEXT, ARRAY_SIZE(name), (LPARAM)name); + return acc_client_get_kbd_shortcut_str(name, len, kbd_shortcut_out); +} + static const win_class_vtbl edit_vtbl = { edit_init, edit_get_state, edit_get_name, + edit_get_kbd_shortcut, };
static const struct win_class_data classes[] = {
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/client.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/dlls/oleacc/client.c b/dlls/oleacc/client.c index ed7dd86b13b..636e7a1cfea 100644 --- a/dlls/oleacc/client.c +++ b/dlls/oleacc/client.c @@ -47,6 +47,7 @@ struct win_class_vtbl { HRESULT (*get_state)(Client*, VARIANT, VARIANT*); HRESULT (*get_name)(Client*, VARIANT, BSTR*); HRESULT (*get_kbd_shortcut)(Client*, VARIANT, BSTR*); + HRESULT (*get_value)(Client*, VARIANT, BSTR*); };
static HRESULT acc_client_get_name_str(WCHAR *name, UINT len, BSTR *name_out) @@ -226,14 +227,17 @@ static HRESULT WINAPI Client_get_accName(IAccessible *iface, VARIANT id, BSTR *n return acc_client_get_name_str(name, len, name_out); }
-static HRESULT WINAPI Client_get_accValue(IAccessible *iface, VARIANT varID, BSTR *pszValue) +static HRESULT WINAPI Client_get_accValue(IAccessible *iface, VARIANT id, BSTR *value_out) { Client *This = impl_from_Client(iface);
- TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&varID), pszValue); + TRACE("(%p)->(%s %p)\n", This, debugstr_variant(&id), value_out);
- *pszValue = NULL; - if(convert_child_id(&varID) != CHILDID_SELF) + *value_out = NULL; + if (This->vtbl && This->vtbl->get_value) + return This->vtbl->get_value(This, id, value_out); + + if(convert_child_id(&id) != CHILDID_SELF) return E_INVALIDARG; return S_FALSE; } @@ -777,11 +781,33 @@ static HRESULT edit_get_kbd_shortcut(Client *client, VARIANT id, BSTR *kbd_short return acc_client_get_kbd_shortcut_str(name, len, kbd_shortcut_out); }
+static HRESULT edit_get_value(Client *client, VARIANT id, BSTR *value_out) +{ + WCHAR *buf; + UINT len; + + if (convert_child_id(&id) != CHILDID_SELF) return E_INVALIDARG; + + if (GetWindowLongW(client->hwnd, GWL_STYLE) & ES_PASSWORD) + return E_ACCESSDENIED; + + len = SendMessageW(client->hwnd, WM_GETTEXTLENGTH, 0, 0); + buf = heap_alloc_zero((len + 1) * sizeof(*buf)); + if (!buf) return E_OUTOFMEMORY; + + SendMessageW(client->hwnd, WM_GETTEXT, len + 1, (LPARAM)buf); + *value_out = SysAllocString(buf); + heap_free(buf); + + return S_OK; +} + static const win_class_vtbl edit_vtbl = { edit_init, edit_get_state, edit_get_name, edit_get_kbd_shortcut, + edit_get_value, };
static const struct win_class_data classes[] = {
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/client.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/dlls/oleacc/client.c b/dlls/oleacc/client.c index 636e7a1cfea..7b9d6786bb6 100644 --- a/dlls/oleacc/client.c +++ b/dlls/oleacc/client.c @@ -48,6 +48,7 @@ struct win_class_vtbl { HRESULT (*get_name)(Client*, VARIANT, BSTR*); HRESULT (*get_kbd_shortcut)(Client*, VARIANT, BSTR*); HRESULT (*get_value)(Client*, VARIANT, BSTR*); + HRESULT (*put_value)(Client*, VARIANT, BSTR); };
static HRESULT acc_client_get_name_str(WCHAR *name, UINT len, BSTR *name_out) @@ -488,10 +489,15 @@ static HRESULT WINAPI Client_put_accName(IAccessible *iface, VARIANT varID, BSTR return E_NOTIMPL; }
-static HRESULT WINAPI Client_put_accValue(IAccessible *iface, VARIANT varID, BSTR pszValue) +static HRESULT WINAPI Client_put_accValue(IAccessible *iface, VARIANT id, BSTR value) { Client *This = impl_from_Client(iface); - FIXME("(%p)->(%s %s)\n", This, debugstr_variant(&varID), debugstr_w(pszValue)); + + if (This->vtbl && This->vtbl->put_value) + return This->vtbl->put_value(This, id, value); + + FIXME("(%p)->(%s %s)\n", This, debugstr_variant(&id), debugstr_w(value)); + return E_NOTIMPL; }
@@ -802,12 +808,25 @@ static HRESULT edit_get_value(Client *client, VARIANT id, BSTR *value_out) return S_OK; }
+static HRESULT edit_put_value(Client *client, VARIANT id, BSTR value) +{ + TRACE("(%p, %s, %s)\n", client, debugstr_variant(&id), debugstr_w(value)); + + if(convert_child_id(&id) != CHILDID_SELF || !IsWindow(client->hwnd)) + return E_INVALIDARG; + + SendMessageW(client->hwnd, WM_SETTEXT, 0, (LPARAM)value); + + return S_OK; +} + static const win_class_vtbl edit_vtbl = { edit_init, edit_get_state, edit_get_name, edit_get_kbd_shortcut, edit_get_value, + edit_put_value, };
static const struct win_class_data classes[] = {
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/oleacc/tests/main.c | 436 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 436 insertions(+)
diff --git a/dlls/oleacc/tests/main.c b/dlls/oleacc/tests/main.c index 98da7eb3ddc..629813587b5 100644 --- a/dlls/oleacc/tests/main.c +++ b/dlls/oleacc/tests/main.c @@ -1313,6 +1313,441 @@ static void test_CAccPropServices(void) IAccPropServices_Release(acc_prop_services); }
+typedef struct +{ + INT child_id; + + const WCHAR *expected_name; + HRESULT expected_name_hr; + + const WCHAR *expected_value; + HRESULT expected_value_hr; + + const WCHAR *expected_description; + HRESULT expected_description_hr; + + const WCHAR *expected_help; + HRESULT expected_help_hr; + + const WCHAR *expected_kbd_shortcut; + HRESULT expected_kbd_shortcut_hr; + + const WCHAR *expected_default_action; + HRESULT expected_default_action_hr; + + INT expected_role; + HRESULT expected_role_hr; + + INT expected_state; + HRESULT expected_state_hr; + + LONG left_offset, top_offset, width_offset, height_offset; + HRESULT expected_location_hr; + + LONG expected_child_count; + HRESULT expected_child_count_hr; + + BOOL expected_valid_child; + HRESULT expected_child_hr; + + BOOL expected_valid_parent; + HRESULT expected_parent_hr; + + INT expected_focus_vt; + INT expected_focus_cid; + HRESULT expected_focus_hr; +} acc_expected_vals; + +#define check_acc_vals( acc, vals) \ + check_acc_vals_( (acc), (vals), __LINE__) +static void check_acc_vals_(IAccessible *acc, const acc_expected_vals *vals, + int line) +{ + LONG left, top, width, height; + LONG child_count; + VARIANT vid, var; + IDispatch *disp; + HRESULT hr; + RECT rect; + HWND hwnd; + POINT pt; + BSTR str; + + V_VT(&vid) = VT_I4; + V_I4(&vid) = vals->child_id; + hr = IAccessible_get_accName(acc, vid, &str); + ok_(__FILE__, line) (hr == vals->expected_name_hr, "get_accName returned %#x, expected %#x\n", + hr, vals->expected_name_hr); + ok_(__FILE__, line) (!lstrcmpW(str, vals->expected_name), "get_accName returned %s, expected %s\n", + wine_dbgstr_w(str), wine_dbgstr_w(vals->expected_name)); + SysFreeString(str); + + hr = IAccessible_get_accValue(acc, vid, &str); + ok_(__FILE__, line) (hr == vals->expected_value_hr, "get_accValue returned %#x, expected %#x\n", + hr, vals->expected_value_hr); + ok_(__FILE__, line) (!lstrcmpW(str, vals->expected_value), "get_accValue returned %s, expected %s\n", + wine_dbgstr_w(str), wine_dbgstr_w(vals->expected_value)); + SysFreeString(str); + + hr = IAccessible_get_accDescription(acc, vid, &str); + ok_(__FILE__, line) (hr == vals->expected_description_hr, "get_accDescription returned %#x, expected %#x\n", + hr, vals->expected_description_hr); + ok_(__FILE__, line) (!lstrcmpW(str, vals->expected_description), "get_accDescription returned %s, expected %s\n", + wine_dbgstr_w(str), wine_dbgstr_w(vals->expected_description)); + SysFreeString(str); + + hr = IAccessible_get_accHelp(acc, vid, &str); + ok_(__FILE__, line) (hr == vals->expected_help_hr, "get_accHelp returned %#x, expected %#x\n", + hr, vals->expected_help_hr); + ok_(__FILE__, line) (!lstrcmpW(str, vals->expected_help), "get_accHelp returned %s, expected %s\n", + wine_dbgstr_w(str), wine_dbgstr_w(vals->expected_help)); + SysFreeString(str); + + hr = IAccessible_get_accKeyboardShortcut(acc, vid, &str); + ok_(__FILE__, line) (hr == vals->expected_kbd_shortcut_hr, "get_accKeyboardShortcut returned %#x, expected %#x\n", + hr, vals->expected_kbd_shortcut_hr); + ok_(__FILE__, line) (!lstrcmpW(str, vals->expected_kbd_shortcut), "get_accKeyboardShortcut returned %s, expected %s\n", + wine_dbgstr_w(str), wine_dbgstr_w(vals->expected_kbd_shortcut)); + SysFreeString(str); + + hr = IAccessible_get_accDefaultAction(acc, vid, &str); + ok_(__FILE__, line) (hr == vals->expected_default_action_hr, "get_accDefaultAction returned %#x, expected %#x\n", + hr, vals->expected_default_action_hr); + ok_(__FILE__, line) (!lstrcmpW(str, vals->expected_default_action), "get_accDefaultAction returned %s, expected %s\n", + wine_dbgstr_w(str), wine_dbgstr_w(vals->expected_default_action)); + SysFreeString(str); + + V_VT(&var) = VT_DISPATCH; + V_DISPATCH(&var) = (void*)0xdeadbeef; + hr = IAccessible_get_accRole(acc, vid, &var); + ok_(__FILE__, line) (hr == vals->expected_role_hr, "get_accRole returned %#x, expected %#x\n", + hr, vals->expected_role_hr); + ok_(__FILE__, line) (V_VT(&var) == VT_I4, "V_VT(&var) returned %d, expected %d\n", V_VT(&var), VT_I4); + ok_(__FILE__, line) (V_I4(&var) == vals->expected_role, "get_accRole returned %d, expected %d\n", + V_I4(&var), vals->expected_role); + + V_VT(&var) = VT_DISPATCH; + V_DISPATCH(&var) = (void*)0xdeadbeef; + hr = IAccessible_get_accState(acc, vid, &var); + ok_(__FILE__, line) (hr == vals->expected_state_hr, "get_accState returned %#x, expected %#x\n", + hr, vals->expected_state_hr); + ok_(__FILE__, line) (V_VT(&var) == VT_I4, "V_VT(&var) returned %d, expected %d\n", V_VT(&var), VT_I4); + ok_(__FILE__, line) (V_I4(&var) == vals->expected_state, "get_accState returned %#x, expected %#x\n", + V_I4(&var), vals->expected_state); + + hr = WindowFromAccessibleObject(acc, &hwnd); + ok_(__FILE__, line) (hr == S_OK, "got %x\n", hr); + ok_(__FILE__, line) (GetClientRect(hwnd, &rect), "GetClientRect failed\n"); + pt.x = rect.left + vals->left_offset; + pt.y = rect.top + vals->top_offset; + MapWindowPoints(hwnd, NULL, &pt, 1); + rect.left = pt.x; + rect.top = pt.y; + pt.x = rect.right + vals->width_offset; + pt.y = rect.bottom + vals->height_offset; + MapWindowPoints(hwnd, NULL, &pt, 1); + hr = IAccessible_accLocation(acc, &left, &top, &width, &height, vid); + ok_(__FILE__, line) (hr == vals->expected_location_hr, "got %x\n", hr); + ok_(__FILE__, line) (left == rect.left, "left = %d, expected %d\n", left, rect.left); + ok_(__FILE__, line) (top == rect.top, "top = %d, expected %d\n", top, rect.top); + ok_(__FILE__, line) (width == pt.x-rect.left, "width = %d, expected %d\n", width, pt.x-rect.left); + ok_(__FILE__, line) (height == pt.y-rect.top, "height = %d, expected %d\n", height, pt.y-rect.top); + + /* + * Tests beyond this point are only applicable to full accessible objects + * and not simple elements. + */ + if (vals->child_id != CHILDID_SELF) + return; + + child_count = -1; + hr = IAccessible_get_accChildCount(acc, &child_count); + ok_(__FILE__, line) (hr == vals->expected_child_count_hr, "get_accChildCount returned %#x, expected %#x\n", + hr, vals->expected_child_count_hr); + ok_(__FILE__, line) (child_count == vals->expected_child_count, "get_accChildCount returned %d, expected %#x\n", + child_count, vals->expected_child_count); + + disp = NULL; + V_VT(&var) = VT_I4; + V_I4(&var) = 1; + hr = IAccessible_get_accChild(acc, var, &disp); + ok_(__FILE__, line) (hr == vals->expected_child_hr, "get_accChild returned %#x, expected %#x\n", + hr, vals->expected_child_hr); + if (disp) + { + ok_(__FILE__, line) (vals->expected_valid_child, "get_accChild unexpectedly returned a child\n"); + IDispatch_Release(disp); + } + else + ok_(__FILE__, line) (!vals->expected_valid_child, "get_accChild expected a valid child, none was returned\n"); + + disp = NULL; + hr = IAccessible_get_accParent(acc, &disp); + ok_(__FILE__, line) (hr == vals->expected_parent_hr, "get_accParent returned %#x, expected %#x\n", + hr, vals->expected_parent_hr); + if (disp) + { + ok_(__FILE__, line) (vals->expected_valid_parent, "get_accParent unexpectedly returned a parent\n"); + IDispatch_Release(disp); + } + else + ok_(__FILE__, line) (!vals->expected_valid_parent, "get_accParent expected a valid parent, none was returned\n"); + + V_VT(&var) = VT_EMPTY; + hr = IAccessible_get_accFocus(acc, &var); + ok_(__FILE__, line) (hr == vals->expected_focus_hr, "get_accFocus returned %#x, expected %#x\n", + hr, vals->expected_focus_hr); + ok_(__FILE__, line) (V_VT(&var) == vals->expected_focus_vt, "get_accFocus returned V_VT(&var) %d, expected %d\n", + V_VT(&var), vals->expected_focus_vt); + if (V_VT(&var) == VT_I4) + { + ok_(__FILE__, line) (V_I4(&var) == vals->expected_focus_cid, "get_accFocus returned childID %d, expected %d\n", + V_I4(&var), vals->expected_focus_cid); + } +} + +static const acc_expected_vals edit_acc_vals[] = { + /* edit0, regular edit, no label. */ + { .child_id = CHILDID_SELF, + .expected_name = NULL, + .expected_name_hr = S_FALSE, + .expected_value = L"edit0-test", + .expected_value_hr = S_OK, + .expected_description = NULL, + .expected_description_hr = S_FALSE, + .expected_help = NULL, + .expected_help_hr = S_FALSE, + .expected_kbd_shortcut = NULL, + .expected_kbd_shortcut_hr = S_FALSE, + .expected_default_action = NULL, + .expected_default_action_hr = S_FALSE, + .expected_role = ROLE_SYSTEM_TEXT, + .expected_role_hr = S_OK, + .expected_state = STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_READONLY, + .expected_state_hr = S_OK, + .left_offset = 0, + .top_offset = 0, + .width_offset = 0, + .height_offset = 0, + .expected_location_hr = S_OK, + .expected_child_count = 0, + .expected_child_count_hr = S_OK, + .expected_valid_child = FALSE, + .expected_child_hr = E_INVALIDARG, + .expected_valid_parent = TRUE, + .expected_parent_hr = S_OK, + .expected_focus_vt = VT_EMPTY, + .expected_focus_cid = 0, + .expected_focus_hr = S_OK }, + /* edit1, ES_PASSWORD edit style. */ + { .child_id = CHILDID_SELF, + .expected_name = L"label0:", + .expected_name_hr = S_OK, + .expected_value = NULL, + .expected_value_hr = E_ACCESSDENIED, + .expected_description = NULL, + .expected_description_hr = S_FALSE, + .expected_help = NULL, + .expected_help_hr = S_FALSE, + .expected_kbd_shortcut = L"Alt+l", + .expected_kbd_shortcut_hr = S_OK, + .expected_default_action = NULL, + .expected_default_action_hr = S_FALSE, + .expected_role = ROLE_SYSTEM_TEXT, + .expected_role_hr = S_OK, + .expected_state = STATE_SYSTEM_PROTECTED | STATE_SYSTEM_FOCUSABLE, + .expected_state_hr = S_OK, + .left_offset = 0, + .top_offset = 0, + .width_offset = 0, + .height_offset = 0, + .expected_location_hr = S_OK, + .expected_child_count = 0, + .expected_child_count_hr = S_OK, + .expected_valid_child = FALSE, + .expected_child_hr = E_INVALIDARG, + .expected_valid_parent = TRUE, + .expected_parent_hr = S_OK, + .expected_focus_vt = VT_EMPTY, + .expected_focus_cid = 0, + .expected_focus_hr = S_OK }, + /* edit2 */ + { .child_id = CHILDID_SELF, + .expected_name = L"label1:", + .expected_name_hr = S_OK, + .expected_value = L"edit2-test\r\ntest-edit2\n", + .expected_value_hr = S_OK, + .expected_description = NULL, + .expected_description_hr = S_FALSE, + .expected_help = NULL, + .expected_help_hr = S_FALSE, + .expected_kbd_shortcut = L"Alt+e", + .expected_kbd_shortcut_hr = S_OK, + .expected_default_action = NULL, + .expected_default_action_hr = S_FALSE, + .expected_role = ROLE_SYSTEM_TEXT, + .expected_role_hr = S_OK, + .expected_state = STATE_SYSTEM_FOCUSABLE | STATE_SYSTEM_FOCUSED, + .expected_state_hr = S_OK, + .left_offset = 0, + .top_offset = 0, + .width_offset = 0, + .height_offset = 0, + .expected_location_hr = S_OK, + .expected_child_count = 0, + .expected_child_count_hr = S_OK, + .expected_valid_child = FALSE, + .expected_child_hr = E_INVALIDARG, + .expected_valid_parent = TRUE, + .expected_parent_hr = S_OK, + .expected_focus_vt = VT_I4, + .expected_focus_cid = CHILDID_SELF, + .expected_focus_hr = S_OK }, + /* edit3 */ + { .child_id = CHILDID_SELF, + .expected_name = L"label1:", + .expected_name_hr = S_OK, + .expected_value = L"", + .expected_value_hr = S_OK, + .expected_description = NULL, + .expected_description_hr = S_FALSE, + .expected_help = NULL, + .expected_help_hr = S_FALSE, + .expected_kbd_shortcut = L"Alt+l", + .expected_kbd_shortcut_hr = S_OK, + .expected_default_action = NULL, + .expected_default_action_hr = S_FALSE, + .expected_role = ROLE_SYSTEM_TEXT, + .expected_role_hr = S_OK, + .expected_state = STATE_SYSTEM_FOCUSABLE, + .expected_state_hr = S_OK, + .left_offset = 0, + .top_offset = 0, + .width_offset = 0, + .height_offset = 0, + .expected_location_hr = S_OK, + /* Embedded button control HWND. */ + .expected_child_count = 1, + .expected_child_count_hr = S_OK, + .expected_valid_child = FALSE, + .expected_child_hr = E_INVALIDARG, + .expected_valid_parent = TRUE, + .expected_parent_hr = S_OK, + .expected_focus_vt = VT_DISPATCH, + .expected_focus_cid = 0, + .expected_focus_hr = S_OK }, +}; + +static void test_default_edit_accessible_object(void) +{ + HWND hwnd, label0, label1, btn0, btn1; + IAccessible *acc; + HWND edit[4]; + HRESULT hr; + VARIANT v; + BSTR str; + + /* Create a window that looks like this: + * +----------------------------------------+ + * | ___________________________________ | + * | |___________________________________| | + * | (edit[0]) | + * | ____________________________ | + * | Label0: |____________________________| | + * |(label0) (edit[1]) (password) | + * | ______ _________________ | + * | Label1: |button| |multi-line edit | | + * |(label1) (btn0) |_________________| | + * | (edit[2]) | + * | __________________________________ | + * | | | | + * | | edit with embedded button | | + * | |__________________________________| | + * | (edit[3]) (btn1) | + * +----------------------------------------+ + */ + + hwnd = CreateWindowW(L"oleacc_test", L"edit_acc_test_win", WS_OVERLAPPEDWINDOW, + 0, 0, 220, 160, NULL, NULL, NULL, NULL); + ok(!!hwnd, "CreateWindow failed\n"); + + edit[0] = CreateWindowW(L"EDIT", L"", WS_VISIBLE | WS_CHILD | ES_READONLY, 5, 5, 190, 20, + hwnd, NULL, NULL, NULL); + ok(!!edit[0], "Failed to create edit[0] hwnd\n"); + + label0 = CreateWindowW(L"STATIC", L"&label0:", WS_VISIBLE | WS_CHILD, 5, 30, 55, 20, + hwnd, NULL, NULL, NULL); + ok(!!label0, "Failed to create label0 hwnd\n"); + + edit[1] = CreateWindowW(L"EDIT", L"", WS_VISIBLE | WS_CHILD | ES_PASSWORD, + 65, 30, 130, 20, hwnd, NULL, NULL, NULL); + ok(!!edit[1], "Failed to create edit[1] hwnd\n"); + + label1 = CreateWindowW(L"STATIC", L"lab&el1:", WS_VISIBLE | WS_CHILD, 5, 55, 45, 20, + hwnd, NULL, NULL, NULL); + ok(!!label1, "Failed to create label1 hwnd\n"); + + btn0 = CreateWindowW(L"BUTTON", L"but&ton0", WS_VISIBLE | WS_CHILD, 55, 55, 45, 20, + hwnd, NULL, NULL, NULL); + ok(!!btn0, "Failed to create btn0 hwnd\n"); + + edit[2] = CreateWindowW(L"EDIT", L"", WS_VISIBLE | WS_CHILD | ES_MULTILINE, + 105, 55, 90, 40, hwnd, NULL, NULL, NULL); + ok(!!edit[2], "Failed to create edit[2] hwnd\n"); + + edit[3] = CreateWindowW(L"EDIT", L"", WS_VISIBLE | WS_CHILD, 5, 100, 190, 20, + hwnd, NULL, NULL, NULL); + ok(!!edit[3], "Failed to create edit[3] hwnd\n"); + + /* Button embedded within an edit control window. */ + btn1 = CreateWindowW(L"BUTTON", L"button1", WS_VISIBLE | WS_CHILD, 100, 5, 85, 10, + edit[3], NULL, NULL, NULL); + ok(!!btn1, "Failed to create btn1 hwnd\n"); + + hr = CreateStdAccessibleObject(edit[0], OBJID_CLIENT, &IID_IAccessible, (void**)&acc); + ok(hr == S_OK, "got %x\n", hr); + V_VT(&v) = VT_I4; + V_I4(&v) = CHILDID_SELF; + str = SysAllocString(L"edit0-test"); + hr = IAccessible_put_accValue(acc, v, str); + ok(hr == S_OK, "got %x\n", hr); + SysFreeString(str); + check_acc_vals(acc, &edit_acc_vals[0]); + IAccessible_Release(acc); + + hr = CreateStdAccessibleObject(edit[1], OBJID_CLIENT, &IID_IAccessible, (void**)&acc); + ok(hr == S_OK, "got %x\n", hr); + str = SysAllocString(L"password"); + hr = IAccessible_put_accValue(acc, v, str); + ok(hr == S_OK, "got %x\n", hr); + SysFreeString(str); + check_acc_vals(acc, &edit_acc_vals[1]); + IAccessible_Release(acc); + + SetFocus(edit[2]); + hr = CreateStdAccessibleObject(edit[2], OBJID_CLIENT, &IID_IAccessible, (void**)&acc); + str = SysAllocString(L"edit2-test\r\ntest-edit2\n"); + hr = IAccessible_put_accValue(acc, v, str); + ok(hr == S_OK, "got %x\n", hr); + SysFreeString(str); + check_acc_vals(acc, &edit_acc_vals[2]); + IAccessible_Release(acc); + + /* + * Hiding a label with a keyboard shortcut makes get_accKeyboardShortcut + * on the edit no longer return the labels shortcut, however get_accName + * still returns the labels string. + */ + ShowWindow(label1, SW_HIDE); + SetFocus(btn1); + hr = CreateStdAccessibleObject(edit[3], OBJID_CLIENT, &IID_IAccessible, (void**)&acc); + ok(hr == S_OK, "got %x\n", hr); + check_acc_vals(acc, &edit_acc_vals[3]); + IAccessible_Release(acc); + + DestroyWindow(hwnd); +} + START_TEST(main) { int argc; @@ -1351,6 +1786,7 @@ START_TEST(main) test_default_client_accessible_object(); test_AccessibleChildren(&Accessible); test_AccessibleObjectFromEvent(); + test_default_edit_accessible_object();
unregister_window_class(); CoUninitialize();
Hi Connor,
The window class needs special handling for some windows classes as well. An example of that is a ListBox that is created by ComboBox. The ListBox HWND parent is desktop but get_accParent should return ComboBox accessibility object.
I'm expecting the same to apply for context menus but I was unable to confirm that with quick testing.
Thanks, Piotr
On Fri, Sep 24, 2021 at 08:05:10PM +0200, Piotr Caban wrote:
Hi Connor,
The window class needs special handling for some windows classes as well. An example of that is a ListBox that is created by ComboBox. The ListBox HWND parent is desktop but get_accParent should return ComboBox accessibility object.
I'm expecting the same to apply for context menus but I was unable to confirm that with quick testing.
Thanks, Piotr
Ah, okay, my bad. I guess I should've taken a deeper look then. :) It does seem like the window object has less differences between window classes than the client object, but it sounds like there are some minor ones that need to be addressed.
I'll try and actually do a deeper test and see what I find, then restore that part in a new series. Sorry about that.
Thanks, Connor.