Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/winaccessibility/source/UAccCOM/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 87 kB image not shown  

Quellcode-Bibliothek MAccessible.cxx   Sprache: C

 
/* -*- 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 <systools/win32/oleauto.hxx>

#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
#include <com/sun/star/accessibility/XAccessibleContext2.hpp>
#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
};

enum class NavigationDirection {
    FIRST_CHILD,
    LAST_CHILD,
    NEXT_CHILD,
    PREVIOUS_CHILD,
};

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_pszValue(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_pszValue!=nullptr)
    {
        SysFreeString(std::exchange(m_pszValue, 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())
            {
                // return error code if child count exceeds max long value
                // (for Calc sheets which report all cells as children);
                // tdf#153131: Windows Speech Recognition and apparently some other
                // tools querying information via the a11y API seem to query all children unconditionally,
                // so returning a large number (like std::numeric_limits<long>::max) would cause a freeze
                SAL_WARN("iacc2""CMAccessible::get_accChildCount: Child count exceeds maximum long value");
                return S_FALSE;
            }

            *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)
            {
                if (!m_xAccessible.is())
                    return S_FALSE;

                Reference<XAccessibleContext> xContext = m_xAccessible->getAccessibleContext();
                if (!xContext.is())
                    return S_FALSE;

                const OUString sName = xContext->getAccessibleName();
                SysFreeString(*pszName);
                *pszName = sal::systools::BStr::newBSTR(sName);
                return S_OK;
            }

            long lVal = varChild.lVal;
            varChild.lVal = CHILDID_SELF;
            IMAccessible* pChild = 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 = 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 = sal::systools::BStr::newBSTR(sDescription);
                return S_OK;
            }

            long lVal = varChild.lVal;
            varChild.lVal = CHILDID_SELF;
            IMAccessible* pChild = 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 = 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 = 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 == AccessibleRelationType_LABELED_BY)
                            {
                                accRelation = pRrelationSet->getRelation(i);
                                paccRelation = &accRelation;
                            }
                        }

                        if(paccRelation == nullptr)
                            return S_FALSE;

                        Sequence<Reference<XAccessible>> xTargets = paccRelation->TargetSet;
                        Reference<XAccessible> xAcc = xTargets[0];

                        Reference<XAccessibleContext> xLabelContext = xAcc->getAccessibleContext();
                        if (!xLabelContext.is())
                            return S_FALSE;

                        pRrelationSet = xLabelContext->getAccessibleRelationSet();
                        nRelCount = pRrelationSet->getRelationCount();

                        paccRelation = nullptr;
                        for(int j=0; j<nRelCount ; j++)
                        {
                            if (pRrelationSet->getRelation(j).RelationType == AccessibleRelationType_LABEL_FOR)
                            {
                                accRelation = pRrelationSet->getRelation(j);
                                paccRelation = &accRelation;
                            }
                        }

                        if(paccRelation)
                        {
                            xTargets = paccRelation->TargetSet;
                            xAcc = xTargets[0];
                            if (m_xAccessible.get() != xAcc.get())
                                return S_FALSE;
                        }

                        Reference<XAccessibleExtendedComponent> pRXIE(xLabelContext, 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 = sal::systools::BStr::newBSTR(wString);

                    return S_OK;
                }
                else
                {
                    return S_FALSE;
                }
            }

            long lVal = varChild.lVal;
            varChild.lVal = CHILDID_SELF;
            IMAccessible* pChild = 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 *pyToplong *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 = GetChildInterface(lVal);
            if(!pChild)
                return E_FAIL;
            return pChild->put_accValue(varChild,szValue);
        }
        return E_FAIL;

        } 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

    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

    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 eDirection, the navigation direction.
* @return  IMAccessible*, the child of the end up node.
*/

IMAccessible* CMAccessible::GetNavigateChildForDM(VARIANT varCur, NavigationDirection eDirection)
{

    XAccessibleContext* pXContext = GetContextByXAcc(m_xAccessible.get());
    if(pXContext==nullptr)
    {
        return nullptr;
    }

    sal_Int64 count = pXContext->getAccessibleChildCount();
    if(count<1)
    {
        return nullptr;
    }

    Reference<XAccessible> pRChildXAcc;
    switch(eDirection)
    {
    case NavigationDirection::FIRST_CHILD:
        pRChildXAcc = pXContext->getAccessibleChild(0);
        break;
    case NavigationDirection::LAST_CHILD:
        pRChildXAcc = pXContext->getAccessibleChild(count-1);
        break;
    case NavigationDirection::NEXT_CHILD:
    case NavigationDirection::PREVIOUS_CHILD:
    {
        IMAccessible* pCurChild = GetChildInterface(varCur.lVal);
        if(pCurChild==nullptr)
        {
            return nullptr;
        }

        CMAccessible* pChildCMAcc = static_cast<CMAccessible*>(pCurChild);
        XAccessible* pChildXAcc = pChildCMAcc->m_xAccessible.get();
        if (!pChildXAcc)
            return nullptr;

        XAccessibleContext* pChildContext = GetContextByXAcc(pChildXAcc);
        if(pChildContext == nullptr)
        {
            return nullptr;
        }
        const sal_Int64 delta = (eDirection == NavigationDirection::NEXT_CHILD) ? 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
        const sal_Int64 index = pChildContext->getAccessibleIndexInParent() + delta;
        if((index>=0)&&(index<=count-1))
        {
            pRChildXAcc = pXContext->getAccessibleChild(index);
        }
        break;
    }
    default:
        break;
    }

    if(!pRChildXAcc.is())
    {
        return nullptr;
    }
    g_pAccObjectManager->InsertAccObj(pRChildXAcc.get(), m_xAccessible.get());
    return g_pAccObjectManager->GetIAccessibleFromXAccessible(pRChildXAcc.get());
}

/**
*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, NavigationDirection::FIRST_CHILD);
        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, NavigationDirection::LAST_CHILD);
        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, longlong)
{
    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 == AccessibleRelationType_MEMBER_OF)
        {
            Sequence<Reference<XAccessible>> xTargets = accRelation.TargetSet;
            return 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 == AccessibleRelationType_MEMBER_OF)
                {
                    Sequence<Reference<XAccessible>> xTargets = accRelation.TargetSet;

                    Reference<XAccessible> xTarget = 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())
                            == xTarget.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
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=93 G=93

¤ Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.0.20Bemerkung:  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.