diff options
Diffstat (limited to 'winaccessibility/source')
64 files changed, 15792 insertions, 0 deletions
diff --git a/winaccessibility/source/UAccCOM/AccAction.cxx b/winaccessibility/source/UAccCOM/AccAction.cxx new file mode 100644 index 0000000000..094e102519 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccAction.cxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/** + * AccAction.cpp : Implementation of CAccAction + */ +#include "stdafx.h" +#include <UAccCOM.h> +#include "AccAction.h" + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; + +/** + * Returns the number of action. + * + * @param nActions the number of action. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccAction::nActions(/*[out,retval]*/long* nActions) +{ + + return CAccActionBase::nActions(nActions); +} + +/** + * Performs specified action on the object. + * + * @param actionIndex the index of action. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccAction::doAction(/* [in] */ long actionIndex) +{ + + return CAccActionBase::doAction(actionIndex); +} + +/** + * Gets description of specified action. + * + * @param actionIndex the index of action. + * @param description the description string of the specified action. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccAction::get_description(long actionIndex,BSTR __RPC_FAR *description) +{ + + return CAccActionBase::get_description(actionIndex, description); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccAction::get_name( long actionIndex, BSTR __RPC_FAR *name) +{ + + return CAccActionBase::get_name(actionIndex, name); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccAction::get_localizedName( long actionIndex, BSTR __RPC_FAR *localizedName) +{ + + return CAccActionBase::get_localizedName(actionIndex, localizedName); +} + +/** + * Returns key binding object (if any) associated with specified action + * key binding is string. + * e.g. "alt+d" (like IAccessible::get_accKeyboardShortcut). + * + * @param actionIndex the index of action. + * @param nMaxBinding the max number of key binding. + * @param keyBinding the key binding array. + * @param nBinding the actual number of key binding returned. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccAction::get_keyBinding( + /* [in] */ long actionIndex, + /* [in] */ long nMaxBinding, + /* [length_is][length_is][size_is][size_is][out] */ BSTR __RPC_FAR *__RPC_FAR *keyBinding, + /* [retval][out] */ long __RPC_FAR *nBinding) +{ + + return CAccActionBase::get_keyBinding(actionIndex, nMaxBinding, keyBinding, nBinding); +} + +/** + * Put UNO interface. + * @param pXSubInterface XAccessibleHyperlink interface. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccAction::put_XSubInterface(hyper pXSubInterface) +{ + + + pRXAct = reinterpret_cast<XAccessibleAction*>(pXSubInterface); + + return S_OK; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccAction.h b/winaccessibility/source/UAccCOM/AccAction.h new file mode 100644 index 0000000000..7fcff08105 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccAction.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "Resource.h" // main symbols +#include "AccActionBase.h" + +/** + * CAccAction implements IAccessibleAction interface. + */ +class ATL_NO_VTABLE CAccAction : + public CComObjectRoot, + public CComCoClass<CAccAction, &CLSID_AccAction>, + public IAccessibleAction, + public CAccActionBase +{ +public: + CAccAction() + { + + } + + DECLARE_NO_REGISTRY() + + BEGIN_COM_MAP(CAccAction) + COM_INTERFACE_ENTRY(IAccessibleAction) + COM_INTERFACE_ENTRY(IUNOXWrapper) + COM_INTERFACE_ENTRY_FUNC_BLIND(0,SmartQI_) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + static HRESULT WINAPI SmartQI_(void* pv, + REFIID iid, void** ppvObject, DWORD_PTR) + { + return static_cast<CAccAction*>(pv)->SmartQI(iid,ppvObject); + } + + HRESULT SmartQI(REFIID iid, void** ppvObject) + { + if( m_pOuterUnknown ) + return OuterQueryInterface(iid,ppvObject); + return E_FAIL; + } + + // IAccessibleAction +public: + // IAccessibleAction + + // Returns the number of action. + STDMETHOD(nActions)(/*[out,retval]*/long* nActions) override; + + // Performs specified action on the object. + STDMETHOD(doAction)(/* [in] */ long actionIndex) override; + + // Gets description of specified action. + STDMETHOD(get_description)(long actionIndex,BSTR __RPC_FAR *description) override; + + // added , 2006/06/28, for driver 07/11 + // get the action name + STDMETHOD(get_name)( long actionIndex, BSTR __RPC_FAR *name) override; + + // get the localized action name + STDMETHOD(get_localizedName)( long actionIndex, BSTR __RPC_FAR *localizedName) override; + + // Returns key binding object (if any) associated with specified action + // key binding is string. + // e.g. "alt+d" (like IAccessible::get_accKeyboardShortcut). + STDMETHOD(get_keyBinding)( + /* [in] */ long actionIndex, + /* [in] */ long nMaxBinding, + /* [length_is][length_is][size_is][size_is][out] */ BSTR __RPC_FAR *__RPC_FAR *keyBinding, + /* [retval][out] */ long __RPC_FAR *nBinding) override; + + // Override of IUNOXWrapper. + STDMETHOD(put_XSubInterface)(hyper pXSubInterface) override; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccActionBase.cxx b/winaccessibility/source/UAccCOM/AccActionBase.cxx new file mode 100644 index 0000000000..0fb2d7bbce --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccActionBase.cxx @@ -0,0 +1,215 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +// AccActionBase.cpp: implementation of the CAccActionBase class. + +#include "stdafx.h" + +#include "AccActionBase.h" +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> + +#include <vcl/svapp.hxx> +#include <o3tl/char16_t2wchar_t.hxx> +#include <comphelper/AccessibleImplementationHelper.hxx> + +#include "acccommon.h" + +using namespace com::sun::star::accessibility::AccessibleRole; +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; +using namespace com::sun::star::awt; + + +// Construction/Destruction + + +CAccActionBase::CAccActionBase() +{} + +CAccActionBase::~CAccActionBase() +{} + +/** + * Returns the number of action. + * + * @param nActions the number of action. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccActionBase::nActions(/*[out,retval]*/long* nActions) +{ + SolarMutexGuard g; + + try { + + if( pRXAct.is() && nActions != nullptr ) + { + *nActions = pRXAct->getAccessibleActionCount(); + return S_OK; + } + *nActions = 0; + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Performs specified action on the object. + * + * @param actionIndex the index of action. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccActionBase::doAction(/* [in] */ long actionIndex) +{ + SolarMutexGuard g; + + try { + + if( pRXAct.is() ) + { + return pRXAct->doAccessibleAction(actionIndex) ? S_OK : E_FAIL; + } + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets description of specified action. + * + * @param actionIndex the index of action. + * @param description the description string of the specified action. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccActionBase::get_description(long actionIndex,BSTR __RPC_FAR *description) +{ + SolarMutexGuard g; + + try { + + if(description == nullptr) + return E_INVALIDARG; + + if(!pRXAct.is()) + return E_FAIL; + + OUString ouStr = pRXAct->getAccessibleActionDescription(actionIndex); + + SysFreeString(*description); + *description = SysAllocString(o3tl::toW(ouStr.getStr())); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccActionBase::get_name( long, BSTR __RPC_FAR *) +{ + return E_NOTIMPL; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccActionBase::get_localizedName( long, BSTR __RPC_FAR *) +{ + return E_NOTIMPL; +} + +/** + * Returns key binding object (if any) associated with specified action + * key binding is string. + * e.g. "alt+d" (like IAccessible::get_accKeyboardShortcut). + * + * @param actionIndex the index of action. + * @param nMaxBinding the max number of key binding. + * @param keyBinding the key binding array. + * @param nBinding the actual number of key binding returned. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccActionBase::get_keyBinding( + /* [in] */ long actionIndex, + /* [in] */ long, + /* [length_is][length_is][size_is][size_is][out] */ BSTR __RPC_FAR *__RPC_FAR *keyBinding, + /* [retval][out] */ long __RPC_FAR *nBinding) +{ + SolarMutexGuard g; + + try { + + if( !keyBinding || !nBinding) + return E_INVALIDARG; + + if( !pRXAct.is() ) + return E_FAIL; + + Reference< XAccessibleKeyBinding > binding = pRXAct->getAccessibleActionKeyBinding(actionIndex); + if( !binding.is() ) + return E_FAIL; + + sal_Int32 nCount = binding->getAccessibleKeyBindingCount(); + + *keyBinding = static_cast<BSTR*>(::CoTaskMemAlloc(nCount*sizeof(BSTR))); + + // #CHECK Memory Allocation# + if(*keyBinding == nullptr) + return E_FAIL; + + for( sal_Int32 index = 0;index < nCount;index++ ) + { + auto const wString = comphelper::GetkeyBindingStrByXkeyBinding( + binding->getAccessibleKeyBinding(index)); + + (*keyBinding)[index] = SysAllocString(o3tl::toW(wString.getStr())); + } + + *nBinding = nCount; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Override of IUNOXWrapper. + * + * @param pXInterface the pointer of UNO interface. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccActionBase::put_XInterface(hyper pXInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + try { + + CUNOXWrapper::put_XInterface(pXInterface); + + //special query. + if(pUNOInterface == nullptr) + return E_FAIL; + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + if( !pRContext.is() ) + return E_FAIL; + + Reference<XAccessibleAction> pRXI(pRContext,UNO_QUERY); + if( !pRXI.is() ) + pRXAct = nullptr; + else + pRXAct = pRXI.get(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccActionBase.h b/winaccessibility/source/UAccCOM/AccActionBase.h new file mode 100644 index 0000000000..9bf2c70b4b --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccActionBase.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// AccActionBase.h: interface for the CAccActionBase class. + +#pragma once + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleAction.hpp> +#include "UNOXWrapper.h" + +class ATL_NO_VTABLE CAccActionBase : public CUNOXWrapper +{ +public: + CAccActionBase(); + virtual ~CAccActionBase(); + + // IAccessibleAction +public: + // IAccessibleAction + + // Returns the number of action. + STDMETHOD(nActions)(/*[out,retval]*/ long* nActions); + + // Performs specified action on the object. + STDMETHOD(doAction)(/* [in] */ long actionIndex); + + // Gets description of specified action. + STDMETHOD(get_description)(long actionIndex, BSTR __RPC_FAR* description); + + // added , 2006/06/28, for driver 07/11 + // get the action name + STDMETHOD(get_name)(long actionIndex, BSTR __RPC_FAR* name); + + // get the localized action Name + STDMETHOD(get_localizedName)(long actionIndex, BSTR __RPC_FAR* localizedName); + + // Returns key binding object (if any) associated with specified action + // key binding is string. + // e.g. "alt+d" (like IAccessible::get_accKeyboardShortcut). + STDMETHOD(get_keyBinding) + ( + /* [in] */ long actionIndex, + /* [in] */ long nMaxBinding, + /* [length_is][length_is][size_is][size_is][out] */ BSTR __RPC_FAR* __RPC_FAR* keyBinding, + /* [retval][out] */ long __RPC_FAR* nBinding); + + // Override of IUNOXWrapper. + STDMETHOD(put_XInterface)(hyper pXInterface) override; + +protected: + css::uno::Reference<css::accessibility::XAccessibleAction> pRXAct; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccComponent.cxx b/winaccessibility/source/UAccCOM/AccComponent.cxx new file mode 100644 index 0000000000..e1e7af6abf --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccComponent.cxx @@ -0,0 +1,58 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/** + * AccComponent.cpp : Implementation of CUAccCOMApp and DLL registration. + */ +#include "stdafx.h" +#include <UAccCOM.h> +#include "AccComponent.h" + +/** + * Returns the location of the upper left corner of the object's bounding + * box relative to the parent. + * + * @param Location the upper left corner of the object's bounding box. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccComponent::get_locationInParent(long* x, long* y) +{ + return CAccComponentBase::get_locationInParent(x, y); +} + +/** + * Returns the foreground color of this object. + * + * @param Color the color of foreground. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccComponent::get_foreground(IA2Color* foreground) +{ + return CAccComponentBase::get_foreground(foreground); +} + +/** + * Returns the background color of this object. + * + * @param Color the color of background. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccComponent::get_background(IA2Color* background) +{ + return CAccComponentBase::get_background(background); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccComponent.h b/winaccessibility/source/UAccCOM/AccComponent.h new file mode 100644 index 0000000000..9a620a5231 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccComponent.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "Resource.h" // main symbols + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include "UNOXWrapper.h" +#include "AccComponentBase.h" + + +/** + * CAccComponent implements IAccessibleComponent interface. + */ +class ATL_NO_VTABLE CAccComponent : + public CComObjectRoot, + public CComCoClass<CAccComponent,&CLSID_AccComponent>, + public IAccessibleComponent, + public CAccComponentBase +{ +public: + CAccComponent() + { + } + + BEGIN_COM_MAP(CAccComponent) + COM_INTERFACE_ENTRY(IAccessibleComponent) + COM_INTERFACE_ENTRY(IUNOXWrapper) + COM_INTERFACE_ENTRY_FUNC_BLIND(0,SmartQI_) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + static HRESULT WINAPI SmartQI_(void* pv, + REFIID iid, void** ppvObject, DWORD_PTR) + { + return static_cast<CAccComponent*>(pv)->SmartQI(iid,ppvObject); + } + + HRESULT SmartQI(REFIID iid, void** ppvObject) + { + if( m_pOuterUnknown ) + return OuterQueryInterface(iid,ppvObject); + return E_FAIL; + } + + DECLARE_NO_REGISTRY() + +public: + // IAccessibleComponent + + // Returns the location of the upper left corner of the object's bounding + // box relative to the parent. + STDMETHOD(get_locationInParent)(long *x, long *y) override; + + // Returns the foreground color of this object. + STDMETHOD(get_foreground)(IA2Color * foreground) override; + + // Returns the background color of this object. + STDMETHOD(get_background)(IA2Color * background) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccComponentBase.cxx b/winaccessibility/source/UAccCOM/AccComponentBase.cxx new file mode 100644 index 0000000000..1cd6cdc1c8 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccComponentBase.cxx @@ -0,0 +1,214 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" +#include "AccComponentBase.h" +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <vcl/svapp.hxx> +#include "MAccessible.h" + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; + +// Construction/Destruction + +CAccComponentBase::CAccComponentBase() {} + +CAccComponentBase::~CAccComponentBase() {} + +/** + * Returns the location of the upper left corner of the object's bounding + * box relative to the parent. + * + * @param Location the upper left corner of the object's bounding box. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccComponentBase::get_locationInParent(long* x, long* y) +{ + SolarMutexGuard g; + + try + { + if (x == nullptr || y == nullptr) + return E_INVALIDARG; + + if (!pRXComp.is()) + return E_FAIL; + + const css::awt::Point& pt = GetXInterface()->getLocation(); + *x = pt.X; + *y = pt.Y; + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +/** + * Returns the location of the upper left corner of the object's bounding + * box in screen. + * + * @param Location the upper left corner of the object's bounding + * box in screen coordinates. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccComponentBase::get_locationOnScreen(long* x, long* y) +{ + SolarMutexGuard g; + + try + { + if (x == nullptr || y == nullptr) + return E_INVALIDARG; + + if (!pRXComp.is()) + return E_FAIL; + + const css::awt::Point& pt = GetXInterface()->getLocationOnScreen(); + *x = pt.X; + *y = pt.Y; + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +/** + * Grabs the focus to this object. + * + * @param success the boolean result to be returned. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccComponentBase::grabFocus(boolean* success) +{ + SolarMutexGuard g; + + try + { + if (success == nullptr) + return E_INVALIDARG; + + if (!pRXComp.is()) + { + return E_FAIL; + } + GetXInterface()->grabFocus(); + *success = TRUE; + + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +/** + * Returns the foreground color of this object. + * + * @param Color the color of foreground. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccComponentBase::get_foreground(IA2Color* foreground) +{ + SolarMutexGuard g; + + try + { + if (foreground == nullptr) + return E_INVALIDARG; + + if (!pRXComp.is()) + { + return E_FAIL; + } + *foreground = static_cast<long>(GetXInterface()->getForeground()); + + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +/** + * Returns the background color of this object. + * + * @param Color the color of background. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccComponentBase::get_background(IA2Color* background) +{ + SolarMutexGuard g; + + try + { + if (background == nullptr) + return E_INVALIDARG; + + if (!pRXComp.is()) + { + return E_FAIL; + } + *background = static_cast<long>(GetXInterface()->getBackground()); + + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +/** + * Override of IUNOXWrapper. + * + * @param pXInterface the pointer of UNO interface. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccComponentBase::put_XInterface(hyper pXInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + try + { + CUNOXWrapper::put_XInterface(pXInterface); + //special query. + if (pUNOInterface == nullptr) + return E_FAIL; + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + if (!pRContext.is()) + { + return E_FAIL; + } + Reference<XAccessibleComponent> pRXI(pRContext, UNO_QUERY); + if (!pRXI.is()) + pRXComp = nullptr; + else + pRXComp = pRXI.get(); + + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccComponentBase.h b/winaccessibility/source/UAccCOM/AccComponentBase.h new file mode 100644 index 0000000000..83770ba2d2 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccComponentBase.h @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// AccComponentBase.h: interface for the CAccComponentBase class. + +#pragma once + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include "UNOXWrapper.h" + +class ATL_NO_VTABLE CAccComponentBase : public CUNOXWrapper +{ +public: + CAccComponentBase(); + virtual ~CAccComponentBase(); + // IAccessibleComponent +public: + // IAccessibleComponent + + // Returns the location of the upper left corner of the object's bounding + // box relative to the parent. + STDMETHOD(get_locationInParent)(long* x, long* y); + + // Returns the location of the upper left corner of the object's bounding + // box in screen. + STDMETHOD(get_locationOnScreen)(long* x, long* y); + + // Grabs the focus to this object. + STDMETHOD(grabFocus)(boolean* success); + + // Returns the foreground color of this object. + STDMETHOD(get_foreground)(IA2Color* foreground); + + // Returns the background color of this object. + STDMETHOD(get_background)(IA2Color* background); + + // Override of IUNOXWrapper. + STDMETHOD(put_XInterface)(hyper pXInterface) override; + +protected: + css::uno::Reference<css::accessibility::XAccessibleComponent> pRXComp; + + css::accessibility::XAccessibleComponent* GetXInterface() { return pRXComp.get(); } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccEditableText.cxx b/winaccessibility/source/UAccCOM/AccEditableText.cxx new file mode 100644 index 0000000000..212546e12e --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccEditableText.cxx @@ -0,0 +1,494 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/** + * AccEditableText.cpp : Implementation of CUAccCOMApp and DLL registration. + */ +#include "stdafx.h" +#include <UAccCOM.h> +#include "AccEditableText.h" + +#include <vcl/svapp.hxx> +#include <o3tl/char16_t2wchar_t.hxx> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/accessibility/XAccessibleText.hpp> +#include <com/sun/star/awt/FontSlant.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/style/LineSpacing.hpp> +#include <com/sun/star/style/TabStop.hpp> +#include <vector> + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; +using namespace com::sun::star::awt; +using namespace com::sun::star::beans; + +/** + * Copy a range of text to the clipboard. + * + * @param startOffset the start offset of copying. + * @param endOffset the end offset of copying. + * @param success the boolean result to be returned. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::copyText(long startOffset, long endOffset) +{ + SolarMutexGuard g; + + try { + + if(!pRXEdtTxt.is()) + { + return E_FAIL; + } + + if ( GetXInterface()->copyText( startOffset, endOffset ) ) + return S_OK; + + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Deletes a range of text. + * + * @param startOffset the start offset of deleting. + * @param endOffset the end offset of deleting. + * @param success the boolean result to be returned. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::deleteText(long startOffset, long endOffset) +{ + SolarMutexGuard g; + + try { + + if( !pRXEdtTxt.is() ) + return E_FAIL; + + if( GetXInterface()->deleteText( startOffset, endOffset ) ) + return S_OK; + + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Inserts text at a specified offset. + * + * @param offset the offset of inserting. + * @param text the text to be inserted. + * @param success the boolean result to be returned. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::insertText(long offset, BSTR * text) +{ + SolarMutexGuard g; + + try { + + if (text == nullptr) + return E_INVALIDARG; + + if( !pRXEdtTxt.is() ) + return E_FAIL; + + OUString ouStr(o3tl::toU(*text)); + + if( GetXInterface()->insertText( ouStr, offset ) ) + return S_OK; + + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Cuts a range of text to the clipboard. + * + * @param startOffset the start offset of cutting. + * @param endOffset the end offset of cutting. + * @param success the boolean result to be returned. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::cutText(long startOffset, long endOffset) +{ + SolarMutexGuard g; + + try { + + if( !pRXEdtTxt.is() ) + return E_FAIL; + + if( GetXInterface()->cutText( startOffset, endOffset ) ) + return S_OK; + + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Pastes text from clipboard at specified offset. + * + * @param offset the offset of pasting. + * @param success the boolean result to be returned. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::pasteText(long offset) +{ + SolarMutexGuard g; + + try { + + if( !pRXEdtTxt.is() ) + return E_FAIL; + + if( GetXInterface()->pasteText( offset ) ) + return S_OK; + + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Replaces range of text with new text. + * + * @param startOffset the start offset of replacing. + * @param endOffset the end offset of replacing. + * @param text the replacing text. + * @param success the boolean result to be returned. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::replaceText(long startOffset, long endOffset, BSTR * text) +{ + SolarMutexGuard g; + + try { + + if (text == nullptr) + return E_INVALIDARG; + if( !pRXEdtTxt.is() ) + return E_FAIL; + + OUString ouStr(o3tl::toU(*text)); + + if( GetXInterface()->replaceText( startOffset,endOffset, ouStr) ) + return S_OK; + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Sets attributes of range of text. + * + * @param startOffset the start offset. + * @param endOffset the end offset. + * @param attributes the attribute text. + * @param success the boolean result to be returned. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::setAttributes(long startOffset, long endOffset, BSTR * attributes) +{ + SolarMutexGuard g; + + try { + + if (attributes == nullptr) + return E_INVALIDARG; + if( !pRXEdtTxt.is() ) + return E_FAIL; + + OUString ouStr(o3tl::toU(*attributes)); + + std::vector< OUString > vecAttr; + for (sal_Int32 nIndex {0}; nIndex >= 0; ) + vecAttr.push_back(ouStr.getToken(0, ';', nIndex)); + + Sequence< PropertyValue > beanSeq(vecAttr.size()); + auto beanSeqRange = asNonConstRange(beanSeq); + for(std::vector<OUString>::size_type i = 0; i < vecAttr.size(); i ++) + { + OUString attr = vecAttr[i]; + sal_Int32 nPos = attr.indexOf(':'); + if(nPos > -1) + { + OUString attrName = attr.copy(0, nPos); + OUString attrValue = attr.copy(nPos + 1); + beanSeqRange[i].Name = attrName; + get_AnyFromOLECHAR(attrName, attrValue, beanSeqRange[i].Value); + } + } + + if( GetXInterface()->setAttributes( startOffset,endOffset, beanSeq) ) + return S_OK; + + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Convert attributes string to Any type. + * + * @param ouName the string of attribute name. + * @param ouValue the string of attribute value. + * @param rAny the Any object to be returned. + */ +void CAccEditableText::get_AnyFromOLECHAR(std::u16string_view ouName, const OUString &ouValue, Any &rAny) +{ + if(ouName == u"CharBackColor" || + ouName == u"CharColor" || + ouName == u"ParaAdjust" || + ouName == u"ParaFirstLineIndent" || + ouName == u"ParaLeftMargin" || + ouName == u"ParaRightMargin" || + ouName == u"ParaTopMargin" || + ouName == u"ParaBottomMargin" || + ouName == u"CharFontPitch" ) + { + // Convert to int. + // NOTE: CharFontPitch is not implemented in java file. + sal_Int32 nValue = ouValue.toInt32(); + rAny.setValue(&nValue, cppu::UnoType<sal_Int32>::get()); + } + else if(ouName == u"CharShadowed" || + ouName == u"CharContoured" ) + { + // Convert to boolean. + rAny <<= ouValue.toBoolean(); + } + else if(ouName == u"CharEscapement" || + ouName == u"CharStrikeout" || + ouName == u"CharUnderline" || + ouName == u"CharFontPitch" ) + { + // Convert to short. + short nValue = static_cast<short>(ouValue.toInt32()); + rAny.setValue(&nValue, cppu::UnoType<short>::get()); + } + else if(ouName == u"CharHeight" || + ouName == u"CharWeight" ) + { + // Convert to float. + float fValue = ouValue.toFloat(); + rAny.setValue(&fValue, cppu::UnoType<float>::get()); + } + else if(ouName == u"CharFontName" ) + { + // Convert to string. + rAny.setValue(&ouValue, cppu::UnoType<OUString>::get()); + } + else if(ouName == u"CharPosture" ) + { + // Convert to FontSlant. + css::awt::FontSlant fontSlant = static_cast<css::awt::FontSlant>(ouValue.toInt32()); + rAny.setValue(&fontSlant, cppu::UnoType<css::awt::FontSlant>::get()); + } + else if(ouName == u"ParaTabStops" ) + { + + // Convert to the Sequence with TabStop element. + std::vector< css::style::TabStop > vecTabStop; + css::style::TabStop tabStop; + OUString ouSubValue; + sal_Int32 pos = 0, posComma = 0; + + do + { + // Position. + pos = ouValue.indexOf("Position=", pos); + if(pos != -1) + { + posComma = ouValue.indexOf(',', pos + 9); // 9 = length of "Position=". + if(posComma != -1) + { + ouSubValue = ouValue.copy(pos + 9, posComma - pos - 9); + tabStop.Position = ouSubValue.toInt32(); + pos = posComma + 1; + + // TabAlign. + pos = ouValue.indexOf("TabAlign=", pos); + if(pos != -1) + { + posComma = ouValue.indexOf(',', pos + 9); // 9 = length of "TabAlign=". + if(posComma != -1) + { + ouSubValue = ouValue.copy(pos + 9, posComma - pos - 9); + tabStop.Alignment = static_cast<css::style::TabAlign>(ouSubValue.toInt32()); + pos = posComma + 1; + + // DecimalChar. + pos = ouValue.indexOf("DecimalChar=", pos); + if(pos != -1) + { + posComma = ouValue.indexOf(',', pos + 11); // 11 = length of "TabAlign=". + if(posComma != -1) + { + ouSubValue = ouValue.copy(pos + 11, posComma - pos - 11); + tabStop.DecimalChar = ouSubValue.toChar(); + pos = posComma + 1; + + // FillChar. + pos = ouValue.indexOf("FillChar=", pos); + if(pos != -1) + { + posComma = ouValue.indexOf(',', pos + 9); // 9 = length of "TabAlign=". + if(posComma != -1) + { + ouSubValue = ouValue.copy(pos + 9, posComma - pos - 9); + tabStop.DecimalChar = ouSubValue.toChar(); + pos = posComma + 1; + + // Complete TabStop element. + vecTabStop.push_back(tabStop); + } + else + break; // No match comma. + } + else + break; // No match FillChar. + } + else + break; // No match comma. + } + else + break; // No match DecimalChar. + } + else + break; // No match comma. + } + else + break; // No match TabAlign. + } + else + break; // No match comma. + } + else + break; // No match Position. + } + while(pos < ouValue.getLength()); + + + // Dump into Sequence. + int iSeqLen = vecTabStop.empty() ? 1 : vecTabStop.size(); + Sequence< css::style::TabStop > seqTabStop(iSeqLen); + auto pseqTabStop = seqTabStop.getArray(); + + if (!vecTabStop.empty()) + { + // Dump every element. + for(int i = 0; i < iSeqLen; i ++) + { + pseqTabStop[i] = vecTabStop[i]; + } + } + else + { + // Create default value. + pseqTabStop[0].Position = 0; + pseqTabStop[0].Alignment = css::style::TabAlign_DEFAULT; + pseqTabStop[0].DecimalChar = '.'; + pseqTabStop[0].FillChar = ' '; + } + + // Assign to Any object. + rAny.setValue(&seqTabStop, cppu::UnoType<Sequence< css::style::TabStop >>::get()); + } + else if(ouName == u"ParaLineSpacing" ) + { + // Parse value string. + css::style::LineSpacing lineSpacing; + OUString ouSubValue; + sal_Int32 pos = 0, posComma = 0; + + pos = ouValue.indexOf("Mode=", pos); + if(pos != -1) + { + posComma = ouValue.indexOf(',', pos + 5); // 5 = length of "Mode=". + if(posComma != -1) + { + ouSubValue = ouValue.copy(pos + 5, posComma - pos - 5); + lineSpacing.Mode = static_cast<sal_Int16>(ouSubValue.toInt32()); + pos = posComma + 1; + + pos = ouValue.indexOf("Height=", pos); + if(pos != -1) + { + ouSubValue = ouValue.copy(pos + 7); + lineSpacing.Height = static_cast<sal_Int16>(ouSubValue.toInt32()); + } + else + { + lineSpacing.Height = sal_Int16(100); // Default height. + } + } + else + { + lineSpacing.Height = sal_Int16(100); // Default height. + } + } + else + { + // Default Mode and Height. + lineSpacing.Mode = sal_Int16(0); + lineSpacing.Height = sal_Int16(100); // Default height. + } + + // Convert to Any object. + rAny.setValue(&lineSpacing, cppu::UnoType<css::style::LineSpacing>::get()); + } + else + { + // Do nothing. + sal_Int32 nDefault = 0; + rAny.setValue(&nDefault, cppu::UnoType<sal_Int32>::get()); + } +} + +/** + * Override of IUNOXWrapper. + * + * @param pXInterface the pointer of UNO interface. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccEditableText::put_XInterface(hyper pXInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + try { + + CUNOXWrapper::put_XInterface(pXInterface); + //special query. + if(pUNOInterface == nullptr) + return E_FAIL; + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + if( !pRContext.is() ) + { + return E_FAIL; + } + Reference<XAccessibleEditableText> pRXI(pRContext,UNO_QUERY); + if( !pRXI.is() ) + pRXEdtTxt = nullptr; + else + pRXEdtTxt = pRXI.get(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccEditableText.h b/winaccessibility/source/UAccCOM/AccEditableText.h new file mode 100644 index 0000000000..244dc626bb --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccEditableText.h @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <sal/config.h> + +#include <string_view> + +#include "Resource.h" +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleEditableText.hpp> +#include "UNOXWrapper.h" + +/** + * CAccEditableText implements IAccessibleEditableText interface. + */ +class CAccEditableText : + public CComObjectRoot, + public CComCoClass<CAccEditableText,&CLSID_AccEditableText>, + public IAccessibleEditableText, + public CUNOXWrapper +{ +public: + CAccEditableText() + { + + } + virtual ~CAccEditableText() + { + + } + + BEGIN_COM_MAP(CAccEditableText) + COM_INTERFACE_ENTRY(IAccessibleEditableText) + COM_INTERFACE_ENTRY(IUNOXWrapper) + COM_INTERFACE_ENTRY_FUNC_BLIND(0,SmartQI_) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + static HRESULT WINAPI SmartQI_(void* pv, + REFIID iid, void** ppvObject, DWORD_PTR) + { + return static_cast<CAccEditableText*>(pv)->SmartQI(iid,ppvObject); + } + + HRESULT SmartQI(REFIID iid, void** ppvObject) + { + if( m_pOuterUnknown ) + return OuterQueryInterface(iid,ppvObject); + return E_FAIL; + } + + DECLARE_NO_REGISTRY() + +public: + // IAccessibleEditableText + + // Copies a range of text to the clipboard. + STDMETHOD(copyText)(long startOffset, long endOffset) override; + + // Deletes a range of text. + STDMETHOD(deleteText)(long startOffset, long endOffset) override; + + // Inserts text at a specified offset. + STDMETHOD(insertText)(long offset, BSTR * text) override; + + // Cuts a range of text to the clipboard. + STDMETHOD(cutText)(long startOffset, long endOffset) override; + + // Pastes text from clipboard at specified offset. + STDMETHOD(pasteText)(long offset) override; + + // Replaces range of text with new text. + STDMETHOD(replaceText)(long startOffset, long endOffset, BSTR * text) override; + + + // Sets attributes of range of text. + STDMETHOD(setAttributes)(long startOffset, long endOffset, BSTR * attributes) override; + + // Override of IUNOXWrapper. + STDMETHOD(put_XInterface)(hyper pXInterface) override; + +private: + + css::uno::Reference<css::accessibility::XAccessibleEditableText> pRXEdtTxt; + + static void get_AnyFromOLECHAR(std::u16string_view ouName, const OUString &ouValue, css::uno::Any &rAny); + + css::accessibility::XAccessibleEditableText* GetXInterface() + { + return pRXEdtTxt.get(); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccHyperLink.cxx b/winaccessibility/source/UAccCOM/AccHyperLink.cxx new file mode 100644 index 0000000000..40a5280c2c --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccHyperLink.cxx @@ -0,0 +1,287 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" +#include <UAccCOM.h> +#include "AccHyperLink.h" + +#include <vcl/svapp.hxx> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleAction.hpp> +#include "MAccessible.h" + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; +using namespace com::sun::star::awt; + +/** + * Returns the number of action. + * + * @param nActions the number of action. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::nActions(/*[out,retval]*/long* nActions) +{ + + return CAccActionBase::nActions(nActions); +} + +/** + * Performs specified action on the object. + * + * @param actionIndex the index of action. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::doAction(/* [in] */ long actionIndex) +{ + + return CAccActionBase::doAction(actionIndex); +} + +/** + * Gets description of specified action. + * + * @param actionIndex the index of action. + * @param description the description string of the specified action. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::get_description(long actionIndex,BSTR __RPC_FAR *description) +{ + + return CAccActionBase::get_description(actionIndex, description); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::get_name( long actionIndex, BSTR __RPC_FAR *name) +{ + + return CAccActionBase::get_name(actionIndex, name); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::get_localizedName( long actionIndex, BSTR __RPC_FAR *localizedName) +{ + + return CAccActionBase::get_name(actionIndex, localizedName); +} + +/** + * Returns key binding object (if any) associated with specified action + * key binding is string. + * e.g. "alt+d" (like IAccessible::get_accKeyboardShortcut). + * + * @param actionIndex the index of action. + * @param nMaxBinding the max number of key binding. + * @param keyBinding the key binding array. + * @param nBinding the actual number of key binding returned. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::get_keyBinding( + /* [in] */ long actionIndex, + /* [in] */ long nMaxBinding, + /* [length_is][length_is][size_is][size_is][out] */ BSTR __RPC_FAR *__RPC_FAR *keyBinding, + /* [retval][out] */ long __RPC_FAR *nBinding) +{ + + return CAccActionBase::get_keyBinding(actionIndex, nMaxBinding, keyBinding, nBinding); +} + +/** + * get an object + * @param + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::get_anchor(/* [in] */ long index, + /* [retval][out] */ VARIANT __RPC_FAR *anchor) +{ + SolarMutexGuard g; + + try { + + if(anchor == nullptr) + { + return E_INVALIDARG; + } + + if(!pRXLink.is()) + { + return E_FAIL; + } + // Get Any type value via pRXLink. + css::uno::Any anyVal = GetXInterface()->getAccessibleActionAnchor(index); + // Convert Any to VARIANT. + CMAccessible::ConvertAnyToVariant(anyVal, anchor); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * get an object + * @param + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::get_anchorTarget(/* [in] */ long index, + /* [retval][out] */ VARIANT __RPC_FAR *anchorTarget) +{ + SolarMutexGuard g; + + try { + + if(anchorTarget == nullptr) + { + return E_INVALIDARG; + } + + if(!pRXLink.is()) + { + return E_FAIL; + } + // Get Any type value via pRXLink. + css::uno::Any anyVal = GetXInterface()->getAccessibleActionObject(index); + // Convert Any to VARIANT. + CMAccessible::ConvertAnyToVariant(anyVal, anchorTarget); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + + +/** + * Get start index. + * @param index Variant to get start index. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::get_startIndex(/* [retval][out] */ long __RPC_FAR *index) +{ + SolarMutexGuard g; + + try { + + if(index == nullptr) + { + return E_INVALIDARG; + } + *index = GetXInterface()->getStartIndex(); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get start index. + * @param index Variant to get end index. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::get_endIndex(/* [retval][out] */ long __RPC_FAR *index) +{ + SolarMutexGuard g; + + try { + + if(index == nullptr) + { + return E_INVALIDARG; + } + + if(!pRXLink.is()) + { + return E_FAIL; + } + *index = GetXInterface()->getEndIndex(); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Judge if the hyperlink is valid. + * @param valid Variant to get validity. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::get_valid(/* [retval][out] */ boolean __RPC_FAR *valid) +{ + SolarMutexGuard g; + + try { + + if(valid == nullptr) + { + return E_INVALIDARG; + } + + if(!pRXLink.is()) + { + return E_FAIL; + } + *valid = GetXInterface()->isValid(); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Put UNO interface. + * @param pXInterface XAccessibleContext interface. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::put_XInterface(hyper pXInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + try { + + CAccActionBase::put_XInterface(pXInterface); + //special query. + if(pUNOInterface != nullptr) + { + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + if( !pRContext.is() ) + { + return E_FAIL; + } + Reference<XAccessibleHyperlink> pRXI(pRContext,UNO_QUERY); + if( !pRXI.is() ) + { + pRXLink = nullptr; + } + else + pRXLink = pRXI.get(); + } + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Put UNO interface. + * @param pXSubInterface XAccessibleHyperlink interface. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHyperLink::put_XSubInterface(hyper pXSubInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + pRXLink = reinterpret_cast<XAccessibleHyperlink*>(pXSubInterface); + pRXAct = reinterpret_cast<XAccessibleAction*>(pXSubInterface); + + return S_OK; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccHyperLink.h b/winaccessibility/source/UAccCOM/AccHyperLink.h new file mode 100644 index 0000000000..42d65a8335 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccHyperLink.h @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "Resource.h" // main symbols + +#include <com/sun/star/accessibility/XAccessibleHyperlink.hpp> +#include "AccActionBase.h" +#include "UNOXWrapper.h" + +/** + * CAccHyperLink implements IAccessibleHyperlink interface. + */ +class ATL_NO_VTABLE CAccHyperLink : + public CComObjectRoot, + public CComCoClass<CAccHyperLink,&CLSID_AccHyperLink>, + public IAccessibleHyperlink, + public CAccActionBase +{ +public: + CAccHyperLink() + { + } + + BEGIN_COM_MAP(CAccHyperLink) + COM_INTERFACE_ENTRY(IAccessibleAction) + COM_INTERFACE_ENTRY(IAccessibleHyperlink) + COM_INTERFACE_ENTRY(IUNOXWrapper) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + DECLARE_NO_REGISTRY() + + static HRESULT WINAPI SmartQI_(void* pv, + REFIID iid, void** ppvObject, DWORD_PTR) + { + return static_cast<CAccHyperLink*>(pv)->SmartQI(iid,ppvObject); + } + + HRESULT SmartQI(REFIID iid, void** ppvObject) + { + if( m_pOuterUnknown ) + return OuterQueryInterface(iid,ppvObject); + return E_FAIL; + } + + // IAccessibleHyperlink +public: + // IAccessibleAction + + // Returns the number of action. + STDMETHOD(nActions)(/*[out,retval]*/long* nActions) override; + + // Performs specified action on the object. + STDMETHOD(doAction)(/* [in] */ long actionIndex) override; + + // get the action name + STDMETHOD(get_name)( long actionIndex, BSTR __RPC_FAR *name) override; + + // get the localized action name + STDMETHOD(get_localizedName)( long actionIndex, BSTR __RPC_FAR *localizedName) override; + + // Gets description of specified action. + STDMETHOD(get_description)(long actionIndex,BSTR __RPC_FAR *description) override; + + // Returns key binding object (if any) associated with specified action + // key binding is string. + // e.g. "alt+d" (like IAccessible::get_accKeyboardShortcut). + STDMETHOD(get_keyBinding)( + /* [in] */ long actionIndex, + /* [in] */ long nMaxBinding, + /* [length_is][length_is][size_is][size_is][out] */ BSTR __RPC_FAR *__RPC_FAR *keyBinding, + /* [retval][out] */ long __RPC_FAR *nBinding) override; + + // IAccessibleHyperlink + + // get an object, e.g. BSTR or image object, that is overloaded with link behavior + STDMETHOD(get_anchor)(/* [in] */ long index, + /* [retval][out] */ VARIANT __RPC_FAR *anchor) override; + + // get an object representing the target of the link, usually a BSTR of the URI + STDMETHOD(get_anchorTarget)(/* [in] */ long index, + /* [retval][out] */ VARIANT __RPC_FAR *anchorTarget) override; + + // Returns the index at which the textual representation of the + // hyperlink (group) starts. + STDMETHOD(get_startIndex)(/* [retval][out] */ long __RPC_FAR *index) override; + + // Returns the index at which the textual representation of the + // hyperlink (group) ends. + STDMETHOD(get_endIndex)(/* [retval][out] */ long __RPC_FAR *index) override; + + // Returns whether the document referenced by this links is still valid. + STDMETHOD(get_valid)(/* [retval][out] */ boolean __RPC_FAR *valid) override; + + // Override of IUNOXWrapper. + STDMETHOD(put_XInterface)(hyper pXInterface) override; + + // Override of IUNOXWrapper. + STDMETHOD(put_XSubInterface)(hyper pXSubInterface) override; + +private: + + css::uno::Reference<css::accessibility::XAccessibleHyperlink> pRXLink; + + css::accessibility::XAccessibleHyperlink* GetXInterface() + { + return pRXLink.get(); + } + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccHypertext.cxx b/winaccessibility/source/UAccCOM/AccHypertext.cxx new file mode 100644 index 0000000000..c1f81c8884 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccHypertext.cxx @@ -0,0 +1,390 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" +#include <UAccCOM.h> +#include "AccHypertext.h" +#include "AccHyperLink.h" +#include "acccommon.h" + +#include <vcl/svapp.hxx> + + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; + + +/** + * Get special selection. + * @param startOffset Start selection offset. + * @param endOffset End selection offset. + * @param success Variant to accept the result of if the method call is successful. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::addSelection(long startOffset, long endOffset) +{ + + return CAccTextBase::get_addSelection(startOffset, endOffset); +} + + +/** + * Get special attributes. + * @param offset Offset. + * @param startOffset Variant to accept start offset. + * @param endOffset Variant to accept end offset. + * @param textAttributes Variant to accept attributes. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_attributes(long offset, long * startOffset, long * endOffset, BSTR * textAttributes) +{ + + return CAccTextBase::get_attributes(offset, startOffset, endOffset, textAttributes); +} + +/** + * Get caret position. + * @param offset Variant to accept caret offset. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_caretOffset(long * offset) +{ + + return CAccTextBase::get_caretOffset(offset); +} + +/** + * Get character extents. + * @param offset Offset. + * @param x Variant to accept x position. + * @param y Variant to accept y position. + * @param width Variant to accept width. + * @param Height Variant to accept height. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_characterExtents(long offset, IA2CoordinateType coordType, long * x, long * y, long * width, long * height) +{ + + return CAccTextBase::get_characterExtents(offset, coordType, x, y, width, height); +} + +/** + * Get selections count. + * @param nSelections Variant to accept selections count. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_nSelections(long * nSelections) +{ + + return CAccTextBase::get_nSelections(nSelections); +} + +/** + * Get offset of some special point. + * @param x X position of one point. + * @param x Y position of one point. + * @param coordType Type. + * @param offset Variant to accept offset. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_offsetAtPoint(long x, long y, IA2CoordinateType coordType, long * offset) +{ + return CAccTextBase::get_offsetAtPoint(x, y, coordType, offset); +} + +/** + * Get selection range. + * @param selection selection count. + * @param startOffset Variant to accept the start offset of special selection. + * @param endOffset Variant to accept the end offset of special selection. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_selection(long selection, long * startOffset, long * endOffset) +{ + + return CAccTextBase::get_selection(selection, startOffset, endOffset); +} + +/** + * Get special text. + * @param startOffset Start position of special range. + * @param endOffset End position of special range. + * @param text Variant to accept the text of special range. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_text(long startOffset, long endOffset, BSTR * text) +{ + + return CAccTextBase::get_text(startOffset, endOffset, text); +} + +/** + * Get special text before some position. + * @param offset Special position. + * @param boundaryType Boundary type. + * @param startOffset Variant to accept the start offset. + * @param endOffset Variant to accept the end offset. + * @param text Variant to accept the special text. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_textBeforeOffset(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) +{ + + return CAccTextBase::get_textBeforeOffset(offset, boundaryType, + startOffset, endOffset, text); +} + +/** + * Get special text after some position. + * @param offset Special position. + * @param boundaryType Boundary type. + * @param startOffset Variant to accept the start offset. + * @param endOffset Variant to accept the end offset. + * @param text Variant to accept the special text. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_textAfterOffset(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) +{ + + return CAccTextBase::get_textAfterOffset(offset, boundaryType, + startOffset, endOffset, text); +} + +/** + * Get special text at some position. + * @param offset Special position. + * @param boundaryType Boundary type. + * @param startOffset Variant to accept the start offset. + * @param endOffset Variant to accept the end offset. + * @param text Variant to accept the special text. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_textAtOffset(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) +{ + + return CAccTextBase::get_textAtOffset(offset, boundaryType, + startOffset, endOffset, text); +} + +/** + * Remove selection. + * @param selectionIndex Special selection index + * @param success Variant to accept the method called result. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::removeSelection(long selectionIndex) +{ + + return CAccTextBase::removeSelection(selectionIndex); +} + +/** + * Set caret position. + * @param offset Special position. + * @param success Variant to accept the method called result. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::setCaretOffset(long offset) +{ + + return CAccTextBase::setCaretOffset(offset); +} + +/** + * Set special selection. + * @param selectionIndex Special selection index. + * @param startOffset start position. + * @param endOffset end position. + * @param success Variant to accept the method called result. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::setSelection(long selectionIndex, long startOffset, long endOffset) +{ + + return CAccTextBase::setSelection(selectionIndex, startOffset, + endOffset); +} + +/** + * Get characters count. + * @param nCharacters Variant to accept the characters count. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_nCharacters(long * nCharacters) +{ + + return CAccTextBase::get_nCharacters(nCharacters); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_newText( IA2TextSegment *newText) +{ + return CAccTextBase::get_newText(newText); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_oldText( IA2TextSegment *oldText) +{ + return CAccTextBase::get_oldText(oldText); +} + +/** + * Scroll to special sub-string . + * @param startIndex Start index of sub string. + * @param endIndex End index of sub string. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::scrollSubstringToPoint(long startIndex, long endIndex,enum IA2CoordinateType coordinateType, long x, long y ) +{ + + return CAccTextBase::scrollSubstringToPoint(startIndex, endIndex, coordinateType, x, y); +} +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::scrollSubstringTo(long startIndex, long endIndex,enum IA2ScrollType scrollType) +{ + + return CAccTextBase::scrollSubstringTo(startIndex, endIndex,scrollType); +} + +/** + * Get hyperlink count. + * @param hyperlinkCount Variant to accept hyperlink count. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_nHyperlinks(long *hyperlinkCount) +{ + SolarMutexGuard g; + + try { + + if(hyperlinkCount == nullptr) + return E_INVALIDARG; + + if(!pHyperText.is()) + { + return E_FAIL; + } + + *hyperlinkCount = pHyperText->getHyperLinkCount(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get special hyperlink. + * @param index Special hyperlink index. + * @param hyperlink Variant to accept special hyperlink via index. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_hyperlink(long index,IAccessibleHyperlink **hyperlink) +{ + SolarMutexGuard g; + + try { + + if(hyperlink == nullptr) + return E_INVALIDARG; + + if(!pHyperText.is()) + { + return E_FAIL; + } + + Reference<XAccessibleHyperlink> pRLink = pHyperText->getHyperLink(index); + if(!pRLink.is()) + { + *hyperlink = nullptr; + return E_FAIL; + } + + IAccessibleHyperlink* plink = nullptr; + HRESULT hr = createInstance<CAccHyperLink>(IID_IAccessibleHyperlink, &plink); + if( SUCCEEDED(hr) ) + { + IUNOXWrapper* wrapper = nullptr; + plink->QueryInterface(IID_IUNOXWrapper, reinterpret_cast<void**>(&wrapper)); + if(wrapper) + { + wrapper->put_XSubInterface(reinterpret_cast<hyper>(pRLink.get())); + wrapper->Release(); + } + *hyperlink = plink; + return S_OK; + } + + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Returns the index of the hyperlink that is associated with this character index. + * @param charIndex Special char index. + * @param hyperlinkIndex Variant to accept special hyperlink index. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::get_hyperlinkIndex(long charIndex, long *hyperlinkIndex) +{ + SolarMutexGuard g; + + try { + + if(hyperlinkIndex == nullptr) + return E_INVALIDARG; + + if(!pHyperText.is()) + { + return E_FAIL; + } + + *hyperlinkIndex = pHyperText->getHyperLinkIndex(charIndex); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Put UNO interface. + * @param pXInterface UNO interface. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccHypertext::put_XInterface(hyper pXInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + try { + + CAccTextBase::put_XInterface(pXInterface); + //special query. + if(pUNOInterface == nullptr) + return E_FAIL; + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + if( !pRContext.is() ) + { + return E_FAIL; + } + Reference<XAccessibleHypertext> pRXI(pRContext,UNO_QUERY); + if( !pRXI.is() ) + pHyperText = nullptr; + else + pHyperText = pRXI.get(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccHypertext.h b/winaccessibility/source/UAccCOM/AccHypertext.h new file mode 100644 index 0000000000..3a6dccfb12 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccHypertext.h @@ -0,0 +1,153 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "Resource.h" // main symbols + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleHypertext.hpp> +#include "AccTextBase.h" + +/** + * CAccHypertext implements IAccessibleHypertext interface. + */ +class ATL_NO_VTABLE CAccHypertext : + public CComObjectRoot, + public CComCoClass<CAccHypertext,&CLSID_AccHypertext>, + public IAccessibleHypertext, + public CAccTextBase +{ +public: + CAccHypertext() + { + } + + BEGIN_COM_MAP(CAccHypertext) + COM_INTERFACE_ENTRY(IAccessibleText) + COM_INTERFACE_ENTRY(IAccessibleHypertext) + COM_INTERFACE_ENTRY(IUNOXWrapper) + COM_INTERFACE_ENTRY_FUNC_BLIND(0,SmartQI_) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + static HRESULT WINAPI SmartQI_(void* pv, + REFIID iid, void** ppvObject, DWORD_PTR) + { + return static_cast<CAccHypertext*>(pv)->SmartQI(iid,ppvObject); + } + + HRESULT SmartQI(REFIID iid, void** ppvObject) + { + if( m_pOuterUnknown ) + return OuterQueryInterface(iid,ppvObject); + return E_FAIL; + } + + DECLARE_NO_REGISTRY() + +public: + // IAccessibleText + + // Adds a text selection. + STDMETHOD(addSelection)(long startOffset, long endOffset) override;//, unsigned char * success) + + // Gets text attributes. + STDMETHOD(get_attributes)(long offset, long * startOffset, long * endOffset, BSTR * textAttributes) override; + + // Gets caret offset. + STDMETHOD(get_caretOffset)(long * offset) override; + + // Gets bounding rect containing the glyph(s) representing the character + // at the specified text offset + STDMETHOD(get_characterExtents)(long offset, IA2CoordinateType coordType, long * x, long * y, long * width, long * height) override; + + // Gets number of active non-contiguous selections. + STDMETHOD(get_nSelections)(long * nSelections) override; + + // Gets bounding rect for the glyph at a certain point. + STDMETHOD(get_offsetAtPoint)(long x, long y, IA2CoordinateType coordType, long * offset) override; + + // Gets character offsets of N-th active text selection. + STDMETHOD(get_selection)(long selection, long * startOffset, long * endOffset) override; + + // Gets a range of text by offset NOTE: returned string may be longer + // than endOffset-startOffset bytes if text contains multi-byte characters. + STDMETHOD(get_text)(long startOffset, long endOffset, BSTR * text) override; + + // Gets a specified amount of text that ends before a specified offset. + STDMETHOD(get_textBeforeOffset)(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) override; + + // Gets a specified amount of text that spans the specified offset. + STDMETHOD(get_textAfterOffset)(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) override; + + // Gets a specified amount of text that starts after a specified offset. + STDMETHOD(get_textAtOffset)(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) override; + + // Unselects a range of text. + STDMETHOD(removeSelection)(long selectionIndex) override; + + // Moves text caret. + STDMETHOD(setCaretOffset)(long offset) override; + + // Changes the bounds of an existing selection. + STDMETHOD(setSelection)(long selectionIndex, long startOffset, long endOffset) override; + + // Gets total number of characters. + // NOTE: this may be different than the total number of bytes required + // to store the text, if the text contains multi-byte characters. + STDMETHOD(get_nCharacters)(long * nCharacters) override; + + // Makes specific part of string visible on screen. + STDMETHOD(scrollSubstringTo)(long startIndex, long endIndex,enum IA2ScrollType scrollType) override; + + STDMETHOD(scrollSubstringToPoint)(long startIndex, long endIndex,enum IA2CoordinateType coordinateType, long x, long y ) override; + + STDMETHOD(get_newText)( IA2TextSegment *newText) override; + + STDMETHOD(get_oldText)( IA2TextSegment *oldText) override; + + //IAccessibleHypertext + + // Gets the number of hyperlink. + STDMETHOD(get_nHyperlinks)(long *hyperlinkCount) override; + + // Gets the hyperlink object via specified index. + STDMETHOD(get_hyperlink)(long index,IAccessibleHyperlink **hyperlink) override; + + // Returns the index of the hyperlink that is associated with this + // character index. + STDMETHOD(get_hyperlinkIndex)(long charIndex, long *hyperlinkIndex) override; + + // Override of IUNOXWrapper. + STDMETHOD(put_XInterface)(hyper pXInterface) override; + +private: + + css::uno::Reference<css::accessibility::XAccessibleHypertext> pHyperText; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccImage.cxx b/winaccessibility/source/UAccCOM/AccImage.cxx new file mode 100644 index 0000000000..7dbfcc339c --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccImage.cxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" +#include <UAccCOM.h> +#include "AccImage.h" + +#include <vcl/svapp.hxx> +#include <o3tl/char16_t2wchar_t.hxx> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> + +using namespace css::accessibility; +using namespace css::uno; + +/** + * Get description. + * @param description Variant to get description. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccImage::get_description(BSTR* description) +{ + SolarMutexGuard g; + + try + { + if (description == nullptr) + return E_INVALIDARG; + if (!pRXImg.is()) + return E_FAIL; + + OUString ouStr = GetXInterface()->getAccessibleImageDescription(); + SysFreeString(*description); + *description = SysAllocString(o3tl::toW(ouStr.getStr())); + + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccImage::get_imagePosition( + /* [in] */ enum IA2CoordinateType, + /* [out] */ long __RPC_FAR*, + /* [retval][out] */ long __RPC_FAR*) +{ + return E_NOTIMPL; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccImage::get_imageSize( + /* [out] */ long __RPC_FAR*, + /* [retval][out] */ long __RPC_FAR*) +{ + return E_NOTIMPL; +} + +/** + * Put UNO interface. + * @param pXInterface UNO interface. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccImage::put_XInterface(hyper pXInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + try + { + CUNOXWrapper::put_XInterface(pXInterface); + //special query. + if (pUNOInterface == nullptr) + return E_FAIL; + + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + if (!pRContext.is()) + { + return E_FAIL; + } + Reference<XAccessibleImage> pRXI(pRContext, UNO_QUERY); + if (!pRXI.is()) + pRXImg = nullptr; + else + pRXImg = pRXI.get(); + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccImage.h b/winaccessibility/source/UAccCOM/AccImage.h new file mode 100644 index 0000000000..4e0708a180 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccImage.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "Resource.h" // main symbols + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleImage.hpp> +#include "UNOXWrapper.h" + +/** + * CAccImage implements IAccessibleImage interface. + */ +class ATL_NO_VTABLE CAccImage : + public CComObjectRoot, + public CComCoClass<CAccImage,&CLSID_AccImage>, + public IAccessibleImage, + public CUNOXWrapper +{ +public: + CAccImage() + { + } + virtual ~CAccImage() + { + } + BEGIN_COM_MAP(CAccImage) + COM_INTERFACE_ENTRY(IAccessibleImage) + COM_INTERFACE_ENTRY(IUNOXWrapper) + COM_INTERFACE_ENTRY_FUNC_BLIND(0,SmartQI_) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + static HRESULT WINAPI SmartQI_(void* pv, + REFIID iid, void** ppvObject, DWORD_PTR) + { + return static_cast<CAccImage*>(pv)->SmartQI(iid,ppvObject); + } + + HRESULT SmartQI(REFIID iid, void** ppvObject) + { + if( m_pOuterUnknown ) + return OuterQueryInterface(iid,ppvObject); + return E_FAIL; + } + + DECLARE_NO_REGISTRY() + +public: + // IAccessibleImage + + // Gets the description of the image. + STDMETHOD(get_description)(BSTR * description) override; + + STDMETHOD(get_imagePosition)( enum IA2CoordinateType coordinateType, + long __RPC_FAR *x, + long __RPC_FAR *y) override; + + STDMETHOD(get_imageSize)( + long __RPC_FAR *height, + long __RPC_FAR *width) override; + + // Override of IUNOXWrapper. + STDMETHOD(put_XInterface)(hyper pXInterface) override; + +private: + + css::uno::Reference<css::accessibility::XAccessibleImage> pRXImg; + + css::accessibility::XAccessibleImage* GetXInterface() + { + return pRXImg.get(); + } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccRelation.cxx b/winaccessibility/source/UAccCOM/AccRelation.cxx new file mode 100644 index 0000000000..b866d3f0ba --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccRelation.cxx @@ -0,0 +1,206 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" +#include <UAccCOM.h> +#include "AccRelation.h" + +#include <vcl/svapp.hxx> + +#include <com/sun/star/accessibility/AccessibleRelationType.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include "MAccessible.h" + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; + +/** + * Get relation type. + * @param relationType Variant to get relation type. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccRelation::get_relationType(BSTR * relationType) +{ + SolarMutexGuard g; + + try { + + if (relationType == nullptr) + return E_INVALIDARG; + + int type = relation.RelationType; + SysFreeString(*relationType); + + *relationType = getRelationTypeBSTR(type); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +// Gets what the type of localized relation is. +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccRelation::get_localizedRelationType(BSTR *) +{ + + + try { + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get targets length. + * @param nTargets Variant to get targets length. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccRelation::get_nTargets(long * nTargets) +{ + SolarMutexGuard g; + + try { + + if (nTargets == nullptr) + return E_INVALIDARG; + + Sequence< Reference< XInterface > > xTargets = relation.TargetSet; + *nTargets = xTargets.getLength(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get special target. + * @param targetIndex target index. + * @param target Variant to get special target. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccRelation::get_target(long targetIndex, IUnknown * * target) +{ + SolarMutexGuard g; + + try { + + if (target == nullptr) + return E_FAIL; + + Sequence< Reference< XInterface > > xTargets = relation.TargetSet; + int nCount = xTargets.getLength(); + if( targetIndex >= nCount ) + return E_FAIL; + + Reference<XAccessible> xRAcc(xTargets[targetIndex], UNO_QUERY); + IAccessible* pRet = CMAccessible::get_IAccessibleFromXAccessible(xRAcc.get()); + if (pRet) + { + *target = pRet; + pRet->AddRef(); + return S_OK; + } + + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Get special targets. + * @param maxTargets Special targets count. + * @param target Variant to get special target. + * @param nTargets Variant to accept actual target length. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccRelation::get_targets(long, IUnknown * * target, long * nTargets) +{ + SolarMutexGuard g; + + try { + + if(target == nullptr) + return E_INVALIDARG; + if (nTargets == nullptr) + return E_INVALIDARG; + + Sequence< Reference< XInterface > > xTargets = relation.TargetSet; + int nCount = xTargets.getLength(); + + *target = static_cast<IUnknown*>(::CoTaskMemAlloc(nCount*sizeof(IUnknown))); + + // #CHECK Memory Allocation# + if(*target == nullptr) + { + return E_FAIL; + } + + for(int i=0; i<nCount ; i++) + { + IUnknown* pAcc = nullptr; + HRESULT hr = get_target(i,&pAcc); + if(SUCCEEDED(hr)) + target[i] = pAcc; + } + + *nTargets = nCount; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Put UNO interface. + * @param pXSubInterface AccessibleRelation pointer. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccRelation::put_XSubInterface(hyper pXSubInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + relation = *reinterpret_cast<AccessibleRelation*>(pXSubInterface); + return S_OK; +} + +/** + * Get relation type string by type. + * @param type Relation type. + * @return relation type string. +*/ +BSTR CAccRelation::getRelationTypeBSTR(int type) +{ + static LPCWSTR map[] = + { + L"INVALID", // AccessibleRelationType::INVALID + IA2_RELATION_FLOWS_FROM, // AccessibleRelationType::CONTENT_FLOWS_FROM + IA2_RELATION_FLOWS_TO, // AccessibleRelationType::CONTENT_FLOWS_TO + IA2_RELATION_CONTROLLED_BY, // AccessibleRelationType::CONTROLLED_BY + IA2_RELATION_CONTROLLER_FOR, // AccessibleRelationType::CONTROLLER_FOR + IA2_RELATION_LABEL_FOR, // AccessibleRelationType::LABEL_FOR + IA2_RELATION_LABELED_BY, // AccessibleRelationType::LABELED_BY + IA2_RELATION_MEMBER_OF, // AccessibleRelationType::MEMBER_OF + IA2_RELATION_SUBWINDOW_OF, // AccessibleRelationType::SUB_WINDOW_OF + IA2_RELATION_NODE_CHILD_OF, // AccessibleRelationType::NODE_CHILD_OF + IA2_RELATION_DESCRIBED_BY // AccessibleRelationType::DESCRIBED_BY + }; + + return ::SysAllocString( (type >= AccessibleRelationType::INVALID && type <= AccessibleRelationType::DESCRIBED_BY) + ? map[type] : L""); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccRelation.h b/winaccessibility/source/UAccCOM/AccRelation.h new file mode 100644 index 0000000000..df258f709d --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccRelation.h @@ -0,0 +1,91 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "Resource.h" // main symbols + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp> +#include "UNOXWrapper.h" + +/** + * CAccRelation implements IAccessibleRelation interface. + */ +class ATL_NO_VTABLE CAccRelation : + public CComObjectRoot, + public CComCoClass<CAccRelation, &CLSID_AccRelation>, + public IAccessibleRelation, + public CUNOXWrapper +{ +public: + CAccRelation() + { + } + virtual ~CAccRelation() + { + } + + DECLARE_NO_REGISTRY() + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CAccRelation) + COM_INTERFACE_ENTRY(IAccessibleRelation) + COM_INTERFACE_ENTRY(IUNOXWrapper) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + // IAccessibleRelation +public: + // IAccessibleRelation + + // Gets what the type of relation is. + STDMETHOD(get_relationType)(BSTR * relationType) override; + + // Gets what the type of localized relation is. + STDMETHOD(get_localizedRelationType)(BSTR * relationType) override; + + // Gets how many targets this relation have. + STDMETHOD(get_nTargets)(long * nTargets) override; + + // Gets one accessible relation target. + STDMETHOD(get_target)(long targetIndex, IUnknown * * target) override; + + // Gets multiple accessible relation targets. + STDMETHOD(get_targets)(long maxTargets, IUnknown * * target, long * nTargets) override; + + // Override of IUNOXWrapper. + STDMETHOD(put_XSubInterface)(hyper pXSubInterface) override; + + //static OLECHAR* getRelationTypeOLECHAR(int type); + static BSTR getRelationTypeBSTR(int type); + +private: + + css::accessibility::AccessibleRelation relation; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccTable.cxx b/winaccessibility/source/UAccCOM/AccTable.cxx new file mode 100644 index 0000000000..a158cf7066 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccTable.cxx @@ -0,0 +1,1078 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/** + * AccTable.cpp : Implementation of CAccTable. + */ +#include "stdafx.h" +#include <UAccCOM.h> +#include "AccTable.h" + +#include <sal/log.hxx> +#include <vcl/svapp.hxx> +#include <o3tl/char16_t2wchar_t.hxx> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include "MAccessible.h" + +#include <com/sun/star/accessibility/XAccessibleTableSelection.hpp> + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; +/** + * Gets accessible table cell. + * + * @param row the row of the specified cell. + * @param column the column of the specified cell. + * @param accessible the accessible object of the cell. + */ + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_accessibleAt(long row, long column, IUnknown * * accessible) +{ + SolarMutexGuard g; + + try { + + if(accessible == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + Reference<XAccessible> pRAcc = pRXTable->getAccessibleCellAt(row, column); + + if(!pRAcc.is()) + { + *accessible = nullptr; + return E_FAIL; + } + + IAccessible* pRet = CMAccessible::get_IAccessibleFromXAccessible(pRAcc.get()); + if (pRet) + { + *accessible = pRet; + pRet->AddRef(); + return S_OK; + } + else if(pRAcc.is()) + { + Reference<XAccessible> pxTable(pRXTable, UNO_QUERY); + + CMAccessible::g_pAccObjectManager->InsertAccObj(pRAcc.get(),pxTable.get()); + pRet = CMAccessible::get_IAccessibleFromXAccessible(pRAcc.get()); + + if (pRet) + { + *accessible = pRet; + pRet->AddRef(); + return S_OK; + } + } + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_cellAt(long row, long column, IUnknown * * cell) +{ + return get_accessibleAt(row, column, cell); +} + +/** + * Gets accessible table caption. + * + * @param accessible the accessible object of table caption. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_caption(IUnknown * *) +{ + return E_NOTIMPL; +} + +/** + * Gets accessible column description (as string). + * + * @param column the column index. + * @param description the description of the specified column. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_columnDescription(long column, BSTR * description) +{ + SolarMutexGuard g; + + try { + + if(description == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + const OUString& ouStr = pRXTable->getAccessibleColumnDescription(column); + + SysFreeString(*description); + *description = SysAllocString(o3tl::toW(ouStr.getStr())); + if (*description==nullptr) + return E_FAIL; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets number of columns spanned by table cell. + * + * @param row the row of the specified cell. + * @param column the column of the specified cell. + * @param spanColumns the column span of the specified cell. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_columnExtentAt(long row, long column, long * nColumnsSpanned) +{ + SolarMutexGuard g; + + try { + + // Check pointer. + if(nColumnsSpanned == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + *nColumnsSpanned = pRXTable->getAccessibleColumnExtentAt(row, column); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets accessible column header. + * + * @param column the column index. + * @param accessible the accessible object of the specified column. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_columnHeader(IAccessibleTable __RPC_FAR *__RPC_FAR *accessibleTable, long *startingRowIndex) +{ + SolarMutexGuard g; + + try { + + if(accessibleTable == nullptr || startingRowIndex == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + Reference<XAccessibleTable> pRColumnHeaderTable = pRXTable->getAccessibleColumnHeaders(); + if(!pRColumnHeaderTable.is()) + { + *accessibleTable = nullptr; + return E_FAIL; + } + + Reference<XAccessible> pRXColumnHeader(pRColumnHeaderTable,UNO_QUERY); + + if(!pRXColumnHeader.is()) + { + *accessibleTable = nullptr; + return E_FAIL; + } + *startingRowIndex = 0 ; + + IMAccessible* pIMacc = nullptr; + HRESULT hr = createInstance<CMAccessible>(IID_IMAccessible, &pIMacc); + if (!SUCCEEDED(hr)) + { + return E_FAIL; + } + pIMacc->SetXAccessible( + reinterpret_cast<hyper>(pRXColumnHeader.get())); + pIMacc->QueryInterface(IID_IAccessibleTable,reinterpret_cast<void **>(accessibleTable)); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets total number of columns in table. + * + * @param columnCount the number of columns in table. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_nColumns(long * columnCount) +{ + SolarMutexGuard g; + + try { + + if(columnCount == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + *columnCount = pRXTable->getAccessibleColumnCount(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets total number of rows in table. + * + * @param rowCount the number of rows in table. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_nRows(long * rowCount) +{ + SolarMutexGuard g; + + try { + + if(rowCount == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + *rowCount = pRXTable->getAccessibleRowCount(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets total number of selected columns. + * + * @param columnCount the number of selected columns. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_nSelectedColumns(long * columnCount) +{ + SolarMutexGuard g; + + try { + + if(columnCount == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + Sequence<long> pSelected = pRXTable->getSelectedAccessibleColumns(); + *columnCount = pSelected.getLength(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets total number of selected rows. + * + * @param rowCount the number of selected rows. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_nSelectedRows(long * rowCount) +{ + SolarMutexGuard g; + + try { + + if(rowCount == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + Sequence<long> pSelected = pRXTable->getSelectedAccessibleRows(); + *rowCount = pSelected.getLength(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets accessible row description (as string). + * + * @param row the row index. + * @param description the description of the specified row. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_rowDescription(long row, BSTR * description) +{ + SolarMutexGuard g; + + try { + + if(description == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + const OUString& ouStr = pRXTable->getAccessibleRowDescription(row); + + SysFreeString(*description); + *description = SysAllocString(o3tl::toW(ouStr.getStr())); + if (*description==nullptr) + return E_FAIL; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets number of rows spanned by a table cell. + * + * @param row the row of the specified cell. + * @param column the column of the specified cell. + * @param spanRows the row span of the specified cell. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_rowExtentAt(long row, long column, long * nRowsSpanned) +{ + SolarMutexGuard g; + + try { + + // Check pointer. + if(nRowsSpanned == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + *nRowsSpanned= pRXTable->getAccessibleRowExtentAt(row, column); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets accessible row header. + * + * @param row the row index. + * @param accessible the accessible object of the row header. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_rowHeader(IAccessibleTable __RPC_FAR *__RPC_FAR *accessibleTable, long *startingColumnIndex) +{ + SolarMutexGuard g; + + try { + + if(accessibleTable == nullptr || startingColumnIndex == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + Reference<XAccessibleTable> pRRowHeaderTable = pRXTable->getAccessibleRowHeaders(); + if(!pRRowHeaderTable.is()) + { + *accessibleTable = nullptr; + return E_FAIL; + } + + Reference<XAccessible> pRXRowHeader(pRRowHeaderTable,UNO_QUERY); + + if(!pRXRowHeader.is()) + { + *accessibleTable = nullptr; + return E_FAIL; + } + *startingColumnIndex = 0 ; + + IMAccessible* pIMacc = nullptr; + HRESULT hr = createInstance<CMAccessible>(IID_IMAccessible, &pIMacc); + if (!SUCCEEDED(hr)) + { + return E_FAIL; + } + pIMacc->SetXAccessible( + reinterpret_cast<hyper>(pRXRowHeader.get())); + pIMacc->QueryInterface(IID_IAccessibleTable,reinterpret_cast<void **>(accessibleTable)); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets list of row indexes currently selected (0-based). + * + * @param accessible the accessible object array of the selected rows. + * @param nRows the actual size of the accessible object array. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_selectedRows(long** rows, long* nRows) +{ + SolarMutexGuard g; + + try { + + if(rows == nullptr || nRows == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + Sequence<long> pSelected = pRXTable->getSelectedAccessibleRows(); + long count = pSelected.getLength() ; + *nRows = count; + + *rows = static_cast<long*>(CoTaskMemAlloc(count * sizeof(long))); + // #CHECK Memory Allocation# + if(*rows == nullptr) + { + return E_FAIL; + } + for(int i=0; i<count; i++) + (*rows)[i] = pSelected[i]; + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets list of row indexes currently selected (0-based). + * + * @param maxRows This parameter is ignored. + * @param accessible the accessible object array of the selected rows. + * @param nRows the actual size of the accessible object array. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_selectedRows(long, long ** rows, long * nRows) +{ + return get_selectedRows(rows, nRows); +} + +/** + * Gets list of column indexes currently selected (0-based). + * + * @param accessible the accessible object array of the selected columns. + * @param numColumns the actual size of accessible object array. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_selectedColumns(long ** columns, long * numColumns) +{ + SolarMutexGuard g; + + try { + + if(columns == nullptr || numColumns == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + Sequence<long> pSelected = pRXTable->getSelectedAccessibleColumns(); + long count = pSelected.getLength() ; + *numColumns = count; + + *columns = static_cast<long*>(CoTaskMemAlloc(count * sizeof(long))); + // #CHECK Memory Allocation# + if(*columns == nullptr) + { + return E_FAIL; + } + for(int i=0; i<count; i++) + (*columns)[i] = pSelected[i]; + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets list of column indexes currently selected (0-based). + * + * @param maxColumns This parameter is ignored + * @param accessible the accessible object array of the selected columns. + * @param numColumns the actual size of accessible object array. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_selectedColumns(long, long ** columns, long * numColumns) +{ + return get_selectedColumns(columns, numColumns); +} + +/** + * Gets accessible table summary. + * + * @param accessible the accessible object of the summary. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_summary(IUnknown * * accessible) +{ + SolarMutexGuard g; + + try { + + if(accessible == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + Reference<XAccessible> pRAcc = pRXTable->getAccessibleSummary(); + + IAccessible* pRet = CMAccessible::get_IAccessibleFromXAccessible(pRAcc.get()); + + if(pRet) + { + *accessible = pRet; + pRet->AddRef(); + return S_OK; + } + + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Determines if table column is selected. + * + * @param column the column index. + * @param isSelected the result. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_isColumnSelected(long column, boolean * isSelected) +{ + SolarMutexGuard g; + + try { + + if(isSelected == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + *isSelected = pRXTable->isAccessibleColumnSelected(column); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Determines if table row is selected. + * + * @param row the row index. + * @param isSelected the result. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_isRowSelected(long row, boolean * isSelected) +{ + SolarMutexGuard g; + + try { + + if(isSelected == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + *isSelected = pRXTable->isAccessibleRowSelected(row); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Determines if table cell is selected. + * + * @param row the row index. + * @param column the column index. + * @param isSelected the result. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_isSelected(long row, long column, boolean * isSelected) +{ + SolarMutexGuard g; + + try { + + if(isSelected == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + *isSelected = pRXTable->isAccessibleSelected(row, column); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Selects a row and unselect all previously selected rows. + * + * @param row the row index. + * @param success the result. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::selectRow(long row) +{ + SolarMutexGuard g; + + try { + + // Check XAccessibleTable reference. + if(!pRXTable.is()) + return E_FAIL; + + Reference<XAccessibleTableSelection> pRTableExtent(pRXTable, UNO_QUERY); + if(pRTableExtent.is()) + { + pRTableExtent->selectRow(row); + return S_OK; + } + else + { + // Get XAccessibleSelection. + Reference<XAccessibleSelection> pRSelection(pRXTable, UNO_QUERY); + if(!pRSelection.is()) + return E_FAIL; + + // Select row. + long lCol, lColumnCount; + lColumnCount = pRXTable->getAccessibleColumnCount(); + for(lCol = 0; lCol < lColumnCount; lCol ++) + { + sal_Int64 nChildIndex = pRXTable->getAccessibleIndex(row, lCol); + pRSelection->selectAccessibleChild(nChildIndex); + } + + return S_OK; + } + + } catch(...) { return E_FAIL; } +} + +/** + * Selects a column and unselect all previously selected columns. + * + * @param column the column index. + * @param success the result. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::selectColumn(long column) +{ + SolarMutexGuard g; + + try { + + // Check XAccessibleTable reference. + if(!pRXTable.is()) + return E_FAIL; + + Reference<XAccessibleTableSelection> pRTableExtent(pRXTable, UNO_QUERY); + if(pRTableExtent.is()) + { + pRTableExtent->selectColumn(column); + return S_OK; + } + else + { + // Get XAccessibleSelection. + Reference<XAccessibleSelection> pRSelection(pRXTable, UNO_QUERY); + if(!pRSelection.is()) + return E_FAIL; + + // Select column. + long lRow, lRowCount; + lRowCount = pRXTable->getAccessibleRowCount(); + for(lRow = 0; lRow < lRowCount; lRow ++) + { + sal_Int64 nChildIndex = pRXTable->getAccessibleIndex(lRow, column); + pRSelection->selectAccessibleChild(nChildIndex); + } + + return S_OK; + } + // End of added. + + } catch(...) { return E_FAIL; } +} + +/** + * Unselects one row, leaving other selected rows selected (if any). + * + * @param row the row index. + * @param success the result. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::unselectRow(long row) +{ + SolarMutexGuard g; + + try { + + // Check XAccessibleTable reference. + if(!pRXTable.is()) + return E_FAIL; + + Reference<XAccessibleTableSelection> pRTableExtent(pRXTable, UNO_QUERY); + if(pRTableExtent.is()) + { + if(pRTableExtent->unselectRow(row)) + return S_OK; + else + return E_FAIL; + } + else + { + // Get XAccessibleSelection. + Reference<XAccessibleSelection> pRSelection(pRXTable, UNO_QUERY); + if(!pRSelection.is()) + return E_FAIL; + + // Select column. + long lColumn, lColumnCount; + lColumnCount = pRXTable->getAccessibleColumnCount(); + for(lColumn = 0; lColumn < lColumnCount; lColumn ++) + { + sal_Int64 nChildIndex = pRXTable->getAccessibleIndex(row, lColumn); + pRSelection->deselectAccessibleChild(nChildIndex); + } + + return S_OK; + } + // End of added. + + } catch(...) { return E_FAIL; } +} + +/** + * Unselects one column, leaving other selected columns selected (if any). + * + * @param column the column index. + * @param success the result. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::unselectColumn(long column) +{ + SolarMutexGuard g; + + try { + + // Check XAccessibleTable reference. + if(!pRXTable.is()) + return E_FAIL; + + Reference<XAccessibleTableSelection> pRTableExtent(pRXTable, UNO_QUERY); + if(pRTableExtent.is()) + { + if(pRTableExtent->unselectColumn(column)) + return S_OK; + else + return E_FAIL; + } + else + { + // Get XAccessibleSelection. + Reference<XAccessibleSelection> pRSelection(pRXTable, UNO_QUERY); + if(!pRSelection.is()) + return E_FAIL; + + // Unselect columns. + long lRow, lRowCount; + lRowCount = pRXTable->getAccessibleRowCount(); + + for(lRow = 0; lRow < lRowCount; lRow ++) + { + sal_Int64 nChildIndex = pRXTable->getAccessibleIndex(lRow, column); + pRSelection->deselectAccessibleChild(nChildIndex); + } + return S_OK; + } + + } catch(...) { return E_FAIL; } +} + +/** + * Override of IUNOXWrapper. + * + * @param pXInterface the pointer of UNO interface. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::put_XInterface(hyper pXInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + try { + + CUNOXWrapper::put_XInterface(pXInterface); + //special query. + if(pUNOInterface == nullptr) + return E_INVALIDARG; + + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + if( !pRContext.is() ) + return E_FAIL; + + Reference<XAccessibleTable> pRXI(pRContext,UNO_QUERY); + if( !pRXI.is() ) + pRXTable = nullptr; + else + pRXTable = pRXI.get(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + + +/** + * Gets columnIndex of childIndex. + * + * @param childIndex childIndex + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_columnIndex(long childIndex, long * columnIndex) +{ + SolarMutexGuard g; + + try { + + if(columnIndex == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + *columnIndex = pRXTable->getAccessibleColumn(childIndex); + return S_OK; + + } catch(...) { return E_FAIL; } +} +/** + * Gets rowIndex of childIndex. + * + * @param childIndex childIndex + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_rowIndex(long childIndex, long * rowIndex) +{ + SolarMutexGuard g; + + try { + + if(rowIndex == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + *rowIndex = pRXTable->getAccessibleRow(childIndex); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Gets childIndex of childIndex. + * + * @param childIndex childIndex + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_childIndex(long RowIndex , long columnIndex, long * childIndex ) +{ + SolarMutexGuard g; + + try { + + if(childIndex == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + sal_Int64 nIndex = pRXTable->getAccessibleIndex(RowIndex, columnIndex); + if (nIndex > std::numeric_limits<long>::max()) + { + // use -2 when the child index is too large to fit into 32 bit to neither use the + // valid index of another child nor -1, which is more commonly used to indicate that + // a child is no more inside of a parent or invalid otherwise + SAL_WARN("vcl.qt", "CAccTable::get_childIndex: Child index exceeds maximum long value, " + "returning -2."); + nIndex = -2; + } + *childIndex = nIndex; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_rowColumnExtentsAtIndex(long, + long *, + long *, + long *, + long *, + boolean *) +{ + return E_NOTIMPL; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_modelChange(IA2TableModelChange *) +{ + return E_NOTIMPL; +} + +// @brief Returns the total number of selected children +// @param [out] childCount +// Number of children currently selected +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_nSelectedChildren(long *childCount) +{ + SolarMutexGuard g; + + try { + + if(childCount == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + Reference<XAccessibleSelection> pRSelection(pRXTable, UNO_QUERY); + if(!pRSelection.is()) + return E_FAIL; + + sal_Int64 nSelected = pRSelection->getSelectedAccessibleChildCount(); + if (nSelected > std::numeric_limits<long>::max()) + { + SAL_WARN("iacc2", "CAccTable::get_nSelectedChildren: Selected item count exceeds maximum long value, " + "using max long."); + nSelected = std::numeric_limits<long>::max(); + } + *childCount = nSelected; + return S_OK; + + } catch(...) { return E_FAIL; } +} + + + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_nSelectedCells(long *cellCount) +{ + return get_nSelectedChildren(cellCount); +} + +// @brief Returns a list of child indexes currently selected (0-based). +// @param [in] maxChildren +// Max children requested (possibly from IAccessibleTable::nSelectedChildren) +// @param [out] children +// array of indexes of selected children (each index is 0-based) +// @param [out] nChildren +// Length of array (not more than maxChildren) +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_selectedChildren(long, long **children, long *nChildren) +{ + SolarMutexGuard g; + + try { + + if(children == nullptr || nChildren == nullptr) + return E_INVALIDARG; + + if(!pRXTable.is()) + return E_FAIL; + + Reference<XAccessibleSelection> pRSelection(pRXTable, UNO_QUERY); + if(!pRSelection.is()) + return E_FAIL; + + sal_Int64 nChildCount = pRSelection->getSelectedAccessibleChildCount(); + if (nChildCount > std::numeric_limits<long>::max()) + { + SAL_WARN("iacc2", "CAccTable::get_selectedChildren: Selected child count exceeds maximum long value, " + "using max long."); + nChildCount = std::numeric_limits<long>::max(); + } + + *nChildren = nChildCount; + *children = static_cast<long*>(CoTaskMemAlloc(nChildCount * sizeof(long))); + + for( sal_Int64 i = 0; i< nChildCount; i++) + { + Reference<XAccessible> pRAcc = pRSelection->getSelectedAccessibleChild(i); + if(pRAcc.is()) + { + Reference<XAccessibleContext> pRContext(pRAcc, UNO_QUERY); + if( !pRContext.is() ) + return E_FAIL; + + + sal_Int64 nChildIndex = pRContext->getAccessibleIndexInParent(); + if (nChildIndex > std::numeric_limits<long>::max()) + { + SAL_WARN("iacc2", "CAccTable::get_selectedChildren: Child index exceeds maximum long value, " + "using max long."); + nChildIndex = std::numeric_limits<long>::max(); + } + (*children)[i] = nChildIndex; + } + } + + return S_OK; + + } catch(...) { return E_FAIL; } + +} + +/** + * @brief Returns a list of accessibles currently selected. + * @param cells Pointer to an array of references to selected accessibles. + * The array is allocated by the server with CoTaskMemAlloc and + * freed by the client with CoTaskMemFree. + * @param nSelectedCells The number of accessibles returned; the size of the returned array. + * @return S_FALSE if there are none, [out] values are NULL and 0 respectively, otherwise S_OK + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTable::get_selectedCells(IUnknown * * * cells, long *nSelectedCells) +{ + SolarMutexGuard g; + + try { + + if (cells == nullptr || nSelectedCells == nullptr) + return E_INVALIDARG; + + if (!pRXTable.is()) + return E_FAIL; + + Reference<XAccessibleSelection> xSelection(pRXTable, UNO_QUERY); + if (!xSelection.is()) + return E_FAIL; + + sal_Int64 nSelected = xSelection->getSelectedAccessibleChildCount(); + if (nSelected > std::numeric_limits<long>::max()) + { + SAL_WARN("iacc2", "CAccTable::get_selectedCells: Selected cell count exceeds maximum long value, " + "using max long."); + nSelected = std::numeric_limits<long>::max(); + } + *nSelectedCells = nSelected; + + *cells = static_cast<IUnknown**>(CoTaskMemAlloc(nSelected * sizeof(IUnknown*))); + + for (sal_Int64 i = 0; i < nSelected; i++) + { + Reference<XAccessible> xAcc = xSelection->getSelectedAccessibleChild(i); + assert(xAcc.is()); + + IAccessible* pIAccessible = CMAccessible::get_IAccessibleFromXAccessible(xAcc.get()); + + if (!pIAccessible) + { + Reference<XAccessible> xTable(pRXTable, UNO_QUERY); + CMAccessible::g_pAccObjectManager->InsertAccObj(xAcc.get(), xTable.get()); + pIAccessible = CMAccessible::get_IAccessibleFromXAccessible(xAcc.get()); + } + + assert(pIAccessible && "Couldn't retrieve IAccessible object"); + + pIAccessible->AddRef(); + (*cells)[i] = pIAccessible; + } + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccTable.h b/winaccessibility/source/UAccCOM/AccTable.h new file mode 100644 index 0000000000..d5805c3c0b --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccTable.h @@ -0,0 +1,184 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "Resource.h" // main symbols + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleTable.hpp> +#include "UNOXWrapper.h" + +/** + * CAccTable implements the IAccessibleTable and IAccessibleTable2 interfaces. + */ +class ATL_NO_VTABLE CAccTable : + public CComObjectRoot, + public CComCoClass<CAccTable, &CLSID_AccTable>, + public IAccessibleTable, + public IAccessibleTable2, + public CUNOXWrapper + +{ +public: + CAccTable() + { + } + virtual ~CAccTable() + { + } + + BEGIN_COM_MAP(CAccTable) + COM_INTERFACE_ENTRY(IAccessibleTable) + COM_INTERFACE_ENTRY(IAccessibleTable2) + COM_INTERFACE_ENTRY(IUNOXWrapper) + COM_INTERFACE_ENTRY_FUNC_BLIND(0,SmartQI_) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + static HRESULT WINAPI SmartQI_(void* pv, + REFIID iid, void** ppvObject, DWORD_PTR) + { + return static_cast<CAccTable*>(pv)->SmartQI(iid,ppvObject); + } + + HRESULT SmartQI(REFIID iid, void** ppvObject) + { + if( m_pOuterUnknown ) + return OuterQueryInterface(iid,ppvObject); + return E_FAIL; + } + + DECLARE_NO_REGISTRY() + +public: + // IAccessibleTable and IAccessibleTable2 + + // Gets accessible table cell (IAccessibleTable version). + STDMETHOD(get_accessibleAt)(long row, long column, IUnknown * * accessible) override; + + // Gets accessible table cell (IAccessibleTable2 version). + STDMETHOD(get_cellAt)(long row, long column, IUnknown * * cell) override; + + // Gets accessible table caption. + STDMETHOD(get_caption)(IUnknown * * accessible) override; + + // Gets accessible column description (as string). + STDMETHOD(get_columnDescription)(long column, BSTR * description) override; + + // Gets number of columns spanned by table cell. + STDMETHOD(get_columnExtentAt)(long row, long column, long * nColumnsSpanned) override; + + // Gets accessible column header. + STDMETHOD(get_columnHeader)(IAccessibleTable __RPC_FAR *__RPC_FAR *accessibleTable, long *startingRowIndex) override; + + // Gets total number of columns in table. + STDMETHOD(get_nColumns)(long * columnCount) override; + + // Gets total number of rows in table. + STDMETHOD(get_nRows)(long * rowCount) override; + + // Gets total number of selected columns. + STDMETHOD(get_nSelectedColumns)(long * columnCount) override; + + // Gets total number of selected rows. + STDMETHOD(get_nSelectedRows)(long * rowCount) override; + + // Gets accessible row description (as string). + STDMETHOD(get_rowDescription)(long row, BSTR * description) override; + + // Gets number of rows spanned by a table cell. + STDMETHOD(get_rowExtentAt)(long row, long column, long * nRowsSpanned) override; + + // Gets accessible row header. + STDMETHOD(get_rowHeader)(IAccessibleTable __RPC_FAR *__RPC_FAR *accessibleTable, long *startingColumnIndex) override; + + // Gets list of row indexes currently selected (0-based). + STDMETHOD(get_selectedRows)(long **rows, long * nRows) override; + STDMETHOD(get_selectedRows)(long maxRows, long **rows, long * nRows) override; + + // Gets list of column indexes currently selected (0-based). + STDMETHOD(get_selectedColumns)(long **columns, long * numColumns) override; + STDMETHOD(get_selectedColumns)(long maxColumns, long **columns, long * numColumns) override; + + // Gets accessible table summary. + STDMETHOD(get_summary)(IUnknown * * accessible) override; + + // Determines if table column is selected. + STDMETHOD(get_isColumnSelected)(long column, boolean * isSelected) override; + + // Determines if table row is selected. + STDMETHOD(get_isRowSelected)(long row, boolean * isSelected) override; + + // Determines if table cell is selected. + STDMETHOD(get_isSelected)(long row, long column, boolean * isSelected) override; + + // Selects a row and unselect all previously selected rows. + STDMETHOD(selectRow)(long row ) override; + + + // Selects a column and unselect all previously selected columns. + + STDMETHOD(selectColumn)(long column) override; + + // Unselects one row, leaving other selected rows selected (if any). + STDMETHOD(unselectRow)(long row) override; + + // Unselects one column, leaving other selected columns selected (if any). + STDMETHOD(unselectColumn)(long column) override; + + //get Column index + STDMETHOD(get_columnIndex)(long childIndex, long * columnIndex) override; + + STDMETHOD(get_rowIndex)(long childIndex, long * rowIndex) override; + + STDMETHOD(get_childIndex)(long rowIndex,long columnIndex, long * childIndex) override; + + // get total number of selected cells + STDMETHOD(get_nSelectedChildren)(long *childCount) override; + STDMETHOD(get_nSelectedCells)(long *childCount) override; + + STDMETHOD(get_selectedChildren)(long maxChildren, long **children, long *nChildren) override; + + // Returns a list of accessibles currently selected + STDMETHOD(get_selectedCells)(IUnknown * * * cells, long *nSelectedCells) override; + + STDMETHOD(get_rowColumnExtentsAtIndex)( long index, + long *row, + long *column, + long *rowExtents, + long *columnExtents, + boolean *isSelected) override; + + STDMETHOD(get_modelChange)(IA2TableModelChange *modelChange) override; + + // Override of IUNOXWrapper. + STDMETHOD(put_XInterface)(hyper pXInterface) override; + +private: + css::uno::Reference<css::accessibility::XAccessibleTable> pRXTable; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccTableCell.cxx b/winaccessibility/source/UAccCOM/AccTableCell.cxx new file mode 100644 index 0000000000..95725c2a40 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccTableCell.cxx @@ -0,0 +1,311 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "AccTableCell.h" +#include "MAccessible.h" + +#include <vcl/svapp.hxx> +#include <com/sun/star/accessibility/XAccessible.hpp> + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; + +CAccTableCell::CAccTableCell() + : m_nIndexInParent(0) +{ +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTableCell::put_XInterface(hyper pXInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + try + { + CUNOXWrapper::put_XInterface(pXInterface); + if (pUNOInterface == nullptr) + return E_INVALIDARG; + + Reference<XAccessibleContext> xContext = pUNOInterface->getAccessibleContext(); + if (!xContext.is()) + return E_FAIL; + + // retrieve reference to table (parent of the cell) + Reference<XAccessibleContext> xParentContext + = xContext->getAccessibleParent()->getAccessibleContext(); + Reference<XAccessibleTable> xTable(xParentContext, UNO_QUERY); + + if (!xTable.is()) + { + m_xTable.clear(); + return E_FAIL; + } + + m_xTable = xTable; + m_nIndexInParent = xContext->getAccessibleIndexInParent(); + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTableCell::get_columnExtent(long* pColumnsSpanned) +{ + SolarMutexGuard g; + + try + { + if (pColumnsSpanned == nullptr) + return E_INVALIDARG; + + if (!m_xTable.is()) + return E_FAIL; + + long nRow = 0, nColumn = 0; + get_rowIndex(&nRow); + get_columnIndex(&nColumn); + + *pColumnsSpanned = m_xTable->getAccessibleColumnExtentAt(nRow, nColumn); + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTableCell::get_columnHeaderCells(IUnknown*** cellAccessibles, + long* pColumnHeaderCellCount) +{ + SolarMutexGuard g; + + if (!cellAccessibles || !pColumnHeaderCellCount) + return E_INVALIDARG; + + if (!m_xTable.is()) + return E_FAIL; + + Reference<XAccessibleTable> xHeaders = m_xTable->getAccessibleColumnHeaders(); + if (!xHeaders.is()) + return E_FAIL; + + const sal_Int32 nCount = xHeaders->getAccessibleRowCount(); + *pColumnHeaderCellCount = nCount; + *cellAccessibles = static_cast<IUnknown**>(CoTaskMemAlloc(nCount * sizeof(IUnknown*))); + sal_Int32 nCol = 0; + get_columnIndex(&nCol); + for (sal_Int32 nRow = 0; nRow < nCount; nRow++) + { + Reference<XAccessible> xCell = xHeaders->getAccessibleCellAt(nRow, nCol); + assert(xCell.is()); + + IAccessible* pIAccessible = CMAccessible::get_IAccessibleFromXAccessible(xCell.get()); + if (!pIAccessible) + { + Reference<XAccessible> xTableAcc(m_xTable, UNO_QUERY); + CMAccessible::g_pAccObjectManager->InsertAccObj(xCell.get(), xTableAcc.get()); + pIAccessible = CMAccessible::get_IAccessibleFromXAccessible(xCell.get()); + } + assert(pIAccessible && "Couldn't retrieve IAccessible object for cell."); + + pIAccessible->AddRef(); + (*cellAccessibles)[nRow] = pIAccessible; + } + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTableCell::get_columnIndex(long* pColumnIndex) +{ + SolarMutexGuard g; + + try + { + if (pColumnIndex == nullptr) + return E_INVALIDARG; + + if (!m_xTable.is()) + return E_FAIL; + + *pColumnIndex = m_xTable->getAccessibleColumn(m_nIndexInParent); + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTableCell::get_rowExtent(long* pRowsSpanned) +{ + SolarMutexGuard g; + + try + { + if (pRowsSpanned == nullptr) + return E_INVALIDARG; + + if (!m_xTable.is()) + return E_FAIL; + + long nRow = 0, nColumn = 0; + get_rowIndex(&nRow); + get_columnIndex(&nColumn); + + *pRowsSpanned = m_xTable->getAccessibleRowExtentAt(nRow, nColumn); + + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTableCell::get_rowHeaderCells(IUnknown*** cellAccessibles, + long* pRowHeaderCellCount) +{ + SolarMutexGuard g; + + if (!cellAccessibles || !pRowHeaderCellCount) + return E_INVALIDARG; + + if (!m_xTable.is()) + return E_FAIL; + + Reference<XAccessibleTable> xHeaders = m_xTable->getAccessibleRowHeaders(); + if (!xHeaders.is()) + return E_FAIL; + + const sal_Int32 nCount = xHeaders->getAccessibleColumnCount(); + *pRowHeaderCellCount = nCount; + *cellAccessibles = static_cast<IUnknown**>(CoTaskMemAlloc(nCount * sizeof(IUnknown*))); + sal_Int32 nRow = 0; + get_rowIndex(&nRow); + for (sal_Int32 nCol = 0; nCol < nCount; nCol++) + { + Reference<XAccessible> xCell = xHeaders->getAccessibleCellAt(nRow, nCol); + assert(xCell.is()); + + IAccessible* pIAccessible = CMAccessible::get_IAccessibleFromXAccessible(xCell.get()); + if (!pIAccessible) + { + Reference<XAccessible> xTableAcc(m_xTable, UNO_QUERY); + CMAccessible::g_pAccObjectManager->InsertAccObj(xCell.get(), xTableAcc.get()); + pIAccessible = CMAccessible::get_IAccessibleFromXAccessible(xCell.get()); + } + assert(pIAccessible && "Couldn't retrieve IAccessible object for cell."); + + pIAccessible->AddRef(); + (*cellAccessibles)[nCol] = pIAccessible; + } + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTableCell::get_rowIndex(long* pRowIndex) +{ + SolarMutexGuard g; + + try + { + if (pRowIndex == nullptr) + return E_INVALIDARG; + + if (!m_xTable.is()) + return E_FAIL; + + *pRowIndex = m_xTable->getAccessibleRow(m_nIndexInParent); + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTableCell::get_isSelected(boolean* pIsSelected) +{ + SolarMutexGuard g; + + try + { + if (pIsSelected == nullptr) + return E_INVALIDARG; + + if (!m_xTable.is()) + return E_FAIL; + + long nRow = 0, nColumn = 0; + get_rowIndex(&nRow); + get_columnIndex(&nColumn); + + *pIsSelected = m_xTable->isAccessibleSelected(nRow, nColumn); + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTableCell::get_rowColumnExtents(long* pRow, long* pColumn, + long* pRowExtents, + long* pColumnExtents, + boolean* pIsSelected) +{ + SolarMutexGuard g; + + if (!pRow || !pColumn || !pRowExtents || !pColumnExtents || !pIsSelected) + return E_INVALIDARG; + + if (get_rowIndex(pRow) != S_OK) + return E_FAIL; + if (get_columnIndex(pColumn) != S_OK) + return E_FAIL; + if (get_rowExtent(pRowExtents) != S_OK) + return E_FAIL; + if (get_columnExtent(pColumnExtents) != S_OK) + return E_FAIL; + if (get_isSelected(pIsSelected) != S_OK) + return E_FAIL; + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTableCell::get_table(IUnknown** ppTable) +{ + if (!ppTable) + return E_INVALIDARG; + + if (!m_xTable.is()) + return E_FAIL; + + Reference<XAccessible> xAcc(m_xTable, UNO_QUERY); + if (!xAcc.is()) + return E_FAIL; + + IAccessible* pRet = CMAccessible::get_IAccessibleFromXAccessible(xAcc.get()); + if (!pRet) + return E_FAIL; + + *ppTable = pRet; + pRet->AddRef(); + return S_OK; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccTableCell.h b/winaccessibility/source/UAccCOM/AccTableCell.h new file mode 100644 index 0000000000..95250d53ad --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccTableCell.h @@ -0,0 +1,87 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "Resource.h" + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleTable.hpp> +#include "UNOXWrapper.h" + +/** + * CAccTableCell implements the IAccessibleTableCell interface. + */ +class ATL_NO_VTABLE CAccTableCell : public CComObjectRoot, + public CComCoClass<CAccTableCell, &CLSID_AccTableCell>, + public IAccessibleTableCell, + public CUNOXWrapper + +{ +public: + CAccTableCell(); + virtual ~CAccTableCell() {} + + BEGIN_COM_MAP(CAccTableCell) + COM_INTERFACE_ENTRY(IAccessibleTableCell) + COM_INTERFACE_ENTRY(IUNOXWrapper) + COM_INTERFACE_ENTRY_FUNC_BLIND(0, SmartQI_) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + static HRESULT WINAPI SmartQI_(void* pv, REFIID iid, void** ppvObject, DWORD_PTR) + { + return static_cast<CAccTableCell*>(pv)->SmartQI(iid, ppvObject); + } + + HRESULT SmartQI(REFIID iid, void** ppvObject) + { + if (m_pOuterUnknown) + return OuterQueryInterface(iid, ppvObject); + return E_FAIL; + } + + DECLARE_NO_REGISTRY() + +public: + STDMETHOD(put_XInterface)(hyper pXInterface) override; + + // IAccessibleTableCell interfaces + STDMETHOD(get_columnExtent)(long*) override; + STDMETHOD(get_columnHeaderCells)(IUnknown***, long*) override; + STDMETHOD(get_columnIndex)(long*) override; + STDMETHOD(get_rowExtent)(long*) override; + STDMETHOD(get_rowHeaderCells)(IUnknown***, long*) override; + STDMETHOD(get_rowIndex)(long*) override; + STDMETHOD(get_isSelected)(boolean*) override; + STDMETHOD(get_rowColumnExtents)(long*, long*, long*, long*, boolean*) override; + STDMETHOD(get_table)(IUnknown**) override; + +private: + css::uno::Reference<css::accessibility::XAccessibleTable> m_xTable; + sal_Int64 m_nIndexInParent; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccText.cxx b/winaccessibility/source/UAccCOM/AccText.cxx new file mode 100644 index 0000000000..0cddc52a8f --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccText.cxx @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" +#include <UAccCOM.h> +#include "AccText.h" + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; + +/** + * Get special selection. + * @param startOffset Start selection offset. + * @param endOffset End selection offset. + * @param success Variant to accept the result of if the method call is successful. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::addSelection(long startOffset, long endOffset)//, unsigned char * success) +{ + + return CAccTextBase::get_addSelection(startOffset, endOffset);//, success); +} + +/** + * Get special attributes. + * @param offset Offset. + * @param startOffset Variant to accept start offset. + * @param endOffset Variant to accept end offset. + * @param textAttributes Variant to accept attributes. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_attributes(long offset, long * startOffset, long * endOffset, BSTR * textAttributes) +{ + + return CAccTextBase::get_attributes(offset, startOffset, endOffset, textAttributes); +} + +/** + * Get caret position. + * @param offset Variant to accept caret offset. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_caretOffset(long * offset) +{ + + return CAccTextBase::get_caretOffset(offset); +} + +/** + * Get character extents. + * @param offset Offset. + * @param x Variant to accept x position. + * @param y Variant to accept y position. + * @param width Variant to accept width. + * @param Height Variant to accept height. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_characterExtents(long offset, IA2CoordinateType coordType, long * x, long * y, long * width, long * height) +{ + + return CAccTextBase::get_characterExtents(offset, coordType, x, y, width, height); +} + +/** + * Get selections count. + * @param nSelections Variant to accept selections count. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_nSelections(long * nSelections) +{ + + return CAccTextBase::get_nSelections(nSelections); +} + +/** + * Get offset of some special point. + * @param x X position of one point. + * @param x Y position of one point. + * @param coordType Type. + * @param offset Variant to accept offset. + * @return Result. +*/ + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_offsetAtPoint(long x, long y, IA2CoordinateType coordType, long * offset) +{ + + return CAccTextBase::get_offsetAtPoint(x, y, coordType, offset); +} + +/** + * Get selection range. + * @param selection selection count. + * @param startOffset Variant to accept the start offset of special selection. + * @param endOffset Variant to accept the end offset of special selection. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_selection(long selection, long * startOffset, long * endOffset) +{ + + return CAccTextBase::get_selection(selection, startOffset, endOffset); +} + +/** + * Get special text. + * @param startOffset Start position of special range. + * @param endOffset End position of special range. + * @param text Variant to accept the text of special range. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_text(long startOffset, long endOffset, BSTR * text) +{ + + return CAccTextBase::get_text(startOffset, endOffset, text); +} + +/** + * Get special text before some position. + * @param offset Special position. + * @param boundaryType Boundary type. + * @param startOffset Variant to accept the start offset. + * @param endOffset Variant to accept the end offset. + * @param text Variant to accept the special text. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_textBeforeOffset(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) +{ + + return CAccTextBase::get_textBeforeOffset(offset, boundaryType, + startOffset, endOffset, text); +} + +/** + * Get special text after some position. + * @param offset Special position. + * @param boundaryType Boundary type. + * @param startOffset Variant to accept the start offset. + * @param endOffset Variant to accept the end offset. + * @param text Variant to accept the special text. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_textAfterOffset(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) +{ + + return CAccTextBase::get_textAfterOffset(offset, boundaryType, + startOffset, endOffset, text); +} + +/** + * Get special text at some position. + * @param offset Special position. + * @param boundaryType Boundary type. + * @param startOffset Variant to accept the start offset. + * @param endOffset Variant to accept the end offset. + * @param text Variant to accept the special text. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_textAtOffset(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) +{ + + return CAccTextBase::get_textAtOffset(offset, boundaryType, + startOffset, endOffset, text); +} + +/** + * Remove selection. + * @param selectionIndex Special selection index + * @param success Variant to accept the method called result. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::removeSelection(long selectionIndex)//, unsigned char * success) +{ + + return CAccTextBase::removeSelection(selectionIndex);//, success); +} + +/** + * Set caret position. + * @param offset Special position. + * @param success Variant to accept the method called result. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::setCaretOffset(long offset) +{ + + return CAccTextBase::setCaretOffset(offset); +} + +/** + * Set special selection. + * @param selectionIndex Special selection index. + * @param startOffset start position. + * @param endOffset end position. + * @param success Variant to accept the method called result. + * @return Result. +*/ + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::setSelection(long selectionIndex, long startOffset, long endOffset) +{ + + return CAccTextBase::setSelection(selectionIndex, startOffset, + endOffset); +} + +/** + * Get characters count. + * @param nCharacters Variant to accept the characters count. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_nCharacters(long * nCharacters) +{ + + return CAccTextBase::get_nCharacters(nCharacters); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_newText( IA2TextSegment *newText) +{ + return CAccTextBase::get_newText(newText); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::get_oldText( IA2TextSegment *oldText) +{ + return CAccTextBase::get_oldText(oldText); +} + +/** + * Scroll to special sub-string . + * @param startIndex Start index of sub string. + * @param endIndex End index of sub string. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::scrollSubstringToPoint(long startIndex, long endIndex,enum IA2CoordinateType coordinateType, long x, long y ) +{ + + return CAccTextBase::scrollSubstringToPoint(startIndex, endIndex, coordinateType, x, y); +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccText::scrollSubstringTo(long startIndex, long endIndex,enum IA2ScrollType scrollType) +{ + + return CAccTextBase::scrollSubstringTo(startIndex, endIndex,scrollType); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccText.h b/winaccessibility/source/UAccCOM/AccText.h new file mode 100644 index 0000000000..eba821aae8 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccText.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "Resource.h" // main symbols + +#include "AccTextBase.h" + +/** + * CAccText implements IAccessibleText interface. + */ +class ATL_NO_VTABLE CAccText : + public CComObjectRoot, + public CComCoClass<CAccText,&CLSID_AccText>, + public IAccessibleText, + public CAccTextBase +{ +public: + CAccText() + { + } + + BEGIN_COM_MAP(CAccText) + COM_INTERFACE_ENTRY(IAccessibleText) + COM_INTERFACE_ENTRY(IUNOXWrapper) + COM_INTERFACE_ENTRY_FUNC_BLIND(0,SmartQI_) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + static HRESULT WINAPI SmartQI_(void* pv, + REFIID iid, void** ppvObject, DWORD_PTR) + { + return static_cast<CAccText*>(pv)->SmartQI(iid,ppvObject); + } + + HRESULT SmartQI(REFIID iid, void** ppvObject) + { + if( m_pOuterUnknown ) + return OuterQueryInterface(iid,ppvObject); + return E_FAIL; + } + + DECLARE_NO_REGISTRY() + +public: + // IAccessibleText + + // Adds a text selection. + STDMETHOD(addSelection)(long startOffset, long endOffset) override;//, unsigned char * success); + + // Gets text attributes. + STDMETHOD(get_attributes)(long offset, long * startOffset, long * endOffset, BSTR * textAttributes) override; + + // Gets caret offset. + STDMETHOD(get_caretOffset)(long * offset) override; + + // Gets bounding rect containing the glyph(s) representing the character + // at the specified text offset + STDMETHOD(get_characterExtents)(long offset, IA2CoordinateType coordType, long * x, long * y, long * width, long * height) override; + + // Gets number of active non-contiguous selections. + STDMETHOD(get_nSelections)(long * nSelections) override; + + // Gets bounding rect for the glyph at a certain point. + STDMETHOD(get_offsetAtPoint)(long x, long y, IA2CoordinateType coordType, long * offset) override; + + // Gets character offsets of N-th active text selection. + STDMETHOD(get_selection)(long selection, long * startOffset, long * endOffset) override; + + // Gets a range of text by offset NOTE: returned string may be longer + // than endOffset-startOffset bytes if text contains multi-byte characters. + STDMETHOD(get_text)(long startOffset, long endOffset, BSTR * text) override; + + // Gets a specified amount of text that ends before a specified offset. + STDMETHOD(get_textBeforeOffset)(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) override; + + // Gets a specified amount of text that spans the specified offset. + STDMETHOD(get_textAfterOffset)(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) override; + + // Gets a specified amount of text that starts after a specified offset. + STDMETHOD(get_textAtOffset)(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) override; + + // Unselects a range of text. + STDMETHOD(removeSelection)(long selectionIndex) override;//, unsigned char * success); + + // Moves text caret. + STDMETHOD(setCaretOffset)(long offset) override;//, unsigned char * success); + + // Changes the bounds of an existing selection. + STDMETHOD(setSelection)(long selectionIndex, long startOffset, long endOffset) override;//, unsigned char * success); + + // Gets total number of characters. + // NOTE: this may be different than the total number of bytes required + // to store the text, if the text contains multi-byte characters. + STDMETHOD(get_nCharacters)(long * nCharacters) override; + + // Makes specific part of string visible on screen. + STDMETHOD(scrollSubstringTo)(long startIndex, long endIndex,enum IA2ScrollType scrollType) override; + STDMETHOD(scrollSubstringToPoint)(long startIndex, long endIndex,enum IA2CoordinateType coordinateType, long x, long y ) override; + + STDMETHOD(get_newText)( IA2TextSegment *newText) override; + + STDMETHOD(get_oldText)( IA2TextSegment *oldText) override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccTextBase.cxx b/winaccessibility/source/UAccCOM/AccTextBase.cxx new file mode 100644 index 0000000000..a50cee9dd4 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccTextBase.cxx @@ -0,0 +1,810 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +// AccTextBase.cpp: implementation of the CAccTextBase class. + +#include "stdafx.h" + +#include "AccTextBase.h" + +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <vcl/accessibility/AccessibleTextAttributeHelper.hxx> +#include <vcl/svapp.hxx> +#include <o3tl/char16_t2wchar_t.hxx> + +#include <com/sun/star/accessibility/AccessibleScrollType.hpp> +#include <com/sun/star/accessibility/AccessibleTextType.hpp> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleTextSelection.hpp> +#include "MAccessible.h" + +using namespace css::accessibility; +using namespace css::uno; + +namespace +{ +sal_Int16 lcl_matchIA2TextBoundaryType(IA2TextBoundaryType boundaryType) +{ + switch (boundaryType) + { + case IA2_TEXT_BOUNDARY_CHAR: + return com::sun::star::accessibility::AccessibleTextType::CHARACTER; + case IA2_TEXT_BOUNDARY_WORD: + return com::sun::star::accessibility::AccessibleTextType::WORD; + case IA2_TEXT_BOUNDARY_SENTENCE: + return com::sun::star::accessibility::AccessibleTextType::SENTENCE; + case IA2_TEXT_BOUNDARY_PARAGRAPH: + return com::sun::star::accessibility::AccessibleTextType::PARAGRAPH; + case IA2_TEXT_BOUNDARY_LINE: + return com::sun::star::accessibility::AccessibleTextType::LINE; + case IA2_TEXT_BOUNDARY_ALL: + // assert here, better handle it directly at call site + assert(false + && "No match for IA2_TEXT_BOUNDARY_ALL, handle at call site."); + break; + default: + break; + } + + SAL_WARN("iacc2", "Unmatched text boundary type: " << boundaryType); + return -1; +} +} + + +// Construction/Destruction + + +CAccTextBase::CAccTextBase() +{} + +CAccTextBase::~CAccTextBase() +{} + + +/** + * Get special selection. + * @param startOffset Start selection offset. + * @param endOffset End selection offset. + * @param success Variant to accept the result of if the method call is successful. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_addSelection(long startOffset, long endOffset) +{ + SolarMutexGuard g; + + try { + + if(pUNOInterface == nullptr) + return E_FAIL; + + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + + Reference< XAccessibleTextSelection > pRExtension(pRContext,UNO_QUERY); + + if( pRExtension.is() ) + { + pRExtension->addSelection(0, startOffset, endOffset); + return S_OK; + } + else + { + pRXText->setSelection(startOffset, endOffset); + return S_OK; + } + + } catch(...) { return E_FAIL; } +} + +/** + * Get special attributes. + * @param offset Offset. + * @param startOffset Variant to accept start offset. + * @param endOffset Variant to accept end offset. + * @param textAttributes Variant to accept attributes. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_attributes(long offset, long * startOffset, long * endOffset, BSTR * textAttributes) +{ + SolarMutexGuard g; + + try { + + if (startOffset == nullptr || endOffset == nullptr || textAttributes == nullptr) + return E_INVALIDARG; + + if(!pRXText.is()) + { + return E_FAIL; + } + + if (offset < 0 || offset > pRXText->getCharacterCount() ) + return E_FAIL; + + + const OUString sAttrs = AccessibleTextAttributeHelper::GetIAccessible2TextAttributes(pRXText, + IA2AttributeType::TextAttributes, + offset, *startOffset, *endOffset); + + if(*textAttributes) + SysFreeString(*textAttributes); + *textAttributes = SysAllocString(o3tl::toW(sAttrs.getStr())); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get caret position. + * @param offset Variant to accept caret offset. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_caretOffset(long * offset) +{ + SolarMutexGuard g; + + try { + + if (offset == nullptr) + return E_INVALIDARG; + + if(!pRXText.is()) + { + *offset = 0; + return S_OK; + } + + *offset = pRXText->getCaretPosition(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get character count. + * @param nCharacters Variant to accept character count. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_characterCount(long * nCharacters) +{ + SolarMutexGuard g; + + try { + + if (nCharacters == nullptr) + return E_INVALIDARG; + + if(!pRXText.is()) + { + *nCharacters = 0; + return S_OK; + } + + *nCharacters = pRXText->getCharacterCount(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get character extents. + * @param offset Offset. + * @param x Variant to accept x position. + * @param y Variant to accept y position. + * @param width Variant to accept width. + * @param Height Variant to accept height. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_characterExtents(long offset, IA2CoordinateType coordType, long * x, long * y, long * width, long * height) +{ + SolarMutexGuard g; + + try { + + if (x == nullptr || height == nullptr || y == nullptr || width == nullptr) + return E_INVALIDARG; + + if(!pRXText.is()) + return E_FAIL; + + if (offset < 0 || offset > pRXText->getCharacterCount()) + return E_FAIL; + + css::awt::Rectangle rectangle; + rectangle = pRXText->getCharacterBounds(offset); + + //IA2Point aPoint; + css::awt::Point aPoint; + + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + if( !pRContext.is() ) + { + return E_FAIL; + } + Reference<XAccessibleComponent> pRComp(pRContext,UNO_QUERY); + if( pRComp.is() ) + { + if(coordType == IA2_COORDTYPE_SCREEN_RELATIVE) + { + css::awt::Point pt = pRComp->getLocationOnScreen(); + aPoint.X = pt.X; + aPoint.Y = pt.Y; + } + else if(coordType == IA2_COORDTYPE_PARENT_RELATIVE) + { + css::awt::Point pt = pRComp->getLocation(); + aPoint.X = pt.X; + aPoint.Y = pt.Y; + } + } + rectangle.X = rectangle.X + aPoint.X; + rectangle.Y = rectangle.Y + aPoint.Y; + + *x = rectangle.X; + *y = rectangle.Y; + + // pRXText->getCharacterBounds() have different implement in different acc component + // But we need return the width/height == 1 for every component when offset == text length. + // So we ignore the return result of pRXText->getCharacterBounds() when offset == text length. + if (offset == pRXText->getCharacterCount()) + { + *width = 1; + *height = 1; + } + else + { + *width = rectangle.Width; + *height = rectangle.Height; + } + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get selections count. + * @param nSelections Variant to accept selections count. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_nSelections(long * nSelections) +{ + SolarMutexGuard g; + + try { + + if (nSelections == nullptr) + return E_INVALIDARG; + + if(pUNOInterface == nullptr) + { + *nSelections = 0; + return S_OK; + } + + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + + Reference< XAccessibleTextSelection > pRExtension(pRContext,UNO_QUERY); + + if( pRExtension.is() ) + { + *nSelections = pRExtension->getSelectedPortionCount(); + return S_OK; + } + + long iLength = pRXText->getSelectedText().getLength(); + if( iLength> 0) + { + *nSelections = 1; + return S_OK; + } + + *nSelections = 0; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get offset of some special point. + * @param x X position of one point. + * @param x Y position of one point. + * @param coordType Type. + * @param offset Variant to accept offset. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_offsetAtPoint(long x, long y, IA2CoordinateType coordType, long * offset) +{ + SolarMutexGuard g; + + try { + + if (offset == nullptr) + return E_INVALIDARG; + + if(!pRXText.is()) + return E_FAIL; + + css::awt::Point point; + point.X = x; + point.Y = y; + + if (coordType == IA2_COORDTYPE_SCREEN_RELATIVE) + { + // convert from screen to local coordinates + Reference<XAccessibleContext> xContext = pUNOInterface->getAccessibleContext(); + Reference<XAccessibleComponent> xComponent(xContext, UNO_QUERY); + if (!xComponent.is()) + return S_FALSE; + + css::awt::Point aObjectPos = xComponent->getLocationOnScreen(); + point.X -= aObjectPos.X; + point.Y -= aObjectPos.Y; + } + + *offset = pRXText->getIndexAtPoint(point); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get selection range. + * @param selection selection count. + * @param startOffset Variant to accept the start offset of special selection. + * @param endOffset Variant to accept the end offset of special selection. + * @return Result. +*/ + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_selection(long selectionIndex, long * startOffset, long * endOffset) +{ + SolarMutexGuard g; + + try { + + if (startOffset == nullptr || endOffset == nullptr ) + return E_INVALIDARG; + + if(pUNOInterface == nullptr ) + return E_FAIL; + + long nSelection = 0; + get_nSelections(&nSelection); + + if(selectionIndex >= nSelection || selectionIndex < 0 ) + return E_FAIL; + + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + + Reference< XAccessibleTextSelection > pRExtension(pRContext,UNO_QUERY); + + if( pRExtension.is() ) + { + *startOffset = pRExtension->getSeletedPositionStart(selectionIndex); + *endOffset = pRExtension->getSeletedPositionEnd(selectionIndex); + return S_OK; + } + else if (pRXText->getSelectionEnd() > -1) + { + *startOffset = pRXText->getSelectionStart(); + *endOffset = pRXText->getSelectionEnd(); + return S_OK; + } + + *startOffset = 0; + *endOffset = 0; + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** + * Get special text. + * @param startOffset Start position of special range. + * @param endOffset End position of special range. + * @param text Variant to accept the text of special range. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_text(long startOffset, long endOffset, BSTR * text) +{ + SolarMutexGuard g; + + try { + + if (text == nullptr) + return E_INVALIDARG; + + if(!pRXText.is()) + return E_FAIL; + + if (endOffset < -1 || endOffset < startOffset ) + { + return E_FAIL; + } + + OUString ouStr; + if (endOffset == -1 ) + { + long nLen=0; + if(SUCCEEDED(get_characterCount(&nLen))) + { + ouStr = pRXText->getTextRange(0, nLen); + } + } + else + { + ouStr = pRXText->getTextRange(startOffset, endOffset); + } + + SysFreeString(*text); + *text = SysAllocString(o3tl::toW(ouStr.getStr())); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get special text before some position. + * @param offset Special position. + * @param boundaryType Boundary type. + * @param startOffset Variant to accept the start offset. + * @param endOffset Variant to accept the end offset. + * @param text Variant to accept the special text. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_textBeforeOffset(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) +{ + SolarMutexGuard g; + + try { + + if (startOffset == nullptr || endOffset == nullptr || text == nullptr) + return E_INVALIDARG; + + if(!pRXText.is()) + return E_FAIL; + + if (boundaryType == IA2_TEXT_BOUNDARY_ALL) + { + long nChar; + get_nCharacters( &nChar ); + *startOffset = 0; + *endOffset = nChar; + return get_text(0, nChar, text); + } + + const sal_Int16 nUnoBoundaryType = lcl_matchIA2TextBoundaryType(boundaryType); + if (nUnoBoundaryType < 0) + return E_FAIL; + + TextSegment segment = pRXText->getTextBeforeIndex(offset, nUnoBoundaryType); + OUString ouStr = segment.SegmentText; + SysFreeString(*text); + *text = SysAllocString(o3tl::toW(ouStr.getStr())); + *startOffset = segment.SegmentStart; + *endOffset = segment.SegmentEnd; + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get special text after some position. + * @param offset Special position. + * @param boundaryType Boundary type. + * @param startOffset Variant to accept the start offset. + * @param endOffset Variant to accept the end offset. + * @param text Variant to accept the special text. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_textAfterOffset(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) +{ + SolarMutexGuard g; + + try { + + if (startOffset == nullptr || endOffset == nullptr || text == nullptr) + return E_INVALIDARG; + + if(!pRXText.is()) + return E_FAIL; + + if (boundaryType == IA2_TEXT_BOUNDARY_ALL) + { + long nChar; + get_nCharacters( &nChar ); + *startOffset = 0; + *endOffset = nChar; + return get_text(0, nChar, text); + } + + const sal_Int16 nUnoBoundaryType = lcl_matchIA2TextBoundaryType(boundaryType); + if (nUnoBoundaryType < 0) + return E_FAIL; + + TextSegment segment = pRXText->getTextBehindIndex(offset, nUnoBoundaryType); + OUString ouStr = segment.SegmentText; + SysFreeString(*text); + *text = SysAllocString(o3tl::toW(ouStr.getStr())); + *startOffset = segment.SegmentStart; + *endOffset = segment.SegmentEnd; + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get special text at some position. + * @param offset Special position. + * @param boundaryType Boundary type. + * @param startOffset Variant to accept the start offset. + * @param endOffset Variant to accept the end offset. + * @param text Variant to accept the special text. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_textAtOffset(long offset, IA2TextBoundaryType boundaryType, long * startOffset, long * endOffset, BSTR * text) +{ + SolarMutexGuard g; + + try { + + if (startOffset == nullptr || text == nullptr ||endOffset == nullptr) + return E_INVALIDARG; + + if(!pRXText.is()) + return E_FAIL; + + if (boundaryType == IA2_TEXT_BOUNDARY_ALL) + { + long nChar; + get_nCharacters( &nChar ); + *startOffset = 0; + *endOffset = nChar; + return get_text(0, nChar, text); + } + + const sal_Int16 nUnoBoundaryType = lcl_matchIA2TextBoundaryType(boundaryType); + if (nUnoBoundaryType < 0) + return E_FAIL; + + TextSegment segment = pRXText->getTextAtIndex(offset, nUnoBoundaryType); + OUString ouStr = segment.SegmentText; + SysFreeString(*text); + *text = SysAllocString(o3tl::toW(ouStr.getStr())); + *startOffset = segment.SegmentStart; + *endOffset = segment.SegmentEnd; + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Remove selection. + * @param selectionIndex Special selection index + * @param success Variant to accept the method called result. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::removeSelection(long selectionIndex) +{ + SolarMutexGuard g; + + try { + + if(pUNOInterface == nullptr) + { + return E_FAIL; + } + + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + + Reference< XAccessibleTextSelection > pRExtension(pRContext,UNO_QUERY); + + if( pRExtension.is() ) + { + pRExtension->removeSelection(selectionIndex); + return S_OK; + } + else + { + pRXText->setSelection(0, 0); + return S_OK; + } + + } catch(...) { return E_FAIL; } +} + +/** + * Set caret position. + * @param offset Special position. + * @param success Variant to accept the method called result. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::setCaretOffset(long offset) +{ + SolarMutexGuard g; + + try { + + if(!pRXText.is()) + return E_FAIL; + + pRXText->setCaretPosition(offset); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Set special selection. + * @param selectionIndex Special selection index. + * @param startOffset start position. + * @param endOffset end position. + * @param success Variant to accept the method called result. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::setSelection(long, long startOffset, long endOffset) +{ + SolarMutexGuard g; + + try { + + if(!pRXText.is()) + { + return E_FAIL; + } + + pRXText->setSelection(startOffset, endOffset); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** + * Get characters count. + * @param nCharacters Variant to accept the characters count. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_nCharacters(long * nCharacters) +{ + SolarMutexGuard g; + + try { + + if (nCharacters == nullptr) + return E_INVALIDARG; + + if(!pRXText.is()) + { + *nCharacters = 0; + return S_OK; + } + + *nCharacters = pRXText->getCharacterCount(); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +// added by qiuhd, 2006/07/03, for direver 07/11 +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_newText( IA2TextSegment *) +{ + return E_NOTIMPL; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::get_oldText( IA2TextSegment *) +{ + return E_NOTIMPL; +} + +/** + * Scroll to special sub-string . + * @param startIndex Start index of sub string. + * @param endIndex End index of sub string. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::scrollSubstringToPoint(long, long, IA2CoordinateType, long, long ) +{ + return E_NOTIMPL; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::scrollSubstringTo(long startIndex, long endIndex, IA2ScrollType type) +{ + SolarMutexGuard g; + + try { + + if(!pRXText.is()) + return E_FAIL; + + AccessibleScrollType lUnoType; + + switch(type) + { + case IA2_SCROLL_TYPE_TOP_LEFT: + lUnoType = AccessibleScrollType_SCROLL_TOP_LEFT; + break; + case IA2_SCROLL_TYPE_BOTTOM_RIGHT: + lUnoType = AccessibleScrollType_SCROLL_BOTTOM_RIGHT; + break; + case IA2_SCROLL_TYPE_TOP_EDGE: + lUnoType = AccessibleScrollType_SCROLL_TOP_EDGE; + break; + case IA2_SCROLL_TYPE_BOTTOM_EDGE: + lUnoType = AccessibleScrollType_SCROLL_BOTTOM_EDGE; + break; + case IA2_SCROLL_TYPE_LEFT_EDGE: + lUnoType = AccessibleScrollType_SCROLL_LEFT_EDGE; + break; + case IA2_SCROLL_TYPE_RIGHT_EDGE: + lUnoType = AccessibleScrollType_SCROLL_RIGHT_EDGE; + break; + case IA2_SCROLL_TYPE_ANYWHERE: + lUnoType = AccessibleScrollType_SCROLL_ANYWHERE; + break; + default: + return E_NOTIMPL; + } + + if (pRXText->scrollSubstringTo(startIndex, endIndex, lUnoType)) + return S_OK; + + return E_NOTIMPL; + + } catch(...) { return E_FAIL; } +} + +/** + * Put UNO interface. + * @param pXInterface UNO interface. + * @return Result. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccTextBase::put_XInterface(hyper pXInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + try { + + CUNOXWrapper::put_XInterface(pXInterface); + //special query. + if(pUNOInterface == nullptr) + return E_FAIL; + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + if( !pRContext.is() ) + { + return E_FAIL; + } + Reference<XAccessibleText> pRXI(pRContext,UNO_QUERY); + pRXText = pRXI; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccTextBase.h b/winaccessibility/source/UAccCOM/AccTextBase.h new file mode 100644 index 0000000000..50d50cb077 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccTextBase.h @@ -0,0 +1,111 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// AccTextBase.h: interface for the CAccTextBase class. + +#pragma once + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleText.hpp> +#include "UNOXWrapper.h" + +class ATL_NO_VTABLE CAccTextBase : public CUNOXWrapper +{ +public: + CAccTextBase(); + virtual ~CAccTextBase(); + + // IAccessibleText +public: + // IAccessibleText + + // Adds a text selection. + STDMETHOD(get_addSelection)(long startOffset, long endOffset); + + // Gets text attributes. + STDMETHOD(get_attributes) + (long offset, long* startOffset, long* endOffset, BSTR* textAttributes); + + // Gets caret offset. + STDMETHOD(get_caretOffset)(long* offset); + + // Gets total number of characters. + STDMETHOD(get_characterCount)(long* nCharacters); + + // Gets bounding rect containing the glyph(s) representing the character + // at the specified text offset + STDMETHOD(get_characterExtents) + (long offset, IA2CoordinateType coordType, long* x, long* y, long* width, long* height); + + // Gets number of active non-contiguous selections. + STDMETHOD(get_nSelections)(long* nSelections); + + // Gets bounding rect for the glyph at a certain point. + STDMETHOD(get_offsetAtPoint)(long x, long y, IA2CoordinateType coordType, long* offset); + + // Gets character offsets of N-th active text selection. + STDMETHOD(get_selection)(long selectionIndex, long* startOffset, long* endOffset); + + // Gets a range of text by offset NOTE: returned string may be longer + // than endOffset-startOffset bytes if text contains multi-byte characters. + STDMETHOD(get_text)(long startOffset, long endOffset, BSTR* text); + + // Gets a specified amount of text that ends before a specified offset. + STDMETHOD(get_textBeforeOffset) + (long offset, IA2TextBoundaryType boundaryType, long* startOffset, long* endOffset, BSTR* text); + + // Gets a specified amount of text that spans the specified offset. + STDMETHOD(get_textAfterOffset) + (long offset, IA2TextBoundaryType boundaryType, long* startOffset, long* endOffset, BSTR* text); + + // Gets a specified amount of text that starts after a specified offset. + STDMETHOD(get_textAtOffset) + (long offset, IA2TextBoundaryType boundaryType, long* startOffset, long* endOffset, BSTR* text); + + // Unselects a range of text. + STDMETHOD(removeSelection)(long selectionIndex); + + // Moves text caret. + STDMETHOD(setCaretOffset)(long offset); + + // Changes the bounds of an existing selection. + STDMETHOD(setSelection)(long selectionIndex, long startOffset, long endOffset); + + // Gets total number of characters. + // NOTE: this may be different than the total number of bytes required + // to store the text, if the text contains multi-byte characters. + STDMETHOD(get_nCharacters)(long* nCharacters); + + STDMETHOD(get_newText)(IA2TextSegment* newText); + + STDMETHOD(get_oldText)(IA2TextSegment* oldText); + + // Makes specific part of string visible on screen. + STDMETHOD(scrollSubstringTo)(long startIndex, long endIndex, enum IA2ScrollType scrollType); + STDMETHOD(scrollSubstringToPoint) + (long startIndex, long endIndex, enum IA2CoordinateType coordinateType, long x, long y); + + // Override of IUNOXWrapper. + STDMETHOD(put_XInterface)(hyper pXInterface) override; + +private: + css::uno::Reference<css::accessibility::XAccessibleText> pRXText; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccValue.cxx b/winaccessibility/source/UAccCOM/AccValue.cxx new file mode 100644 index 0000000000..8465fb5718 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccValue.cxx @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" +#include <UAccCOM.h> +#include "AccValue.h" +#include "MAccessible.h" + +#include <vcl/svapp.hxx> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleContext.hpp> + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; + +/** + * Get current value. + * @param currentValue Variant that accepts current value. + * @return Result. + */ + +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccValue::get_currentValue(VARIANT* currentValue) +{ + SolarMutexGuard g; + + try + { + if (currentValue == nullptr) + return E_INVALIDARG; + if (!pRXVal.is()) + return E_FAIL; + + // Get Any type value from UNO. + css::uno::Any anyVal = GetXInterface()->getCurrentValue(); + // Convert Any to VARIANT. + CMAccessible::ConvertAnyToVariant(anyVal, currentValue); + + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +/** + * Set current value. + * @param Value New value should be set. + * @param success If the method is successfully called. + * @return Result. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccValue::setCurrentValue(VARIANT value) +{ + SolarMutexGuard g; + + try + { + if (!pRXVal.is()) + return E_FAIL; + + HRESULT hRet = S_OK; + css::uno::Any anyVal; + + // Set value according to value type. + switch (value.vt) + { + case VT_UI1: + { + anyVal <<= sal_Unicode(value.bVal); + } + break; + + case VT_BOOL: + { + css::uno::Type typeInfo(TypeClass_BOOLEAN, "bool"); + anyVal.setValue(&value.boolVal, typeInfo); + } + break; + + case VT_I2: + { + css::uno::Type typeInfo(TypeClass_SHORT, "short"); + anyVal.setValue(&value.iVal, typeInfo); + } + break; + + case VT_I4: + { + css::uno::Type typeInfo(TypeClass_LONG, "long"); + anyVal.setValue(&value.lVal, typeInfo); + } + break; + + case VT_R4: + { + css::uno::Type typeInfo(TypeClass_FLOAT, "float"); + anyVal.setValue(&value.fltVal, typeInfo); + } + break; + + case VT_R8: + { + css::uno::Type typeInfo(TypeClass_DOUBLE, "double"); + anyVal.setValue(&value.dblVal, typeInfo); + } + break; + + default: + { + // Unsupported type conversion. + hRet = E_FAIL; + } + break; + } + + if (hRet == S_OK) + { + hRet = pRXVal->setCurrentValue(anyVal) ? S_OK : E_FAIL; + } + + return hRet; + } + catch (...) + { + return E_FAIL; + } +} + +/** + * Get maximum value. + * @param maximumValue Variant that accepts maximum value. + * @return Result. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccValue::get_maximumValue(VARIANT* maximumValue) +{ + SolarMutexGuard g; + + try + { + if (maximumValue == nullptr) + return E_INVALIDARG; + if (!pRXVal.is()) + return E_FAIL; + + // Get Any type value from UNO. + css::uno::Any anyVal = GetXInterface()->getMaximumValue(); + // Convert Any to VARIANT. + CMAccessible::ConvertAnyToVariant(anyVal, maximumValue); + + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +/** + * Get minimum value. + * @param minimumValue Variant that accepts minimum value. + * @return Result. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccValue::get_minimumValue(VARIANT* minimumValue) +{ + SolarMutexGuard g; + + try + { + if (minimumValue == nullptr) + return E_FAIL; + if (!pRXVal.is()) + return E_FAIL; + + // Get Any type value from UNO. + css::uno::Any anyVal = GetXInterface()->getMinimumValue(); + // Convert Any to VARIANT. + CMAccessible::ConvertAnyToVariant(anyVal, minimumValue); + + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +/** + * Put valid UNO interface into com class. + * @param pXInterface UNO interface. + * @return Result. + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CAccValue::put_XInterface(hyper pXInterface) +{ + // internal IUNOXWrapper - no mutex meeded + + try + { + CUNOXWrapper::put_XInterface(pXInterface); + //special query. + if (pUNOInterface == nullptr) + return E_FAIL; + Reference<XAccessibleContext> pRContext = pUNOInterface->getAccessibleContext(); + if (!pRContext.is()) + { + return E_FAIL; + } + Reference<XAccessibleValue> pRXI(pRContext, UNO_QUERY); + if (!pRXI.is()) + pRXVal = nullptr; + else + pRXVal = pRXI.get(); + return S_OK; + } + catch (...) + { + return E_FAIL; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccValue.h b/winaccessibility/source/UAccCOM/AccValue.h new file mode 100644 index 0000000000..056eeb2619 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccValue.h @@ -0,0 +1,102 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "Resource.h" // main symbols + +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/accessibility/XAccessibleValue.hpp> +#include "UNOXWrapper.h" + +/** + * CAccValue implements IAccessibleValue interface. + */ +class CAccValue : + public CComObjectRoot, + public CComCoClass<CAccValue,&CLSID_AccValue>, + public IAccessibleValue, + public CUNOXWrapper +{ +public: + CAccValue() + { + } + virtual ~CAccValue() + { + } + + BEGIN_COM_MAP(CAccValue) + COM_INTERFACE_ENTRY(IAccessibleValue) + COM_INTERFACE_ENTRY(IUNOXWrapper) + COM_INTERFACE_ENTRY_FUNC_BLIND(0,SmartQI_) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + static HRESULT WINAPI SmartQI_(void* pv, + REFIID iid, void** ppvObject, DWORD_PTR) + { + return static_cast<CAccValue*>(pv)->SmartQI(iid,ppvObject); + } + + HRESULT SmartQI(REFIID iid, void** ppvObject) + { + if( m_pOuterUnknown ) + return OuterQueryInterface(iid,ppvObject); + return E_FAIL; + } + + DECLARE_NO_REGISTRY() + +public: + // IAccessibleValue + + // Returns the value of this object as a number. + STDMETHOD(get_currentValue)(VARIANT *currentValue) override; + + // Sets the value of this object to the given number. + STDMETHOD(setCurrentValue)(VARIANT value) override; + + // Returns the maximal value that can be represented by this object. + STDMETHOD(get_maximumValue)(VARIANT *maximumValue) override; + + // Returns the minimal value that can be represented by this object. + STDMETHOD(get_minimumValue)(VARIANT *minimumValue) override; + + // Override of IUNOXWrapper. + STDMETHOD(put_XInterface)(hyper pXInterface) override; + +private: + + css::uno::Reference<css::accessibility::XAccessibleValue> pRXVal; + + css::accessibility::XAccessibleValue* GetXInterface() + { + return pRXVal.get(); + } + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/AccessibleKeyStroke.h b/winaccessibility/source/UAccCOM/AccessibleKeyStroke.h new file mode 100644 index 0000000000..db3903cbd6 --- /dev/null +++ b/winaccessibility/source/UAccCOM/AccessibleKeyStroke.h @@ -0,0 +1,152 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +struct ACCESSIBLE_KEYSTROKE +{ + short modifiers; + short keyCode; + char keyChar; + short keyFunc; +}; + +const short MODIFIER_SHIFT = 1; +const short MODIFIER_CTRL = 2; +const short MODIFIER_ALT = 4; + +const short KEYCODE_NUM0 = 256; +const short KEYCODE_NUM1 = 257; +const short KEYCODE_NUM2 = 258; +const short KEYCODE_NUM3 = 259; +const short KEYCODE_NUM4 = 260; +const short KEYCODE_NUM5 = 261; +const short KEYCODE_NUM6 = 262; +const short KEYCODE_NUM7 = 263; +const short KEYCODE_NUM8 = 264; +const short KEYCODE_NUM9 = 265; +const short KEYCODE_A = 512; +const short KEYCODE_B = 513; +const short KEYCODE_C = 514; +const short KEYCODE_D = 515; +const short KEYCODE_E = 516; +const short KEYCODE_F = 517; +const short KEYCODE_G = 518; +const short KEYCODE_H = 519; +const short KEYCODE_I = 520; +const short KEYCODE_J = 521; +const short KEYCODE_K = 522; +const short KEYCODE_L = 523; +const short KEYCODE_M = 524; +const short KEYCODE_N = 525; +const short KEYCODE_O = 526; +const short KEYCODE_P = 527; +const short KEYCODE_Q = 528; +const short KEYCODE_R = 529; +const short KEYCODE_S = 530; +const short KEYCODE_T = 531; +const short KEYCODE_U = 532; +const short KEYCODE_V = 533; +const short KEYCODE_W = 534; +const short KEYCODE_X = 535; +const short KEYCODE_Y = 536; +const short KEYCODE_Z = 537; +const short KEYCODE_F1 = 768; +const short KEYCODE_F2 = 769; +const short KEYCODE_F3 = 770; +const short KEYCODE_F4 = 771; +const short KEYCODE_F5 = 772; +const short KEYCODE_F6 = 773; +const short KEYCODE_F7 = 774; +const short KEYCODE_F8 = 775; +const short KEYCODE_F9 = 776; +const short KEYCODE_F10 = 777; +const short KEYCODE_F11 = 778; +const short KEYCODE_F12 = 779; +const short KEYCODE_F13 = 780; +const short KEYCODE_F14 = 781; +const short KEYCODE_F15 = 782; +const short KEYCODE_F16 = 783; +const short KEYCODE_F17 = 784; +const short KEYCODE_F18 = 785; +const short KEYCODE_F19 = 786; +const short KEYCODE_F20 = 787; +const short KEYCODE_F21 = 788; +const short KEYCODE_F22 = 789; +const short KEYCODE_F23 = 790; +const short KEYCODE_F24 = 791; +const short KEYCODE_F25 = 792; +const short KEYCODE_F26 = 793; +const short KEYCODE_DOWN = 1024; +const short KEYCODE_UP = 1025; +const short KEYCODE_LEFT = 1026; +const short KEYCODE_RIGHT = 1027; +const short KEYCODE_HOME = 1028; +const short KEYCODE_END = 1029; +const short KEYCODE_PAGEUP = 1030; +const short KEYCODE_PAGEDOWN = 1031; +const short KEYCODE_RETURN = 1280; +const short KEYCODE_ESCAPE = 1281; +const short KEYCODE_TAB = 1282; +const short KEYCODE_BACKSPACE = 1283; +const short KEYCODE_SPACE = 1284; +const short KEYCODE_INSERT = 1285; +const short KEYCODE_DELETE = 1286; +const short KEYCODE_ADD = 1287; +const short KEYCODE_SUBTRACT = 1288; +const short KEYCODE_MULTIPLY = 1289; +const short KEYCODE_DIVIDE = 1290; +const short KEYCODE_POINT = 1291; +const short KEYCODE_COMMA = 1292; +const short KEYCODE_LESS = 1293; +const short KEYCODE_GREATER = 1294; +const short KEYCODE_EQUAL = 1295; +const short KEYCODE_OPEN = 1296; +const short KEYCODE_CUT = 1297; +const short KEYCODE_COPY = 1298; +const short KEYCODE_PASTE = 1299; +const short KEYCODE_UNDO = 1300; +const short KEYCODE_REPEAT = 1301; +const short KEYCODE_FIND = 1302; +const short KEYCODE_PROPERTIES = 1303; +const short KEYCODE_FRONT = 1304; +const short KEYCODE_CONTEXTMENU = 1305; +const short KEYCODE_HELP = 1306; + +const short SHORTCUT_DONTKNOW = 0; +const short NEW = 1; +const short OPEN = 2; +const short SAVE = 3; +const short SAVEAS = 4; +const short PRINT = 5; +const short CLOSE = 6; +const short QUIT = 7; +const short CUT = 8; +const short COPY = 9; +const short PASTE = 10; +const short UNDO = 11; +const short REDO = 12; +const short UNODELETE = 13; +const short REPEAT = 14; +const short FIND = 15; +const short FINDBACKWARD = 16; +const short PROPERTIES = 17; +const short FRONT = 18; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/EnumVariant.cxx b/winaccessibility/source/UAccCOM/EnumVariant.cxx new file mode 100644 index 0000000000..698461ac7a --- /dev/null +++ b/winaccessibility/source/UAccCOM/EnumVariant.cxx @@ -0,0 +1,258 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" +#include <UAccCOM.h> +#include "EnumVariant.h" +#include "MAccessible.h" + +#include <sal/log.hxx> +#include <vcl/svapp.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + + +// CEnumVariant + + +/** + * enumerate method,get next element + * @param cElements The number of elements to be returned. + * @param pvar An array of at least size celt in which the elements are to be returned. + * @param pcElementFetched Pointer to the number of elements returned in rgVar, or Null + * @return Result. + */ +HRESULT STDMETHODCALLTYPE CEnumVariant::Next(ULONG cElements,VARIANT __RPC_FAR *pvar,ULONG __RPC_FAR *pcElementFetched) +{ + SolarMutexGuard g; + + ULONG l2; + + if (pvar == nullptr) + return E_INVALIDARG; + + if (pcElementFetched != nullptr) + *pcElementFetched = 0; + + sal_Int64 nChildCount = m_pXAccessibleSelection->getSelectedAccessibleChildCount(); + if (nChildCount > std::numeric_limits<long>::max()) + { + SAL_WARN("iacc2", "CEnumVariant::Next: Child count exceeds maximum long value, " + "using max long."); + nChildCount = std::numeric_limits<long>::max(); + } + + // Retrieve the next cElements. + sal_Int64 l1; + for (l1 = m_nCurrent, l2 = 0; l1 < nChildCount && l2 < cElements; l1++, l2++) + { + Reference< XAccessible > pRXAcc = m_pXAccessibleSelection->getSelectedAccessibleChild(l1); + IAccessible* pChild = CMAccessible::get_IAccessibleFromXAccessible(pRXAcc.get()); + if(pChild) + { + pvar[l2].vt = VT_DISPATCH; + pvar[l2].pdispVal = pChild; + pChild->AddRef(); + } + else if(pRXAcc.is()) + { + if (CMAccessible::g_pAccObjectManager) + CMAccessible::g_pAccObjectManager->InsertAccObj(pRXAcc.get(),pUNOInterface); + pChild = CMAccessible::get_IAccessibleFromXAccessible(pRXAcc.get()); + if(pChild) + { + pvar[l2].vt = VT_DISPATCH; + pvar[l2].pdispVal = pChild; + pChild->AddRef(); + } + } + } + // Set count of elements retrieved. + if (pcElementFetched != nullptr) + *pcElementFetched = l2; + m_nCurrent = l1; + + return (l2 < cElements) ? S_FALSE : NOERROR; +} + +/** + * skip the elements in the given range when enumerate elements + * @param cElements The number of elements to skip. + * @return Result. + */ +HRESULT STDMETHODCALLTYPE CEnumVariant::Skip(ULONG cElements) +{ + SolarMutexGuard g; + + m_nCurrent += cElements; + sal_Int64 nChildCount = m_pXAccessibleSelection->getSelectedAccessibleChildCount(); + if (nChildCount > std::numeric_limits<long>::max()) + { + SAL_WARN("iacc2", "CEnumVariant::Skip: Child count exceeds maximum long value, " + "using max long."); + nChildCount = std::numeric_limits<long>::max(); + } + if (m_nCurrent > nChildCount) + { + m_nCurrent = nChildCount; + return E_FAIL; + } + else + return NOERROR; +} + + +/** + * reset the enumeration position to initial value + * @param + * @return Result. + */ +HRESULT STDMETHODCALLTYPE CEnumVariant::Reset() +{ + SolarMutexGuard g; + + m_nCurrent = 0; + return NOERROR; +} + + +/** + *create a new IEnumVariant object, + *copy current enumeration container and its state to + *the new object + *AT will use the copy object to get elements + * @param ppenum On return, pointer to the location of the clone enumerator + * @return Result. + */ +HRESULT STDMETHODCALLTYPE CEnumVariant::Clone(IEnumVARIANT __RPC_FAR *__RPC_FAR *ppenum) +{ + SolarMutexGuard g; + + CEnumVariant * penum = nullptr; + HRESULT hr; + if (ppenum == nullptr) + return E_INVALIDARG; + + *ppenum = nullptr; + + hr = Create(&penum); + if( hr == S_OK ) + { + penum->PutSelection(reinterpret_cast<hyper>(pUNOInterface)); + *ppenum = penum; + } + else + { + if (penum) + penum->Release(); + } + return hr; +} + +/** + *Static public method to create a CLSID_EnumVariant com object. + * @param ppenum Pointer to accept com object. + * @return Result. + */ +HRESULT STDMETHODCALLTYPE CEnumVariant::Create(CEnumVariant __RPC_FAR *__RPC_FAR *ppenum) +{ + SolarMutexGuard g; + + HRESULT hr = createInstance<CEnumVariant>(IID_IEnumVariant, ppenum); + if (S_OK != hr) + { + return E_FAIL; + } + + return S_OK; +} + +/** + *Return count of elements in current container + * @param. + * @return count of elements in current container. + */ +long CEnumVariant::GetCountOfElements() +{ + if(m_pXAccessibleSelection.is()) + { + sal_Int64 nCount = m_pXAccessibleSelection->getSelectedAccessibleChildCount(); + if (nCount > std::numeric_limits<long>::max()) + { + SAL_WARN("iacc2", "CEnumVariant::GetCountOfElements: Count exceeds maximum long value, " + "using max long."); + nCount = std::numeric_limits<long>::max(); + } + return nCount; + } + return 0; +} + +/** + * Set member m_pXAccessibleSelection to NULL and m_nCurrent to 0. + * @param. + * @return Result + */ +COM_DECLSPEC_NOTHROW STDMETHODIMP CEnumVariant::ClearEnumeration() +{ + // internal IEnumVariant - no mutex meeded + + pUNOInterface = nullptr; + m_pXAccessibleSelection = nullptr; + m_nCurrent = 0; + return S_OK; +} + +/** + *Static method to fetch XAccessibleSelection + * @param pXAcc XAccessible interface. + * @return XAccessibleSelection interface. + */ +static Reference<XAccessibleSelection> GetXAccessibleSelection(XAccessible* pXAcc) +{ + if( pXAcc == nullptr) + return nullptr; + + Reference< XAccessibleContext > pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return nullptr; + + Reference< XAccessibleSelection > pRSelection(pRContext,UNO_QUERY); + if( !pRSelection.is() ) + return nullptr; + + return pRSelection; +} + +/** + * Put valid UNO XAccessible interface. + * @param pXSelection XAccessible interface. + * @return Result... + */ +STDMETHODIMP CEnumVariant::PutSelection(hyper pXSelection) +{ + // internal IEnumVariant - no mutex meeded + + pUNOInterface = reinterpret_cast<XAccessible*>(pXSelection); + m_pXAccessibleSelection = GetXAccessibleSelection(pUNOInterface); + return S_OK; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/EnumVariant.h b/winaccessibility/source/UAccCOM/EnumVariant.h new file mode 100644 index 0000000000..c00e30a6a5 --- /dev/null +++ b/winaccessibility/source/UAccCOM/EnumVariant.h @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "Resource.h" // main symbols +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> +#include <UAccCOM.h> + +/** + * CEnumVariant implements IEnumVARIANT interface. + */ +class ATL_NO_VTABLE CEnumVariant : + public CComObjectRootEx<CComMultiThreadModel>, + public CComCoClass<CEnumVariant, &CLSID_EnumVariant>, + public IDispatchImpl<IEnumVariant, &IID_IEnumVariant, &LIBID_UACCCOMLib> +{ +public: + CEnumVariant() + :m_nCurrent(0), + pUNOInterface(nullptr) + { + } + + virtual ~CEnumVariant() {}; + + DECLARE_NO_REGISTRY() + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CEnumVariant) + COM_INTERFACE_ENTRY(IEnumVariant) + COM_INTERFACE_ENTRY(IEnumVARIANT) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + // IEnumVariant +public: + + STDMETHOD(ClearEnumeration)() override; + + // IEnumVARIANT + + + HRESULT STDMETHODCALLTYPE Next(ULONG cElements,VARIANT __RPC_FAR *pvar,ULONG __RPC_FAR *pcElementFetched) override; + + + HRESULT STDMETHODCALLTYPE Skip(ULONG cElements) override; + + + HRESULT STDMETHODCALLTYPE Reset( void) override; + + + HRESULT STDMETHODCALLTYPE Clone(IEnumVARIANT __RPC_FAR *__RPC_FAR *ppenum) override; + + // IEnumVariant + + + HRESULT STDMETHODCALLTYPE PutSelection(hyper pXSelection) override; + + + static HRESULT STDMETHODCALLTYPE Create(CEnumVariant __RPC_FAR *__RPC_FAR *ppenum); + + + long GetCountOfElements(); + +private: + + sal_Int64 m_nCurrent; + css::accessibility::XAccessible* pUNOInterface; + css::uno::Reference<css::accessibility::XAccessibleSelection> + m_pXAccessibleSelection; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/MAccessible.cxx b/winaccessibility/source/UAccCOM/MAccessible.cxx new file mode 100644 index 0000000000..6c1367185c --- /dev/null +++ b/winaccessibility/source/UAccCOM/MAccessible.cxx @@ -0,0 +1,2767 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <UAccCOM.h> +#include "MAccessible.h" + +#include <algorithm> +#include <cstddef> + +#include "AccAction.h" +#include "AccRelation.h" +#include "AccComponent.h" +#include "AccText.h" +#include "AccEditableText.h" +#include "AccImage.h" +#include "AccTable.h" +#include "AccTableCell.h" +#include "AccValue.h" +#include "AccHypertext.h" +#include "AccHyperLink.h" + +#include <rtl/ustrbuf.hxx> +#include <sal/log.hxx> +#include <unotools/configmgr.hxx> +#include <vcl/accessibility/AccessibleTextAttributeHelper.hxx> +#include <vcl/svapp.hxx> +#include <o3tl/char16_t2wchar_t.hxx> +#include <comphelper/AccessibleImplementationHelper.hxx> + +#include <com/sun/star/accessibility/XAccessibleText.hpp> +#include <com/sun/star/accessibility/XAccessibleEditableText.hpp> +#include <com/sun/star/accessibility/XAccessibleImage.hpp> +#include <com/sun/star/accessibility/XAccessibleTable.hpp> +#include <com/sun/star/accessibility/XAccessibleExtendedComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleAction.hpp> +#include <com/sun/star/accessibility/XAccessibleKeyBinding.hpp> +#include <com/sun/star/accessibility/XAccessibleHypertext.hpp> +#include <com/sun/star/accessibility/XAccessibleHyperlink.hpp> +#include <com/sun/star/accessibility/XAccessibleRelationSet.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleGroupPosition.hpp> +#include <com/sun/star/accessibility/XAccessibleValue.hpp> +#include <com/sun/star/accessibility/XAccessibleExtendedAttributes.hpp> +#include <com/sun/star/style/LineSpacing.hpp> +#include <com/sun/star/style/TabStop.hpp> +#include <com/sun/star/container/XIndexReplace.hpp> + + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +namespace { + +enum class XInterfaceType { + XI_COMPONENT, + XI_TEXT, + XI_TABLE, + XI_TABLECELL, + XI_EDITABLETEXT, + XI_IMAGE, + XI_SELECTION, + XI_EXTENDEDCOMP, + XI_VALUE, + XI_KEYBINDING, + XI_ACTION, + XI_HYPERTEXT, + XI_HYPERLINK, + XI_ATTRIBUTE +}; + +template <class Interface> +bool queryXInterface(XAccessible* pXAcc, XInterface** ppXI) +{ + if (!pXAcc) + return false; + + Reference<XAccessibleContext> pRContext = pXAcc->getAccessibleContext(); + if (!pRContext.is()) + return false; + + Reference<Interface> pRXI(pRContext, UNO_QUERY); + if (!pRXI.is()) + return false; + + *ppXI = pRXI.get(); + return true; +} + +// Since there's no specific XInterface for table cells, this +// method checks that the accessible's parent is a table +// (implements XAccessibleTable) and pXAcc's context implements +// XAccessibleComponent. +bool queryTableCell(XAccessible* pXAcc, XInterface** ppXI) +{ + XInterface* pXInterface = nullptr; + + const bool bSupportsInterface = queryXInterface<XAccessibleComponent>(pXAcc, &pXInterface); + if (!bSupportsInterface) + return false; + + // check whether parent is a table (its accessible context implements XAccessibleTable) + XInterface* pParentXInterface = nullptr; + Reference<XAccessible> xParentAcc = pXAcc->getAccessibleContext()->getAccessibleParent(); + const bool bParentIsTable = queryXInterface<XAccessibleTable>(xParentAcc.get(), &pParentXInterface); + + if (!bParentIsTable) + return false; + + *ppXI = pXInterface; + return true; +} + + +void lcl_addIA2State(AccessibleStates& rStates, sal_Int64 nUnoState, sal_Int16 nRole) +{ + switch (nUnoState) + { + case css::accessibility::AccessibleStateType::ACTIVE: + rStates |= IA2_STATE_ACTIVE; + break; + case css::accessibility::AccessibleStateType::ARMED: + rStates |= IA2_STATE_ARMED; + break; + case css::accessibility::AccessibleStateType::CHECKABLE: + // STATE_SYSTEM_PRESSED is used instead of STATE_SYSTEM_CHECKED for these button + // roles (s. AccObject::GetMSAAStateFromUNO), so don't set CHECKABLE state for them + if (nRole != AccessibleRole::PUSH_BUTTON && nRole != AccessibleRole::TOGGLE_BUTTON) + rStates |= IA2_STATE_CHECKABLE; + break; + case css::accessibility::AccessibleStateType::DEFUNC: + rStates |= IA2_STATE_DEFUNCT; + break; + case css::accessibility::AccessibleStateType::EDITABLE: + rStates |= IA2_STATE_EDITABLE; + break; + case css::accessibility::AccessibleStateType::HORIZONTAL: + rStates |= IA2_STATE_HORIZONTAL; + break; + case css::accessibility::AccessibleStateType::ICONIFIED: + rStates |= IA2_STATE_ICONIFIED; + break; + case css::accessibility::AccessibleStateType::MANAGES_DESCENDANTS: + rStates |= IA2_STATE_MANAGES_DESCENDANTS; + break; + case css::accessibility::AccessibleStateType::MODAL: + rStates |= IA2_STATE_MODAL; + break; + case css::accessibility::AccessibleStateType::MULTI_LINE: + rStates |= IA2_STATE_MULTI_LINE; + break; + case css::accessibility::AccessibleStateType::OPAQUE: + rStates |= IA2_STATE_OPAQUE; + break; + case css::accessibility::AccessibleStateType::SINGLE_LINE: + rStates |= IA2_STATE_SINGLE_LINE; + break; + case css::accessibility::AccessibleStateType::STALE: + rStates |= IA2_STATE_STALE; + break; + case css::accessibility::AccessibleStateType::TRANSIENT: + rStates |= IA2_STATE_TRANSIENT; + break; + case css::accessibility::AccessibleStateType::VERTICAL: + rStates |= IA2_STATE_VERTICAL; + break; + default: + // no match + break; + } +} + +} + +AccObjectWinManager* CMAccessible::g_pAccObjectManager = nullptr; + +CMAccessible::CMAccessible(): +m_pszName(nullptr), +m_pszValue(nullptr), +m_pszActionDescription(nullptr), +m_iRole(0x00), +m_dState(0x00), +m_pIParent(nullptr), +m_dChildID(0x00), +m_dFocusChildID(UACC_NO_FOCUS), +m_hwnd(nullptr), +m_isDestroy(false) +{ + CEnumVariant::Create(&m_pEnumVar); + m_containedObjects.clear(); +} + +CMAccessible::~CMAccessible() +{ + SolarMutexGuard g; + + if(m_pszName!=nullptr) + { + SysFreeString(std::exchange(m_pszName, nullptr)); + } + if(m_pszValue!=nullptr) + { + SysFreeString(std::exchange(m_pszValue, nullptr)); + } + + if(m_pszActionDescription!=nullptr) + { + SysFreeString(std::exchange(m_pszActionDescription, nullptr)); + } + + if(m_pIParent) + { + m_pIParent->Release(); + m_pIParent=nullptr; + } + m_pEnumVar->Release(); + m_containedObjects.clear(); +} + +/** +* Returns the Parent IAccessible interface pointer to AT. +* It should add reference, and the client should release the component. +* It should return E_FAIL when the parent point is null. +* @param ppdispParent [in,out] used to return the parent interface point. +* when the point is null, should return null. +* @return S_OK if successful and E_FAIL if the m_pIParent is NULL. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accParent(IDispatch **ppdispParent) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(ppdispParent == nullptr) + { + return E_INVALIDARG; + } + + if(m_pIParent) + { + *ppdispParent = m_pIParent; + (*ppdispParent)->AddRef(); + return S_OK; + } + else if(m_hwnd) + { + HRESULT hr = AccessibleObjectFromWindow(m_hwnd, OBJID_WINDOW, IID_IAccessible, reinterpret_cast<void**>(ppdispParent)); + if (!SUCCEEDED(hr) || !*ppdispParent) + { + return S_FALSE; + } + return S_OK; + } + return S_FALSE; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns child count of current COM object. +* @param pcountChildren [in,out] used to return the children count. +* @return S_OK if successful. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accChildCount(long *pcountChildren) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(pcountChildren == nullptr) + { + return E_INVALIDARG; + } + + if (!m_xAccessible.is()) + return S_FALSE; + + Reference<XAccessibleContext> const pRContext = + m_xAccessible->getAccessibleContext(); + if( pRContext.is() ) + { + sal_Int64 nChildCount = pRContext->getAccessibleChildCount(); + if (nChildCount > std::numeric_limits<long>::max()) + { + SAL_WARN("iacc2", "CMAccessible::get_accChildCount: Child count exceeds maximum long value, " + "returning max long."); + nChildCount = std::numeric_limits<long>::max(); + } + + *pcountChildren = nChildCount; + } + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns child interface pointer for AT according to input child ID. +* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @param ppdispChild, [in,out] use to return the child interface point. +* @return S_OK if successful and S_FALSE if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accChild(VARIANT varChild, IDispatch **ppdispChild) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(ppdispChild == nullptr) + { + return E_INVALIDARG; + } + if(varChild.vt==VT_I4) + { + //get child interface pointer due to child ID + if(varChild.lVal==CHILDID_SELF) + { + AddRef(); + *ppdispChild = this; + return S_OK; + } + *ppdispChild = GetChildInterface(varChild.lVal); + if((*ppdispChild) == nullptr) + return E_FAIL; + (*ppdispChild)->AddRef(); + return S_OK; + } + return S_FALSE; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns the accessible name of the current COM object self or its one child to AT. +* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @param pszName, [in,out] use to return the name of the proper object. +* @return S_OK if successful and S_FALSE if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accName(VARIANT varChild, BSTR *pszName) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(pszName == nullptr) + { + return E_INVALIDARG; + } + if(varChild.vt==VT_I4) + { + if(varChild.lVal==CHILDID_SELF) + { + SysFreeString(*pszName); + *pszName = SysAllocString(m_pszName); + return S_OK; + } + + long lVal = varChild.lVal; + varChild.lVal = CHILDID_SELF; + IMAccessible *pChild = this->GetChildInterface(lVal); + if(!pChild) + return E_FAIL; + return pChild->get_accName(varChild,pszName); + } + return S_FALSE; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns the accessible value of the current COM object self or its one child to AT. +* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @param pszValue, [in,out] use to return the value of the proper object. +* @return S_OK if successful and S_FALSE if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accValue(VARIANT varChild, BSTR *pszValue) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if( pszValue == nullptr ) + { + return E_INVALIDARG; + } + if( varChild.vt==VT_I4 ) + { + if(varChild.lVal==CHILDID_SELF) + { + if(m_dState & STATE_SYSTEM_PROTECTED) + return E_ACCESSDENIED; + + if ( m_pszValue !=nullptr && wcslen(m_pszValue) == 0 ) + return S_OK; + + SysFreeString(*pszValue); + *pszValue = SysAllocString(m_pszValue); + return S_OK; + } + + long lVal = varChild.lVal; + varChild.lVal = CHILDID_SELF; + IMAccessible *pChild = this->GetChildInterface(lVal); + if(!pChild) + return E_FAIL; + return pChild->get_accValue(varChild,pszValue); + } + return S_FALSE; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns the accessible description of the current COM object self or its one child to AT. +* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @param pszDescription, [in,out] use to return the description of the proper object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accDescription(VARIANT varChild, BSTR *pszDescription) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(pszDescription == nullptr) + { + return E_INVALIDARG; + } + if(varChild.vt==VT_I4) + { + if(varChild.lVal==CHILDID_SELF) + { + if (!m_xAccessible.is()) + return S_FALSE; + + Reference<XAccessibleContext> xContext = m_xAccessible->getAccessibleContext(); + if (!xContext.is()) + return S_FALSE; + + const OUString sDescription = xContext->getAccessibleDescription(); + SysFreeString(*pszDescription); + *pszDescription = SysAllocString(o3tl::toW(sDescription.getStr())); + return S_OK; + } + + long lVal = varChild.lVal; + varChild.lVal = CHILDID_SELF; + IMAccessible *pChild = this->GetChildInterface(lVal); + if(!pChild) + return E_FAIL; + return pChild->get_accDescription(varChild,pszDescription); + } + return S_FALSE; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns the accessible role of the current COM object self or its one child to AT. +* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @param pvarRole, [in,out] use to return the role of the proper object. +* @return S_OK if successful and S_FALSE if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accRole(VARIANT varChild, VARIANT *pvarRole) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(pvarRole == nullptr) + { + return E_INVALIDARG; + } + if(varChild.vt == VT_I4) + { + + if(varChild.lVal == CHILDID_SELF) + { + VariantInit(pvarRole); + pvarRole->vt = VT_I4; + + if (m_iRole < IA2_ROLE_CAPTION) + pvarRole->lVal = m_iRole; + else + pvarRole->lVal = ROLE_SYSTEM_CLIENT; + + return S_OK; + } + + + long lVal = varChild.lVal; + varChild.lVal = CHILDID_SELF; + IMAccessible *pChild = this->GetChildInterface(lVal); + if(!pChild) + return E_FAIL; + return pChild->get_accRole(varChild,pvarRole); + } + return S_FALSE; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns the accessible state of the current COM object self or its one child to AT. +* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @param pvarState, [in,out] use to return the state of the proper object. +* @return S_OK if successful and S_FALSE if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accState(VARIANT varChild, VARIANT *pvarState) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(pvarState == nullptr) + { + return E_INVALIDARG; + } + if(varChild.vt==VT_I4) + { + if(varChild.lVal == CHILDID_SELF) + { + if (m_xAccessible.is()) + { + Reference<XAccessibleContext> const pContext = + m_xAccessible->getAccessibleContext(); + if(pContext.is()) + { + // add the STATE_SYSTEM_LINKED state + Reference< XAccessibleHypertext > pRHypertext(pContext,UNO_QUERY); + if(pRHypertext.is()) + { + if( pRHypertext->getHyperLinkCount() > 0 ) + m_dState |= STATE_SYSTEM_LINKED; + else + m_dState &= ~STATE_SYSTEM_LINKED; + } + else + m_dState &= ~STATE_SYSTEM_LINKED; + } + } + + VariantInit(pvarState); + pvarState->vt = VT_I4; + pvarState->lVal = m_dState; + return S_OK; + } + + long lVal = varChild.lVal; + varChild.lVal = CHILDID_SELF; + IMAccessible *pChild = this->GetChildInterface(lVal); + if(!pChild) + return E_FAIL; + return pChild->get_accState(varChild,pvarState); + } + return S_FALSE; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns the accessible helpString of the current COM object self or its one child to AT. +* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @param pszHelp, [in,out] use to return the helpString of the proper object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accHelp(VARIANT, BSTR *) +{ + return E_NOTIMPL; +} + +/** +* Returns the accessible HelpTopic of the current COM object self or its one child to AT. +* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @param pszHelpFile, [in,out] use to return the HelpTopic of the proper object. +* @param pidTopic, use to return the HelpTopic ID of the proper object. +* @return S_OK if successful and E_FAIL if failure. +* Not implemented yet +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accHelpTopic(BSTR *, VARIANT, long *) +{ + return E_NOTIMPL; +} + +static bool GetMnemonicChar( const OUString& aStr, sal_Unicode* wStr) +{ + for (sal_Int32 i = 0;; i += 2) { + i = aStr.indexOf('~', i); + if (i == -1 || i == aStr.getLength() - 1) { + return false; + } + auto c = aStr[i + 1]; + if (c != '~') { + *wStr = c; + return true; + } + } +} + +/** +* Returns the accessible keyboard shortcut of the current COM object self or its one child to AT. +* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @param pszKeyboardShortcut, [in,out] use to return the kbshortcut of the proper object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut) +{ + SolarMutexGuard g; + + try { + + if (m_isDestroy) return S_FALSE; + + if(pszKeyboardShortcut == nullptr) + { + return E_INVALIDARG; + } + + if(varChild.vt==VT_I4) + { + if(varChild.lVal == CHILDID_SELF) + { + if (m_xAccessible.is()) + { + Reference<XAccessibleContext> const pRContext = + m_xAccessible->getAccessibleContext(); + if( !pRContext.is() ) + return S_FALSE; + + Reference<XAccessibleAction> pRXI(pRContext,UNO_QUERY); + + OUString wString; + + if( pRXI.is() && pRXI->getAccessibleActionCount() >= 1) + { + Reference< XAccessibleKeyBinding > binding = pRXI->getAccessibleActionKeyBinding(0); + if( binding.is() ) + { + long nCount = binding->getAccessibleKeyBindingCount(); + if(nCount >= 1) + { + wString = comphelper::GetkeyBindingStrByXkeyBinding( binding->getAccessibleKeyBinding(0) ); + } + } + } + if(wString.isEmpty()) + { + Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet(); + if(!pRrelationSet.is()) + { + return S_FALSE; + } + + long nRelCount = pRrelationSet->getRelationCount(); + + // Modified by Steve Yin, for SODC_1552 + if( /*nRelCount <= 0 &&*/ m_iRole == ROLE_SYSTEM_TEXT ) + { + VARIANT varParentRole; + VariantInit( &varParentRole ); + + if (m_pIParent + && SUCCEEDED(m_pIParent->get_accRole(varChild, &varParentRole)) + && varParentRole.lVal == ROLE_SYSTEM_COMBOBOX) // edit in comboBox + { + m_pIParent->get_accKeyboardShortcut(varChild, pszKeyboardShortcut); + return S_OK; + } + } + + AccessibleRelation *paccRelation = nullptr; + AccessibleRelation accRelation; + for(int i=0; i<nRelCount ; i++) + { + if( pRrelationSet->getRelation(i).RelationType == 6 ) + { + accRelation = pRrelationSet->getRelation(i); + paccRelation = &accRelation; + } + } + + if(paccRelation == nullptr) + return S_FALSE; + + Sequence< Reference< XInterface > > xTargets = paccRelation->TargetSet; + Reference<XInterface> pRAcc = xTargets[0]; + + XAccessible* pXAcc = static_cast<XAccessible*>(pRAcc.get()); + + Reference<XAccessibleContext> pRLebelContext = pXAcc->getAccessibleContext(); + if(!pRLebelContext.is()) + return S_FALSE; + + pRrelationSet = pRLebelContext->getAccessibleRelationSet(); + nRelCount = pRrelationSet->getRelationCount(); + + paccRelation = nullptr; + for(int j=0; j<nRelCount ; j++) + { + if( pRrelationSet->getRelation(j).RelationType == 5 ) + { + accRelation = pRrelationSet->getRelation(j); + paccRelation = &accRelation; + } + } + + if(paccRelation) + { + xTargets = paccRelation->TargetSet; + pRAcc = xTargets[0]; + if (m_xAccessible.get() != static_cast<XAccessible*>(pRAcc.get())) + return S_FALSE; + } + + Reference<XAccessibleExtendedComponent> pRXIE(pRLebelContext,UNO_QUERY); + if(!pRXIE.is()) + return S_FALSE; + + OUString ouStr = pRXIE->getTitledBorderText(); + sal_Unicode key; + if(GetMnemonicChar(ouStr, &key)) + { + wString = "Alt+" + OUStringChar(key); + } + else + return S_FALSE; + } + + SysFreeString(*pszKeyboardShortcut); + *pszKeyboardShortcut = SysAllocString(o3tl::toW(wString.getStr())); + + return S_OK; + } + else + { + return S_FALSE; + } + } + + long lVal = varChild.lVal; + varChild.lVal = CHILDID_SELF; + IMAccessible *pChild = this->GetChildInterface(lVal); + if(!pChild) + return E_FAIL; + + return pChild->get_accKeyboardShortcut(varChild,pszKeyboardShortcut); + } + return S_FALSE; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns the current focused child to AT. +* @param pvarChild, [in,out] vt member of pvarChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accFocus(VARIANT *pvarChild) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(pvarChild == nullptr) + { + return E_INVALIDARG; + } + if( m_dFocusChildID==UACC_NO_FOCUS ) + { + pvarChild->vt = VT_EMPTY;//no focus on the object and its children + return S_OK; + } + //if the descendant of current object has focus indicated by m_dFocusChildID, return the IDispatch of this focused object + else + { + IMAccessible* pIMAcc = g_pAccObjectManager->GetIAccessibleFromResID(m_dFocusChildID); + if (pIMAcc == nullptr) + { + return E_FAIL; + } + pIMAcc->AddRef(); + pvarChild->vt = VT_DISPATCH; + pvarChild->pdispVal = pIMAcc; + + } + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns the selection of the current COM object to AT. +* @param pvarChildren,[in,out] +* if selection num is 0,return VT_EMPTY for vt, +* if selection num is 1,return VT_I4 for vt,and child index for lVal +* if selection num >1,return VT_UNKNOWN for vt, and IEnumVariant* for punkVal +* @return S_OK if successful and S_FALSE if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_accSelection(VARIANT *pvarChildren) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(pvarChildren == nullptr) + { + return E_INVALIDARG; + } + switch(m_pEnumVar->GetCountOfElements()) + { + case 0: + pvarChildren->vt = VT_EMPTY; + break; + case 1: + VARIANT varTmp[1]; + ULONG count; + VariantInit(&varTmp[0]); + m_pEnumVar->Next(1,varTmp,&count); + if(count!=1) + return S_FALSE; + pvarChildren->vt = VT_DISPATCH; + pvarChildren->pdispVal = varTmp[0].pdispVal; + pvarChildren->pdispVal->AddRef(); + VariantClear(&varTmp[0]); + m_pEnumVar->Reset(); + break; + default: + pvarChildren->vt = VT_UNKNOWN; + IEnumVARIANT* pClone; + m_pEnumVar->Clone(&pClone); + pClone->Reset(); + pvarChildren->punkVal = pClone; + break; + } + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns the location of the current COM object self or its one child to AT. +* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @param pxLeft, [in,out] use to return the x-coordination of the proper object. +* @param pyTop, [in,out] use to return the y-coordination of the proper object. +* @param pcxWidth, [in,out] use to return the x-coordination width of the proper object. +* @param pcyHeight, [in,out] use to return the y-coordination height of the proper object. +* @return S_OK if successful and S_FALSE if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varChild) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(pxLeft == nullptr || pyTop == nullptr || pcxWidth == nullptr || pcyHeight == nullptr) + { + return E_INVALIDARG; + } + + if(varChild.vt==VT_I4) + { + if(varChild.lVal==CHILDID_SELF) + { + if (!m_xAccessible.is()) + return S_FALSE; + + Reference<XAccessibleContext> const pRContext = + m_xAccessible->getAccessibleContext(); + if( !pRContext.is() ) + return S_FALSE; + Reference< XAccessibleComponent > pRComponent(pRContext,UNO_QUERY); + if( !pRComponent.is() ) + return S_FALSE; + + css::awt::Point pCPoint = pRComponent->getLocationOnScreen(); + css::awt::Size pCSize = pRComponent->getSize(); + *pxLeft = pCPoint.X; + *pyTop = pCPoint.Y; + *pcxWidth = pCSize.Width; + *pcyHeight = pCSize.Height; + return S_OK; + } + } + return S_FALSE; + + } catch(...) { return E_FAIL; } +} + +/** +* Returns the current focused child to AT. +* @param navDir, the direction flag of the navigation. +* @param varStart, the start child id of this navigation action. +* @param pvarEndUpAt, [in,out] the end up child of this navigation action. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEndUpAt) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(pvarEndUpAt == nullptr) + { + return E_INVALIDARG; + } + HRESULT ret = E_FAIL; + switch (navDir) + { + case NAVDIR_FIRSTCHILD: + ret = GetFirstChild(varStart,pvarEndUpAt); + break; + case NAVDIR_LASTCHILD: + ret = GetLastChild(varStart,pvarEndUpAt); + break; + case NAVDIR_NEXT: + ret = GetNextSibling(varStart,pvarEndUpAt); + break; + case NAVDIR_PREVIOUS: + ret = GetPreSibling(varStart,pvarEndUpAt); + break; + case NAVDIR_DOWN://do not implement temporarily + break; + case NAVDIR_UP://do not implement temporarily + break; + case NAVDIR_LEFT://do not implement temporarily + break; + case NAVDIR_RIGHT://do not implement temporarily + break; + default: + break; + } + return ret; + + } catch(...) { return E_FAIL; } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarChild) +{ + SolarMutexGuard g; + + if (m_isDestroy) + return S_FALSE; + + if (!pvarChild) + return E_INVALIDARG; + + try + { + pvarChild->vt = VT_EMPTY; + + Reference<XAccessibleContext> xContext = GetContextByXAcc(m_xAccessible.get()); + Reference<XAccessibleComponent> xComponent(xContext, UNO_QUERY); + if (!xComponent.is()) + return S_FALSE; + + // convert from screen to object-local coordinates + css::awt::Point aTopLeft = xComponent->getLocationOnScreen(); + css::awt::Point aPoint(xLeft - aTopLeft.X, yTop - aTopLeft.Y); + + Reference<XAccessible> xAccAtPoint = xComponent->getAccessibleAtPoint(aPoint); + if (!xAccAtPoint.is()) + return S_FALSE; + + IAccessible* pRet = get_IAccessibleFromXAccessible(xAccAtPoint.get()); + if (!pRet) + { + g_pAccObjectManager->InsertAccObj(xAccAtPoint.get(), m_xAccessible.get(), m_hwnd); + pRet = get_IAccessibleFromXAccessible(xAccAtPoint.get()); + } + if (!pRet) + return S_FALSE; + + pvarChild->vt = VT_DISPATCH; + pvarChild->pdispVal = pRet; + pRet->AddRef(); + + return S_OK; + } catch(...) { return E_FAIL; } +} + +/** +* Get The other Interface from CMAccessible. +* @param guidService, must be IID_IAccessible here. +* @param riid, the IID interface . +* @return S_OK if successful and S_FALSE if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::QueryService(REFGUID guidService, REFIID riid, void** ppvObject) +{ + if( InlineIsEqualGUID(guidService, IID_IAccessible) ) + return QueryInterface(riid, ppvObject); + return S_FALSE; +} + +/** +* No longer supported according to IAccessible doc. +* Servers should return E_NOTIMPL +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::put_accName(VARIANT, BSTR) +{ + return E_NOTIMPL; +} + +/** +* Set the accessible value of the current COM object self or its one child from UNO. +* @param varChild, vt member of varChild must be VT_I4,and lVal member stores the child ID, +* the child ID specify child index from 0 to children count, 0 stands for object self. +* @param szValue, the value used to set the value of the proper object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::put_accValue(VARIANT varChild, BSTR szValue) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + if(varChild.vt==VT_I4) + { + if(varChild.lVal==CHILDID_SELF) + { + SysFreeString(m_pszValue); + m_pszValue=SysAllocString(szValue); + return S_OK; + } + + long lVal = varChild.lVal; + varChild.lVal = CHILDID_SELF; + IMAccessible *pChild = this->GetChildInterface(lVal); + if(!pChild) + return E_FAIL; + return pChild->put_accValue(varChild,szValue); + } + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** +* Set the accessible name of the current COM object self from UNO. +* @param pszName, the name value used to set the name of the current object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::Put_XAccName(const OLECHAR __RPC_FAR *pszName) +{ + // internal IMAccessible - no mutex meeded + + try { + if (m_isDestroy) return S_FALSE; + + if(pszName == nullptr) + { + return E_INVALIDARG; + } + + SysFreeString(m_pszName); + m_pszName = SysAllocString(pszName); + if(m_pszName==nullptr) + return E_FAIL; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** +* Set the accessible role of the current COM object self from UNO. +* @param pRole, the role value used to set the role of the current object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::Put_XAccRole(unsigned short pRole) +{ + // internal IMAccessible - no mutex meeded + + m_iRole = pRole; + return S_OK; +} + +/** +* Add one state into the current state set for the current COM object from UNO. +* @param pXSate, the state used to set the name of the current object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::DecreaseState(DWORD pXSate) +{ + // internal IMAccessible - no mutex meeded + + m_dState &= (~pXSate); + return S_OK; +} + +/** +* Delete one state into the current state set for the current COM object from UNO. +* @param pXSate, the state used to set the name of the current object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::IncreaseState(DWORD pXSate) +{ + // internal IMAccessible - no mutex meeded + + m_dState |= pXSate; + return S_OK; +} + +/** +* Set state into the current state set for the current COM object from UNO. +* @param pXSate, the state used to set the name of the current object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::SetState(DWORD pXSate) +{ + // internal IMAccessible - no mutex meeded + + m_dState = pXSate; + return S_OK; +} + +/** +* Set the accessible value of the current COM object self from UNO. +* @param pszAccValue, the name used to set the value of the current object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::Put_XAccValue(const OLECHAR __RPC_FAR *pszAccValue) +{ + // internal IMAccessible - no mutex meeded + + try { + if (m_isDestroy) return S_FALSE; + + if(pszAccValue == nullptr) + { + return E_INVALIDARG; + } + SysFreeString(m_pszValue); + m_pszValue = SysAllocString(pszAccValue); + if(m_pszValue==nullptr) + return E_FAIL; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** +* Set the HWND value of the current COM object self from UNO. It should set the parent IAccessible +* Object through the method AccessibleObjectFromWindow(...). +* @param hwnd, the HWND used to set the value of the current object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::Put_XAccWindowHandle(HWND hwnd) +{ + // internal IMAccessible - no mutex meeded + + try { + if (m_isDestroy) return S_FALSE; + m_hwnd = hwnd; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** +* Set accessible focus by specifying child ID +* @param dChildID, the child id identifies the focus child. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::Put_XAccFocus(long dChildID) +{ + // internal IMAccessible - no mutex meeded + + try { + if (m_isDestroy) return S_FALSE; + + if(dChildID==CHILDID_SELF) + { + if(m_pIParent) + { + m_pIParent->Put_XAccFocus(m_dChildID); + } + } + else + { + m_dFocusChildID = dChildID; + //traverse all ancestors to set the focused child ID so that when the get_accFocus is called on + //any of the ancestors, this id can be used to get the IAccessible of focused object. + if(m_pIParent) + { + m_pIParent->Put_XAccFocus(dChildID); + } + } + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** +* Set accessible parent object for the current COM object if +* the current object is a child of some COM object +* @param pIParent, the parent of the current object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::Put_XAccParent(IMAccessible __RPC_FAR *pIParent) +{ + // internal IMAccessible - no mutex meeded + + this->m_pIParent = pIParent; + + if(pIParent) + m_pIParent->AddRef(); + + return S_OK; +} + +/** +* Set unique child id to COM +* @param dChildID, the id of the current object. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::Put_XAccChildID(long dChildID) +{ + // internal IMAccessible - no mutex meeded + + this->m_dChildID = dChildID; + return S_OK; +} + +/** +* Set AccObjectWinManager object pointer to COM +* @param pManager, the AccObjectWinManager pointer. +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::Put_XAccObjectManager(hyper pManager) +{ + // internal IMAccessible - no mutex meeded + + g_pAccObjectManager = reinterpret_cast<AccObjectWinManager*>(pManager); + return S_OK; +} + +/** +* When a UNO control disposing, it disposes its listeners, +* then notify AccObject in bridge management, then notify +* COM that the XAccessible is invalid, so set m_xAccessible as NULL +* @return S_OK if successful and E_FAIL if failure. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::NotifyDestroy() +{ + // internal IMAccessible - no mutex meeded + + m_isDestroy = true; + m_xAccessible.clear(); + return S_OK; +} + +/** +*private methods that help implement public functions +*/ + +/** +* Return child interface pointer by child ID,note: need to call AddRef() +* @param lChildID, specify child index,which AT(such as Inspect32) gives. +* @return IMAccessible*, pointer to the corresponding child object. +*/ +IMAccessible* CMAccessible::GetChildInterface(long dChildID)//for test +{ + if(dChildID<0) + { + if(g_pAccObjectManager) + { + IMAccessible* pIMAcc = g_pAccObjectManager->GetIAccessibleFromResID(dChildID); + return pIMAcc; + } + return nullptr; + } + else + { + if (!m_xAccessible.is()) + return nullptr; + + Reference<XAccessibleContext> const pRContext = + m_xAccessible->getAccessibleContext(); + if( !pRContext.is() ) + return nullptr; + + if(dChildID<1 || dChildID>pRContext->getAccessibleChildCount()) + return nullptr; + + Reference< XAccessible > pXChild = pRContext->getAccessibleChild(dChildID-1); + IAccessible* pChild = get_IAccessibleFromXAccessible(pXChild.get()); + + if(!pChild) + { + g_pAccObjectManager->InsertAccObj(pXChild.get(), m_xAccessible.get(), m_hwnd); + pChild = get_IAccessibleFromXAccessible(pXChild.get()); + } + + if (pChild) + { + IMAccessible* pIMAcc = static_cast<IMAccessible*>(pChild); + return pIMAcc; + } + } + + return nullptr; +} + +/** +* for descendantmanager circumstance,provide child interface when navigate +* @param varCur, the current child. +* @param flags, the navigation direction. +* @return IMAccessible*, the child of the end up node. +*/ +IMAccessible* CMAccessible::GetNavigateChildForDM(VARIANT varCur, short flags) +{ + + XAccessibleContext* pXContext = GetContextByXAcc(m_xAccessible.get()); + if(pXContext==nullptr) + { + return nullptr; + } + + sal_Int64 count = pXContext->getAccessibleChildCount(); + if(count<1) + { + return nullptr; + } + + IMAccessible* pCurChild = nullptr; + union { + XAccessible* pChildXAcc; + hyper nHyper = 0; + }; + Reference<XAccessible> pRChildXAcc; + XAccessibleContext* pChildContext = nullptr; + sal_Int64 index = 0, delta = 0; + switch(flags) + { + case DM_FIRSTCHILD: + pRChildXAcc = pXContext->getAccessibleChild(0); + break; + case DM_LASTCHILD: + pRChildXAcc = pXContext->getAccessibleChild(count-1); + break; + case DM_NEXTCHILD: + case DM_PREVCHILD: + pCurChild = GetChildInterface(varCur.lVal); + if(pCurChild==nullptr) + { + return nullptr; + } + pCurChild->GetUNOInterface(&nHyper); + if(pChildXAcc==nullptr) + { + return nullptr; + } + pChildContext = GetContextByXAcc(pChildXAcc); + if(pChildContext == nullptr) + { + return nullptr; + } + delta = (flags==DM_NEXTCHILD)?1:-1; + //currently, getAccessibleIndexInParent is error in UNO for + //some kind of List,such as ValueSet, the index will be less 1 than + //what should be, need to fix UNO code + index = pChildContext->getAccessibleIndexInParent()+delta; + if((index>=0)&&(index<=count-1)) + { + pRChildXAcc = pXContext->getAccessibleChild(index); + } + break; + default: + break; + } + + if(!pRChildXAcc.is()) + { + return nullptr; + } + pChildXAcc = pRChildXAcc.get(); + g_pAccObjectManager->InsertAccObj(pChildXAcc, m_xAccessible.get()); + return g_pAccObjectManager->GetIAccessibleFromXAccessible(pChildXAcc); +} + +/** +*the following 4 private methods are for accNavigate implementation +*/ + +/** +* Return first child for parent container, process differently according +* to whether it is descendant manage +* @param varStart, the start child id of this navigation action. +* @param pvarEndUpAt, [in,out] the end up child of this navigation action. +* @return S_OK if successful and E_FAIL if failure. +*/ +HRESULT CMAccessible::GetFirstChild(VARIANT varStart,VARIANT* pvarEndUpAt) +{ + + try { + if (m_isDestroy) return S_FALSE; + + if(pvarEndUpAt == nullptr) + { + return E_INVALIDARG; + } + if(varStart.vt != VT_I4) + { + pvarEndUpAt->vt = VT_EMPTY; + return E_INVALIDARG; + } + + pvarEndUpAt->pdispVal = GetNavigateChildForDM(varStart, DM_FIRSTCHILD); + if(pvarEndUpAt->pdispVal) + { + pvarEndUpAt->pdispVal->AddRef(); + pvarEndUpAt->vt = VT_DISPATCH; + return S_OK; + } + + pvarEndUpAt->vt = VT_EMPTY; + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** +* Return last child for parent container, process differently according +* to whether it is descendant manage +* @param varStart, the start child id of this navigation action. +* @param pvarEndUpAt, [in,out] the end up child of this navigation action. +* @return S_OK if successful and E_FAIL if failure. +*/ +HRESULT CMAccessible::GetLastChild(VARIANT varStart,VARIANT* pvarEndUpAt) +{ + + try { + if (m_isDestroy) return S_FALSE; + + if(pvarEndUpAt == nullptr) + { + return E_INVALIDARG; + } + if(varStart.vt != VT_I4) + { + pvarEndUpAt->vt = VT_EMPTY; + return E_INVALIDARG; + } + + pvarEndUpAt->pdispVal = GetNavigateChildForDM(varStart, DM_LASTCHILD); + if(pvarEndUpAt->pdispVal) + { + pvarEndUpAt->pdispVal->AddRef(); + pvarEndUpAt->vt = VT_DISPATCH; + return S_OK; + } + pvarEndUpAt->vt = VT_EMPTY; + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** +* The method GetNextSibling is general, whatever it is descendant manage or not +* Get the next sibling object. +* @param varStart, the start child id of this navigation action. +* @param pvarEndUpAt, [in,out] the end up child of this navigation action. +* @return S_OK if successful and E_FAIL if failure. +*/ +HRESULT CMAccessible::GetNextSibling(VARIANT varStart,VARIANT* pvarEndUpAt) +{ + + try { + if (m_isDestroy) return S_FALSE; + if(varStart.vt != VT_I4) + { + pvarEndUpAt->vt = VT_EMPTY; + return E_INVALIDARG; + } + + Reference<XAccessibleContext> const pRContext = + GetContextByXAcc(m_xAccessible.get()); + if(pRContext.is()) + { + varStart.iVal = sal_Int16(pRContext->getAccessibleIndexInParent() + 2); + if(m_pIParent) + if( m_pIParent->get_accChild(varStart,&pvarEndUpAt->pdispVal) == S_OK) + { + pvarEndUpAt->vt = VT_DISPATCH; + return S_OK; + } + } + pvarEndUpAt->vt = VT_EMPTY; + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** +*the method GetPreSibling is general, whatever it is descendant manage or not +* @param varStart, the start child id of this navigation action. +* @param pvarEndUpAt, [in,out] the end up child of this navigation action. +* @return S_OK if successful and E_FAIL if failure. +*/ +HRESULT CMAccessible::GetPreSibling(VARIANT varStart,VARIANT* pvarEndUpAt) +{ + + try { + if (m_isDestroy) return S_FALSE; + + if(pvarEndUpAt == nullptr) + { + return E_INVALIDARG; + } + if(varStart.vt != VT_I4) + { + pvarEndUpAt->vt = VT_EMPTY; + return E_INVALIDARG; + } + + Reference<XAccessibleContext> const pRContext = + GetContextByXAcc(m_xAccessible.get()); + if(pRContext.is()) + { + varStart.iVal = sal_Int16(pRContext->getAccessibleIndexInParent()); + if(m_pIParent && varStart.iVal > 0) + if( m_pIParent->get_accChild(varStart,&pvarEndUpAt->pdispVal) == S_OK) + { + pvarEndUpAt->vt = VT_DISPATCH; + return S_OK; + } + } + pvarEndUpAt->vt = VT_EMPTY; + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +/** +* For IAccessible2 implementation methods +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_nRelations( long __RPC_FAR *nRelations) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(nRelations == nullptr) + { + return E_INVALIDARG; + } + + *nRelations = 0; + + if (!m_xContext.is()) + return E_FAIL; + Reference<XAccessibleRelationSet> pRrelationSet = + m_xContext->getAccessibleRelationSet(); + if(!pRrelationSet.is()) + { + *nRelations = 0; + return S_OK; + } + + *nRelations = pRrelationSet->getRelationCount(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_relation( long relationIndex, IAccessibleRelation __RPC_FAR *__RPC_FAR *relation) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(relation == nullptr) + { + return E_INVALIDARG; + } + + if (!m_xContext.is()) + return E_FAIL; + + + long nMax = 0; + get_nRelations(&nMax); + + *relation = static_cast<IAccessibleRelation*>(::CoTaskMemAlloc(sizeof(IAccessibleRelation))); + + // #CHECK Memory Allocation# + if(*relation == nullptr) + { + return E_FAIL; + } + + if( relationIndex < nMax ) + { + Reference<XAccessibleRelationSet> const pRrelationSet = + m_xContext->getAccessibleRelationSet(); + if(!pRrelationSet.is()) + { + + return E_FAIL; + } + + IAccessibleRelation* pRelation = nullptr; + HRESULT hr = createInstance<CAccRelation>(IID_IAccessibleRelation, + &pRelation); + if(SUCCEEDED(hr)) + { + IUNOXWrapper* wrapper = nullptr; + hr = pRelation->QueryInterface(IID_IUNOXWrapper, reinterpret_cast<void**>(&wrapper)); + if(SUCCEEDED(hr)) + { + AccessibleRelation accRelation = pRrelationSet->getRelation(relationIndex); + wrapper->put_XSubInterface( + reinterpret_cast<hyper>(&accRelation)); + wrapper->Release(); + *relation = pRelation; + return S_OK; + } + + } + } + + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_relations( long, IAccessibleRelation __RPC_FAR *__RPC_FAR *relation, long __RPC_FAR *nRelations) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(relation == nullptr || nRelations == nullptr) + { + return E_INVALIDARG; + } + + if (!m_xContext.is()) + return E_FAIL; + + Reference<XAccessibleRelationSet> const pRrelationSet = + m_xContext->getAccessibleRelationSet(); + if(!pRrelationSet.is()) + { + *nRelations = 0; + return S_OK; + } + + long nCount = pRrelationSet->getRelationCount(); + + *relation = static_cast<IAccessibleRelation*>(::CoTaskMemAlloc(nCount*sizeof(IAccessibleRelation))); + + // #CHECK Memory Allocation# + if(*relation == nullptr) + { + return E_FAIL; + } + + for(int i=0; i<nCount ; i++) + { + IAccessibleRelation* pRelation = nullptr; + HRESULT hr = createInstance<CAccRelation>(IID_IAccessibleRelation, + &pRelation); + if(SUCCEEDED(hr)) + { + IUNOXWrapper* wrapper = nullptr; + hr = pRelation->QueryInterface(IID_IUNOXWrapper, reinterpret_cast<void**>(&wrapper)); + if(SUCCEEDED(hr)) + { + AccessibleRelation accRelation = pRrelationSet->getRelation(i); + wrapper->put_XSubInterface( + reinterpret_cast<hyper>(&accRelation)); + wrapper->Release(); + } + relation[i] = pRelation; + } + } + + *nRelations = nCount; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::role(long __RPC_FAR *role) +{ + SolarMutexGuard g; + + try { + + (*role) = m_iRole; + + return S_OK; + + } catch(...) { return E_FAIL; } +} + + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_nActions(long __RPC_FAR *nActions) +{ + SolarMutexGuard g; + + try + { + if (m_isDestroy) return S_FALSE; + + if(nActions == nullptr) + { + return E_INVALIDARG; + } + *nActions = 0; + IAccessibleAction* pAcc = nullptr; + HRESULT hr = QueryInterface(IID_IAccessibleAction, reinterpret_cast<void**>(&pAcc)); + if( hr == S_OK ) + { + pAcc->nActions(nActions); + pAcc->Release(); + } + + return S_OK; + } + catch(...) + { + *nActions = 0; + return S_OK; + } +} + + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::scrollToPoint(enum IA2CoordinateType, long, long) +{ + return E_NOTIMPL; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::scrollTo(enum IA2ScrollType) +{ + return E_NOTIMPL; +} + +static XAccessible* getTheParentOfMember(XAccessible* pXAcc) +{ + if(pXAcc == nullptr) + { + return nullptr; + } + Reference<XAccessibleContext> pRContext = pXAcc->getAccessibleContext(); + Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet(); + sal_Int32 nRelations = pRrelationSet->getRelationCount(); + for(sal_Int32 i=0 ; i<nRelations ; i++) + { + AccessibleRelation accRelation = pRrelationSet->getRelation(i); + if(accRelation.RelationType == 7) + { + Sequence< Reference< XInterface > > xTargets = accRelation.TargetSet; + return static_cast<XAccessible*>(xTargets[0].get()); + } + } + return nullptr; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_groupPosition(long __RPC_FAR *groupLevel,long __RPC_FAR *similarItemsInGroup,long __RPC_FAR *positionInGroup) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(groupLevel == nullptr || similarItemsInGroup == nullptr || positionInGroup == nullptr) + { + return E_INVALIDARG; + } + + if (!m_xAccessible.is()) + return E_FAIL; + + Reference<XAccessibleContext> const pRContext = + m_xAccessible->getAccessibleContext(); + if(!pRContext.is()) + return E_FAIL; + const sal_Int16 nRole = pRContext->getAccessibleRole(); + + *groupLevel = 0; + *similarItemsInGroup = 0; + *positionInGroup = 0; + + if (nRole != AccessibleRole::DOCUMENT && nRole != AccessibleRole::DOCUMENT_PRESENTATION && + nRole != AccessibleRole::DOCUMENT_SPREADSHEET && nRole != AccessibleRole::DOCUMENT_TEXT) + { + Reference< XAccessibleGroupPosition > xGroupPosition( pRContext, UNO_QUERY ); + if ( xGroupPosition.is() ) + { + Sequence< sal_Int32 > rSeq = xGroupPosition->getGroupPosition( Any( pRContext ) ); + if (rSeq.getLength() >= 3) + { + *groupLevel = rSeq[0]; + *similarItemsInGroup = rSeq[1]; + *positionInGroup = rSeq[2]; + return S_OK; + } + return S_OK; + } + } + + Reference< XAccessible> pParentAcc = pRContext->getAccessibleParent(); + if( !pParentAcc.is() ) + { + return S_OK; + } + + Reference<XAccessibleContext> pRParentContext = pParentAcc->getAccessibleContext(); + + if (nRole == AccessibleRole::RADIO_BUTTON) + { + int index = 0; + int number = 0; + Reference<XAccessibleRelationSet> pRrelationSet = pRContext->getAccessibleRelationSet(); + long nRel = pRrelationSet->getRelationCount(); + for(int i=0 ; i<nRel ; i++) + { + AccessibleRelation accRelation = pRrelationSet->getRelation(i); + if(accRelation.RelationType == 7) + { + Sequence< Reference< XInterface > > xTargets = accRelation.TargetSet; + + Reference<XInterface> pRAcc = xTargets[0]; + sal_Int64 nChildCount = pRParentContext->getAccessibleChildCount(); + assert(nChildCount < std::numeric_limits<long>::max()); + for (sal_Int64 j = 0; j< nChildCount; j++) + { + if( getTheParentOfMember(pRParentContext->getAccessibleChild(j).get()) + == static_cast<XAccessible*>(pRAcc.get()) && + pRParentContext->getAccessibleChild(j)->getAccessibleContext()->getAccessibleRole() == AccessibleRole::RADIO_BUTTON) + number++; + if (pRParentContext->getAccessibleChild(j).get() == m_xAccessible.get()) + index = number; + } + } + } + *groupLevel = 1; + *similarItemsInGroup = number; + *positionInGroup = index; + return S_OK; + } + + else if (nRole == AccessibleRole::COMBO_BOX) + { + *groupLevel = 1; + *similarItemsInGroup = 0; + *positionInGroup = -1; + + if (pRContext->getAccessibleChildCount() != 2) + { + return S_OK; + } + Reference<XAccessible> xList=pRContext->getAccessibleChild(1); + if (!xList.is()) + { + return S_OK; + } + Reference<XAccessibleContext> xListContext(xList,UNO_QUERY); + if (!xListContext.is()) + { + return S_OK; + } + Reference<XAccessibleSelection> xListSel(xList,UNO_QUERY); + if (!xListSel.is()) + { + return S_OK; + } + sal_Int64 nChildCount = xListContext->getAccessibleChildCount(); + assert(nChildCount < std::numeric_limits<long>::max()); + *similarItemsInGroup = nChildCount; + if (*similarItemsInGroup > 0 ) + { + try + { + Reference<XAccessible> xChild = xListSel->getSelectedAccessibleChild(0); + if (xChild.is()) + { + Reference<XAccessibleContext> xChildContext(xChild,UNO_QUERY); + if (xChildContext.is()) + { + *positionInGroup=xChildContext->getAccessibleIndexInParent() + 1 ; + return S_OK; + } + } + } + catch(...) + {} + } + return S_OK; + } + else if (nRole == AccessibleRole::PAGE_TAB) + { + *groupLevel = 1; + sal_Int64 nChildCount = pRParentContext->getAccessibleChildCount(); + assert(nChildCount < std::numeric_limits<long>::max()); + *similarItemsInGroup = nChildCount; + if (*similarItemsInGroup > 0 ) + { + *positionInGroup=pRContext->getAccessibleIndexInParent() + 1 ; + } + else + { + *positionInGroup = -1; + } + return S_OK; + } + + int level = 0; + bool isFound = false; + while( pParentAcc.is() && !isFound) + { + level++; + pRParentContext = pParentAcc->getAccessibleContext(); + const sal_Int16 nParentRole = pRParentContext->getAccessibleRole(); + if ((nParentRole == AccessibleRole::TREE) || (nParentRole == AccessibleRole::LIST)) + isFound = true; + pParentAcc = pRParentContext->getAccessibleParent(); + } + + if( isFound ) + { + Reference< XAccessible> pTempAcc = pRContext->getAccessibleParent(); + pRParentContext = pTempAcc->getAccessibleContext(); + *groupLevel = level; + sal_Int64 nChildCount = pRParentContext->getAccessibleChildCount(); + assert(nChildCount < std::numeric_limits<long>::max()); + *similarItemsInGroup = nChildCount; + *positionInGroup = pRContext->getAccessibleIndexInParent() + 1; + } + else + { + *groupLevel = 0; + *similarItemsInGroup = 0; + *positionInGroup = 0; + } + return S_OK; + + } catch(...) { return E_FAIL; } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_extendedStates(long, BSTR __RPC_FAR *__RPC_FAR *, long __RPC_FAR *) +{ + return E_NOTIMPL; +} + + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_uniqueID(long __RPC_FAR *uniqueID) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(uniqueID == nullptr) + { + return E_INVALIDARG; + } + *uniqueID = m_dChildID; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_windowHandle(HWND __RPC_FAR *windowHandle) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(windowHandle == nullptr) + { + return E_INVALIDARG; + } + + HWND nHwnd = m_hwnd; + IAccessible* pParent = m_pIParent; + while((nHwnd==nullptr) && pParent) + { + if (CMAccessible* pChild = dynamic_cast<CMAccessible*>(pParent)) + { + pParent = pChild->m_pIParent; + nHwnd = pChild->m_hwnd; + } + else + pParent = nullptr; + } + + *windowHandle = nHwnd; + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** +* Get XAccessibleContext directly from UNO by the stored XAccessible pointer +* @param pXAcc, UNO XAccessible object point. +* @return XAccessibleContext*, the context of the pXAcc. +*/ +XAccessibleContext* CMAccessible::GetContextByXAcc( XAccessible* pXAcc ) +{ + Reference< XAccessibleContext > pRContext; + if( pXAcc == nullptr) + return nullptr; + + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return nullptr; + return pRContext.get(); +} + +/** +* When COM is created, UNO set XAccessible pointer to it +* in order to COM can operate UNO information +* @param pXAcc, the XAccessible object of current object. +* @return S_OK if successful. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::SetXAccessible(hyper pXAcc) +{ + // internal IMAccessible - no mutex meeded + + m_xAccessible = reinterpret_cast<XAccessible*>(pXAcc); + m_pEnumVar->PutSelection(/*XAccessibleSelection*/ + reinterpret_cast<hyper>(m_xAccessible.get())); + + m_xContext = m_xAccessible->getAccessibleContext(); + + return S_OK; +} + +/** +* accSelect method has many optional flags, needs to process comprehensively +* Mozilla and Microsoft do not implement SELFLAG_EXTENDSELECTION flag. +* The implementation of this flag is a little trouble-shooting,so we also +* do not implement it now +* @param flagsSelect, the selection flag of the select action. +* @param varChild, the child object pointer of current action. +* @return S_OK if successful. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::accSelect(long flagsSelect, VARIANT varChild) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + if( (flagsSelect&SELFLAG_ADDSELECTION) && + (SELFLAG_REMOVESELECTION&flagsSelect) ) + return E_INVALIDARG; + + if ( (flagsSelect&SELFLAG_TAKESELECTION) && + ( + (flagsSelect&SELFLAG_ADDSELECTION) || + (flagsSelect&SELFLAG_REMOVESELECTION) || + (flagsSelect&SELFLAG_EXTENDSELECTION ) + ) + ) + return E_INVALIDARG; + + if ( varChild.vt != VT_I4 ) + return E_INVALIDARG; + + IMAccessible* pSelectAcc; + if( varChild.lVal == CHILDID_SELF ) + { + pSelectAcc = this; + pSelectAcc->AddRef(); + } + else + { + pSelectAcc = GetChildInterface(varChild.lVal); + } + + if( pSelectAcc == nullptr ) + return E_INVALIDARG; + + if( flagsSelect&SELFLAG_TAKEFOCUS ) + { + union { + XAccessible* pTempUNO; + hyper nHyper = 0; + }; + pSelectAcc->GetUNOInterface(&nHyper); + + if( pTempUNO == nullptr ) + return 0; + + Reference<XAccessibleContext> pRContext = pTempUNO->getAccessibleContext(); + Reference< XAccessibleComponent > pRComponent(pRContext,UNO_QUERY); + Reference< XAccessible > pRParentXAcc = pRContext->getAccessibleParent(); + Reference< XAccessibleContext > pRParentContext = pRParentXAcc->getAccessibleContext(); + Reference< XAccessibleComponent > pRParentComponent(pRParentContext,UNO_QUERY); + Reference< XAccessibleSelection > pRParentSelection(pRParentContext,UNO_QUERY); + + + pRComponent->grabFocus(); + + if( flagsSelect & SELFLAG_TAKESELECTION ) + { + pRParentSelection->clearAccessibleSelection(); + pRParentSelection->selectAccessibleChild( pRContext->getAccessibleIndexInParent() ); + } + + if( flagsSelect & SELFLAG_ADDSELECTION ) + { + pRParentSelection->selectAccessibleChild( pRContext->getAccessibleIndexInParent() ); + } + + if( flagsSelect & SELFLAG_REMOVESELECTION ) + { + pRParentSelection->deselectAccessibleChild( pRContext->getAccessibleIndexInParent() ); + } + + if( flagsSelect & SELFLAG_EXTENDSELECTION ) + { + sal_Int64 indexInParrent = pRContext->getAccessibleIndexInParent(); + + if( pRParentSelection->isAccessibleChildSelected( indexInParrent + 1 ) || + pRParentSelection->isAccessibleChildSelected( indexInParrent - 1 ) ) + { + pRParentSelection->selectAccessibleChild( indexInParrent ); + } + } + + } + + pSelectAcc->Release(); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +/** +* Return XAccessible interface pointer when needed +* @param pXAcc, [in, out] the Uno interface of the current object. +* @return S_OK if successful. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::GetUNOInterface(hyper * pXAcc) +{ + // internal IMAccessible - no mutex meeded + + if(pXAcc == nullptr) + return E_INVALIDARG; + + *pXAcc = reinterpret_cast<hyper>(m_xAccessible.get()); + return S_OK; +} + +/** +* Helper method for Implementation of get_accDefaultAction +* @param pAction, the default action point of the current object. +* @return S_OK if successful. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::SetDefaultAction(hyper pAction) +{ + // internal IMAccessible - no mutex meeded + + m_xAction = reinterpret_cast<XAccessibleAction*>(pAction); + return S_OK; +} + +/** +* This method is called when AT open some UI elements initially +* the UI element takes the default action defined here +* @param varChild, the child id of the defaultaction. +* @param pszDefaultAction,[in/out] the description of the current action. +* @return S_OK if successful. +*/ +COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CMAccessible::get_accDefaultAction(VARIANT varChild, BSTR *pszDefaultAction) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if(pszDefaultAction == nullptr) + { + return E_INVALIDARG; + } + if(varChild.vt==VT_I4) + { + if(varChild.lVal==CHILDID_SELF) + { + if (!m_xAction.is()) + return DISP_E_MEMBERNOTFOUND; + SysFreeString(*pszDefaultAction); + *pszDefaultAction = SysAllocString(m_pszActionDescription); + return S_OK; + } + + long lVal = varChild.lVal; + varChild.lVal = CHILDID_SELF; + IMAccessible *pChild = this->GetChildInterface(lVal); + if(!pChild) + return E_FAIL; + return pChild->get_accDefaultAction(varChild,pszDefaultAction); + } + return S_FALSE; + + } catch(...) { return E_FAIL; } +} + +/** +* AT call this method to operate application +* @param varChild, the child id of the action object. +* @return S_OK if successful. +*/ +COM_DECLSPEC_NOTHROW HRESULT STDMETHODCALLTYPE CMAccessible::accDoDefaultAction(VARIANT varChild) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + if( varChild.vt != VT_I4 ) + return E_INVALIDARG; + if (!m_xAction.is()) + return E_FAIL; + if (m_xAction->getAccessibleActionCount() == 0) + return E_FAIL; + + if(varChild.lVal==CHILDID_SELF) + { + if (m_xAction->getAccessibleActionCount() > 0) + m_xAction->doAccessibleAction(0); + return S_OK; + } + + long lVal = varChild.lVal; + varChild.lVal = CHILDID_SELF; + IMAccessible *pChild = this->GetChildInterface(lVal); + if(!pChild) + return E_FAIL; + return pChild->accDoDefaultAction( varChild ); + + } catch(...) { return E_FAIL; } +} + +/** +* UNO set description information for action to COM. +* @param szAction, the action description of the current object. +* @return S_OK if successful. +*/ +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::Put_ActionDescription( const OLECHAR* szAction) +{ + // internal IMAccessible - no mutex meeded + + try { + if (m_isDestroy) return S_FALSE; + + if(szAction == nullptr) + { + return E_INVALIDARG; + } + SysFreeString(m_pszActionDescription ); + m_pszActionDescription = SysAllocString( szAction ); + return S_OK; + + } catch(...) { return E_FAIL; } +} + +bool CMAccessible::GetXInterfaceFromXAccessible(XAccessible* pXAcc, XInterface** ppXI, XInterfaceType eType) +{ + switch(eType) + { + case XInterfaceType::XI_COMPONENT: + return queryXInterface<XAccessibleComponent>(pXAcc, ppXI); + case XInterfaceType::XI_TEXT: + return queryXInterface<XAccessibleText>(pXAcc, ppXI); + case XInterfaceType::XI_EDITABLETEXT: + return queryXInterface<XAccessibleEditableText>(pXAcc, ppXI); + case XInterfaceType::XI_TABLE: + return queryXInterface<XAccessibleTable>(pXAcc, ppXI); + case XInterfaceType::XI_TABLECELL: + // needs specific handling, since there's no XInterface for table cells + return queryTableCell(pXAcc, ppXI); + case XInterfaceType::XI_SELECTION: + return queryXInterface<XAccessibleSelection>(pXAcc, ppXI); + case XInterfaceType::XI_EXTENDEDCOMP: + return queryXInterface<XAccessibleExtendedComponent>(pXAcc, ppXI); + case XInterfaceType::XI_KEYBINDING: + return queryXInterface<XAccessibleKeyBinding>(pXAcc, ppXI); + case XInterfaceType::XI_ACTION: + return queryXInterface<XAccessibleAction>(pXAcc, ppXI); + case XInterfaceType::XI_VALUE: + return queryXInterface<XAccessibleValue>(pXAcc, ppXI); + case XInterfaceType::XI_HYPERTEXT: + return queryXInterface<XAccessibleHypertext>(pXAcc, ppXI); + case XInterfaceType::XI_HYPERLINK: + return queryXInterface<XAccessibleHyperlink>(pXAcc, ppXI); + case XInterfaceType::XI_IMAGE: + return queryXInterface<XAccessibleImage>(pXAcc, ppXI); + default: + return false; + } +} + +template<typename T> static HRESULT +createAggInstance(CMAccessible &rOuter, void ** ppvObject) +{ + // Note: CComAggObject has special handling for IUnknown - must + // query for that when creating it! Otherwise we get a T member of it + // which will redirect QueryInterface back to CMAccessible infinitely. + // (CComAggObject has its own ref-count too which is not a problem + // since it is inserted in m_containedObjects.) + return CComCreator< CComAggObject<T> >::CreateInstance( + rOuter.GetControllingUnknown(), IID_IUnknown, ppvObject); +} + +typedef HRESULT (AggCreatorFunc)(CMAccessible &, void **); + +namespace { + +struct AggMapEntry +{ + const IID* piid; + AggCreatorFunc* pfnCreateInstance; + const XInterfaceType eXInterfaceType; +}; + +} + +static AggMapEntry g_CMAccessible_AggMap[] = { + { &IID_IAccessibleComponent, &createAggInstance<CAccComponent>, XInterfaceType::XI_COMPONENT }, + { &IID_IAccessibleText, &createAggInstance<CAccText>, XInterfaceType::XI_TEXT }, + { &IID_IAccessibleEditableText, &createAggInstance<CAccEditableText>, XInterfaceType::XI_EDITABLETEXT }, + { &IID_IAccessibleImage, &createAggInstance<CAccImage>, XInterfaceType::XI_IMAGE }, + { &IID_IAccessibleTable, &createAggInstance<CAccTable>, XInterfaceType::XI_TABLE }, + { &IID_IAccessibleTable2, &createAggInstance<CAccTable>, XInterfaceType::XI_TABLE }, + { &IID_IAccessibleTableCell, &createAggInstance<CAccTableCell>, XInterfaceType::XI_TABLECELL }, + { &IID_IAccessibleAction, &createAggInstance<CAccAction>, XInterfaceType::XI_ACTION }, + { &IID_IAccessibleValue, &createAggInstance<CAccValue>, XInterfaceType::XI_VALUE }, + { &IID_IAccessibleHypertext, &createAggInstance<CAccHypertext>, XInterfaceType::XI_HYPERTEXT }, + { &IID_IAccessibleHyperlink, &createAggInstance<CAccHyperLink>, XInterfaceType::XI_HYPERLINK } +}; + + +HRESULT WINAPI CMAccessible::SmartQI(void* /*pv*/, REFIID iid, void** ppvObject) +{ + try { + + if (m_isDestroy) return S_FALSE; + if (InlineIsEqualGUID(iid,IID_IAccIdentity) || + InlineIsEqualGUID(iid,IID_IStdMarshalInfo) || + InlineIsEqualGUID(iid,IID_IMarshal) || + InlineIsEqualGUID(iid,IID_IExternalConnection)|| + InlineIsEqualGUID(iid,IID_IOleWindow)) + { + return E_FAIL; + } + + for (const AggMapEntry& rEntry : g_CMAccessible_AggMap) + { + if (InlineIsEqualGUID(iid, *rEntry.piid)) + { + SolarMutexGuard g; + + XInterface* pXI = nullptr; + bool bFound = GetXInterfaceFromXAccessible(m_xAccessible.get(), + &pXI, rEntry.eXInterfaceType); + if(!bFound) + { + return E_FAIL; + } + + XGUIDToComObjHash::iterator pIndTemp = m_containedObjects.find( iid ); + if ( pIndTemp != m_containedObjects.end() ) + { + return pIndTemp->second.p->QueryInterface( iid, ppvObject ); + } + else + { + HRESULT hr = rEntry.pfnCreateInstance(*this, ppvObject); + assert(hr == S_OK); + if(hr == S_OK) + { + m_containedObjects.emplace(*rEntry.piid, static_cast<IUnknown*>(*ppvObject)); + IUNOXWrapper* wrapper = nullptr; + static_cast<IUnknown*>(*ppvObject)->QueryInterface(IID_IUNOXWrapper, reinterpret_cast<void**>(&wrapper)); + if(wrapper) + { + wrapper->put_XInterface( + reinterpret_cast<hyper>(m_xAccessible.get())); + wrapper->Release(); + } + return S_OK; + } + } + return E_FAIL; + } + } + return E_FAIL; + + } catch(...) { return E_FAIL; } +} + +IAccessible* CMAccessible::get_IAccessibleFromXAccessible(XAccessible* pXAcc) +{ + try + { + if (g_pAccObjectManager) + return g_pAccObjectManager->GetIAccessibleFromXAccessible(pXAcc); + } + catch(...) + { + } + return nullptr; +} + +void CMAccessible::ConvertAnyToVariant(const css::uno::Any &rAnyVal, VARIANT *pvData) +{ + if(rAnyVal.hasValue()) + { + // Clear VARIANT variable. + VariantClear(pvData); + + // Set value according to value type. + switch(rAnyVal.getValueTypeClass()) + { + case TypeClass_CHAR: + pvData->vt = VT_UI1; + memcpy(&pvData->bVal, rAnyVal.getValue(), sizeof(char)); + break; + + case TypeClass_BOOLEAN: + { + bool bBoolean(false); + rAnyVal >>= bBoolean; + pvData->vt = VT_BOOL; + pvData->boolVal = VARIANT_BOOL(bBoolean); // boolVal is a VARIANT_BOOL, a 16bit field + break; + } + case TypeClass_BYTE: + pvData->vt = VT_UI1; + memcpy(&pvData->bVal, rAnyVal.getValue(), sizeof(sal_Int8)); + break; + + case TypeClass_SHORT: + pvData->vt = VT_I2; + memcpy(&pvData->iVal, rAnyVal.getValue(), sizeof(sal_Int16)); + break; + + case TypeClass_UNSIGNED_SHORT: + pvData->vt = VT_I2; + memcpy(&pvData->iVal, rAnyVal.getValue(), sizeof(sal_uInt16)); + break; + + case TypeClass_LONG: + pvData->vt = VT_I4; + memcpy(&pvData->lVal, rAnyVal.getValue(), sizeof(sal_Int32)); + break; + + case TypeClass_UNSIGNED_LONG: + pvData->vt = VT_I4; + memcpy(&pvData->lVal, rAnyVal.getValue(), sizeof(sal_uInt32)); + break; + + case TypeClass_FLOAT: + pvData->vt = VT_R4; + memcpy(&pvData->fltVal, rAnyVal.getValue(), sizeof(float)); + break; + + case TypeClass_DOUBLE: + pvData->vt = VT_R8; + memcpy(&pvData->dblVal, rAnyVal.getValue(), sizeof(double)); + break; + + case TypeClass_STRING: + { + pvData->vt = VT_BSTR; + OUString val; + rAnyVal >>= val; + pvData->bstrVal = SysAllocString(o3tl::toW(val.getStr())); + break; + } + + case TypeClass_VOID: + case TypeClass_HYPER: + case TypeClass_UNSIGNED_HYPER: + case TypeClass_TYPE: + case TypeClass_ANY: + case TypeClass_ENUM: + case TypeClass_TYPEDEF: + case TypeClass_STRUCT: + case TypeClass_EXCEPTION: + case TypeClass_SEQUENCE: + case TypeClass_INTERFACE: + { + Reference< XAccessible > pXAcc; + if(rAnyVal >>= pXAcc) + { + if(pXAcc.is()) + { + IAccessible* pIAcc = get_IAccessibleFromXAccessible(pXAcc.get()); + if(pIAcc == nullptr) + { + Reference< XAccessibleContext > pXAccContext = pXAcc->getAccessibleContext(); + g_pAccObjectManager->InsertAccObj(pXAcc.get(),pXAccContext->getAccessibleParent().get()); + pIAcc = get_IAccessibleFromXAccessible(pXAcc.get()); + } + if(pIAcc) + { + pIAcc->AddRef(); + + pvData->vt = VT_UNKNOWN; + pvData->pdispVal = pIAcc; + break; + } + } + } + [[fallthrough]]; + } + case TypeClass_SERVICE: + case TypeClass_MODULE: + case TypeClass_INTERFACE_METHOD: + case TypeClass_INTERFACE_ATTRIBUTE: + case TypeClass_UNKNOWN: + case TypeClass_PROPERTY: + case TypeClass_CONSTANT: + case TypeClass_CONSTANTS: + case TypeClass_SINGLETON: + case TypeClass::TypeClass_MAKE_FIXED_SIZE: + // Output the type string, if there is other uno value type. + pvData->vt = VT_BSTR; + pvData->bstrVal = SysAllocString(o3tl::toW(rAnyVal.getValueTypeName().getStr())); + break; + + default: + break; + } + } + else + { + VariantClear(pvData); + } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_states(AccessibleStates __RPC_FAR *states) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if (!m_xContext.is()) + return E_FAIL; + + sal_Int64 const nRStateSet = + m_xContext->getAccessibleStateSet(); + + *states = 0x0; + for (int i = 0; i < 63; ++i) + { + sal_Int64 nUnoState = sal_Int64(1) << i; + if (nRStateSet & nUnoState) + lcl_addIA2State(*states, nUnoState, m_xContext->getAccessibleRole()); + } + + return S_OK; + + + } catch(...) { return E_FAIL; } +} + +// return the UNO roles +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_extendedRole(BSTR __RPC_FAR *) +{ + return E_NOTIMPL; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_localizedExtendedRole(BSTR __RPC_FAR *) +{ + return E_NOTIMPL; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_nExtendedStates(long __RPC_FAR *) +{ + return E_NOTIMPL; +} + + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_localizedExtendedStates(long, BSTR __RPC_FAR *__RPC_FAR *, long __RPC_FAR *) +{ + return E_NOTIMPL; +} + + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_indexInParent(long __RPC_FAR *accParentIndex) +{ + try { + if (m_isDestroy) return S_FALSE; + + if(accParentIndex == nullptr) + return E_INVALIDARG; + + if (!m_xContext.is()) + return E_FAIL; + + sal_Int64 nIndex = m_xContext->getAccessibleIndexInParent(); + if (nIndex > std::numeric_limits<long>::max()) + { + SAL_WARN("iacc2", "CMAccessible::get_indexInParent: Child index exceeds maximum long value, " + "returning max long."); + nIndex = std::numeric_limits<long>::max(); + } + *accParentIndex = nIndex; + return S_OK; + + + } catch(...) { return E_FAIL; } +} +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_locale( IA2Locale __RPC_FAR *locale ) +{ + try { + if (m_isDestroy) return S_FALSE; + if(locale == nullptr) + return E_INVALIDARG; + + if (!m_xContext.is()) + return E_FAIL; + + css::lang::Locale unoLoc = m_xContext->getLocale(); + locale->language = SysAllocString(o3tl::toW(unoLoc.Language.getStr())); + locale->country = SysAllocString(o3tl::toW(unoLoc.Country.getStr())); + locale->variant = SysAllocString(o3tl::toW(unoLoc.Variant.getStr())); + + return S_OK; + + } catch(...) { return E_FAIL; } +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_appName(BSTR __RPC_FAR *name) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + if(name == nullptr) + return E_INVALIDARG; + + static const OUString sAppName = utl::ConfigManager::getProductName(); + *name = SysAllocString(o3tl::toW(sAppName.getStr())); + return S_OK; + } catch(...) { return E_FAIL; } +} +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_appVersion(BSTR __RPC_FAR *version) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + if(version == nullptr) + return E_INVALIDARG; + static const OUString sVersion = utl::ConfigManager::getProductVersion(); + *version=SysAllocString(o3tl::toW(sVersion.getStr())); + return S_OK; + } catch(...) { return E_FAIL; } +} +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_toolkitName(BSTR __RPC_FAR *name) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + if(name == nullptr) + return E_INVALIDARG; + *name = SysAllocString(OLESTR("VCL")); + return S_OK; + } catch(...) { return E_FAIL; } +} +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_toolkitVersion(BSTR __RPC_FAR *version) +{ + return get_appVersion(version); +} + + +COM_DECLSPEC_NOTHROW STDMETHODIMP CMAccessible::get_attributes(/*[out]*/ BSTR *pAttr) +{ + SolarMutexGuard g; + + try { + if (m_isDestroy) return S_FALSE; + + if (!m_xAccessible.is()) + return E_FAIL; + + Reference<XAccessibleContext> pRContext = m_xAccessible->getAccessibleContext(); + if( !pRContext.is() ) + { + return E_FAIL; + } + + OUString sAttributes; + Reference<XAccessibleExtendedAttributes> pRXI(pRContext,UNO_QUERY); + if (pRXI.is()) + { + css::uno::Reference<css::accessibility::XAccessibleExtendedAttributes> pRXAttr; + pRXAttr = pRXI.get(); + css::uno::Any anyVal = pRXAttr->getExtendedAttributes(); + + OUString val; + anyVal >>= val; + sAttributes += val; + } + + // some text-specific IAccessible2 object attributes (like text alignment + // of a paragraph) are handled as text attributes in LibreOffice + Reference<XAccessibleText> xText(pRContext, UNO_QUERY); + if (xText.is()) + { + sal_Int32 nStartOffset = 0; + sal_Int32 nEndOffset = 0; + sAttributes += AccessibleTextAttributeHelper::GetIAccessible2TextAttributes( + xText, IA2AttributeType::ObjectAttributes, 0, nStartOffset, nEndOffset); + } + + if (*pAttr) + SysFreeString(*pAttr); + *pAttr = SysAllocString(o3tl::toW(sAttributes.getStr())); + + return S_OK; + } catch(...) { return E_FAIL; } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/MAccessible.h b/winaccessibility/source/UAccCOM/MAccessible.h new file mode 100644 index 0000000000..b0196267b7 --- /dev/null +++ b/winaccessibility/source/UAccCOM/MAccessible.h @@ -0,0 +1,225 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "stdafx.h" +#include "Resource.h" // main symbols +#include <map> +#include <string_view> +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleSelection.hpp> +#include <com/sun/star/accessibility/XAccessibleAction.hpp> +#include <AccObjectWinManager.hxx> +#include "EnumVariant.h" +#include "acccommon.h" +#include <rtl/ustring.hxx> + +namespace { +enum class XInterfaceType; +} + +/** + *This class implements IMAccessible interface, which inherits from IAccessible2, and + *in turn inherits from IAccessible. So its methods include the methods defined only in + *IAccessible, plus the methods defined only in IAccessible2, plus the methods defined + *only in IMAccessible. + */ +class ATL_NO_VTABLE CMAccessible : + public CComObjectRoot, + public CComCoClass<CMAccessible, &CLSID_MAccessible>, + public IDispatchImpl<IMAccessible, &IID_IMAccessible, &LIBID_UACCCOMLib>, + public IServiceProvider, + public IAccessibleApplication +{ + typedef ::std::map<const GUID, CComPtr<IUnknown>, ltComp> XGUIDToComObjHash; + +public: + CMAccessible(); + virtual ~CMAccessible(); + + DECLARE_NO_REGISTRY() + + DECLARE_GET_CONTROLLING_UNKNOWN() + + DECLARE_PROTECT_FINAL_CONSTRUCT() + + BEGIN_COM_MAP(CMAccessible) + COM_INTERFACE_ENTRY(IMAccessible) + COM_INTERFACE_ENTRY(IAccessible) + COM_INTERFACE_ENTRY(IAccessible2) + COM_INTERFACE_ENTRY(IDispatch) + COM_INTERFACE_ENTRY(IAccessibleApplication) + COM_INTERFACE_ENTRY(IServiceProvider) + COM_INTERFACE_ENTRY_FUNC_BLIND(0,SmartQI_) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winconsistent-missing-override" +#endif + END_COM_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + + // IMAccessible + STDMETHOD(put_accValue)(VARIANT varChild,BSTR szValue) override; + STDMETHOD(put_accName)(VARIANT varChild,BSTR szName) override; + STDMETHOD(accDoDefaultAction)(VARIANT varChild) override; + STDMETHOD(accHitTest)(long xLeft,long yTop,VARIANT *pvarChild) override; + STDMETHOD(accNavigate)(long navDir,VARIANT varStart,VARIANT *pvarEndUpAt) override; + STDMETHOD(accLocation)(long *pxLeft,long *pyTop,long *pcxWidth,long *pcyHeight,VARIANT varChild) override; + STDMETHOD(accSelect)(long flagsSelect,VARIANT varChild) override; + STDMETHOD(get_accDefaultAction)( VARIANT varChild,BSTR *pszDefaultAction) override; + STDMETHOD(get_accSelection)(VARIANT *pvarChildren) override; + STDMETHOD(get_accFocus)(VARIANT *pvarChild) override; + STDMETHOD(get_accKeyboardShortcut)( VARIANT varChild,BSTR *pszKeyboardShortcut) override; + STDMETHOD(get_accHelpTopic)(BSTR *pszHelpFile,VARIANT varChild,long *pidTopic) override; + STDMETHOD(get_accHelp)(VARIANT varChild,BSTR *pszHelp) override; + STDMETHOD(get_accState)(VARIANT varChild,VARIANT *pvarState) override; + STDMETHOD(get_accRole)(VARIANT varChild,VARIANT *pvarRole) override; + STDMETHOD(get_accDescription)(VARIANT varChild,BSTR *pszDescription) override; + STDMETHOD(get_accValue)( VARIANT varChild,BSTR *pszValue) override; + STDMETHOD(get_accName)(VARIANT varChild,BSTR *pszName) override; + STDMETHOD(get_accChild)(VARIANT varChild,IDispatch **ppdispChild) override; + STDMETHOD(get_accChildCount)(long *pcountChildren) override; + STDMETHOD(get_accParent)( IDispatch **ppdispParent) override; + + // methods which are defined only in the IAccessible2 + // These methods only declare here, and their implementation bodies are empty now. + STDMETHOD(get_nRelations)( long __RPC_FAR *nRelations) override; + STDMETHOD(get_relation)( long relationIndex, IAccessibleRelation __RPC_FAR *__RPC_FAR *relation) override; + STDMETHOD(get_relations)( long maxRelations, IAccessibleRelation __RPC_FAR *__RPC_FAR *relation, long __RPC_FAR *nRelations) override; + STDMETHOD(role)(long __RPC_FAR *role) override; + STDMETHOD(get_nActions)(long __RPC_FAR *nActions); + STDMETHOD(scrollTo)(enum IA2ScrollType scrollType) override; + STDMETHOD(scrollToPoint)(enum IA2CoordinateType coordinateType, long x, long y) override; + STDMETHOD(get_groupPosition)(long __RPC_FAR *groupLevel,long __RPC_FAR *similarItemsInGroup,long __RPC_FAR *positionInGroup) override; + STDMETHOD(get_states)( AccessibleStates __RPC_FAR *states ) override; + STDMETHOD(get_extendedRole)( BSTR __RPC_FAR *extendedRole ) override; + STDMETHOD(get_localizedExtendedRole)( BSTR __RPC_FAR *localizedExtendedRole ) override; + STDMETHOD(get_nExtendedStates)( long __RPC_FAR *nExtendedStates) override; + STDMETHOD(get_extendedStates)( long maxExtendedStates, BSTR __RPC_FAR *__RPC_FAR *extendedStates, long __RPC_FAR *nExtendedStates) override; + STDMETHOD(get_localizedExtendedStates)(long maxLocalizedExtendedStates,BSTR __RPC_FAR *__RPC_FAR *localizedExtendedStates,long __RPC_FAR *nLocalizedExtendedStates) override; + STDMETHOD(get_uniqueID)(long __RPC_FAR *uniqueID) override; + STDMETHOD(get_windowHandle)(HWND __RPC_FAR *windowHandle) override; + STDMETHOD(get_indexInParent)( long __RPC_FAR *accParentIndex ) override; + STDMETHOD(get_locale)( IA2Locale __RPC_FAR *locale ) override; + STDMETHOD(get_attributes)(/*[out]*/ BSTR *pAttr) override; + + //IServiceProvider. + STDMETHOD(QueryService)(REFGUID guidService, REFIID riid, void** ppvObject) override; + + //IAccessibleApplication + STDMETHOD(get_appName)(BSTR __RPC_FAR *name) override; + STDMETHOD(get_appVersion)(BSTR __RPC_FAR *version) override; + STDMETHOD(get_toolkitName)(BSTR __RPC_FAR *name) override; + STDMETHOD(get_toolkitVersion)(BSTR __RPC_FAR *version) override; + + // methods which are defined only in IMAccessible + // These methods are provided for UNO management system. + // The UNO management system use these methods to put Accessibility + // information to COM. + STDMETHOD(Put_XAccName)(const OLECHAR __RPC_FAR *pszName) override; + STDMETHOD(Put_XAccRole)(unsigned short pRole) override; + STDMETHOD(DecreaseState)(DWORD pXSate) override; + STDMETHOD(IncreaseState)(DWORD pXSate) override; + STDMETHOD(SetState)(DWORD pXSate) override; + STDMETHOD(Put_XAccValue)(const OLECHAR __RPC_FAR *pszAccValue) override; + STDMETHOD(Put_XAccFocus)(long dChildID) override; + STDMETHOD(Put_XAccParent)(IMAccessible __RPC_FAR *pIParent) override; + STDMETHOD(Put_XAccWindowHandle)(HWND hwnd) override; + STDMETHOD(Put_XAccChildID)(long dChildID) override; + STDMETHOD(Put_XAccObjectManager)(hyper pManager) override; + STDMETHOD(NotifyDestroy)() override; + STDMETHOD(Put_ActionDescription)( const OLECHAR* szAction) override; + STDMETHOD(SetDefaultAction)(hyper pAction) override; + STDMETHOD(GetUNOInterface)(hyper*) override; + STDMETHOD(SetXAccessible)(hyper) override; + +private: + BSTR m_pszName; + BSTR m_pszValue; + BSTR m_pszActionDescription; + unsigned short m_iRole; + DWORD m_dState; + IMAccessible* m_pIParent; + + // identify a COM object/Acc object uniquely + long m_dChildID; + // specify the focus child ID in object self and its direct children + + long m_dFocusChildID; + // parent window handle,will be used in the future application, its value comes from UNO + + HWND m_hwnd; + + // the COM class which implements IEnumVARIANT interface,currently only used in + // the implementation of get_accSelection + CEnumVariant* m_pEnumVar; + + // specify if the XAccessible is invalid + bool m_isDestroy; + + css::uno::Reference<css::accessibility::XAccessible> m_xAccessible; + // initially m_xAction and m_xContext are the same object + // but they may be different once AccObject::UpdateAction() is called? + css::uno::Reference<css::accessibility::XAccessibleAction> m_xAction; + css::uno::Reference<css::accessibility::XAccessibleContext> m_xContext; + +private: + + // the helper methods in order to implement the above public methods + IMAccessible* GetChildInterface(long dChildIndex);//notice here the parameter is child index,not child id + IMAccessible* GetNavigateChildForDM(VARIANT varCur,short flags);//for descendant manage + HRESULT GetFirstChild(VARIANT varStart,VARIANT* pvarEndUpAt);//for accNavigate implementation + HRESULT GetLastChild(VARIANT varStart,VARIANT* pvarEndUpAt);//for accNavigate implementation + HRESULT GetNextSibling(VARIANT varStart,VARIANT* pvarEndUpAt);//for accNavigate implementation + HRESULT GetPreSibling(VARIANT varStart,VARIANT* pvarEndUpAt);//for accNavigate implementation + + static css::accessibility::XAccessibleContext* GetContextByXAcc( + css::accessibility::XAccessible* pXAcc); + static bool GetXInterfaceFromXAccessible(css::accessibility::XAccessible*, + css::uno::XInterface**, XInterfaceType); + HRESULT WINAPI SmartQI(void* pv, REFIID iid, void** ppvObject); + +public: + // AccObjectWinManager is a management object in UNO, here keep its pointer for + // the implementation of accNavigate when descendant manage happens for List,Tree, or Table + // AccObjectWinManager and the following UNO objects XAccessible,XAccessibleSelection, + // XAccessibleAction are all used to operate UNO accessibility information directly when + // implement some specific MSAA methods,such as accSelection,accNavigate + static AccObjectWinManager* g_pAccObjectManager; + + static IAccessible* get_IAccessibleFromXAccessible(css::accessibility::XAccessible* pXAcc); + XGUIDToComObjHash m_containedObjects; + + static HRESULT WINAPI SmartQI_(void* pv, + REFIID iid, void** ppvObject, DWORD_PTR) + { + return static_cast<CMAccessible*>(pv)->SmartQI(pv,iid,ppvObject); + } + + // Helper function for data conversion. + static void ConvertAnyToVariant(const css::uno::Any &rAnyVal, + VARIANT *pvData); +}; + + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/Resource.h b/winaccessibility/source/UAccCOM/Resource.h new file mode 100644 index 0000000000..d8abe9bcc5 --- /dev/null +++ b/winaccessibility/source/UAccCOM/Resource.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by UAccCOM.rc + + +#define IDS_PROJNAME 100 + +// Next default values for new objects + +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 203 +#define _APS_NEXT_COMMAND_VALUE 32768 +#define _APS_NEXT_CONTROL_VALUE 201 +#define _APS_NEXT_SYMED_VALUE 137 +#endif +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/StdAfx.cxx b/winaccessibility/source/UAccCOM/StdAfx.cxx new file mode 100644 index 0000000000..71ebbdb6b3 --- /dev/null +++ b/winaccessibility/source/UAccCOM/StdAfx.cxx @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" + +#ifdef _ATL_STATIC_REGISTRY +#include <statreg.h> +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/UAccCOM.cxx b/winaccessibility/source/UAccCOM/UAccCOM.cxx new file mode 100644 index 0000000000..2914e16c36 --- /dev/null +++ b/winaccessibility/source/UAccCOM/UAccCOM.cxx @@ -0,0 +1,109 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "stdafx.h" +#include "Resource.h" +#include <initguid.h> +#include <UAccCOM.h> +#include <accHelper.hxx> + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored \ + "-Wextra-tokens" // "#endif !_MIDL_USE_GUIDDEF_" in midl-generated code +#endif +#include <UAccCOM_i.c> +#include <ia2_api_all_i.c> +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +#include "MAccessible.h" +#include "EnumVariant.h" +#include "UNOXWrapper.h" +#include "AccComponent.h" +#include "AccRelation.h" +#include "AccAction.h" +#include "AccText.h" +#include "AccEditableText.h" +#include "AccImage.h" +#include "AccValue.h" +#include "AccTable.h" +#include "AccTableCell.h" +#include "AccHyperLink.h" +#include "AccHypertext.h" + +CComModule _Module; + +BEGIN_OBJECT_MAP(ObjectMap) +OBJECT_ENTRY(CLSID_MAccessible, CMAccessible) +OBJECT_ENTRY(CLSID_EnumVariant, CEnumVariant) +OBJECT_ENTRY(CLSID_AccComponent, CAccComponent) +OBJECT_ENTRY(CLSID_AccRelation, CAccRelation) +OBJECT_ENTRY(CLSID_AccAction, CAccAction) +OBJECT_ENTRY(CLSID_AccText, CAccText) +OBJECT_ENTRY(CLSID_AccEditableText, CAccEditableText) +OBJECT_ENTRY(CLSID_AccImage, CAccImage) +OBJECT_ENTRY(CLSID_AccValue, CAccValue) +OBJECT_ENTRY(CLSID_AccTable, CAccTable) +OBJECT_ENTRY(CLSID_AccTableCell, CAccTableCell) +OBJECT_ENTRY(CLSID_AccHyperLink, CAccHyperLink) +OBJECT_ENTRY(CLSID_AccHypertext, CAccHypertext) +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-field-initializers" +#endif +END_OBJECT_MAP() +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +// DLL Entry Point + +extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + _Module.Init(ObjectMap, hInstance, &LIBID_UACCCOMLib); + DisableThreadLibraryCalls(hInstance); + } + else if (dwReason == DLL_PROCESS_DETACH) + _Module.Term(); + return TRUE; // ok +} + +// Used to determine whether the DLL can be unloaded by OLE + +STDAPI DllCanUnloadNow() { return (_Module.GetLockCount() == 0) ? S_OK : E_FAIL; } + +// Returns a class factory to create an object of the requested type + +STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv) +{ + return _Module.GetClassObject(rclsid, riid, ppv); +} + +IMAccessible* UAccCOMCreateInstance() +{ + IMAccessible* pIMA = nullptr; + HRESULT hr = createInstance<CMAccessible>(IID_IMAccessible, &pIMA); + return (S_OK == hr) ? pIMA : nullptr; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/UAccCOM.def b/winaccessibility/source/UAccCOM/UAccCOM.def new file mode 100644 index 0000000000..45baa527b4 --- /dev/null +++ b/winaccessibility/source/UAccCOM/UAccCOM.def @@ -0,0 +1,5 @@ +LIBRARY "UAccCOM.DLL" + +EXPORTS + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE diff --git a/winaccessibility/source/UAccCOM/UAccCOM.rc b/winaccessibility/source/UAccCOM/UAccCOM.rc new file mode 100644 index 0000000000..d81746ed3f --- /dev/null +++ b/winaccessibility/source/UAccCOM/UAccCOM.rc @@ -0,0 +1,90 @@ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +//Microsoft Developer Studio generated resource script. + +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS + + +// Generated from the TEXTINCLUDE 2 resource. + +#include "winres.h" + + +#undef APSTUDIO_READONLY_SYMBOLS + + +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED + + +// TEXTINCLUDE + + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "1 TYPELIB ""UAccCOM.tlb""\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +// String Table + + +STRINGTABLE DISCARDABLE +BEGIN + IDS_PROJNAME "UAccCOM" +END + +#endif // English (U.S.) resources + + + + +#ifndef APSTUDIO_INVOKED + + +// Generated from the TEXTINCLUDE 3 resource. + +1 TYPELIB "UAccCOM.tlb" + + +#endif // not APSTUDIO_INVOKED + diff --git a/winaccessibility/source/UAccCOM/UNOXWrapper.cxx b/winaccessibility/source/UAccCOM/UNOXWrapper.cxx new file mode 100644 index 0000000000..df55dc09a4 --- /dev/null +++ b/winaccessibility/source/UAccCOM/UNOXWrapper.cxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <UAccCOM.h> +#include "UNOXWrapper.h" + +using namespace ::com::sun::star; + +// CUNOXWrapper + +COM_DECLSPEC_NOTHROW STDMETHODIMP CUNOXWrapper::put_XInterface(hyper nXInterface) +{ + pUNOInterface = reinterpret_cast<accessibility::XAccessible*>(nXInterface); + return S_OK; +} + +COM_DECLSPEC_NOTHROW STDMETHODIMP CUNOXWrapper::put_XSubInterface(hyper) { return S_OK; } + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/UNOXWrapper.h b/winaccessibility/source/UAccCOM/UNOXWrapper.h new file mode 100644 index 0000000000..b319d4e2b6 --- /dev/null +++ b/winaccessibility/source/UAccCOM/UNOXWrapper.h @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include "stdafx.h" +#include "Resource.h" // main symbols + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <UAccCOM.h> + +/** + * CUNOXWrapper implements IUNOXWrapper interface. + */ +class ATL_NO_VTABLE CUNOXWrapper : public IUNOXWrapper +{ +protected: + css::accessibility::XAccessible* pUNOInterface; + +public: + CUNOXWrapper() + : pUNOInterface(nullptr) + { + } + + // IUNOXWrapper + STDMETHOD(put_XInterface)(hyper pXInterface) override; + STDMETHOD(put_XSubInterface)(hyper) override; + +protected: + ~CUNOXWrapper() {} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/acccommon.h b/winaccessibility/source/UAccCOM/acccommon.h new file mode 100644 index 0000000000..d2dffc5e60 --- /dev/null +++ b/winaccessibility/source/UAccCOM/acccommon.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +//for MAccessible.cxx +struct ltComp +{ + bool operator()(REFGUID rguid1, REFGUID rguid2) const + { + if(reinterpret_cast<LONG const *>(&rguid1)[0] < reinterpret_cast<LONG const *>(&rguid2)[0]) + return true; + else if(reinterpret_cast<LONG const *>(&rguid1)[0] > reinterpret_cast<LONG const *>(&rguid2)[0]) + return false; + if(reinterpret_cast<LONG const *>(&rguid1)[1] < reinterpret_cast<LONG const *>(&rguid2)[1]) + return true; + else if(reinterpret_cast<LONG const *>(&rguid1)[1] > reinterpret_cast<LONG const *>(&rguid2)[1]) + return false; + if(reinterpret_cast<LONG const *>(&rguid1)[2] < reinterpret_cast<LONG const *>(&rguid2)[2]) + return true; + else if(reinterpret_cast<LONG const *>(&rguid1)[2] > reinterpret_cast<LONG const *>(&rguid2)[2]) + return false; + if(reinterpret_cast<LONG const *>(&rguid1)[3] < reinterpret_cast<LONG const *>(&rguid2)[3]) + return true; + else if(reinterpret_cast<LONG const *>(&rguid1)[3] > reinterpret_cast<LONG const *>(&rguid2)[3]) + return false; + return false; + } +}; + +enum DM_NIR { + DM_FIRSTCHILD = 0x00, + DM_LASTCHILD = 0x01, + DM_NEXTCHILD = 0x02, + DM_PREVCHILD = 0x03 +}; + + +#define SELECT_STR L"Select" +#define PRESS_STR L"Press" +#define UNCHECK_STR L"UnCheck" +#define CHECK_STR L"Check" +//End + +template<typename T, typename Ifc> HRESULT +createInstance(REFIID iid, Ifc ** ppIfc) +{ + return + CComCreator< CComObject<T> >::CreateInstance(nullptr, iid, reinterpret_cast<void**>(ppIfc)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOM/stdafx.h b/winaccessibility/source/UAccCOM/stdafx.h new file mode 100644 index 0000000000..6a68376a8e --- /dev/null +++ b/winaccessibility/source/UAccCOM/stdafx.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, +// but are changed infrequently + +#pragma once + +#pragma once + +// this turns off ATL's locking in the COM component implementations +// (we don't need it since we use SolarMutex instead) +#define _ATL_APARTMENT_THREADED + +#include <prewin.h> +#if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif +#include <windows.h> + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wall" +#pragma clang diagnostic ignored "-Wattributes" +#pragma clang diagnostic ignored "-Wdelete-incomplete" +#pragma clang diagnostic ignored "-Wextra" +#pragma clang diagnostic ignored "-Wint-to-pointer-cast" +#pragma clang diagnostic ignored "-Winvalid-noreturn" +#pragma clang diagnostic ignored "-Wmicrosoft" +#pragma clang diagnostic ignored "-Wnon-pod-varargs" +#endif +#include <atlbase.h> +// You may derive a class from CComModule and use it if you want to override +// something, but do not change the name of _Module +extern CComModule _Module; +#include <atlcom.h> +#if defined __clang__ +#pragma clang diagnostic pop +#endif +#include <postwin.h> +#undef OPAQUE + + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOMIDL/UAccCOM.idl b/winaccessibility/source/UAccCOMIDL/UAccCOM.idl new file mode 100644 index 0000000000..871e5c3084 --- /dev/null +++ b/winaccessibility/source/UAccCOMIDL/UAccCOM.idl @@ -0,0 +1,212 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +import "oaidl.idl"; +import "ocidl.idl"; + +import "ia2_api_all.idl"; +import "defines.idl"; + + [ + object, + uuid(D00F5EB7-588A-487F-A6F6-0B5D7D1815AA), + dual, + helpstring("IMAccessible Interface"), + pointer_default(unique) + ] + interface IMAccessible : IAccessible2 + { + [id(1), helpstring("method Put_XAccName")] HRESULT Put_XAccName(const OLECHAR* pszName); + [id(2), helpstring("method Put_XAccRole")] HRESULT Put_XAccRole(unsigned short pRole); + [id(3), helpstring("method DecreaseState")] HRESULT DecreaseState(DWORD pXSate); + [id(4), helpstring("method IncreaseState")] HRESULT IncreaseState(DWORD pXSate); + [id(6), helpstring("method Put_XAccValue")] HRESULT Put_XAccValue(const OLECHAR* pszAccValue); + [id(7), helpstring("method SetState")] HRESULT SetState(DWORD pXSate); + [id(9), helpstring("method Put_XAccFocus")] HRESULT Put_XAccFocus(long dChildID); + [id(10), helpstring("method Put_XAccParent")] HRESULT Put_XAccParent(IMAccessible* pIParent); + [id(13), helpstring("method Put_XAccWindowHandle")] HRESULT Put_XAccWindowHandle(HWND hwnd); + [id(14), helpstring("method Put_XAccChildID")] HRESULT Put_XAccChildID(long dChildID); + [id(19), helpstring("method SetXAccessible")] HRESULT SetXAccessible(hyper XAccessible); + [id(20), helpstring("method GetUNOInterface")] HRESULT GetUNOInterface(hyper* UNOInterface); + [id(23), helpstring("method SetDefaultAction")] HRESULT SetDefaultAction(hyper pAction); + [id(24), helpstring("method Put_ActionDescription")] HRESULT Put_ActionDescription( const OLECHAR* szAction); + [id(25), helpstring("method Put_XAccObjectManager")] HRESULT Put_XAccObjectManager(hyper pManager); + [id(26), helpstring("method NotifyDestroy")] HRESULT NotifyDestroy(); + }; + [ + object, + uuid(951299EE-1841-4249-9E07-812C0739E489), + dual, + helpstring("IEnumVariant Interface"), + pointer_default(unique) + ] + interface IEnumVariant : IEnumVARIANT + { + [id(1), helpstring("method ClearEnumeration")] HRESULT ClearEnumeration(); + [id(2), helpstring("method PutSelection")] HRESULT PutSelection(hyper pXSelection); + }; + [ + object, + uuid(6641185C-E099-4C45-B753-3FBC0EE40646), + dual, + helpstring("IUNOXWrapper Interface"), + pointer_default(unique) + ] + interface IUNOXWrapper : IUnknown + { + [id(1), helpstring("method put_XInterface")] HRESULT put_XInterface(hyper pXInterface); + [id(2), helpstring("method put_XSubInterface")] HRESULT put_XSubInterface(hyper pXSubInterface); + }; + +[ + uuid(19ECB1B0-9376-4FF9-B580-223FC9C200B8), + version(1.0), + helpstring("UAccCOM 1.0 Type Library") +] +library UACCCOMLib +{ + importlib("stdole32.tlb"); + importlib("stdole2.tlb"); + importlib("oleacc.dll"); + + [ + uuid(CF8DF8BA-44FE-4B10-BD2E-8C8CB322485F), + helpstring("MAccessible Class") + ] + coclass MAccessible + { + [default] interface IMAccessible; + }; + [ + uuid(152884E0-268B-4481-9AE7-1B372D3AA97F), + helpstring("EnumVariant Class") + ] + coclass EnumVariant + { + [default] interface IEnumVariant; + }; + [ + uuid(AA360FB0-BC98-41C1-A885-BB921F5ED601), + helpstring("UNOXWrapper Class") + ] + coclass UNOXWrapper + { + [default] interface IUNOXWrapper; + }; + + [ + uuid(9FD9BA47-70AF-4160-99F1-526F2B9F111B), + helpstring("AccComponent Class") + ] + coclass AccComponent + { + [default] interface IAccessibleComponent; + }; + + [ + uuid(8745CF0C-3104-4BAE-B7D0-D7B1717C006E), + helpstring("AccRelation Class") + ] + coclass AccRelation + { + [default] interface IAccessibleRelation; + }; + [ + uuid(AA49F20E-BB4E-400D-A5B0-6F5B7B770227), + helpstring("AccAction Class") + ] + coclass AccAction + { + [default] interface IAccessibleAction; + }; + + [ + uuid(6D8AB08B-CCE9-471E-8A41-35773D5263F5), + helpstring("AccText Class") + ] + coclass AccText + { + [default] interface IAccessibleText; + }; + + [ + uuid(79CE1450-1F61-48E2-BF76-C07BD10105E2), + helpstring("AccEditableText Class") + ] + coclass AccEditableText + { + [default] interface IAccessibleEditableText; + }; + + [ + uuid(CC55D71B-1828-4EE0-89E2-C3749CF9C9AB), + helpstring("AccHypertext Class") + ] + coclass AccHypertext + { + [default] interface IAccessibletext; + }; + + + [ + uuid(73A45800-7A62-432C-A1A6-BF8852994331), + helpstring("AccImage Class") + ] + coclass AccImage + { + [default] interface IAccessibleImage; + }; + + [ + uuid(730A561B-1AF6-49E1-9C04-9A2F48CD8512), + helpstring("AccValue Class") + ] + coclass AccValue + { + [default] interface IAccessibleValue; + }; + [ + uuid(92BAA62D-535A-4EAB-9ABB-BFA60B7A6DB6), + helpstring("AccTable Class") + ] + coclass AccTable + { + [default] interface IAccessibleTable; + }; + [ + uuid(77948F17-05C8-4DAA-93D4-BCCD16ADC660), + helpstring("AccTableCell Class") + ] + coclass AccTableCell + { + [default] interface IAccessibleTableCell; + }; + + [ + uuid(519A64CD-F6A6-4793-BE50-4E36C4C593EF), + helpstring("AccHyperLink Class") + ] + coclass AccHyperLink + { + [default] interface IAccessibleAction; + }; + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/UAccCOMIDL/defines.idl b/winaccessibility/source/UAccCOMIDL/defines.idl new file mode 100644 index 0000000000..3ca8c88a04 --- /dev/null +++ b/winaccessibility/source/UAccCOMIDL/defines.idl @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +import "objidl.idl"; +import "oaidl.idl"; +import "oleacc.idl"; + +interface IMAccessible; + +const long UACC_NO_FOCUS=0xFFFF; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccComponentEventListener.cxx b/winaccessibility/source/service/AccComponentEventListener.cxx new file mode 100644 index 0000000000..e63317b59e --- /dev/null +++ b/winaccessibility/source/service/AccComponentEventListener.cxx @@ -0,0 +1,327 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccComponentEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccComponentEventListener::AccComponentEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccEventListener(pAcc, pManager) +{ +} + +AccComponentEventListener::~AccComponentEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * + * @param AccessibleEventObject the event object which contains information about event + */ +void AccComponentEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::VALUE_CHANGED: + HandleValueChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::ACTION_CHANGED: + HandleActionChangedEvent(); + break; + case AccessibleEventId::TEXT_CHANGED: + HandleTextChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::CARET_CHANGED: + HandleCaretChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + case AccessibleEventId::SELECTION_CHANGED: + HandleSelectionChangedEventNoArgs(); + break; + //to add TEXT_SELECTION_CHANGED event + case AccessibleEventId::TEXT_SELECTION_CHANGED: + HandleTextSelectionChangedEvent(); + break; + //End + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the VALUE_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccComponentEventListener::HandleValueChangedEvent(Any, Any) +{ + m_pObjManager->UpdateValue(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_VALUECHANGE); +} + +/** + * handle the NAME_CHANGED event + */ +void AccComponentEventListener::HandleActionChangedEvent() +{ + m_pObjManager->UpdateAction(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_DEFACTIONCHANGE); +} + +/** + * handle the TEXT_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccComponentEventListener::HandleTextChangedEvent(Any, Any newValue) +{ + m_pObjManager->SetValue(m_xAccessible.get(), newValue); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_VALUECHANGE); +} + +/** + * handle the CARET_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccComponentEventListener::HandleCaretChangedEvent(Any, Any) +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_CARETCHANGE); +} + +/** + * set the new state and fire the MSAA event + * + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccComponentEventListener::SetComponentState(sal_Int64 state, bool enable) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::CHECKED: + case AccessibleStateType::PRESSED: + case AccessibleStateType::SELECTED: + case AccessibleStateType::ARMED: + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::SHOWING: + FireStatePropertyChange(state, enable); + break; + case AccessibleStateType::VISIBLE: + if (GetRole() == AccessibleRole::MENU_ITEM) + { + if(enable) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + else + { + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + } + else + { + FireStatePropertyChange(state, enable); + } + break; + case AccessibleStateType::FOCUSED: + FireStateFocusedChange(enable); + break; + case AccessibleStateType::ENABLED: + if(enable) + { + m_pObjManager->UpdateState(m_xAccessible.get()); + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + // 8. label should have no FOCUSABLE state, Firefox has READONLY state, we can also have. + if ( GetRole() != AccessibleRole::LABEL + && GetRole() != AccessibleRole::STATIC + && GetRole() != AccessibleRole::NOTIFICATION + && GetRole() != AccessibleRole::SCROLL_BAR) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + } + else + { + m_pObjManager->UpdateState(m_xAccessible.get()); + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + break; + default: + break; + } +} + +/** + * fire the MSAA state changed event + * + * @param state the state id + * @param set true if state is set, false if state is unset + */ +void AccComponentEventListener::FireStatePropertyChange(sal_Int64 state, bool set) +{ + if( set) + { + // new value + switch(state) + { + case AccessibleStateType::CHECKED: + case AccessibleStateType::INDETERMINATE: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + m_pObjManager->UpdateAction(m_xAccessible.get()); + + if (!m_pObjManager->IsSpecialToolbarItem(m_xAccessible.get())) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_CHECKED); + } + break; + case AccessibleStateType::PRESSED: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_PRESSED); + break; + case AccessibleStateType::SELECTED: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + break; + case AccessibleStateType::ARMED: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_ARMED); + break; + case AccessibleStateType::SHOWING: + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + // UNO !SHOWING == MSAA OFFSCREEN + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING ); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_SHOWING); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE ); + break; + default: + break; + } + } + else + { + // old value + switch(state) + { + case AccessibleStateType::CHECKED: + case AccessibleStateType::INDETERMINATE: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + m_pObjManager->UpdateAction(m_xAccessible.get()); + + if (!m_pObjManager->IsSpecialToolbarItem(m_xAccessible.get())) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_CHECKED); + } + break; + case AccessibleStateType::PRESSED: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_PRESSED); + break; + case AccessibleStateType::SELECTED: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + //if the state is unset, no need to send MSAA SELECTION event + //m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_SELECTED); + break; + case AccessibleStateType::ARMED: + { + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + //if the state is unset, no need to send MSAA MENU event + //m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_ARMED); + } + break; + case AccessibleStateType::SHOWING: + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + // UNO !SHOWING == MSAA OFFSCREEN + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + + default: + break; + } + } +} + +/** + * handle the focused event + * + * @param enable true if get focus, false if lose focus + */ +void AccComponentEventListener::FireStateFocusedChange(bool enable) +{ + if(enable) + { + if (GetParentRole() != AccessibleRole::COMBO_BOX) + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_FOCUSED); + } + else + { + //if lose focus, no need to send MSAA FOCUS event + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + } +} + +void AccComponentEventListener::HandleSelectionChangedEventNoArgs() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED); +} + +//add TEXT_SELECTION_CHANGED event +void AccComponentEventListener::HandleTextSelectionChangedEvent() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TEXT_SELECTION_CHANGED); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccContainerEventListener.cxx b/winaccessibility/source/service/AccContainerEventListener.cxx new file mode 100644 index 0000000000..d05b9f5a27 --- /dev/null +++ b/winaccessibility/source/service/AccContainerEventListener.cxx @@ -0,0 +1,498 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccContainerEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccContainerEventListener::AccContainerEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccEventListener(pAcc, pManager) +{ +} + +AccContainerEventListener::~AccContainerEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * + * @param AccessibleEventObject the event object which contains information about event + */ +void AccContainerEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::SELECTION_CHANGED: + HandleSelectionChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::INVALIDATE_ALL_CHILDREN: + HandleAllChildrenChangedEvent(); + break; + case AccessibleEventId::TEXT_CHANGED: + HandleTextChangedEvent(aEvent.OldValue, aEvent.NewValue); + [[fallthrough]]; //TODO ??? + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + case AccessibleEventId::STATE_CHANGED: + HandleStateChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VALUE_CHANGED: + HandleValueChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_ADD: + HandleSelectionChangedAddEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_REMOVE: + HandleSelectionChangedRemoveEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_WITHIN: + HandleSelectionChangedWithinEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::PAGE_CHANGED: + HandlePageChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SECTION_CHANGED: + HandleSectionChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::COLUMN_CHANGED: + HandleColumnChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +void AccContainerEventListener::HandleStateChangedEvent(Any oldValue, Any newValue) +{ + sal_Int64 State; + if( newValue >>= State) + { + SetComponentState(State, true); + } + else if (oldValue >>= State) + { + SetComponentState(State, false); + } + +} + +/** + * handle the SELECTION_CHANGED event + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccContainerEventListener::HandleSelectionChangedEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED, newValue)) + { + return ; + } + + //menu bar does not process selection change event,just same as word behavior + if (GetRole()!=AccessibleRole::MENU_BAR) + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED); +} + +/** + * handle the INVALIDATE_ALL_CHILDREN event + */ +void AccContainerEventListener::HandleAllChildrenChangedEvent() +{ + //TODO: update all the children + if (m_xAccessible.is()) + { + //delete all oldValue's existing children + m_pObjManager->DeleteChildrenAccObj(m_xAccessible.get()); + //add all oldValue's existing children + m_pObjManager->InsertChildrenAccObj(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_REORDER); + } +} + +/** + * handle the TEXT_CHANGED event + */ +void AccContainerEventListener::HandleTextChangedEvent(Any, Any newValue) +{ + m_pObjManager->SetValue(m_xAccessible.get(), newValue); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_TEXTCHANGE); +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccContainerEventListener::SetComponentState(sal_Int64 state, bool enable ) +{ + // only the following state can be fired state event. + + switch (state) + { + case AccessibleStateType::SELECTED: + case AccessibleStateType::BUSY: + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::OFFSCREEN: + case AccessibleStateType::FOCUSABLE: + case AccessibleStateType::SHOWING: + case AccessibleStateType::VISIBLE: + FireStatePropertyChange(state, enable); + break; + case AccessibleStateType::FOCUSED: + FireStateFocusedChange(enable); + break; + case AccessibleStateType::ENABLED: + if(enable) + { + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + m_pObjManager->UpdateState(m_xAccessible.get()); + + UpdateAllChildrenState(m_xAccessible.get()); + } + else + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + m_pObjManager->UpdateState(m_xAccessible.get()); + + UpdateAllChildrenState(m_xAccessible.get()); + } + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + //for PAGE_TAB_LIST, there will be ACTIVE state, then it should be converted to FOCUSED event. + if (GetRole() == AccessibleRole::PAGE_TAB_LIST) + { + if (!enable) /* get the active state */ + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + } + + else /* lose the active state */ + { + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + } + } + break; + + case AccessibleStateType::EXPANDED: + case AccessibleStateType::COLLAPSE: + case AccessibleStateType::CHECKED: + { + m_pObjManager->UpdateState(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_BUSY); + break; + } + + default: + break; + } +} + +/** + * fire the MSAA state changed event + * @param state the state id + * @param set true if state is set, false if state is unset + */ +void AccContainerEventListener::FireStatePropertyChange(sal_Int64 state, bool set) +{ + if( set ) + { + // new value + switch(state) + { + case AccessibleStateType::SELECTED: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + break; + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::BUSY: + case AccessibleStateType::FOCUSABLE: + case AccessibleStateType::OFFSCREEN: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_BUSY); + break; + case AccessibleStateType::SHOWING: + // UNO !SHOWING == MSAA OFFSCREEN + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + default: + break; + } + } + else + { + // old value + switch(state) + { + case AccessibleStateType::SELECTED: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + break; + case AccessibleStateType::BUSY: + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::FOCUSABLE: + case AccessibleStateType::OFFSCREEN: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_BUSY); + break; + case AccessibleStateType::SHOWING: + // UNO !SHOWING == MSAA OFFSCREEN + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + default: + break; + } + } +} + +/** + * handle the focused event + * @param enable true if get focus, false if lose focus + */ +void AccContainerEventListener::FireStateFocusedChange(bool enable) +{ + if(enable) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + // if the acc role is MENU_BAR, UnoMSAAEvent::MENU_START event should be sent + // if the acc role is POPUP_MENU, UnoMSAAEvent::MENUPOPUPSTART event should be sent + short role = GetRole(); + if(role == AccessibleRole::MENU_BAR) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::MENU_START); + } + else if (role == AccessibleRole::POPUP_MENU) + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::MENUPOPUPSTART); + //Disable the focused event on option_pane and Panel. + //only disable option_pane for toolbar has panel to get focus + else if (role == AccessibleRole::PANEL || role == AccessibleRole::OPTION_PANE ) + { + //don't send focused event on PANEL & OPTION_PANE if the parent is not toolbar + short parentRole = GetParentRole(); + if (parentRole == AccessibleRole::TOOL_BAR + || parentRole == AccessibleRole::SCROLL_PANE // sidebar + || parentRole == AccessibleRole::PANEL) // sidebar + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_FOCUSED); + } + else if (role == AccessibleRole::COMBO_BOX ) + { + //for editable combobox, send focus event on only edit control, + bool bSendFocusOnCombobox = true; + //send focused event to the first text child + Reference<XAccessibleContext> mxContext = m_xAccessible->getAccessibleContext(); + if(mxContext.is()) + { + Reference<XAccessible> mxChild = mxContext->getAccessibleChild(0); + if(mxChild.is()) + { + Reference<XAccessibleContext> mxChildContext = mxChild->getAccessibleContext(); + short childrole = mxChildContext->getAccessibleRole(); + if (childrole == AccessibleRole::TEXT) + { + if (IsEditable(mxChildContext)) + { + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + m_pObjManager->IncreaseState( mxChild.get(), AccessibleStateType::FOCUSED); + m_pObjManager->NotifyAccEvent(mxChild.get(), UnoMSAAEvent::STATE_FOCUSED); + bSendFocusOnCombobox = false; + } + } + } + } + if (bSendFocusOnCombobox) + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_FOCUSED); + } + else + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_FOCUSED); + } + else + { + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + // if the acc role is MENU_BAR, UnoMSAAEvent::MENU_END event should be sent + // if the acc role is POPUP_MENU, UnoMSAAEvent::MENUPOPUPEND event should be sent + if (GetRole() == AccessibleRole::MENU_BAR) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::MENU_END); + } + else if (GetRole() == AccessibleRole::POPUP_MENU) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::MENUPOPUPEND); + } + } +} + +/** + * handle the VALUE_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccContainerEventListener::HandleValueChangedEvent(Any, Any) +{ + m_pObjManager->UpdateValue(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_VALUECHANGE); +} + +bool AccContainerEventListener::IsEditable(Reference<XAccessibleContext> const & xContext) +{ + sal_Int64 nRState = xContext->getAccessibleStateSet(); + return nRState & AccessibleStateType::EDITABLE; +} + +bool AccContainerEventListener::NotifyChildEvent(UnoMSAAEvent eWinEvent, const Any& Value) +{ + Reference< XAccessible > xChild; + if(Value >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->NotifyAccEvent(pAcc, eWinEvent); + return true; + } + } + return false; +} + +void AccContainerEventListener::HandleSelectionChangedAddEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_ADD, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_ADD); +} + +void AccContainerEventListener::HandleSelectionChangedRemoveEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_REMOVE, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_REMOVE); +} + +void AccContainerEventListener::HandleSelectionChangedWithinEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_WITHIN, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_WITHIN); +} + +void AccContainerEventListener::UpdateAllChildrenState(XAccessible* pXAccessible) +{ + Reference<css::accessibility::XAccessibleContext> xContext = pXAccessible->getAccessibleContext(); + if(!xContext.is()) + { + return; + } + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + if(pAccessibleContext == nullptr) + { + return; + } + + if (AccObjectWinManager::IsStateManageDescendant(pXAccessible)) + { + return; + } + + const sal_Int64 nCount = pAccessibleContext->getAccessibleChildCount(); + for (sal_Int64 i = 0; i < nCount; i++) + { + Reference<css::accessibility::XAccessible> mxAccessible + = pAccessibleContext->getAccessibleChild(i); + + css::accessibility::XAccessible* mpAccessible = mxAccessible.get(); + if(mpAccessible != nullptr) + { + m_pObjManager->UpdateState(mpAccessible); + UpdateAllChildrenState(mpAccessible); + } + } +} + +void AccContainerEventListener::HandlePageChangedEvent(const Any& /*oldValue*/, const Any& /*newValue*/) +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_PAGECHANGED); +} + +void AccContainerEventListener::HandleSectionChangedEvent(const Any& /*oldValue*/, const Any& /*newValue*/ ) +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SECTION_CHANGED); +} + +void AccContainerEventListener::HandleColumnChangedEvent(const Any& /*oldValue*/, const Any& /*newValue*/) +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::COLUMN_CHANGED); +} + +void AccContainerEventListener::HandleNameChangedEvent( Any name ) +{ + if (GetRole() == AccessibleRole::COMBO_BOX) + { + Reference<XAccessibleContext> mxContext(m_xAccessible->getAccessibleContext()); + if(mxContext.is()) + { + Reference<XAccessible> mxChild = mxContext->getAccessibleChild(0); + if(mxChild.is()) + { + Reference<XAccessibleContext> mxChildContext = mxChild->getAccessibleContext(); + short childrole = mxChildContext->getAccessibleRole(); + if (childrole == AccessibleRole::TEXT) + { + m_pObjManager->SetAccName(mxChild.get(), name); + } + } + } + } + AccEventListener::HandleNameChangedEvent(name); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccDescendantManagerEventListener.cxx b/winaccessibility/source/service/AccDescendantManagerEventListener.cxx new file mode 100644 index 0000000000..d3fcb2d0fe --- /dev/null +++ b/winaccessibility/source/service/AccDescendantManagerEventListener.cxx @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccDescendantManagerEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccDescendantManagerEventListener::AccDescendantManagerEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + : AccComponentEventListener(pAcc, pManager) +{ +} + +AccDescendantManagerEventListener::~AccDescendantManagerEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccDescendantManagerEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::SELECTION_CHANGED: + HandleSelectionChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS: + HandleChildChangedNoFocusEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_ADD: + HandleSelectionChangedAddEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_REMOVE: + HandleSelectionChangedRemoveEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_WITHIN: + HandleSelectionChangedWithinEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccComponentEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the SELECTION_CHANGED event + */ +void AccDescendantManagerEventListener::HandleSelectionChangedEvent(Any oldValue, Any newValue) +{ + bool bSend =false; + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + Reference<css::accessibility::XAccessibleContext> xContext = pAcc->getAccessibleContext(); + //if the Role is the SC cell ,don't add the selected state. + if (xContext.is() && xContext->getAccessibleRole() != AccessibleRole::TABLE_CELL) + { + m_pObjManager->IncreaseState( pAcc, AccessibleStateType::SELECTED); + } + + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::SELECTION_CHANGED); + bSend=true; + } + } + if(oldValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->DecreaseState( pAcc, AccessibleStateType::SELECTED); + } + } + if (!bSend) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED); + } +} + + +void AccDescendantManagerEventListener::HandleChildChangedNoFocusEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + + m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get()); + m_pObjManager->InsertChildrenAccObj(pAcc); + } + } + if (oldValue >>= xChild) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->DeleteChildrenAccObj( pAcc ); + m_pObjManager->DeleteAccObj( pAcc ); + } + } +} + +bool AccDescendantManagerEventListener::NotifyChildEvent(UnoMSAAEvent eWinEvent, const Any& Value) +{ + Reference< XAccessible > xChild; + if(Value >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->NotifyAccEvent(pAcc, eWinEvent); + + if (AccObjectWinManager::IsStateManageDescendant(m_xAccessible.get())) + { + if (eWinEvent == UnoMSAAEvent::SELECTION_CHANGED_REMOVE) + { + // The object has just been sent in a SELECTION_CHANGED_REMOVE event + // and accessibility tools may query for the object and call methods on + // it as a response to this. + // Therefore, don't delete the object yet, but remember it for deletion + // once the next event of a different type occurs. + m_aUnselectedChildrenForDeletion.push_back(pAcc); + } + else + { + // handle any pending deletions for objects previously removed from selection + for (XAccessible* pAcc2 : m_aUnselectedChildrenForDeletion) + m_pObjManager->DeleteAccObj(pAcc2); + m_aUnselectedChildrenForDeletion.clear(); + } + } + return true; + } + } + return false; +} +void AccDescendantManagerEventListener::HandleSelectionChangedAddEvent(const Any& /*oldValue*/, const Any &newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_ADD, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_ADD); +} + +void AccDescendantManagerEventListener::HandleSelectionChangedRemoveEvent(const Any& /*oldValue*/, const Any &newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_REMOVE, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_REMOVE); +} + +void AccDescendantManagerEventListener::HandleSelectionChangedWithinEvent(const Any& /*oldValue*/, const Any &newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_WITHIN, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_WITHIN); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccDialogEventListener.cxx b/winaccessibility/source/service/AccDialogEventListener.cxx new file mode 100644 index 0000000000..1236fc458a --- /dev/null +++ b/winaccessibility/source/service/AccDialogEventListener.cxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccDialogEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccDialogEventListener::AccDialogEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccEventListener(pAcc, pManager) +{} +AccDialogEventListener::~AccDialogEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccDialogEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccDialogEventListener::SetComponentState(sal_Int64 state, bool enable) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::ICONIFIED: + // no msaa state mapping + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + if( enable ) + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + else + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccEventListener.cxx b/winaccessibility/source/service/AccEventListener.cxx new file mode 100644 index 0000000000..d8e6223403 --- /dev/null +++ b/winaccessibility/source/service/AccEventListener.cxx @@ -0,0 +1,296 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <cppuhelper/bootstrap.hxx> +#include <com/sun/star/bridge/XUnoUrlResolver.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include <vcl/svapp.hxx> + +#include <AccEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> + +#include <stdio.h> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; +using namespace cppu; + +AccEventListener::AccEventListener(css::accessibility::XAccessible* pAcc, + AccObjectWinManager* pManager) + : m_xAccessible(pAcc) + , m_pObjManager(pManager) +{ +} + +AccEventListener::~AccEventListener() {} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccEventListener::notifyEvent(const css::accessibility::AccessibleEventObject& aEvent) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::CHILD: + HandleChildChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::NAME_CHANGED: + HandleNameChangedEvent(aEvent.NewValue); + break; + case AccessibleEventId::DESCRIPTION_CHANGED: + HandleDescriptionChangedEvent(); + break; + case AccessibleEventId::STATE_CHANGED: + HandleStateChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + break; + } +} + +/** + * handle the NAME_CHANGED event + * @param name the new name with changed. + */ +void AccEventListener::HandleNameChangedEvent(Any name) +{ + if (m_pObjManager->IsTopWinAcc(m_xAccessible.get())) + { + XAccessible* pAccDoc = m_pObjManager->GetAccDocByAccTopWin(m_xAccessible.get()); + if (pAccDoc) + { + m_pObjManager->UpdateAccName(pAccDoc); + m_pObjManager->NotifyAccEvent(pAccDoc, UnoMSAAEvent::OBJECT_NAMECHANGE); + } + } + + m_pObjManager->SetAccName(m_xAccessible.get(), name); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_NAMECHANGE); +} + +/** + * Handle the CHILD event + * @param oldValue the child to be deleted + * @param newValue the child to be added + */ +void AccEventListener::HandleChildChangedEvent(com::sun::star::uno::Any oldValue, + com::sun::star::uno::Any newValue) +{ + Reference<XAccessible> xChild; + if (newValue >>= xChild) + { + if (xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get()); + m_pObjManager->InsertChildrenAccObj(pAcc); + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::CHILD_ADDED); + } + } + else if (oldValue >>= xChild) + { + if (xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::CHILD_REMOVED); + m_pObjManager->DeleteChildrenAccObj(pAcc); + m_pObjManager->DeleteAccObj(pAcc); + } + } +} + +/** + * handle the DESCRIPTION_CHANGED event + */ +void AccEventListener::HandleDescriptionChangedEvent() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_DESCRIPTIONCHANGE); +} + +/** + * handle the BOUNDRECT_CHANGED event + */ +void AccEventListener::HandleBoundrectChangedEvent() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::BOUNDRECT_CHANGED); +} + +/** + * handle the VISIBLE_DATA_CHANGED event + */ +void AccEventListener::HandleVisibleDataChangedEvent() +{ + m_pObjManager->UpdateValue(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::VISIBLE_DATA_CHANGED); +} + +/** + * handle the STATE_CHANGED event + * @param oldValue the old state of the source of event + * @param newValue the new state of the source of event + */ +void AccEventListener::HandleStateChangedEvent(Any oldValue, Any newValue) +{ + sal_Int64 newV, oldV; + if (newValue >>= newV) + { + SetComponentState(newV, true); + } + else if (oldValue >>= oldV) + { + SetComponentState(oldV, false); + } +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccEventListener::SetComponentState(sal_Int64 state, bool enable) +{ + switch (state) + { + case AccessibleStateType::FOCUSED: + FireStateFocusedChange(enable); + break; + default: + FireStatePropertyChange(state, enable); + break; + } +} + +/** + * handle the focused event + * @param enable true if get focus, false if lose focus + */ +void AccEventListener::FireStateFocusedChange(bool enable) +{ + if (enable) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_FOCUSED); + } + else + { + // no focus lost event in MSAA + } +} + +/** + * fire the MSAA state changed event + * @param state the state id + * @param set true if state is set, false if state is unset + */ +void AccEventListener::FireStatePropertyChange(sal_Int64 /*state*/, bool set) +{ + if (set) + { + //get new state + } + else + { + //lose old state + } +} + +/** + * get the role of accessible object which is observed + */ +short AccEventListener::GetRole() +{ + css::uno::Reference<css::accessibility::XAccessibleContext> const xContext( + m_xAccessible->getAccessibleContext()); + if (xContext.is()) + { + return xContext->getAccessibleRole(); + } + return -1; +} + +/** + * get the role of accessible parent object which is observed + */ +short AccEventListener::GetParentRole() +{ + if (m_xAccessible.is()) + { + return m_pObjManager->GetParentRole(m_xAccessible.get()); + } + return -1; +} +/** + * remove the listener from accessible object + */ +void AccEventListener::RemoveMeFromBroadcaster(bool const isNotifyDestroy) +{ + try + { + if (!m_xAccessible.is()) + { + return; + } + try + { + css::uno::Reference<XAccessibleEventBroadcaster> const xBroadcaster( + m_xAccessible->getAccessibleContext(), UNO_QUERY); + if (xBroadcaster.is()) + { + //remove the lister from accessible object + xBroadcaster->removeAccessibleEventListener(this); + } + } + catch (Exception const&) + { // may throw if it's already disposed - ignore that + } + if (isNotifyDestroy) + { + m_pObjManager->NotifyDestroy(m_xAccessible.get()); + } + m_xAccessible.clear(); // release cyclic reference + } + catch (...) + { + return; + } +} + +/** + * this method is invoked before listener is disposed + */ +void AccEventListener::disposing(const css::lang::EventObject& /*Source*/) +{ + SolarMutexGuard g; + + RemoveMeFromBroadcaster(true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccFrameEventListener.cxx b/winaccessibility/source/service/AccFrameEventListener.cxx new file mode 100644 index 0000000000..55ecf24792 --- /dev/null +++ b/winaccessibility/source/service/AccFrameEventListener.cxx @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccFrameEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +#include <vcl/window.hxx> +#include <toolkit/awt/vclxwindow.hxx> +#include <vcl/sysdata.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccFrameEventListener::AccFrameEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccEventListener(pAcc, pManager) +{ +} + +AccFrameEventListener::~AccFrameEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccFrameEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the CHILD event + * @param oldValue the child to be deleted + * @param newValue the child to be added + */ +void AccFrameEventListener::HandleChildChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if( newValue >>= xChild) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + VCLXWindow* pvclwindow = dynamic_cast<VCLXWindow*>(m_xAccessible.get()); + assert(pvclwindow); + const SystemEnvData* systemdata + = pvclwindow->GetWindow()->GetSystemData(); + + m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get(), systemdata->hWnd); + m_pObjManager->InsertChildrenAccObj(pAcc); + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::CHILD_ADDED); + } + } + else if (oldValue >>= xChild) + { + AccEventListener::HandleChildChangedEvent(oldValue, newValue); + } +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccFrameEventListener::SetComponentState(sal_Int64 state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::ICONIFIED: + // no msaa state + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + if( enable ) + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + else + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccListEventListener.cxx b/winaccessibility/source/service/AccListEventListener.cxx new file mode 100644 index 0000000000..9eaab9fd0c --- /dev/null +++ b/winaccessibility/source/service/AccListEventListener.cxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccListEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccListEventListener::AccListEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccDescendantManagerEventListener(pAcc, pManager) +{ +} + +AccListEventListener::~AccListEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccListEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + HandleActiveDescendantChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::INVALIDATE_ALL_CHILDREN: + // Since List items a transient a child events are mostly used + // to attach/detach listeners, it is safe to ignore it here + //TODO: investigate again + break; + case AccessibleEventId::VALUE_CHANGED: + HandleValueChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccDescendantManagerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the ACTIVE_DESCENDANT_CHANGED event + * @param oldValue the child to lose active + * @param newValue the child to get active + */ +void AccListEventListener::HandleActiveDescendantChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + + // Valueset has cache the child item xacc,Update state if no insert obj + bool bHasCache = m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get()); + if (!bHasCache) + { + m_pObjManager->UpdateState(pAcc); + } + + m_pObjManager->IncreaseState( pAcc, AccessibleStateType::FOCUSED); + + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::ACTIVE_DESCENDANT_CHANGED); + } + } + if (oldValue >>= xChild) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->DeleteAccObj( pAcc ); + } + } +} + +/** + * handle the VALUE_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccListEventListener::HandleValueChangedEvent(Any, Any) +{ + //to enable value changed event + if (GetParentRole() == AccessibleRole::COMBO_BOX) + { + XAccessible* pParentAcc = + m_pObjManager->GetParentXAccessible(m_xAccessible.get()); + m_pObjManager->UpdateValue(pParentAcc); + m_pObjManager->NotifyAccEvent(pParentAcc, UnoMSAAEvent::OBJECT_VALUECHANGE); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccMenuEventListener.cxx b/winaccessibility/source/service/AccMenuEventListener.cxx new file mode 100644 index 0000000000..25b347ebc8 --- /dev/null +++ b/winaccessibility/source/service/AccMenuEventListener.cxx @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccMenuEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccMenuEventListener::AccMenuEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccComponentEventListener(pAcc, pManager) +{} +AccMenuEventListener::~AccMenuEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccMenuEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::SELECTION_CHANGED: + //don't need to process anything,just same as word behavior + //handleSelectionChangedEvent(); + break; + default: + AccComponentEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the SELECTION_CHANGED event + */ +void AccMenuEventListener::HandleSelectionChangedEventNoArgs() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED); +} + +/** + * handle the Menu_popup event + */ +void AccMenuEventListener::FireStatePropertyChange(sal_Int64 state, bool set) +{ + if( set ) + { + // new value + switch(state) + { + //for sub menu is popup, there is a menu selected event. + case AccessibleStateType::SELECTED: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + m_pObjManager->UpdateChildState(m_xAccessible.get()); + break; + default: + AccComponentEventListener::FireStatePropertyChange(state, set); + break; + } + } + else + { + switch(state) + { + //for sub menu is popup, there is a menu selected event. + case AccessibleStateType::SELECTED: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + + break; + default: + AccComponentEventListener::FireStatePropertyChange(state, set); + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccObject.cxx b/winaccessibility/source/service/AccObject.cxx new file mode 100644 index 0000000000..51d04ec18d --- /dev/null +++ b/winaccessibility/source/service/AccObject.cxx @@ -0,0 +1,1164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleValue.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleText.hpp> + +#include <o3tl/char16_t2wchar_t.hxx> +#include <o3tl/safeint.hxx> +#include <sal/log.hxx> + +#include <stdlib.h> +#include <memory.h> +#include <stdio.h> +#include <algorithm> +#include <assert.h> + +#include <AccObject.hxx> +#include <AccEventListener.hxx> + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra-tokens" + // "#endif !_MIDL_USE_GUIDDEF_" in midl-generated code +#endif +#include <UAccCOM_i.c> +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; +using namespace com::sun::star::accessibility::AccessibleRole; +using namespace com::sun::star::accessibility::AccessibleStateType; + +namespace { + +/** + * Map a UNO accessible role to an IAccessible2 role. + * @param nUnoRole The UNO role (css::accessibility::AccessibleRole). + * @return IAccessible2 role. + */ +short lcl_mapToIAccessible2Role(sal_Int16 nUnoRole) +{ + switch(nUnoRole) + { + case css::accessibility::AccessibleRole::UNKNOWN: + return IA2_ROLE_UNKNOWN; + case css::accessibility::AccessibleRole::ALERT: + return ROLE_SYSTEM_DIALOG; + case css::accessibility::AccessibleRole::BLOCK_QUOTE: + return IA2_ROLE_BLOCK_QUOTE; + case css::accessibility::AccessibleRole::COLUMN_HEADER: + return ROLE_SYSTEM_COLUMNHEADER; + case css::accessibility::AccessibleRole::CANVAS: + return IA2_ROLE_CANVAS; + case css::accessibility::AccessibleRole::CHECK_BOX: + return ROLE_SYSTEM_CHECKBUTTON; + case css::accessibility::AccessibleRole::CHECK_MENU_ITEM: + return IA2_ROLE_CHECK_MENU_ITEM; + case css::accessibility::AccessibleRole::COLOR_CHOOSER: + return IA2_ROLE_COLOR_CHOOSER; + case css::accessibility::AccessibleRole::COMBO_BOX: + return ROLE_SYSTEM_COMBOBOX; + case css::accessibility::AccessibleRole::DATE_EDITOR: + return IA2_ROLE_DATE_EDITOR; + case css::accessibility::AccessibleRole::DESKTOP_ICON: + return IA2_ROLE_DESKTOP_ICON; + case css::accessibility::AccessibleRole::DESKTOP_PANE: + return IA2_ROLE_DESKTOP_PANE; + case css::accessibility::AccessibleRole::DIRECTORY_PANE: + return IA2_ROLE_DIRECTORY_PANE; + case css::accessibility::AccessibleRole::DIALOG: + return ROLE_SYSTEM_DIALOG; + case css::accessibility::AccessibleRole::DOCUMENT: + return ROLE_SYSTEM_DOCUMENT; + case css::accessibility::AccessibleRole::EMBEDDED_OBJECT: + return IA2_ROLE_EMBEDDED_OBJECT; + case css::accessibility::AccessibleRole::END_NOTE: + return IA2_ROLE_ENDNOTE; + case css::accessibility::AccessibleRole::FILE_CHOOSER: + return IA2_ROLE_FILE_CHOOSER; + case css::accessibility::AccessibleRole::FILLER: + return ROLE_SYSTEM_WHITESPACE; + case css::accessibility::AccessibleRole::FONT_CHOOSER: + return IA2_ROLE_FONT_CHOOSER; + case css::accessibility::AccessibleRole::FOOTER: + return IA2_ROLE_FOOTER; + case css::accessibility::AccessibleRole::FOOTNOTE: + return IA2_ROLE_FOOTNOTE; + case css::accessibility::AccessibleRole::FRAME: + return IA2_ROLE_FRAME; + case css::accessibility::AccessibleRole::GLASS_PANE: + return IA2_ROLE_GLASS_PANE; + case css::accessibility::AccessibleRole::GRAPHIC: + return ROLE_SYSTEM_GRAPHIC; + case css::accessibility::AccessibleRole::GROUP_BOX: + return ROLE_SYSTEM_GROUPING; + case css::accessibility::AccessibleRole::HEADER: + return IA2_ROLE_HEADER; + case css::accessibility::AccessibleRole::HEADING: + return IA2_ROLE_HEADING; + case css::accessibility::AccessibleRole::HYPER_LINK: + return ROLE_SYSTEM_TEXT; + case css::accessibility::AccessibleRole::ICON: + return IA2_ROLE_ICON; + case css::accessibility::AccessibleRole::INTERNAL_FRAME: + return IA2_ROLE_INTERNAL_FRAME; + case css::accessibility::AccessibleRole::LABEL: + return ROLE_SYSTEM_STATICTEXT; + case css::accessibility::AccessibleRole::LAYERED_PANE: + return IA2_ROLE_LAYERED_PANE; + case css::accessibility::AccessibleRole::LIST: + return ROLE_SYSTEM_LIST; + case css::accessibility::AccessibleRole::LIST_ITEM: + return ROLE_SYSTEM_LISTITEM; + case css::accessibility::AccessibleRole::MENU: + return ROLE_SYSTEM_MENUITEM; + case css::accessibility::AccessibleRole::MENU_BAR: + return ROLE_SYSTEM_MENUBAR; + case css::accessibility::AccessibleRole::MENU_ITEM: + return ROLE_SYSTEM_MENUITEM; + case css::accessibility::AccessibleRole::OPTION_PANE: + return IA2_ROLE_OPTION_PANE; + case css::accessibility::AccessibleRole::PAGE_TAB: + return ROLE_SYSTEM_PAGETAB; + case css::accessibility::AccessibleRole::PAGE_TAB_LIST: + return ROLE_SYSTEM_PAGETABLIST; + case css::accessibility::AccessibleRole::PANEL: + return IA2_ROLE_OPTION_PANE; + case css::accessibility::AccessibleRole::PARAGRAPH: + return IA2_ROLE_PARAGRAPH; + case css::accessibility::AccessibleRole::PASSWORD_TEXT: + return ROLE_SYSTEM_TEXT; + case css::accessibility::AccessibleRole::POPUP_MENU: + return ROLE_SYSTEM_MENUPOPUP; + case css::accessibility::AccessibleRole::PUSH_BUTTON: + return ROLE_SYSTEM_PUSHBUTTON; + case css::accessibility::AccessibleRole::PROGRESS_BAR: + return ROLE_SYSTEM_PROGRESSBAR; + case css::accessibility::AccessibleRole::RADIO_BUTTON: + return ROLE_SYSTEM_RADIOBUTTON; + case css::accessibility::AccessibleRole::RADIO_MENU_ITEM: + return IA2_ROLE_RADIO_MENU_ITEM; + case css::accessibility::AccessibleRole::ROW_HEADER: + return ROLE_SYSTEM_ROWHEADER; + case css::accessibility::AccessibleRole::ROOT_PANE: + return IA2_ROLE_ROOT_PANE; + case css::accessibility::AccessibleRole::SCROLL_BAR: + return ROLE_SYSTEM_SCROLLBAR; + case css::accessibility::AccessibleRole::SCROLL_PANE: + return IA2_ROLE_SCROLL_PANE; + case css::accessibility::AccessibleRole::SHAPE: + return IA2_ROLE_SHAPE; + case css::accessibility::AccessibleRole::SEPARATOR: + return ROLE_SYSTEM_SEPARATOR; + case css::accessibility::AccessibleRole::SLIDER: + return ROLE_SYSTEM_SLIDER; + case css::accessibility::AccessibleRole::SPIN_BOX: + return ROLE_SYSTEM_SPINBUTTON; + case css::accessibility::AccessibleRole::SPLIT_PANE: + return IA2_ROLE_SPLIT_PANE; + case css::accessibility::AccessibleRole::STATUS_BAR: + return ROLE_SYSTEM_STATUSBAR; + case css::accessibility::AccessibleRole::TABLE: + return ROLE_SYSTEM_TABLE; + case css::accessibility::AccessibleRole::TABLE_CELL: + return ROLE_SYSTEM_CELL; + case css::accessibility::AccessibleRole::TEXT: + return ROLE_SYSTEM_TEXT; + case css::accessibility::AccessibleRole::TEXT_FRAME: + return IA2_ROLE_TEXT_FRAME; + case css::accessibility::AccessibleRole::TOGGLE_BUTTON: + return ROLE_SYSTEM_PUSHBUTTON; + case css::accessibility::AccessibleRole::TOOL_BAR: + return ROLE_SYSTEM_TOOLBAR; + case css::accessibility::AccessibleRole::TOOL_TIP: + return ROLE_SYSTEM_TOOLTIP; + case css::accessibility::AccessibleRole::TREE: + return ROLE_SYSTEM_OUTLINE; + case css::accessibility::AccessibleRole::VIEW_PORT: + return IA2_ROLE_VIEW_PORT; + case css::accessibility::AccessibleRole::WINDOW: + return ROLE_SYSTEM_WINDOW; + case css::accessibility::AccessibleRole::BUTTON_DROPDOWN: + return ROLE_SYSTEM_BUTTONDROPDOWN; + case css::accessibility::AccessibleRole::BUTTON_MENU: + return ROLE_SYSTEM_BUTTONMENU; + case css::accessibility::AccessibleRole::CAPTION: + return IA2_ROLE_CAPTION; + case css::accessibility::AccessibleRole::CHART: + return IA2_ROLE_SHAPE; + case css::accessibility::AccessibleRole::EDIT_BAR: + return IA2_ROLE_EDITBAR; + case css::accessibility::AccessibleRole::FORM: + return IA2_ROLE_FORM; + case css::accessibility::AccessibleRole::IMAGE_MAP: + return IA2_ROLE_IMAGE_MAP; + case css::accessibility::AccessibleRole::NOTE: + return IA2_ROLE_NOTE; + case css::accessibility::AccessibleRole::PAGE: + return IA2_ROLE_PAGE; + case css::accessibility::AccessibleRole::RULER: + return IA2_ROLE_RULER; + case css::accessibility::AccessibleRole::SECTION: + return IA2_ROLE_SECTION; + case css::accessibility::AccessibleRole::TREE_ITEM: + return ROLE_SYSTEM_OUTLINEITEM; + case css::accessibility::AccessibleRole::TREE_TABLE: + return ROLE_SYSTEM_OUTLINE; + case css::accessibility::AccessibleRole::COMMENT: + return IA2_ROLE_TEXT_FRAME; + case css::accessibility::AccessibleRole::COMMENT_END: + return IA2_ROLE_TEXT_FRAME; + case css::accessibility::AccessibleRole::DOCUMENT_PRESENTATION: + return ROLE_SYSTEM_DOCUMENT; + case css::accessibility::AccessibleRole::DOCUMENT_SPREADSHEET: + return ROLE_SYSTEM_DOCUMENT; + case css::accessibility::AccessibleRole::DOCUMENT_TEXT: + return ROLE_SYSTEM_DOCUMENT; + case css::accessibility::AccessibleRole::STATIC: + return ROLE_SYSTEM_STATICTEXT; + case css::accessibility::AccessibleRole::NOTIFICATION: + return ROLE_SYSTEM_ALERT; + default: + SAL_WARN("iacc2", "Unmapped role: " << nUnoRole); + return IA2_ROLE_UNKNOWN; + } +} +}; + + +/** + * Constructor. + * @param pXAcc Uno XAccessible interface of control. + * @param pManager The accessible object manager kept in all listeners. + * @param listener listener that registers in UNO system. + * @return. + */ +AccObject::AccObject(XAccessible* pAcc, AccObjectWinManager* pManager, + AccEventListener* pListener) : + m_resID (0), + m_pParantID (nullptr), + m_pIMAcc (UAccCOMCreateInstance()), + m_pParentObj(nullptr), + m_pListener (pListener), + m_xAccRef( pAcc ) +{ + ImplInitializeCreateObj(); + + m_xAccContextRef = m_xAccRef->getAccessibleContext(); + m_xAccActionRef.set(m_xAccContextRef,UNO_QUERY); + m_accRole = m_xAccContextRef -> getAccessibleRole(); + if( m_pIMAcc ) + { + m_pIMAcc->SetXAccessible(reinterpret_cast<hyper>(m_xAccRef.get())); + m_pIMAcc->Put_XAccObjectManager(reinterpret_cast<hyper>(pManager)); + m_pIMAcc->SetDefaultAction(reinterpret_cast<hyper>(m_xAccActionRef.get())); + } +} +/** + * Destructor. + * @param + * @return + */ +AccObject::~AccObject() +{ + m_xAccRef = nullptr; + m_xAccActionRef = nullptr; + m_xAccContextRef = nullptr; +} + + +/** + * Insert a child element. + * @param pChild Child element that should be inserted into child list. + * @param pos Insert position. + * @return + */ +void AccObject::InsertChild( AccObject* pChild,short pos ) +{ + + std::vector<AccObject*>::iterator iter; + iter = std::find(m_childrenList.begin(),m_childrenList.end(),pChild); + if(iter!=m_childrenList.end()) + return; + if(LAST_CHILD==pos) + { + m_childrenList.push_back(pChild); + } + else + { + iter=m_childrenList.begin()+pos; + m_childrenList.insert(iter,pChild); + } + + pChild->SetParentObj(this); +} + +/** + * Delete a child element + * @param pChild Child element that should be inserted into child list. + * @param pos Insert position. + * @return + */ +void AccObject::DeleteChild( AccObject* pChild ) +{ + std::vector<AccObject*>::iterator iter; + iter = std::find(m_childrenList.begin(),m_childrenList.end(),pChild); + if(iter!=m_childrenList.end()) + { + m_childrenList.erase(iter); + if(m_pIMAcc) + pChild->SetParentObj(nullptr); + } +} + +/** + * In order to windows API WindowFromAccessibleObject, we sometimes to set a pure + * top window accessible object created by windows system as top ancestor. + * @param. + * @return + */ +void AccObject::UpdateValidWindow() +{ + if(m_pIMAcc) + m_pIMAcc->Put_XAccWindowHandle(m_pParantID); +} + +/** + * Translate all UNO basic information into MSAA com information. + * @param + * @return If the method is correctly processed. + */ +void AccObject::ImplInitializeCreateObj() +{ + assert(m_pIMAcc); +} + +/** + * Update name property to com object. + * @param + * @return + */ +void AccObject::UpdateName( ) +{ + if (!m_pIMAcc) + { + return; + } + + if( ( TEXT_FRAME == m_accRole ) && ( m_pParentObj !=nullptr )&& ( SCROLL_PANE == m_pParentObj -> m_accRole ) ) + m_pIMAcc->Put_XAccName( o3tl::toW(m_pParentObj->m_xAccContextRef->getAccessibleName().getStr()) ); + //IAccessibility2 Implementation 2009----- + if (m_accRole == AccessibleRole::PARAGRAPH || m_accRole == AccessibleRole::BLOCK_QUOTE) + { + m_pIMAcc->Put_XAccName(L""); + } + //-----IAccessibility2 Implementation 2009 + else + m_pIMAcc->Put_XAccName(o3tl::toW(m_xAccContextRef->getAccessibleName().getStr())); + + return ; +} + +/** + * Update default action property to com object. + * @param + * @return + */ +void AccObject::UpdateAction() +{ + m_xAccActionRef.set(m_xAccContextRef,UNO_QUERY); + + if( m_xAccActionRef.is() && m_pIMAcc ) + { + if( m_xAccActionRef->getAccessibleActionCount() > 0 ) + { + UpdateDefaultAction( ); + m_pIMAcc->SetDefaultAction( + reinterpret_cast<hyper>(m_xAccActionRef.get())); + } + } +} + +/** + * Update value property to com object. + * @param + * @return + */ +void AccObject::UpdateValue() +{ + if( nullptr == m_pIMAcc || !m_xAccContextRef.is() ) + { + assert(false); + return ; + } + + Reference< XAccessibleValue > pRValue(m_xAccContextRef,UNO_QUERY); + Any pAny; + if( pRValue.is() ) + { + pAny = pRValue->getCurrentValue(); + } + + SetValue( pAny ); +} + +/** + * Set special default action description string via UNO role. + * @param Role UNO role + * @return + */ +void AccObject::UpdateDefaultAction( ) +{ + if(!m_xAccActionRef.is()) + return ; + + switch(m_accRole) + { + case PUSH_BUTTON: + case TOGGLE_BUTTON: + case RADIO_BUTTON: + case MENU_ITEM: + case RADIO_MENU_ITEM: + case CHECK_MENU_ITEM: + case LIST_ITEM: + case CHECK_BOX: + case TREE_ITEM: + case BUTTON_DROPDOWN: + m_pIMAcc->Put_ActionDescription( o3tl::toW(m_xAccActionRef->getAccessibleActionDescription(sal_Int32(0)).getStr()) ); + return; + } +} + +/** + * Set value property via pAny. + * @param pAny New value. + * @return + */ +void AccObject::SetValue( Any pAny ) +{ + if( nullptr == m_pIMAcc || !m_xAccContextRef.is() ) + { + assert(false); + return ; + } + Reference< XAccessibleText > pRText(m_xAccContextRef,UNO_QUERY); + OUString val; + switch(m_accRole) + { + case SPIN_BOX: + // 3. date editor's msaa value should be the same as spinbox + case DATE_EDITOR: + case TEXT: + case BLOCK_QUOTE: + case PARAGRAPH: + case HEADING: + case TABLE_CELL: + + if(pRText) + { + val = pRText->getText(); + } + m_pIMAcc->Put_XAccValue( o3tl::toW(val.getStr()) ); + break; + case TREE_ITEM: + //case CHECK_BOX: //Commented by Li Xing to disable the value for general checkbox + case COMBO_BOX: + case NOTE: + case SCROLL_BAR: + m_pIMAcc->Put_XAccValue( o3tl::toW(GetMAccessibleValueFromAny(pAny).getStr()) ); + break ; + // Added by Li Xing, only the checkbox in tree should have the value. + case CHECK_BOX: + if( ( m_pParentObj !=nullptr ) && (TREE == m_pParentObj->m_accRole || TREE_ITEM == m_pParentObj->m_accRole )) + m_pIMAcc->Put_XAccValue( o3tl::toW(GetMAccessibleValueFromAny(pAny).getStr()) ); + break; + default: + break; + } + + return; +} + +OUString AccObject::GetMAccessibleValueFromAny(Any pAny) +{ + OUString strValue; + + if(nullptr == m_pIMAcc) + return strValue; + + if(pAny.getValueType() == cppu::UnoType<cppu::UnoUnsignedShortType>::get() ) + { + sal_uInt16 val; + if (pAny >>= val) + { + strValue=OUString::number(val); + + } + } + else if(pAny.getValueType() == cppu::UnoType<OUString>::get()) + { + + pAny >>= strValue ; + + } + else if(pAny.getValueType() == cppu::UnoType<Sequence< OUString >>::get()) + { + Sequence< OUString > val; + if (pAny >>= val) + { + for (const OUString& rElem : val) + strValue += rElem; + } + } + else if(pAny.getValueType() == cppu::UnoType<double>::get()) + { + double val; + if (pAny >>= val) + { + strValue=OUString::number(val); + } + } + else if(pAny.getValueType() == cppu::UnoType<sal_Int32>::get()) + { + sal_Int32 val; + if (pAny >>= val) + { + strValue=OUString::number(val); + } + } + else if (pAny.getValueType() == cppu::UnoType<css::accessibility::TextSegment>::get()) + { + css::accessibility::TextSegment val; + if (pAny >>= val) + { + OUString realVal(val.SegmentText); + strValue = realVal; + + } + } + + return strValue; +} +/** + * Set name property via pAny. + * @param pAny New accessible name. + * @return + */ +void AccObject::SetName( Any pAny) +{ + if( nullptr == m_pIMAcc ) + return ; + + m_pIMAcc->Put_XAccName( o3tl::toW(GetMAccessibleValueFromAny(pAny).getStr()) ); + +} + +/** +* Get role property via pAny +* @param +* @return accessible role +*/ +short AccObject::GetRole() const +{ + return m_accRole; +} + +/** + * Get MSAA state from UNO state + * @Role nState UNO state. + * @return + */ +DWORD AccObject::GetMSAAStateFromUNO(sal_Int64 nState) +{ + DWORD IState = UNO_MSAA_UNMAPPING; + + if( !m_xAccContextRef.is() ) + { + assert(false); + return IState; + } + + switch( nState ) + { + case BUSY: + IState = STATE_SYSTEM_BUSY; + break; + case CHECKED: + if (m_accRole == PUSH_BUTTON || m_accRole == TOGGLE_BUTTON) + { + IState = STATE_SYSTEM_PRESSED; + } + else + IState = STATE_SYSTEM_CHECKED; + break; + case DEFUNC: + IState = STATE_SYSTEM_UNAVAILABLE; + break; + case EXPANDED: + IState = STATE_SYSTEM_EXPANDED; + break; + case FOCUSABLE: + IState = STATE_SYSTEM_FOCUSABLE; + break; + case FOCUSED: + IState = STATE_SYSTEM_FOCUSED; + break; + case INDETERMINATE: + IState = STATE_SYSTEM_MIXED; + break; + case MULTI_SELECTABLE: + IState = STATE_SYSTEM_MULTISELECTABLE; + break; + case PRESSED: + IState = STATE_SYSTEM_PRESSED; + break; + case RESIZABLE: + IState = STATE_SYSTEM_SIZEABLE; + break; + case SELECTABLE: + if( m_accRole == MENU || m_accRole == MENU_ITEM) + { + IState = UNO_MSAA_UNMAPPING; + } + else + { + IState = STATE_SYSTEM_SELECTABLE; + } + break; + case SELECTED: + if( m_accRole == MENU || m_accRole == MENU_ITEM ) + { + IState = UNO_MSAA_UNMAPPING; + } + else + { + IState = STATE_SYSTEM_SELECTED; + } + break; + case ARMED: + IState = STATE_SYSTEM_FOCUSED; + break; + case EXPANDABLE: + { + sal_Bool isExpanded = true; + sal_Bool isExpandable = true; + if (m_accRole == PUSH_BUTTON || m_accRole == TOGGLE_BUTTON || m_accRole == BUTTON_DROPDOWN) + { + IState = STATE_SYSTEM_HASPOPUP; + } + else + { + GetExpandedState(&isExpandable,&isExpanded); + if(!isExpanded) + IState = STATE_SYSTEM_COLLAPSED; + } + } + break; + //Remove the SENSITIVE state mapping. There is no corresponding MSAA state. + //case SENSITIVE: + // IState = STATE_SYSTEM_PROTECTED; + case EDITABLE: + if( m_pIMAcc ) + { + m_pIMAcc->DecreaseState( STATE_SYSTEM_READONLY ); + } + break; + case OFFSCREEN: + IState = STATE_SYSTEM_OFFSCREEN; + break; + case MOVEABLE: + IState = STATE_SYSTEM_MOVEABLE; + break; + case COLLAPSE: + IState = STATE_SYSTEM_COLLAPSED; + break; + case DEFAULT: + IState = STATE_SYSTEM_DEFAULT; + break; + default: + break; + } + + return IState; +} + +/** + * Decrease state of com object + * @param xState The lost state. + * @return + */ +void AccObject::DecreaseState( sal_Int64 xState ) +{ + if( nullptr == m_pIMAcc ) + { + return; + } + + if( xState == FOCUSABLE) + { + if (m_accRole == MENU_ITEM || m_accRole == RADIO_MENU_ITEM || m_accRole == CHECK_MENU_ITEM) + return; + else + { + if (m_accRole == TOGGLE_BUTTON || m_accRole == PUSH_BUTTON || m_accRole == BUTTON_DROPDOWN) + { + if( ( m_pParentObj !=nullptr ) && (TOOL_BAR == m_pParentObj->m_accRole ) ) + return; + } + } + } + + else if( xState == AccessibleStateType::VISIBLE ) + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_INVISIBLE ); + } + else if( xState == AccessibleStateType::SHOWING ) + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_OFFSCREEN ); + } + + DWORD msState = GetMSAAStateFromUNO(xState); + if(msState!=UNO_MSAA_UNMAPPING) + m_pIMAcc->DecreaseState(msState); +} + +/** + * Increase state of com object + * @param xState The new state. + * @return + */ +void AccObject::IncreaseState( sal_Int64 xState ) +{ + if( nullptr == m_pIMAcc ) + { + assert(false); + return; + } + + + if( xState == AccessibleStateType::VISIBLE ) + { + m_pIMAcc->DecreaseState( STATE_SYSTEM_INVISIBLE ); + } + else if( xState == AccessibleStateType::SHOWING ) + { + m_pIMAcc->DecreaseState( STATE_SYSTEM_OFFSCREEN ); + } + + + DWORD msState = GetMSAAStateFromUNO(xState); + if(msState!=UNO_MSAA_UNMAPPING) + m_pIMAcc->IncreaseState( msState ); +} + +/** + * Get next child element + * @param + * @return AccObject Object interface. + */ +AccObject* AccObject::NextChild() +{ + IAccChildList::iterator pInd = m_childrenList.begin(); + if( pInd != m_childrenList.end() ) + return *pInd; + return nullptr; +} +/** + * update action description desc + * @param + * @return + */ +void AccObject::UpdateActionDesc() +{ + if (!m_pIMAcc) + return; + + long Role = m_accRole; + + if( Role == PUSH_BUTTON || Role == RADIO_BUTTON || Role == MENU_ITEM || + Role == LIST_ITEM || Role == CHECK_BOX || Role == TREE_ITEM || + Role == CHECK_MENU_ITEM || Role == RADIO_MENU_ITEM ) + { + UpdateDefaultAction( ); + } + else + { + + if( m_xAccActionRef.is() ) + { + if( m_xAccActionRef->getAccessibleActionCount() > 0 ) + { + if (!(Role == SPIN_BOX || Role == COMBO_BOX || Role == DATE_EDITOR || + Role == EDIT_BAR || Role == PASSWORD_TEXT || Role == TEXT)) + { + const OUString sActionDesc = m_xAccActionRef->getAccessibleActionDescription(0); + // if string is non-empty, action is set. + if (!sActionDesc.isEmpty()) + m_pIMAcc->Put_ActionDescription(o3tl::toW(sActionDesc.getStr())); + } + } + } + } + +} +/** + * update role information from uno to com + * @param + * @return + */ +void AccObject::UpdateRole() +{ + if (!m_pIMAcc) + { + return; + } + + const sal_Int16 nUnoRole = m_xAccContextRef->getAccessibleRole(); + short nIA2Role = lcl_mapToIAccessible2Role(nUnoRole); + m_pIMAcc->Put_XAccRole(nIA2Role); +} + +/** + * update state information from uno to com + * @param + * @return + */ +void AccObject::UpdateState() +{ + if (!m_pIMAcc) + { + return; + } + + XAccessibleContext* pContext = m_xAccContextRef.get(); + sal_Int64 nRState = pContext->getAccessibleStateSet(); + + m_pIMAcc->SetState(0); + + if ( m_accRole == POPUP_MENU ) + { + return; + } + + bool isEnable = false; + bool isShowing = false; + bool isEditable = false; + bool isVisible = false; + bool isFocusable = false; + + for (int i=0; i<63; ++i) + { + sal_Int64 nState = sal_Int64(1) << i; + if (!(nState & nRState)) + continue; + if (nState == ENABLED) + isEnable = true; + else if (nState == SHOWING) + isShowing = true; + else if (nState == VISIBLE) + isVisible = true; + else if (nState == EDITABLE) + isEditable = true; + else if (nState == FOCUSABLE) + isFocusable = true; + IncreaseState(nState); + } + + bool bIsMenuItem = m_accRole == MENU_ITEM || m_accRole == RADIO_MENU_ITEM || m_accRole == CHECK_MENU_ITEM; + + if(bIsMenuItem) + { + if(!(isShowing && isVisible) ) + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_INVISIBLE ); + m_pIMAcc->DecreaseState( STATE_SYSTEM_FOCUSABLE ); + } + } + else + { + if(!(isShowing || isVisible) ) + m_pIMAcc->IncreaseState( STATE_SYSTEM_INVISIBLE ); + } + + switch(m_accRole) + { + case LABEL: + case STATIC: + case NOTIFICATION: + m_pIMAcc->IncreaseState( STATE_SYSTEM_READONLY ); + break; + case TEXT: + // 2. editable combobox -> readonly ------ bridge + case EMBEDDED_OBJECT: + case END_NOTE: + case FOOTER: + case FOOTNOTE: + case GRAPHIC: + case HEADER: + case HEADING: + + //Image Map + case BLOCK_QUOTE: + case PARAGRAPH: + case PASSWORD_TEXT: + case SHAPE: + case SPIN_BOX: + case TABLE: + case TABLE_CELL: + case TEXT_FRAME: + case DATE_EDITOR: + case DOCUMENT: + case COLUMN_HEADER: + { + if(!isEditable) + m_pIMAcc->IncreaseState( STATE_SYSTEM_READONLY ); + } + break; + default: + break; + } + + if( isEnable ) + { + + if (!(m_accRole == FILLER || m_accRole == END_NOTE || m_accRole == FOOTER || m_accRole == FOOTNOTE || m_accRole == GROUP_BOX || m_accRole == RULER + || m_accRole == HEADER || m_accRole == ICON || m_accRole == INTERNAL_FRAME || m_accRole == LABEL || m_accRole == LAYERED_PANE + || m_accRole == SCROLL_BAR || m_accRole == SCROLL_PANE || m_accRole == SPLIT_PANE || m_accRole == STATIC || m_accRole == STATUS_BAR + || m_accRole == TOOL_TIP || m_accRole == NOTIFICATION)) + { + if (m_accRole == SEPARATOR) + { + if( ( m_pParentObj != nullptr ) && ( MENU == m_pParentObj->m_accRole || POPUP_MENU == m_pParentObj->m_accRole )) + IncreaseState( FOCUSABLE ); + } + + else if (m_accRole == TABLE_CELL || m_accRole == TABLE || m_accRole == PANEL || m_accRole == OPTION_PANE || + m_accRole == COLUMN_HEADER) + { + if (isFocusable) + IncreaseState( FOCUSABLE ); + } + else + { + if(bIsMenuItem) + { + if ( isShowing && isVisible) + { + IncreaseState( FOCUSABLE ); + } + } + else + { + IncreaseState( FOCUSABLE ); + } + } + } + } + else + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_UNAVAILABLE ); + if( !((m_accRole == MENU_ITEM) || + (m_accRole == RADIO_MENU_ITEM) || + (m_accRole == CHECK_MENU_ITEM)) ) + { + if (m_accRole == TOGGLE_BUTTON || m_accRole == PUSH_BUTTON || m_accRole == BUTTON_DROPDOWN) + { + if(( m_pParentObj != nullptr )&& (TOOL_BAR == m_pParentObj->m_accRole ) ) + IncreaseState( FOCUSABLE ); + else + DecreaseState( FOCUSABLE ); + } + else + DecreaseState( FOCUSABLE ); + } + else if( isShowing || isVisible ) + { + IncreaseState( FOCUSABLE ); + } + } + + switch(m_accRole) + { + case POPUP_MENU: + case MENU: + if( pContext->getAccessibleChildCount() > 0 ) + m_pIMAcc->IncreaseState( STATE_SYSTEM_HASPOPUP ); + break; + case PASSWORD_TEXT: + m_pIMAcc->IncreaseState( STATE_SYSTEM_PROTECTED ); + break; + default: + break; + } +} + +/** + * Public method to mapping information between MSAA and UNO. + * @param + * @return If the method is correctly processed. + */ +bool AccObject::UpdateAccessibleInfoFromUnoToMSAA() +{ + if( nullptr == m_pIMAcc || !m_xAccContextRef.is() ) + { + assert(false); + return false; + } + + UpdateName(); + + UpdateValue(); + + UpdateActionDesc(); + + UpdateRole(); + + UpdateState(); + + return true; +} + + +/** + * Set self to focus object in parent child list + * @param + * @return + */ +void AccObject::setFocus() +{ + if(m_pIMAcc) + { + IncreaseState(FOCUSED); + m_pIMAcc->Put_XAccFocus(CHILDID_SELF); + + UpdateRole(); + } +} + +/** + * Unset self from focus object in parent child list. + * @param + * @return + */ +void AccObject::unsetFocus() +{ + if(m_pIMAcc) + { + DecreaseState( FOCUSED ); + m_pIMAcc->Put_XAccFocus(UACC_NO_FOCUS); + } +} + +void AccObject::GetExpandedState( sal_Bool* isExpandable, sal_Bool* isExpanded) +{ + *isExpanded = false; + *isExpandable = false; + + if( !m_xAccContextRef.is() ) + { + return; + } + sal_Int64 nRState = m_xAccContextRef->getAccessibleStateSet(); + + if (nRState & EXPANDED) + *isExpanded = true; + if (nRState & EXPANDABLE) + *isExpandable = true; +} + +void AccObject::NotifyDestroy() +{ + if(m_pIMAcc) + m_pIMAcc->NotifyDestroy(); +} + +void AccObject::SetParentObj(AccObject* pParentAccObj) +{ + m_pParentObj = pParentAccObj; + + if(m_pIMAcc) + { + if(m_pParentObj) + { + m_pIMAcc->Put_XAccParent(m_pParentObj->GetIMAccessible()); + } + else + { + m_pIMAcc->Put_XAccParent(nullptr); + } + } +} +//ResID means ChildID in MSAA +void AccObject::SetResID(long id) +{ + m_resID = id; + if(m_pIMAcc) + m_pIMAcc->Put_XAccChildID(m_resID); +} +//return COM interface in acc object +IMAccessible* AccObject::GetIMAccessible() +{ + return m_pIMAcc; +} + +Reference<XAccessible> const& AccObject::GetXAccessible() +{ + return m_xAccRef; +} + +void AccObject::SetParentHWND(HWND hWnd) +{ + m_pParantID = hWnd; +} + +rtl::Reference<AccEventListener> AccObject::SetListener(rtl::Reference<AccEventListener> const& pListener) +{ + rtl::Reference<AccEventListener> pRet(m_pListener); + m_pListener = pListener; + return pRet; +} + +AccEventListener* AccObject::getListener() +{ + return m_pListener.get(); +} + +long AccObject::GetResID() +{ + return m_resID; +} + +HWND AccObject::GetParentHWND() +{ + return m_pParantID; +} + +AccObject* AccObject::GetParentObj() +{ + return m_pParentObj; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccObjectContainerEventListener.cxx b/winaccessibility/source/service/AccObjectContainerEventListener.cxx new file mode 100644 index 0000000000..137b498a2c --- /dev/null +++ b/winaccessibility/source/service/AccObjectContainerEventListener.cxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// AccObjectContainerEventListener.cpp: implementation of the AccContainerEventListener class. + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <AccObjectContainerEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccObjectContainerEventListener::AccObjectContainerEventListener( + css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + : AccContainerEventListener(pAcc, pManager) +{ +} +AccObjectContainerEventListener::~AccObjectContainerEventListener() {} + +/** + * handle the STATE_CHANGED event + */ +void AccObjectContainerEventListener::HandleStateChangedEvent(Any oldValue, Any newValue) +{ + //set the accessible name before process for there is no NAME_CHANGED event when change + //the text in drawing objects. + sal_Int64 newV; + if (newValue >>= newV) + { + if (newV == AccessibleStateType::FOCUSED) + { + m_pObjManager->UpdateAccName(m_xAccessible.get()); + } + } + AccContainerEventListener::HandleStateChangedEvent(oldValue, newValue); +} +/** + * handle the VISIBLE_DATA_CHANGED event + * For SHAPES, the visible_data_changed event should be mapped to LOCATION_CHANGED event + */ +void AccObjectContainerEventListener::HandleVisibleDataChangedEvent() +{ + AccContainerEventListener::HandleBoundrectChangedEvent(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccObjectWinManager.cxx b/winaccessibility/source/service/AccObjectWinManager.cxx new file mode 100644 index 0000000000..24deb8150c --- /dev/null +++ b/winaccessibility/source/service/AccObjectWinManager.cxx @@ -0,0 +1,1125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <cassert> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/XAccessibleEventListener.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +#include <oleacc.h> +#include <AccObjectWinManager.hxx> +#include <AccEventListener.hxx> +#include <AccComponentEventListener.hxx> +#include <AccContainerEventListener.hxx> +#include <AccDialogEventListener.hxx> +#include <AccWindowEventListener.hxx> +#include <AccFrameEventListener.hxx> +#include <AccMenuEventListener.hxx> +#include <AccObjectContainerEventListener.hxx> +#include <AccParagraphEventListener.hxx> +#include <AccTextComponentEventListener.hxx> +#include <AccListEventListener.hxx> +#include <AccTreeEventListener.hxx> +#include <AccTableEventListener.hxx> +#include <AccObject.hxx> +#include <unomsaaevent.hxx> + + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; + +AccObjectWinManager::AccObjectWinManager(): + oldFocus(nullptr) +{ +} + +/** + * Destructor,clear all resource. + * @param + * @return + */ +AccObjectWinManager::~AccObjectWinManager() +{ + { + std::scoped_lock l(m_Mutex); + + XIdAccList.clear(); + HwndXAcc.clear(); + } + XResIdAccList.clear(); + XHWNDDocList.clear(); +} + + +/** + * Get valid com object interface when notifying some MSAA event + * @param pWND The top window handle that contains that event control. + * @param wParam Windows system interface. + * @return Com interface with event. + */ + +sal_Int64 +AccObjectWinManager::Get_ToATInterface(sal_Int64 nHWnd, long lParam, WPARAM wParam) +{ + IMAccessible* pRetIMAcc = nullptr; + + if(lParam == OBJID_CLIENT ) + { + HWND hWnd = reinterpret_cast<HWND>(nHWnd); + pRetIMAcc = GetTopWindowIMAccessible(hWnd); + } + + if ( pRetIMAcc && lParam == OBJID_CLIENT ) + { + LRESULT result = LresultFromObject(IID_IAccessible, wParam, pRetIMAcc); + pRetIMAcc->Release(); + return static_cast<sal_Int64>(result); + } + return 0; +} + +/** + * Search AccObject by XAccessible pointer from our container. + * @param pXAcc XAccessible interface. + * @return Pointer of accObject that is found. + */ +AccObject* AccObjectWinManager::GetAccObjByXAcc( XAccessible* pXAcc) +{ + if( pXAcc == nullptr) + return nullptr; + + std::scoped_lock l(m_Mutex); + + XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( pXAcc ); + if ( pIndTemp == XIdAccList.end() ) + return nullptr; + + return &(pIndTemp->second); +} + +/** + * get acc object of top window by its handle + * @param hWnd, top window handle + * @return pointer to AccObject + */ +IMAccessible * AccObjectWinManager::GetTopWindowIMAccessible(HWND hWnd) +{ + std::scoped_lock l(m_Mutex); // tdf#155794 for HwndXAcc and XIdAccList + + XHWNDToXAccHash::iterator iterResult =HwndXAcc.find(hWnd); + if(iterResult == HwndXAcc.end()) + return nullptr; + XAccessible* pXAcc = iterResult->second; + AccObject *const pAccObject(GetAccObjByXAcc(pXAcc)); + if (!pAccObject) + { + return nullptr; + } + IMAccessible *const pRet(pAccObject->GetIMAccessible()); + if (!pRet) + { + return nullptr; + } + pRet->AddRef(); + return pRet; +} + +/** + * Simulate MSAA event via XAccessible interface and event type. + * @param pXAcc XAccessible interface. + * @param eEvent event type + * @return The terminate result that identifies if the call is successful. + */ +bool AccObjectWinManager::NotifyAccEvent(XAccessible* pXAcc, UnoMSAAEvent eEvent) +{ + Reference< XAccessibleContext > pRContext; + + if( pXAcc == nullptr) + return false; + + + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return false; + + + AccObject* selfAccObj= GetAccObjByXAcc(pXAcc); + + if(selfAccObj==nullptr) + return false; + + long dChildID = selfAccObj->GetResID(); + HWND hAcc = selfAccObj->GetParentHWND(); + + switch(eEvent) + { + case UnoMSAAEvent::STATE_FOCUSED: + { + UpdateAccFocus(pXAcc); + selfAccObj->UpdateDefaultAction( ); + UpdateValue(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + } + case UnoMSAAEvent::STATE_BUSY: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::STATE_CHECKED: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::STATE_PRESSED: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + + //Removed fire out selected event + //case UnoMSAAEvent::STATE_SELECTED: + // NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + // break; + case UnoMSAAEvent::STATE_ARMED: + UpdateAccFocus(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::STATE_SHOWING: + // send EVENT_SYSTEM_ALERT when notification gets shown + if (pRContext->getAccessibleRole() == AccessibleRole::NOTIFICATION) + NotifyWinEvent(EVENT_SYSTEM_ALERT, hAcc, OBJID_CLIENT, dChildID); + break; + case UnoMSAAEvent::MENU_START: + NotifyWinEvent( EVENT_SYSTEM_MENUSTART,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::MENU_END: + NotifyWinEvent( EVENT_SYSTEM_MENUEND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::MENUPOPUPSTART: + NotifyWinEvent( EVENT_SYSTEM_MENUPOPUPSTART,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::MENUPOPUPEND: + NotifyWinEvent( EVENT_SYSTEM_MENUPOPUPEND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SELECTION_CHANGED: + NotifyWinEvent( EVENT_OBJECT_SELECTION,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SELECTION_CHANGED_ADD: + NotifyWinEvent( EVENT_OBJECT_SELECTIONADD,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SELECTION_CHANGED_REMOVE: + NotifyWinEvent( EVENT_OBJECT_SELECTIONREMOVE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SELECTION_CHANGED_WITHIN: + NotifyWinEvent( EVENT_OBJECT_SELECTIONWITHIN,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_VALUECHANGE: + UpdateValue(pXAcc); + NotifyWinEvent( EVENT_OBJECT_VALUECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_NAMECHANGE: + NotifyWinEvent( EVENT_OBJECT_NAMECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_DESCRIPTIONCHANGE: + NotifyWinEvent( EVENT_OBJECT_DESCRIPTIONCHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_DEFACTIONCHANGE: + NotifyWinEvent( IA2_EVENT_ACTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_CARETCHANGE: + NotifyWinEvent( IA2_EVENT_TEXT_CARET_MOVED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_TEXTCHANGE: + NotifyWinEvent( IA2_EVENT_TEXT_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::ACTIVE_DESCENDANT_CHANGED: + UpdateAccFocus(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::BOUNDRECT_CHANGED: + NotifyWinEvent( EVENT_OBJECT_LOCATIONCHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::VISIBLE_DATA_CHANGED: + NotifyWinEvent( IA2_EVENT_VISIBLE_DATA_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SHOW : + NotifyWinEvent( EVENT_OBJECT_SHOW,hAcc, OBJID_CLIENT,dChildID ); + NotifyWinEvent( EVENT_SYSTEM_FOREGROUND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_CAPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_CAPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_COLUMN_DESCRIPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_COLUMN_HEADER_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_MODEL_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_MODEL_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_ROW_HEADER_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_ROW_HEADER_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_SUMMARY_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_SUMMARY_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_ROW_DESCRIPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_REORDER: + NotifyWinEvent( EVENT_OBJECT_REORDER,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::PAGE_CHANGED: + NotifyWinEvent( IA2_EVENT_PAGE_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::CHILD_REMOVED: + NotifyWinEvent( EVENT_OBJECT_DESTROY,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::CHILD_ADDED: + NotifyWinEvent( EVENT_OBJECT_CREATE ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_PAGECHANGED: + NotifyWinEvent( IA2_EVENT_PAGE_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TEXT_SELECTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TEXT_SELECTION_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SECTION_CHANGED: + NotifyWinEvent( IA2_EVENT_SECTION_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::COLUMN_CHANGED: + NotifyWinEvent( IA2_EVENT_TEXT_COLUMN_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + default: + break; + } + + return true; +} + +/** + * Get Parent XAccessible interface by XAccessible interface. + * @param pXAcc XAccessible interface. + * @return Parent XAccessible interface. + */ +XAccessible* AccObjectWinManager::GetParentXAccessible( XAccessible* pXAcc ) +{ + AccObject* pObj= GetAccObjByXAcc(pXAcc); + if( pObj ==nullptr ) + return nullptr; + if(pObj->GetParentObj()) + { + pObj = pObj->GetParentObj(); + return pObj->GetXAccessible().get(); + } + return nullptr; +} + +/** + * Get Parent role by XAccessible interface. + * @param pXAcc XAccessible interface. + * @return Parent role. + */ +short AccObjectWinManager::GetParentRole( XAccessible* pXAcc ) +{ + AccObject* pObj= GetAccObjByXAcc(pXAcc); + if( pObj ==nullptr ) + return -1; + if(pObj->GetParentObj()) + { + pObj = pObj->GetParentObj(); + if(pObj->GetXAccessible().is()) + { + Reference< XAccessibleContext > pRContext = pObj->GetXAccessible()->getAccessibleContext(); + if(pRContext.is()) + return pRContext->getAccessibleRole(); + } + } + return -1; +} + +/** + * Update focus object by new focused XAccessible interface. + * @param newFocus New XAccessible interface that gets focus. + * @return + */ +void AccObjectWinManager::UpdateAccFocus(XAccessible* newFocus) +{ + AccObject* pAccObjNew = GetAccObjByXAcc(newFocus); + if(pAccObjNew) + { + AccObject* pAccObjOld = GetAccObjByXAcc(oldFocus); + oldFocus = newFocus; + pAccObjNew->setFocus(); + //if old == new, the pAccObjNew will be without focused state + if (pAccObjOld && pAccObjOld != pAccObjNew) + pAccObjOld->unsetFocus(); + } +} + +/** + * Delete child element from children list. + * @param pObj Child element that should be removed from parent child list. + * @return + */ +void AccObjectWinManager::DeleteAccChildNode( AccObject* pObj ) +{ + AccObject *parentAccObj = pObj->GetParentObj(); + if( parentAccObj ) + parentAccObj->DeleteChild( pObj ); +} + +/** + * Delete XAccessible items in top window handle hashtable + * @param pXAcc XAccessible interface. + * @return + */ +void AccObjectWinManager::DeleteFromHwndXAcc(XAccessible const * pXAcc ) +{ + std::scoped_lock l(m_Mutex); + + auto iter = std::find_if(HwndXAcc.begin(), HwndXAcc.end(), + [&pXAcc](XHWNDToXAccHash::value_type& rEntry) { return rEntry.second == pXAcc; }); + if (iter != HwndXAcc.end()) + HwndXAcc.erase(iter); +} + +/** + * Delete all children with the tree root of XAccessible pointer + * @param pXAcc Tree root XAccessible interface. + * @return + */ +void AccObjectWinManager::DeleteChildrenAccObj(XAccessible* pXAcc) +{ + AccObject* currentObj=nullptr; + AccObject* childObj=nullptr; + + currentObj = GetAccObjByXAcc( pXAcc); + if(currentObj) + { + childObj = currentObj->NextChild(); + while(childObj) + { + XAccessible *const pTmpXAcc = childObj->GetXAccessible().get(); + if(pTmpXAcc) + { + DeleteChildrenAccObj(pTmpXAcc); + DeleteAccObj(pTmpXAcc); + } + childObj = currentObj->NextChild(); + } + } +} + +/** + * Delete Acc object self. + * @param pXAcc The XAccessible interface. + * @return + */ +void AccObjectWinManager::DeleteAccObj( XAccessible* pXAcc ) +{ + if( pXAcc == nullptr ) + return; + + rtl::Reference<AccEventListener> pListener; + + { + std::scoped_lock l(m_Mutex); + + XIdToAccObjHash::iterator temp = XIdAccList.find(pXAcc); + if( temp != XIdAccList.end() ) + { + ResIdGen.SetSub( temp->second.GetResID() ); + } + else + { + return; + } + + AccObject& accObj = temp->second; + DeleteAccChildNode( &accObj ); + pListener = DeleteAccListener(&accObj); + accObj.NotifyDestroy(); + if( accObj.GetIMAccessible() ) + { + accObj.GetIMAccessible()->Release(); + } + size_t i = XResIdAccList.erase(accObj.GetResID()); + assert(i != 0); + (void) i; + DeleteFromHwndXAcc(pXAcc); + if (accObj.GetRole() == AccessibleRole::DOCUMENT || + accObj.GetRole() == AccessibleRole::DOCUMENT_PRESENTATION || + accObj.GetRole() == AccessibleRole::DOCUMENT_SPREADSHEET || + accObj.GetRole() == AccessibleRole::DOCUMENT_TEXT) + { + XHWNDDocList.erase(accObj.GetParentHWND()); + } + XIdAccList.erase(pXAcc); // note: this invalidates accObj so do it last! + } + if (pListener) + { + pListener->RemoveMeFromBroadcaster(false); + } +} + +/** + * Delete listener that inspects some XAccessible object + * @param pAccObj Accobject pointer. + * @return + */ +rtl::Reference<AccEventListener> AccObjectWinManager::DeleteAccListener( AccObject* pAccObj ) +{ + return pAccObj->SetListener(nullptr); +} + +/** + * Generate a child ID, which is used for AT + * @param + * @return New resource ID. + */ +inline long AccObjectWinManager::ImpleGenerateResID() +{ + return ResIdGen.GenerateNewResID(); +} + +/** + * Insert all children of the current acc object + * @param pXAcc XAccessible interface + * @param pWnd Top Window handle + * @return The calling result. + */ +bool AccObjectWinManager::InsertChildrenAccObj( css::accessibility::XAccessible* pXAcc, + HWND pWnd) +{ + if(!IsContainer(pXAcc)) + return false; + + Reference< XAccessibleContext > pRContext; + + if( pXAcc == nullptr) + return false; + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return false; + + short role = pRContext->getAccessibleRole(); + + if(css::accessibility::AccessibleRole::DOCUMENT == role || + css::accessibility::AccessibleRole::DOCUMENT_PRESENTATION == role || + css::accessibility::AccessibleRole::DOCUMENT_SPREADSHEET == role || + css::accessibility::AccessibleRole::DOCUMENT_TEXT == role) + { + if(IsStateManageDescendant(pXAcc)) + { + return true; + } + } + + const sal_Int64 nCount = pRContext->getAccessibleChildCount(); + for (sal_Int64 i = 0; i < nCount; i++) + { + Reference<XAccessible> mxAccessible + = pRContext->getAccessibleChild(i); + XAccessible* mpAccessible = mxAccessible.get(); + if(mpAccessible != nullptr) + { + InsertAccObj( mpAccessible,pXAcc,pWnd ); + InsertChildrenAccObj(mpAccessible,pWnd); + } + } + + return true; +} + +/** + * Insert child object. + * @param pCurObj The child object + * @param pParentObj The parent object + * @param pWnd Top window handle. + * @return + */ +void AccObjectWinManager::InsertAccChildNode( AccObject* pCurObj, AccObject* pParentObj, HWND /* pWnd */ ) +{ + if(pCurObj) + { + if(pParentObj) + { + pParentObj->InsertChild(pCurObj); + } + else + { + pCurObj->UpdateValidWindow(); + } + } +} + +/** + * Insert child object. + * @param pCurObj The child object + * @param pParentObj The parent object + * @param pWnd Top window handle. + * @return + */ +bool AccObjectWinManager::InsertAccObj( XAccessible* pXAcc,XAccessible* pParentXAcc,HWND pWnd ) +{ + Reference< XAccessibleContext > pRContext; + + if( pXAcc == nullptr) + return false; + + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return false; + + { + short nCurRole = GetRole(pXAcc); + + std::scoped_lock l(m_Mutex); + + XIdToAccObjHash::iterator itXacc = XIdAccList.find( pXAcc ); + if (itXacc != XIdAccList.end() ) + { + if (AccessibleRole::SHAPE == nCurRole) + { + AccObject &objXacc = itXacc->second; + AccObject *pObjParent = objXacc.GetParentObj(); + if (pObjParent && + pObjParent->GetXAccessible().is() && + pObjParent->GetXAccessible().get() != pParentXAcc) + { + XIdToAccObjHash::iterator itXaccParent = XIdAccList.find( pParentXAcc ); + if(itXaccParent != XIdAccList.end()) + { + objXacc.SetParentObj(&(itXaccParent->second)); + } + } + } + return false; + } + } + + if( pWnd == nullptr ) + { + if(pParentXAcc) + { + AccObject* pObj = GetAccObjByXAcc(pParentXAcc); + if(pObj) + pWnd = pObj->GetParentHWND(); + } + if( pWnd == nullptr ) + return false; + } + + AccObject pObj(pXAcc, this); + if( pObj.GetIMAccessible() == nullptr ) + return false; + pObj.SetResID( this->ImpleGenerateResID()); + pObj.SetParentHWND( pWnd ); + + //for file name support + if (pObj.GetRole() == AccessibleRole::DOCUMENT || + pObj.GetRole() == AccessibleRole::DOCUMENT_PRESENTATION || + pObj.GetRole() == AccessibleRole::DOCUMENT_SPREADSHEET || + pObj.GetRole() == AccessibleRole::DOCUMENT_TEXT) + { + XHWNDToDocumentHash::iterator aIter = XHWNDDocList.find(pWnd); + if ( aIter != XHWNDDocList.end() ) + { + XHWNDDocList.erase( aIter ); + } + XHWNDDocList.emplace( pWnd, pXAcc ); + } + //end of file name + + ::rtl::Reference<AccEventListener> const pListener = + CreateAccEventListener(pXAcc); + if (!pListener.is()) + return false; + Reference<XAccessibleComponent> xComponent(pRContext,UNO_QUERY); + Reference<XAccessibleEventBroadcaster> broadcaster(xComponent,UNO_QUERY); + if (broadcaster.is()) + { + Reference<XAccessibleEventListener> const xListener(pListener); + broadcaster->addAccessibleEventListener(xListener); + } + else + return false; + + { + std::scoped_lock l(m_Mutex); + + XIdAccList.emplace(pXAcc, pObj); + XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( pXAcc ); + XResIdAccList.emplace(pObj.GetResID(),&(pIndTemp->second)); + } + + AccObject* pCurObj = GetAccObjByXAcc(pXAcc); + if( pCurObj ) + { + pCurObj->SetListener(pListener); + } + + AccObject* pParentObj = GetAccObjByXAcc(pParentXAcc); + InsertAccChildNode(pCurObj,pParentObj,pWnd); + if( pCurObj ) + pCurObj->UpdateAccessibleInfoFromUnoToMSAA(); + return true; +} + + +/** + * save the pair <topwindowhandle, XAccessible> + * @param hWnd, top window handle + * @param pXAcc XAccessible interface for top window + * @return void + */ +void AccObjectWinManager::SaveTopWindowHandle(HWND hWnd, css::accessibility::XAccessible* pXAcc) +{ + std::scoped_lock l(m_Mutex); + + HwndXAcc.emplace(hWnd,pXAcc); +} + + +/** Create the corresponding listener. + * @param pXAcc XAccessible interface. + */ +::rtl::Reference<AccEventListener> +AccObjectWinManager::CreateAccEventListener(XAccessible* pXAcc) +{ + ::rtl::Reference<AccEventListener> pRet; + Reference<XAccessibleContext> xContext = pXAcc->getAccessibleContext(); + if(xContext.is()) + { + switch( xContext->getAccessibleRole() ) + { + case AccessibleRole::DIALOG: + pRet = new AccDialogEventListener(pXAcc, this); + break; + case AccessibleRole::FRAME: + pRet = new AccFrameEventListener(pXAcc, this); + break; + case AccessibleRole::WINDOW: + pRet = new AccWindowEventListener(pXAcc, this); + break; + case AccessibleRole::ROOT_PANE: + pRet = new AccFrameEventListener(pXAcc, this); + break; + //Container + case AccessibleRole::CANVAS: + case AccessibleRole::COMBO_BOX: + case AccessibleRole::DOCUMENT: + case AccessibleRole::DOCUMENT_PRESENTATION: + case AccessibleRole::DOCUMENT_SPREADSHEET: + case AccessibleRole::DOCUMENT_TEXT: + case AccessibleRole::END_NOTE: + case AccessibleRole::FILLER: + case AccessibleRole::FOOTNOTE: + case AccessibleRole::FOOTER: + case AccessibleRole::HEADER: + case AccessibleRole::LAYERED_PANE: + case AccessibleRole::MENU_BAR: + case AccessibleRole::POPUP_MENU: + case AccessibleRole::OPTION_PANE: + case AccessibleRole::PAGE_TAB: + case AccessibleRole::PAGE_TAB_LIST: + case AccessibleRole::PANEL: + case AccessibleRole::SCROLL_PANE: + case AccessibleRole::SPLIT_PANE: + case AccessibleRole::STATUS_BAR: + case AccessibleRole::TABLE_CELL: + case AccessibleRole::TOOL_BAR: + case AccessibleRole::VIEW_PORT: + pRet = new AccContainerEventListener(pXAcc, this); + break; + case AccessibleRole::BLOCK_QUOTE: + case AccessibleRole::PARAGRAPH: + case AccessibleRole::HEADING: + pRet = new AccParagraphEventListener(pXAcc, this); + break; + //Component + case AccessibleRole::CHECK_BOX: + case AccessibleRole::ICON: + case AccessibleRole::LABEL: + case AccessibleRole::STATIC: + case AccessibleRole::NOTIFICATION: + case AccessibleRole::MENU_ITEM: + case AccessibleRole::CHECK_MENU_ITEM: + case AccessibleRole::RADIO_MENU_ITEM: + case AccessibleRole::PUSH_BUTTON: + case AccessibleRole::RADIO_BUTTON: + case AccessibleRole::SCROLL_BAR: + case AccessibleRole::SEPARATOR: + case AccessibleRole::TOGGLE_BUTTON: + case AccessibleRole::BUTTON_DROPDOWN: + case AccessibleRole::TOOL_TIP: + case AccessibleRole::SPIN_BOX: + case AccessibleRole::DATE_EDITOR: + pRet = new AccComponentEventListener(pXAcc, this); + break; + //text component + case AccessibleRole::TEXT: + pRet = new AccTextComponentEventListener(pXAcc, this); + break; + //menu + case AccessibleRole::MENU: + pRet = new AccMenuEventListener(pXAcc, this); + break; + //object container + case AccessibleRole::SHAPE: + + case AccessibleRole::EMBEDDED_OBJECT: + case AccessibleRole::GRAPHIC: + case AccessibleRole::TEXT_FRAME: + pRet = new AccObjectContainerEventListener(pXAcc, this); + break; + //descendmanager + case AccessibleRole::LIST: + pRet = new AccListEventListener(pXAcc, this); + break; + case AccessibleRole::TREE: + pRet = new AccTreeEventListener(pXAcc, this); + break; + //special + case AccessibleRole::COLUMN_HEADER: + case AccessibleRole::TABLE: + pRet = new AccTableEventListener(pXAcc, this); + break; + default: + pRet = new AccContainerEventListener(pXAcc, this); + break; + } + } + return pRet; +} + +/** + * state is a combination integer, each bit of which represents a single state, + * such as focused,1 for the state on,0 for the state off. Here call COM interface + * to modify the state value, including DecreaseState. + * @param pXAcc XAccessible interface. + * @param pState Changed state. + * @return + */ +void AccObjectWinManager::DecreaseState(XAccessible* pXAcc, sal_Int64 nState) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->DecreaseState(nState); +} + +/** + * state is a combination integer, each bit of which represents a single state,such as focused,1 for + * the state on,0 for the state off. Here call COM interface to modify the state value, including + * IncreaseState. + * @param pXAcc XAccessible interface. + * @param pState Changed state. + * @return + */ +void AccObjectWinManager::IncreaseState(XAccessible* pXAcc, sal_Int64 nState) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->IncreaseState(nState); +} + +void AccObjectWinManager::UpdateState( css::accessibility::XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateState( ); +} + +/** + * Set corresponding com object's accessible name via XAccessible interface and new + * name + * @param pXAcc XAccessible interface. + * @return + */ +void AccObjectWinManager::UpdateAccName( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateName(); +} + +void AccObjectWinManager::UpdateAction( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateAction(); +} + +/** + * Set corresponding com object's value via XAccessible interface and new value. + * @param pXAcc XAccessible interface. + * @param pAny new value. + * @return + */ +void AccObjectWinManager::SetValue( XAccessible* pXAcc, Any pAny ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->SetValue( pAny ); +} + +/** + * Set corresponding com object's value via XAccessible interface. + * @param pXAcc XAccessible interface. + * @return + */ +void AccObjectWinManager::UpdateValue( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateValue(); +} + +/** + * Set corresponding com object's name via XAccessible interface and new name. + * @param pXAcc XAccessible interface. + * @param newName new name + * @return + */ +void AccObjectWinManager::SetAccName( XAccessible* pXAcc, Any newName) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->SetName( newName ); +} + +/** + * Judge if a XAccessible object is a container object. + * @param pAccessible XAccessible interface. + * @return If XAccessible object is container. + */ +bool AccObjectWinManager::IsContainer(XAccessible* pAccessible) +{ + try + { + if(pAccessible) + { + Reference<XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(xContext.is()) + { + switch( xContext->getAccessibleRole() ) + { + case AccessibleRole::DIALOG: + case AccessibleRole::FRAME: + case AccessibleRole::WINDOW: + case AccessibleRole::ROOT_PANE: + case AccessibleRole::CANVAS: + case AccessibleRole::COMBO_BOX: + case AccessibleRole::DOCUMENT: + case AccessibleRole::DOCUMENT_PRESENTATION: + case AccessibleRole::DOCUMENT_SPREADSHEET: + case AccessibleRole::DOCUMENT_TEXT: + case AccessibleRole::EMBEDDED_OBJECT: + case AccessibleRole::END_NOTE: + case AccessibleRole::FILLER: + case AccessibleRole::FOOTNOTE: + case AccessibleRole::FOOTER: + case AccessibleRole::GRAPHIC: + case AccessibleRole::GROUP_BOX: + case AccessibleRole::HEADER: + case AccessibleRole::LAYERED_PANE: + case AccessibleRole::MENU_BAR: + case AccessibleRole::POPUP_MENU: + case AccessibleRole::OPTION_PANE: + case AccessibleRole::PAGE_TAB: + case AccessibleRole::PAGE_TAB_LIST: + case AccessibleRole::PANEL: + case AccessibleRole::SCROLL_PANE: + case AccessibleRole::SPLIT_PANE: + case AccessibleRole::STATUS_BAR: + case AccessibleRole::TABLE_CELL: + case AccessibleRole::TEXT_FRAME: + case AccessibleRole::TOOL_BAR: + case AccessibleRole::VIEW_PORT: + case AccessibleRole::SHAPE: + return true; + case AccessibleRole::COLUMN_HEADER: + case AccessibleRole::TABLE: + if(!IsStateManageDescendant(pAccessible)) + return true; + break; + case AccessibleRole::MENU: + return true; + default: + return false; + } + } + } + } + catch(...) + { + return false; + } + return false; +} + +/** + * Judge if a XAccessible object has ManageDescendant event. + * @param pAccessible XAccessible interface. + * @return If XAccessible object is managedescendant. + */ +bool AccObjectWinManager::IsStateManageDescendant(XAccessible* pAccessible) +{ + if(pAccessible) + { + Reference<XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(xContext.is()) + { + sal_Int64 nRState = xContext->getAccessibleStateSet(); + return nRState & AccessibleStateType::MANAGES_DESCENDANTS; + } + } + return false; +} + +/** + * Query and get IAccessible interface by XAccessible interface from list. + * @param pXAcc XAccessible interface. + * @return Com accobject interface. + */ +IMAccessible* AccObjectWinManager::GetIAccessibleFromXAccessible(XAccessible* pXAcc) +{ + AccObject* pAccObj = GetAccObjByXAcc(pXAcc); + if (pAccObj) + return pAccObj->GetIMAccessible(); + + return nullptr; +} + +/** + * Query and get IAccessible interface by child id from list. + * @param resID, childID. + * @return Com accobject interface. + */ +IMAccessible * AccObjectWinManager::GetIAccessibleFromResID(long resID) +{ + XResIdToAccObjHash::iterator pIndTemp = XResIdAccList.find( resID ); + if ( pIndTemp == XResIdAccList.end() ) + return nullptr; + + AccObject* pObj = pIndTemp->second; + + if(pObj->GetIMAccessible()) + return pObj->GetIMAccessible(); + return nullptr; +} +/** + * Notify some object will be destroyed. + * @param pXAcc XAccessible interface. + * @return Com accobject interface. + */ +void AccObjectWinManager::NotifyDestroy(XAccessible* pXAcc) +{ + AccObject* accObj = GetAccObjByXAcc(pXAcc); + if(accObj) + { + accObj->NotifyDestroy(); + } +} + + +void AccObjectWinManager::UpdateChildState(css::accessibility::XAccessible* pAccSubMenu) +{ + Reference<css::accessibility::XAccessibleContext> xContext(pAccSubMenu,UNO_QUERY); + if (!xContext.is()) + { + return; + } + const sal_Int64 nCount = xContext->getAccessibleChildCount(); + for (sal_Int64 i = 0 ; i < nCount; ++i) + { + Reference<css::accessibility::XAccessible> xChild = xContext->getAccessibleChild(i); + if (xChild.is()) + { + AccObject *pObj = GetAccObjByXAcc(xChild.get()); + if (pObj) + { + pObj->UpdateState(); + } + } + } +} + + +bool AccObjectWinManager::IsSpecialToolbarItem(css::accessibility::XAccessible* pXAcc) +{ + if (pXAcc && oldFocus != pXAcc) + { + if (GetParentRole(pXAcc) == AccessibleRole::TOOL_BAR) + { + Reference< XAccessibleContext > pRContext(pXAcc->getAccessibleContext()); + if (pRContext.is()) + { + if (pRContext->getAccessibleRole() == AccessibleRole::TOGGLE_BUTTON) + { + return true; + } + } + } + } + return false; +} + +short AccObjectWinManager::GetRole(css::accessibility::XAccessible* pXAcc) +{ + assert(pXAcc != nullptr); + Reference<css::accessibility::XAccessibleContext> xContext = pXAcc->getAccessibleContext(); + if(xContext.is()) + { + return xContext->getAccessibleRole(); + } + return -1; +} + +XAccessible* AccObjectWinManager::GetAccDocByHWND(HWND pWnd) +{ + XHWNDToDocumentHash::iterator aIter; + aIter = XHWNDDocList.find( pWnd ); + if ( aIter != XHWNDDocList.end() ) + { + return aIter->second; + } + + return nullptr; +} + +XAccessible* AccObjectWinManager::GetAccDocByAccTopWin( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + HWND hWnd = pAccObj->GetParentHWND(); + return GetAccDocByHWND(hWnd); +} + +bool AccObjectWinManager::IsTopWinAcc( css::accessibility::XAccessible* pXAcc ) +{ + bool bRet = false; + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if ( pAccObj ) + { + bRet = ( pAccObj->GetParentObj() == nullptr ); + } + return bRet; +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccParagraphEventListener.cxx b/winaccessibility/source/service/AccParagraphEventListener.cxx new file mode 100644 index 0000000000..fe7504901f --- /dev/null +++ b/winaccessibility/source/service/AccParagraphEventListener.cxx @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccParagraphEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccParagraphEventListener::AccParagraphEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccContainerEventListener(pAcc, pManager) +{} +AccParagraphEventListener::~AccParagraphEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccParagraphEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::CARET_CHANGED: + HandleCaretChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + //Added for paragraph selected state. + case AccessibleEventId::STATE_CHANGED: + { + sal_Int64 State; + if( (aEvent.NewValue >>= State) && (State == AccessibleStateType::SELECTED) ) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), State); + break; + } + else if( (aEvent.OldValue >>= State) && (State == AccessibleStateType::SELECTED) ) + { + m_pObjManager->DecreaseState(m_xAccessible.get(), State); + break; + } + + AccContainerEventListener::notifyEvent(aEvent); + break; + } + + case AccessibleEventId::TEXT_SELECTION_CHANGED: + HandleTextSelectionChangedEvent(); + break; + + default: + AccContainerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the CARET_CHANGED event + * @param oldValue in UNO, this parameter is always NULL + * @param newValue in UNO, this parameter is always NULL + */ +void AccParagraphEventListener::HandleCaretChangedEvent(Any, Any) +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_CARETCHANGE); +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccParagraphEventListener::SetComponentState(sal_Int64 state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::EDITABLE: + // no msaa state + break; + case AccessibleStateType::MULTI_LINE: + // no msaa state mapping + break; + case AccessibleStateType::SINGLE_LINE: + // no msaa state mapping + break; + default: + AccContainerEventListener::SetComponentState(state, enable); + break; + } +} + +void AccParagraphEventListener::HandleTextSelectionChangedEvent() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TEXT_SELECTION_CHANGED); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTableEventListener.cxx b/winaccessibility/source/service/AccTableEventListener.cxx new file mode 100644 index 0000000000..ccc67690a6 --- /dev/null +++ b/winaccessibility/source/service/AccTableEventListener.cxx @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp> + +#include <vcl/svapp.hxx> + +#include <AccTableEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccTableEventListener::AccTableEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccDescendantManagerEventListener(pAcc, pManager) +{} +AccTableEventListener::~AccTableEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccTableEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + HandleActiveDescendantChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + + case AccessibleEventId::TABLE_CAPTION_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_CAPTION_CHANGED); + break; + } + case AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_COLUMN_DESCRIPTION_CHANGED); + break; + } + case AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_COLUMN_HEADER_CHANGED); + break; + } + case AccessibleEventId::TABLE_ROW_HEADER_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_ROW_HEADER_CHANGED); + break; + } + case AccessibleEventId::TABLE_MODEL_CHANGED: + { + HandleTableModelChangeEvent(aEvent.NewValue); + break; + } + case AccessibleEventId::TABLE_SUMMARY_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_SUMMARY_CHANGED); + break; + } + case AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_ROW_DESCRIPTION_CHANGED); + break; + } + default: + AccDescendantManagerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the ACTIVE_DESCENDANT_CHANGED event + * @param oldValue the child to lose active + * @param newValue the child to get active + */ +void AccTableEventListener::HandleActiveDescendantChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::ACTIVE_DESCENDANT_CHANGED); + } + } + else if (oldValue >>= xChild) + { + //delete an existing child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->DeleteAccObj( pAcc ); + } + } + +} +void AccTableEventListener::HandleTableModelChangeEvent(Any newValue) +{ + AccessibleTableModelChange aModelChange; + if (newValue >>= aModelChange) + { + if (m_xAccessible.is()) + { + //delete all oldValue's existing children + m_pObjManager->DeleteChildrenAccObj(m_xAccessible.get()); + //add all oldValue's existing children + m_pObjManager->InsertChildrenAccObj(m_xAccessible.get()); + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_MODEL_CHANGED); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTextComponentEventListener.cxx b/winaccessibility/source/service/AccTextComponentEventListener.cxx new file mode 100644 index 0000000000..05643016ea --- /dev/null +++ b/winaccessibility/source/service/AccTextComponentEventListener.cxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccTextComponentEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccTextComponentEventListener::AccTextComponentEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccComponentEventListener(pAcc, pManager) +{} +AccTextComponentEventListener::~AccTextComponentEventListener() +{ +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccTextComponentEventListener::SetComponentState(sal_Int64 state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::EDITABLE: + // no msaa state mapping + break; + case AccessibleStateType::MULTI_LINE: + // no msaa state mapping + break; + case AccessibleStateType::SINGLE_LINE: + // no msaa state mapping + break; + default: + AccComponentEventListener::SetComponentState(state, enable); + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTopWindowListener.cxx b/winaccessibility/source/service/AccTopWindowListener.cxx new file mode 100644 index 0000000000..12cb20f85a --- /dev/null +++ b/winaccessibility/source/service/AccTopWindowListener.cxx @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <sal/log.hxx> +#include <vcl/window.hxx> +#include <toolkit/awt/vclxaccessiblecomponent.hxx> +#include <toolkit/awt/vclxwindow.hxx> + +#include <vcl/sysdata.hxx> +#include <vcl/svapp.hxx> + +#include <AccTopWindowListener.hxx> +#include <unomsaaevent.hxx> + +#include <com/sun/star/accessibility/AccessibleRole.hpp> + +using namespace com::sun::star::uno; + +/** + * For the new opened window, generate all the UNO accessible's object, COM object and add + * accessible listener to monitor all these objects. + * @param pAccessible the accessible of the new opened window + */ +void AccTopWindowListener::HandleWindowOpened( css::accessibility::XAccessible* pAccessible ) +{ + //get SystemData from window + VclPtr<vcl::Window> window; + if (auto pvclwindow = dynamic_cast<VCLXWindow*>(pAccessible)) + window = pvclwindow->GetWindow(); + else if (auto pvclxcomponent = dynamic_cast<VCLXAccessibleComponent*>(pAccessible)) + window = pvclxcomponent->GetWindow(); + assert(window); + // The SalFrame of window may be destructed at this time + const SystemEnvData* systemdata = nullptr; + try + { + systemdata = window->GetSystemData(); + } + catch(...) + { + systemdata = nullptr; + } + Reference<css::accessibility::XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(!xContext.is()) + return; + + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + //Only AccessibleContext exist, add all listeners + if(pAccessibleContext != nullptr && systemdata != nullptr) + { + m_aAccObjectManager.SaveTopWindowHandle(systemdata->hWnd, pAccessible); + + AddAllListeners(pAccessible,nullptr,systemdata->hWnd); + + if( window->GetStyle() & WB_MOVEABLE ) + m_aAccObjectManager.IncreaseState( pAccessible, static_cast<unsigned short>(-1) /* U_MOVEBLE */ ); + + short role = pAccessibleContext->getAccessibleRole(); + + if (role == css::accessibility::AccessibleRole::POPUP_MENU || + role == css::accessibility::AccessibleRole::MENU ) + { + m_aAccObjectManager.NotifyAccEvent(pAccessible, UnoMSAAEvent::MENUPOPUPSTART); + } + + if (role == css::accessibility::AccessibleRole::FRAME || + role == css::accessibility::AccessibleRole::DIALOG || + role == css::accessibility::AccessibleRole::WINDOW || + role == css::accessibility::AccessibleRole::ALERT) + { + m_aAccObjectManager.NotifyAccEvent(pAccessible, UnoMSAAEvent::SHOW); + } + } +} + +AccTopWindowListener::AccTopWindowListener() + : m_aAccObjectManager() +{ +} + +AccTopWindowListener::~AccTopWindowListener() +{ +} + +/** + * It is invoked when a new window is opened, the source of this EventObject is the window + */ +void AccTopWindowListener::windowOpened( const css::lang::EventObject& e ) +{ + SAL_INFO( "iacc2", "windowOpened triggered" ); + + if ( !e.Source.is()) + return; + + Reference< css::accessibility::XAccessible > xAccessible ( e.Source, UNO_QUERY ); + css::accessibility::XAccessible* pAccessible = xAccessible.get(); + if ( !pAccessible ) + return; + + SolarMutexGuard g; + + HandleWindowOpened( pAccessible ); +} + +/** + * Add the accessible event listener to object and all its children objects. + * @param pAccessible the accessible object + * @param pParentXAcc the parent of current accessible object + * @param pWND the handle of top window which current object resides + */ +void AccTopWindowListener::AddAllListeners(css::accessibility::XAccessible* pAccessible, css::accessibility::XAccessible* pParentXAcc, HWND pWND) +{ + Reference<css::accessibility::XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(!xContext.is()) + { + return; + } + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + if(pAccessibleContext == nullptr) + { + return; + } + + m_aAccObjectManager.InsertAccObj(pAccessible, pParentXAcc, pWND); + + if (!AccObjectWinManager::IsContainer(pAccessible)) + { + return; + } + + + short role = pAccessibleContext->getAccessibleRole(); + if(css::accessibility::AccessibleRole::DOCUMENT == role || + css::accessibility::AccessibleRole::DOCUMENT_PRESENTATION == role || + css::accessibility::AccessibleRole::DOCUMENT_SPREADSHEET == role || + css::accessibility::AccessibleRole::DOCUMENT_TEXT == role) + { + if(AccObjectWinManager::IsStateManageDescendant(pAccessible)) + { + return ; + } + } + + sal_Int64 nCount = pAccessibleContext->getAccessibleChildCount(); + for (sal_Int64 i = 0; i < nCount; i++) + { + Reference<css::accessibility::XAccessible> mxAccessible + = pAccessibleContext->getAccessibleChild(i); + + css::accessibility::XAccessible* mpAccessible = mxAccessible.get(); + if(mpAccessible != nullptr) + { + Reference<css::accessibility::XAccessibleContext> mxAccessibleContext + = mpAccessible->getAccessibleContext(); + css::accessibility::XAccessibleContext* mpContext = mxAccessibleContext.get(); + if(mpContext != nullptr) + AddAllListeners( mpAccessible, pAccessible, pWND); + } + } +} + +void AccTopWindowListener::windowClosing( const css::lang::EventObject& ) +{ + SAL_INFO( "iacc2", "windowClosing triggered" ); +} + +/** + * Invoke this method when the top window is closed, remove all the objects and its children + * from current manager's cache, and remove the COM object and the accessible event listener + * assigned to the accessible objects. + */ +void AccTopWindowListener::windowClosed( const css::lang::EventObject& e ) +{ + SAL_INFO( "iacc2", "windowClosed triggered" ); + + if ( !e.Source.is()) + return; + + Reference< css::accessibility::XAccessible > xAccessible ( e.Source, UNO_QUERY ); + css::accessibility::XAccessible* pAccessible = xAccessible.get(); + if ( pAccessible == nullptr) + return; + + Reference<css::accessibility::XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(!xContext.is()) + { + return; + } + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + + short role = -1; + if(pAccessibleContext != nullptr) + { + role = pAccessibleContext->getAccessibleRole(); + + if (role == css::accessibility::AccessibleRole::POPUP_MENU || + role == css::accessibility::AccessibleRole::MENU) + { + m_aAccObjectManager.NotifyAccEvent(pAccessible, UnoMSAAEvent::MENUPOPUPEND); + } + } + + + m_aAccObjectManager.DeleteChildrenAccObj( pAccessible ); + if( role != css::accessibility::AccessibleRole::POPUP_MENU ) + m_aAccObjectManager.DeleteAccObj( pAccessible ); + +} + +void AccTopWindowListener::windowMinimized( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::windowNormalized( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::windowActivated( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::windowDeactivated( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::disposing( const css::lang::EventObject& ) +{ +} + +sal_Int64 AccTopWindowListener::GetMSComPtr( + sal_Int64 hWnd, sal_Int64 lParam, sal_Int64 wParam) +{ + return m_aAccObjectManager.Get_ToATInterface(hWnd, lParam, wParam); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTreeEventListener.cxx b/winaccessibility/source/service/AccTreeEventListener.cxx new file mode 100644 index 0000000000..b7c80b2d1f --- /dev/null +++ b/winaccessibility/source/service/AccTreeEventListener.cxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccTreeEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccTreeEventListener::AccTreeEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccDescendantManagerEventListener(pAcc, pManager) +{} +AccTreeEventListener::~AccTreeEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccTreeEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + HandleActiveDescendantChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccDescendantManagerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the ACTIVE_DESCENDANT_CHANGED event + * @param oldValue the child to lose active + * @param newValue the child to get active + */ +void AccTreeEventListener::HandleActiveDescendantChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::ACTIVE_DESCENDANT_CHANGED); + } + } + if (oldValue >>= xChild) + { + //delete an existing child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->DeleteAccObj(pAcc); + } + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccWindowEventListener.cxx b/winaccessibility/source/service/AccWindowEventListener.cxx new file mode 100644 index 0000000000..5a96914ea5 --- /dev/null +++ b/winaccessibility/source/service/AccWindowEventListener.cxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccWindowEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccWindowEventListener::AccWindowEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccEventListener(pAcc, pManager) +{} +AccWindowEventListener::~AccWindowEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject: the event object which contains information about event + */ +void AccWindowEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccWindowEventListener::SetComponentState(sal_Int64 state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::ICONIFIED: + // no msaa state + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + if( enable ) + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + else + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + case AccessibleStateType::SHOWING: + // UNO !SHOWING == MSAA OFFSCREEN + if( enable ) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + } + else + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/ResIDGenerator.cxx b/winaccessibility/source/service/ResIDGenerator.cxx new file mode 100644 index 0000000000..7498380300 --- /dev/null +++ b/winaccessibility/source/service/ResIDGenerator.cxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ResIDGenerator.hxx> + +#include <cassert> + +ResIDGenerator::~ResIDGenerator() {} + +/** + * SubList stores those IDs that were ever generated and deleted, the method + * return the ID from subList first if subList is not empty, else return m_nMin--. + * Add the obsolete IDs by calling SetSub method + * + * @param + * @return new resource ID. + */ +long ResIDGenerator::GenerateNewResID() +{ + if (!subList.empty()) + { + long nRes = *(subList.begin()); + subList.pop_front(); + return nRes; + } + assert(m_nMin > LONG_MIN); + return m_nMin--; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/msaaservice_impl.cxx b/winaccessibility/source/service/msaaservice_impl.cxx new file mode 100644 index 0000000000..3891b6df48 --- /dev/null +++ b/winaccessibility/source/service/msaaservice_impl.cxx @@ -0,0 +1,275 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <rtl/ref.hxx> +#include <sal/log.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/accessibility/XMSAAService.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> + +#include <com/sun/star/awt/XExtendedToolkit.hpp> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> + +#include <prewin.h> +#include <postwin.h> + +#include <AccTopWindowListener.hxx> + +using namespace ::com::sun::star; // for odk interfaces +using namespace ::com::sun::star::uno; // for basic types +using namespace ::com::sun::star::accessibility; + +using namespace ::com::sun::star::awt; + +namespace my_sc_impl +{ + +namespace { + +class MSAAServiceImpl : public ::cppu::WeakImplHelper< + XMSAAService, lang::XServiceInfo > +{ +private: + rtl::Reference<AccTopWindowListener> m_pTopWindowListener; + +public: + MSAAServiceImpl (); + + // XComponent - as used by VCL to lifecycle manage this bridge. + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& ) override + { /* dummy */ } + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& ) override + { /* dummy */ } + + // XMSAAService + virtual sal_Int64 SAL_CALL getAccObjectPtr( + sal_Int64 hWnd, sal_Int64 lParam, sal_Int64 wParam) override; + virtual void SAL_CALL handleWindowOpened(sal_Int64) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +} + +/** + * Implementation of getAccObjectPtr. + * @param + * @return Com interface. + */ +sal_Int64 MSAAServiceImpl::getAccObjectPtr( + sal_Int64 hWnd, sal_Int64 lParam, sal_Int64 wParam) +{ + // tdf#155794: this must complete without taking SolarMutex + + if (!m_pTopWindowListener.is()) + { + return 0; + } + return m_pTopWindowListener->GetMSComPtr(hWnd, lParam, wParam); +} + +/** + * Implementation of handleWindowOpened, the method will be invoked when a + * top window is opened and AT starts up. + * @param + * @return + */ +void MSAAServiceImpl::handleWindowOpened(sal_Int64 nAcc) +{ + SolarMutexGuard g; + + SAL_INFO( "iacc2", "Window opened " << nAcc ); + + if (m_pTopWindowListener.is() && nAcc) + { + m_pTopWindowListener->HandleWindowOpened( + static_cast<css::accessibility::XAccessible*>( + reinterpret_cast<void*>(nAcc))); + } +} + +OUString MSAAServiceImpl::getImplementationName() +{ + return "com.sun.star.accessibility.my_sc_implementation.MSAAService"; +} + +/** + * Implementation of XServiceInfo, return support service name. + * @param Service name. + * @return If the service name is supported. + */ +sal_Bool MSAAServiceImpl::supportsService( OUString const & serviceName ) +{ + return cppu::supportsService(this, serviceName); +} + +/** + * Implementation of XServiceInfo, return all service names. + * @param. + * @return service name sequence. + */ +Sequence< OUString > MSAAServiceImpl::getSupportedServiceNames() +{ + return { "com.sun.star.accessibility.MSAAService" }; +} + +static void AccessBridgeHandleExistingWindow(const Reference< XMSAAService > &xAccMgr, + vcl::Window *pWindow, bool bShow) +{ + if ( pWindow ) + { + css::uno::Reference< css::accessibility::XAccessible > xAccessible; + + SAL_INFO( "iacc2", "Decide whether to register existing window with IAccessible2" ); + + // Test for combo box - drop down floating windows first + vcl::Window * pParentWindow = pWindow->GetParent(); + + if ( pParentWindow ) + { + try + { + // The parent window of a combo box floating window should have the role COMBO_BOX + css::uno::Reference< css::accessibility::XAccessible > xParentAccessible(pParentWindow->GetAccessible()); + if ( xParentAccessible.is() ) + { + css::uno::Reference< css::accessibility::XAccessibleContext > xParentAC( xParentAccessible->getAccessibleContext() ); + if ( xParentAC.is() && (css::accessibility::AccessibleRole::COMBO_BOX == xParentAC->getAccessibleRole()) ) + { + // O.k. - this is a combo box floating window corresponding to the child of role LIST of the parent. + // Let's not rely on a specific child order, just search for the child with the role LIST + sal_Int64 nCount = xParentAC->getAccessibleChildCount(); + for (sal_Int64 n = 0; (n < nCount) && !xAccessible.is(); n++) + { + css::uno::Reference< css::accessibility::XAccessible > xChild = xParentAC->getAccessibleChild(n); + if ( xChild.is() ) + { + css::uno::Reference< css::accessibility::XAccessibleContext > xChildAC = xChild->getAccessibleContext(); + if ( xChildAC.is() && (css::accessibility::AccessibleRole::LIST == xChildAC->getAccessibleRole()) ) + { + xAccessible = xChild; + } + } + } + } + } + } + catch (css::uno::RuntimeException const&) + { + // Ignore show events that throw DisposedExceptions in getAccessibleContext(), + // but keep revoking these windows in hide(s). + if (bShow) + return; + } + } + + // We have to rely on the fact that Window::GetAccessible()->getAccessibleContext() returns a valid XAccessibleContext + // also for other menus than menubar or toplevel popup window. Otherwise we had to traverse the hierarchy to find the + // context object to this menu floater. This makes the call to Window->IsMenuFloatingWindow() obsolete. + if ( ! xAccessible.is() ) + xAccessible = pWindow->GetAccessible(); + + assert( xAccMgr.is() ); + if ( xAccessible.is() ) + { + xAccMgr->handleWindowOpened( + reinterpret_cast<sal_Int64>(xAccessible.get())); + SAL_INFO( "iacc2", "Decide whether to register existing window with IAccessible2" ); + } + } +} + +/* + * Setup and notify the OS of Accessible peers for all existing windows. + */ +static void AccessBridgeUpdateOldTopWindows( const Reference< XMSAAService > &xAccMgr ) +{ + sal_uInt16 nTopWindowCount = static_cast<sal_uInt16>(Application::GetTopWindowCount()); + + for ( sal_uInt16 i = 0; i < nTopWindowCount; i++ ) + { + vcl::Window* pTopWindow = Application::GetTopWindow( i ); + css::uno::Reference< css::accessibility::XAccessible > xAccessible = pTopWindow->GetAccessible(); + if ( xAccessible.is() ) + { + css::uno::Reference< css::accessibility::XAccessibleContext > xAC( xAccessible->getAccessibleContext() ); + if ( xAC.is()) + { + if ( !xAC->getAccessibleName().isEmpty() ) + AccessBridgeHandleExistingWindow( xAccMgr, pTopWindow, true ); + } + } + } +} + +MSAAServiceImpl::MSAAServiceImpl() +{ + Reference< XExtendedToolkit > xToolkit(Application::GetVCLToolkit(), UNO_QUERY); + + if( xToolkit.is() ) + { + m_pTopWindowListener.set(new AccTopWindowListener()); + Reference<XTopWindowListener> const xRef(m_pTopWindowListener); + xToolkit->addTopWindowListener( xRef ); + SAL_INFO( "iacc2", "successfully connected to the toolkit event hose" ); + } + else + SAL_WARN( "iacc2", "No VCL toolkit interface to listen to for events"); +} + +void MSAAServiceImpl::dispose() +{ + SolarMutexGuard g; + + // As all folders and streams contain references to their parents, + // we must remove these references so that they will be deleted when + // the hash_map of the root folder is cleared, releasing all subfolders + // and substreams which in turn release theirs, etc. When xRootFolder is + // released when this destructor completes, the folder tree should be + // deleted fully (and automagically). + m_pTopWindowListener.clear(); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +winaccessibility_MSAAServiceImpl_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + Reference< XMSAAService > xAccMgr( new MSAAServiceImpl() ); + + AccessBridgeUpdateOldTopWindows( xAccMgr ); + + SAL_INFO("iacc2", "Created new IAccessible2 service impl."); + + xAccMgr->acquire(); + return xAccMgr.get(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/winaccessibility.component b/winaccessibility/source/service/winaccessibility.component new file mode 100644 index 0000000000..fe26e40e20 --- /dev/null +++ b/winaccessibility/source/service/winaccessibility.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.accessibility.my_sc_implementation.MSAAService" + constructor="winaccessibility_MSAAServiceImpl_get_implementation"> + <service name="com.sun.star.accessibility.MSAAService"/> + </implementation> +</component> |