diff options
Diffstat (limited to 'winaccessibility/source/service/AccObjectWinManager.cxx')
-rw-r--r-- | winaccessibility/source/service/AccObjectWinManager.cxx | 1202 |
1 files changed, 1202 insertions, 0 deletions
diff --git a/winaccessibility/source/service/AccObjectWinManager.cxx b/winaccessibility/source/service/AccObjectWinManager.cxx new file mode 100644 index 000000000..bcde1ccf4 --- /dev/null +++ b/winaccessibility/source/service/AccObjectWinManager.cxx @@ -0,0 +1,1202 @@ +/* -*- 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; + +/** + * constructor + * @param Agent The agent kept in all listeners,it's the sole interface by which + * listener communicate with windows manager. + * pEventAccObj The present event accobject. + * oldFocus Last focused object. + * isSelectionChanged flag that identifies if there is selection changed. + * selectionChildObj Selected object. + * dChildID Chile resource ID. + * hAcc TopWindowHWND + * @return + */ +AccObjectWinManager::AccObjectWinManager( AccObjectManagerAgent* Agent ): + oldFocus( nullptr ), + pAgent( Agent ) +{ +} + +/** + * Destructor,clear all resource. + * @param + * @return + */ +AccObjectWinManager::~AccObjectWinManager() +{ + 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. + */ + +LRESULT +AccObjectWinManager::Get_ToATInterface(HWND hWnd, long lParam, WPARAM wParam) +{ + IMAccessible* pRetIMAcc = nullptr; + + if(lParam == OBJID_CLIENT ) + { + AccObject* topWindowAccObj = GetTopWindowAccObj(hWnd); + if(topWindowAccObj) + { + pRetIMAcc = topWindowAccObj->GetIMAccessible(); + if(pRetIMAcc) + pRetIMAcc->AddRef();//increase COM reference count + } + } + + if ( pRetIMAcc && lParam == OBJID_CLIENT ) + { + LRESULT result = LresultFromObject(IID_IAccessible, wParam, pRetIMAcc); + pRetIMAcc->Release(); + return 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; + + 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 + */ +AccObject* AccObjectWinManager::GetTopWindowAccObj(HWND hWnd) +{ + XHWNDToXAccHash::iterator iterResult =HwndXAcc.find(hWnd); + if(iterResult == HwndXAcc.end()) + return nullptr; + XAccessible* pXAcc = iterResult->second; + return GetAccObjByXAcc(pXAcc); +} + +/** + * 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::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(); + } +} + +/** + * Update selected object by new focused XAccessible interface. + * @param pXAcc XAccessible interface that has selected child changed. + * @return Selected children count. + */ +int AccObjectWinManager::UpdateAccSelection(XAccessible* pXAcc) +{ + Reference< XAccessibleContext > pRContext; + + if( pXAcc == nullptr) + return 0; + + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return 0; + + Reference< XAccessibleSelection > pRSelection(pRContext,UNO_QUERY); + if( !pRSelection.is() ) + return 0; + + AccObject* pAccObj = GetAccObjByXAcc(pXAcc); + if(pAccObj==nullptr) + return 0; + + Reference<XAccessible> pRChild; + AccObject* pAccChildObj = nullptr; + int selectNum= pRSelection->getSelectedAccessibleChildCount(); + + IAccSelectionList oldSelection = pAccObj->GetSelection(); + + if(selectNum > 4)//for selected. + return selectNum; + if(selectNum == 1 && oldSelection.size() == 0) + return 1; + + for (int i=0;i<selectNum;i++) + { + pRChild = pRSelection->getSelectedAccessibleChild(i); + if(!pRChild.is()) + { + continue; + } + Reference<XAccessibleContext> pRChildContext = pRChild->getAccessibleContext(); + if(!pRChildContext.is()) + { + continue; + } + long index = pRChildContext->getAccessibleIndexInParent(); + IAccSelectionList::iterator temp = oldSelection.find(index); + if ( temp != oldSelection.end() ) + { + oldSelection.erase(index); + continue; + } + + pAccChildObj = GetAccObjByXAcc(pRChild.get()); + if(!pAccChildObj) + { + InsertAccObj(pRChild.get(), pXAcc,pAccObj->GetParentHWND()); + pAccChildObj = GetAccObjByXAcc(pRChild.get()); + } + + pAccObj->AddSelect(index, pAccChildObj); + + if(pAccChildObj != nullptr) + NotifyWinEvent(EVENT_OBJECT_SELECTIONADD,pAccObj->GetParentHWND(), OBJID_CLIENT,pAccChildObj->GetResID()); + } + + for (const auto& rEntry : oldSelection) + { + pAccObj->GetSelection().erase(rEntry.first); + pAccChildObj = rEntry.second; + if(pAccChildObj != nullptr) + NotifyWinEvent(EVENT_OBJECT_SELECTIONREMOVE,pAccObj->GetParentHWND(), OBJID_CLIENT,pAccChildObj->GetResID()); + } + return 0; + +} + +/** + * 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 ) +{ + 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; + XIdToAccObjHash::iterator temp = XIdAccList.find(pXAcc); + if( temp != XIdAccList.end() ) + { + ResIdGen.SetSub( temp->second.GetResID() ); + } + else + { + return; + } + + AccObject& accObj = temp->second; + DeleteAccChildNode( &accObj ); + DeleteAccListener( &accObj ); + 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! +} + +/** + * Delete listener that inspects some XAccessible object + * @param pAccObj Accobject pointer. + * @return + */ +void AccObjectWinManager::DeleteAccListener( AccObject* pAccObj ) +{ + AccEventListener* listener = pAccObj->getListener(); + if( listener==nullptr ) + return; + listener->RemoveMeFromBroadcaster(); + 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; + } + } + + int count = pRContext->getAccessibleChildCount(); + for (int i=0;i<count;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 ) +{ + XIdToAccObjHash::iterator itXacc = XIdAccList.find( pXAcc ); + if (itXacc != XIdAccList.end() ) + { + short nCurRole =GetRole(pXAcc); + 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; + } + + + Reference< XAccessibleContext > pRContext; + + if( pXAcc == nullptr) + return false; + + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return false; + + if( pWnd == nullptr ) + { + if(pParentXAcc) + { + AccObject* pObj = GetAccObjByXAcc(pParentXAcc); + if(pObj) + pWnd = pObj->GetParentHWND(); + } + if( pWnd == nullptr ) + return false; + } + + AccObject pObj( pXAcc,pAgent ); + 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; + + 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) +{ + 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,pAgent); + break; + case AccessibleRole::FRAME: + pRet = new AccFrameEventListener(pXAcc,pAgent); + break; + case AccessibleRole::WINDOW: + pRet = new AccWindowEventListener(pXAcc,pAgent); + break; + case AccessibleRole::ROOT_PANE: + pRet = new AccFrameEventListener(pXAcc,pAgent); + 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,pAgent); + break; + case AccessibleRole::PARAGRAPH: + case AccessibleRole::HEADING: + pRet = new AccParagraphEventListener(pXAcc,pAgent); + break; + //Component + case AccessibleRole::CHECK_BOX: + case AccessibleRole::ICON: + case AccessibleRole::LABEL: + case AccessibleRole::STATIC: + 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,pAgent); + break; + //text component + case AccessibleRole::TEXT: + pRet = new AccTextComponentEventListener(pXAcc,pAgent); + break; + //menu + case AccessibleRole::MENU: + pRet = new AccMenuEventListener(pXAcc,pAgent); + break; + //object container + case AccessibleRole::SHAPE: + + case AccessibleRole::EMBEDDED_OBJECT: + case AccessibleRole::GRAPHIC: + case AccessibleRole::TEXT_FRAME: + pRet = new AccObjectContainerEventListener(pXAcc,pAgent); + break; + //descendmanager + case AccessibleRole::LIST: + pRet = new AccListEventListener(pXAcc,pAgent); + break; + case AccessibleRole::TREE: + pRet = new AccTreeEventListener(pXAcc,pAgent); + break; + //special + case AccessibleRole::COLUMN_HEADER: + case AccessibleRole::TABLE: + pRet = new AccTableEventListener(pXAcc,pAgent); + break; + default: + pRet = new AccContainerEventListener(pXAcc,pAgent); + 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,unsigned short pState ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->DecreaseState( pState ); +} + +/** + * 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,unsigned short pState ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->IncreaseState( pState ); +} + +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 accessible location via XAccessible interface and new + * location. + * @param pXAcc XAccessible interface. + * @return + */ +void AccObjectWinManager::SetLocation( XAccessible* pXAcc, long /*top*/, long /*left*/, long /*width*/, long /*height*/ ) +{ + AccObject* pObj = GetAccObjByXAcc( pXAcc ); + //get the location from XComponent. + Reference< XAccessibleContext > pRContext = pXAcc->getAccessibleContext(); + if( pObj ) + pObj->UpdateLocation(); +} + +/** + * 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()) + { + Reference< XAccessibleStateSet > pRState = xContext->getAccessibleStateSet(); + if( !pRState.is() ) + return false; + + for (sal_Int16 nState : pRState->getStates()) + { + if (nState == AccessibleStateType::MANAGES_DESCENDANTS) + return true; + } + } + } + return false; +} + +/** + * Query and get IAccessible interface by XAccessible interface from list. + * @param pXAcc XAccessible interface. + * @return Com accobject interface. + */ +IMAccessible* AccObjectWinManager::GetIMAccByXAcc(XAccessible* pXAcc) +{ + AccObject* pAccObj = GetAccObjByXAcc(pXAcc); + if(pAccObj) + { + return pAccObj->GetIMAccessible(); + } + else + { + 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; + } + sal_Int32 nCount = xContext->getAccessibleChildCount(); + for (sal_Int32 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: */ |