diff options
Diffstat (limited to 'winaccessibility/source/service')
21 files changed, 6049 insertions, 0 deletions
diff --git a/winaccessibility/source/service/AccComponentEventListener.cxx b/winaccessibility/source/service/AccComponentEventListener.cxx new file mode 100644 index 000000000..148331acf --- /dev/null +++ b/winaccessibility/source/service/AccComponentEventListener.cxx @@ -0,0 +1,325 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccComponentEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccComponentEventListener::AccComponentEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccEventListener(pAcc, Agent) +{ +} + +AccComponentEventListener::~AccComponentEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * + * @param AccessibleEventObject the event object which contains information about event + */ +void AccComponentEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::VALUE_CHANGED: + HandleValueChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::ACTION_CHANGED: + HandleActionChangedEvent(); + break; + case AccessibleEventId::TEXT_CHANGED: + HandleTextChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::CARET_CHANGED: + HandleCaretChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + case AccessibleEventId::SELECTION_CHANGED: + HandleSelectionChangedEventNoArgs(); + break; + //to add TEXT_SELECTION_CHANGED event + case AccessibleEventId::TEXT_SELECTION_CHANGED: + HandleTextSelectionChangedEvent(); + break; + //End + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the VALUE_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccComponentEventListener::HandleValueChangedEvent(Any, Any) +{ + pAgent->UpdateValue(m_xAccessible.get()); + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_VALUECHANGE, m_xAccessible.get()); +} + +/** + * handle the NAME_CHANGED event + */ +void AccComponentEventListener::HandleActionChangedEvent() +{ + pAgent->UpdateAction(m_xAccessible.get()); + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_DEFACTIONCHANGE, m_xAccessible.get()); +} + +/** + * handle the TEXT_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccComponentEventListener::HandleTextChangedEvent(Any, Any newValue) +{ + pAgent->UpdateValue(m_xAccessible.get(), newValue); + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_VALUECHANGE, m_xAccessible.get()); +} + +/** + * handle the CARET_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccComponentEventListener::HandleCaretChangedEvent(Any, Any) +{ + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_CARETCHANGE, m_xAccessible.get()); +} + +/** + * set the new state and fire the MSAA event + * + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccComponentEventListener::SetComponentState(short state, bool enable) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::CHECKED: + case AccessibleStateType::PRESSED: + case AccessibleStateType::SELECTED: + case AccessibleStateType::ARMED: + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::SHOWING: + FireStatePropertyChange(state, enable); + break; + case AccessibleStateType::VISIBLE: + if (GetRole() == AccessibleRole::MENU_ITEM) + { + if(enable) + { + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + else + { + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + } + else + { + FireStatePropertyChange(state, enable); + } + break; + case AccessibleStateType::FOCUSED: + FireStateFocusedChange(enable); + break; + case AccessibleStateType::ENABLED: + if(enable) + { + pAgent->UpdateState(m_xAccessible.get()); + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + // 8. label should have no FOCUSABLE state, Firefox has READONLY state, we can also have. + if ( GetRole() != AccessibleRole::LABEL + && GetRole() != AccessibleRole::STATIC + && GetRole() != AccessibleRole::SCROLL_BAR) + { + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + } + else + { + pAgent->UpdateState(m_xAccessible.get()); + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + break; + default: + break; + } +} + +/** + * fire the MSAA state changed event + * + * @param state the state id + * @param set true if state is set, false if state is unset + */ +void AccComponentEventListener::FireStatePropertyChange(short state, bool set) +{ + if( set) + { + // new value + switch(state) + { + case AccessibleStateType::CHECKED: + case AccessibleStateType::INDETERMINATE: + pAgent->IncreaseState(m_xAccessible.get(), state); + pAgent->UpdateAction(m_xAccessible.get()); + + if(!pAgent->IsSpecialToolboItem(m_xAccessible.get())) + { + pAgent->NotifyAccEvent(UM_EVENT_STATE_CHECKED, m_xAccessible.get()); + } + break; + case AccessibleStateType::PRESSED: + pAgent->IncreaseState(m_xAccessible.get(), state); + pAgent->NotifyAccEvent(UM_EVENT_STATE_PRESSED, m_xAccessible.get()); + break; + case AccessibleStateType::SELECTED: + pAgent->IncreaseState(m_xAccessible.get(), state); + break; + case AccessibleStateType::ARMED: + pAgent->IncreaseState(m_xAccessible.get(), state); + pAgent->NotifyAccEvent(UM_EVENT_STATE_ARMED, m_xAccessible.get()); + break; + case AccessibleStateType::SHOWING: + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + // UNO !SHOWING == MSAA OFFSCREEN + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING ); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE ); + break; + default: + break; + } + } + else + { + // old value + switch(state) + { + case AccessibleStateType::CHECKED: + case AccessibleStateType::INDETERMINATE: + pAgent->DecreaseState(m_xAccessible.get(), state); + pAgent->UpdateAction(m_xAccessible.get()); + + if(!pAgent->IsSpecialToolboItem(m_xAccessible.get())) + { + pAgent->NotifyAccEvent(UM_EVENT_STATE_CHECKED, m_xAccessible.get()); + } + break; + case AccessibleStateType::PRESSED: + pAgent->DecreaseState(m_xAccessible.get(), state); + pAgent->NotifyAccEvent(UM_EVENT_STATE_PRESSED, m_xAccessible.get()); + break; + case AccessibleStateType::SELECTED: + pAgent->DecreaseState(m_xAccessible.get(), state); + //if the state is unset, no need to send MSAA SELECTION event + //pAgent->NotifyAccEvent(UM_EVENT_STATE_SELECTED, m_xAccessible.get()); + break; + case AccessibleStateType::ARMED: + { + pAgent->DecreaseState(m_xAccessible.get(), state); + //if the state is unset, no need to send MSAA MENU event + //pAgent->NotifyAccEvent(UM_EVENT_STATE_ARMED, m_xAccessible.get()); + } + break; + case AccessibleStateType::SHOWING: + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + // UNO !SHOWING == MSAA OFFSCREEN + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + + default: + break; + } + } +} + +/** + * handle the focused event + * + * @param enable true if get focus, false if lose focus + */ +void AccComponentEventListener::FireStateFocusedChange(bool enable) +{ + if(enable) + { + if (GetParentRole() != AccessibleRole::COMBO_BOX) + pAgent->NotifyAccEvent(UM_EVENT_STATE_FOCUSED, m_xAccessible.get()); + } + else + { + //if lose focus, no need to send MSAA FOCUS event + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + } +} + +void AccComponentEventListener::HandleSelectionChangedEventNoArgs() +{ + pAgent->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED, m_xAccessible.get()); +} + +//add TEXT_SELECTION_CHANGED event +void AccComponentEventListener::HandleTextSelectionChangedEvent() +{ + pAgent->NotifyAccEvent(UM_EVENT_TEXT_SELECTION_CHANGED, m_xAccessible.get()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccContainerEventListener.cxx b/winaccessibility/source/service/AccContainerEventListener.cxx new file mode 100644 index 000000000..9587255ac --- /dev/null +++ b/winaccessibility/source/service/AccContainerEventListener.cxx @@ -0,0 +1,554 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccContainerEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccContainerEventListener::AccContainerEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccEventListener(pAcc, Agent) +{ +} + +AccContainerEventListener::~AccContainerEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * + * @param AccessibleEventObject the event object which contains information about event + */ +void AccContainerEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::CHILD: + HandleChildChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED: + HandleSelectionChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::INVALIDATE_ALL_CHILDREN: + HandleAllChildrenChangedEvent(); + break; + case AccessibleEventId::TEXT_CHANGED: + HandleTextChangedEvent(aEvent.OldValue, aEvent.NewValue); + [[fallthrough]]; //TODO ??? + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + case AccessibleEventId::STATE_CHANGED: + HandleStateChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VALUE_CHANGED: + HandleValueChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_ADD: + HandleSelectionChangedAddEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_REMOVE: + HandleSelectionChangedRemoveEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_WITHIN: + HandleSelectionChangedWithinEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::PAGE_CHANGED: + HandlePageChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SECTION_CHANGED: + HandleSectionChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::COLUMN_CHANGED: + HandleColumnChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +void AccContainerEventListener::HandleStateChangedEvent(Any oldValue, Any newValue) +{ + short State; + if( newValue >>= State) + { + SetComponentState(State, true); + } + else if (oldValue >>= State) + { + SetComponentState(State, false); + } + +} + +/** + * handle the CHILD event + * @param oldValue the child to be deleted + * @param newValue the child to be added + */ +void AccContainerEventListener::HandleChildChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if( newValue >>= xChild) + { + //create a new child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + //add this child + + if (pAgent->InsertAccObj(pAcc, m_xAccessible.get())) + { + //add all oldValue's existing children + pAgent->InsertChildrenAccObj(pAcc); + pAgent->NotifyAccEvent(UM_EVENT_CHILD_ADDED, pAcc); + } + } + } + else if (oldValue >>= xChild) + { + //delete an existing child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->NotifyAccEvent(UM_EVENT_CHILD_REMOVED, pAcc); + //delete all oldValue's existing children + pAgent->DeleteChildrenAccObj( pAcc ); + //delete this child + pAgent->DeleteAccObj( pAcc ); + + } + } + +} + +/** + * handle the SELECTION_CHANGED event + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccContainerEventListener::HandleSelectionChangedEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if(NotifyChildEvent(UM_EVENT_SELECTION_CHANGED,newValue)) + { + return ; + } + + //menu bar does not process selection change event,just same as word behavior + if (GetRole()!=AccessibleRole::MENU_BAR) + pAgent->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED, m_xAccessible.get()); +} + +/** + * handle the INVALIDATE_ALL_CHILDREN event + */ +void AccContainerEventListener::HandleAllChildrenChangedEvent() +{ + //TODO: update all the children + if (m_xAccessible.is()) + { + //delete all oldValue's existing children + pAgent->DeleteChildrenAccObj(m_xAccessible.get()); + //add all oldValue's existing children + pAgent->InsertChildrenAccObj(m_xAccessible.get()); + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_REORDER , m_xAccessible.get()); + } +} + +/** + * handle the TEXT_CHANGED event + */ +void AccContainerEventListener::HandleTextChangedEvent(Any, Any newValue) +{ + pAgent->UpdateValue(m_xAccessible.get(), newValue); + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_TEXTCHANGE, m_xAccessible.get()); +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccContainerEventListener::SetComponentState(short state, bool enable ) +{ + // only the following state can be fired state event. + + switch (state) + { + case AccessibleStateType::SELECTED: + case AccessibleStateType::BUSY: + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::OFFSCREEN: + case AccessibleStateType::FOCUSABLE: + case AccessibleStateType::SHOWING: + case AccessibleStateType::VISIBLE: + FireStatePropertyChange(state, enable); + break; + case AccessibleStateType::FOCUSED: + FireStateFocusedChange(enable); + break; + case AccessibleStateType::ENABLED: + if(enable) + { + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + pAgent->UpdateState(m_xAccessible.get()); + + UpdateAllChildrenState(m_xAccessible.get()); + } + else + { + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + pAgent->UpdateState(m_xAccessible.get()); + + UpdateAllChildrenState(m_xAccessible.get()); + } + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + //for PAGE_TAB_LIST, there will be ACTIVE state, then it should be converted to FOCUSED event. + if (GetRole() == AccessibleRole::PAGE_TAB_LIST) + { + if (!enable) /* get the active state */ + { + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + } + + else /* lose the active state */ + { + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + } + } + break; + + case AccessibleStateType::EXPANDED: + case AccessibleStateType::COLLAPSE: + case AccessibleStateType::CHECKED: + { + pAgent->UpdateState(m_xAccessible.get()); + pAgent->NotifyAccEvent(UM_EVENT_STATE_BUSY, m_xAccessible.get()); + break; + } + + default: + break; + } +} + +/** + * fire the MSAA state changed event + * @param state the state id + * @param set true if state is set, false if state is unset + */ +void AccContainerEventListener::FireStatePropertyChange(short state, bool set) +{ + if( set ) + { + // new value + switch(state) + { + case AccessibleStateType::SELECTED: + pAgent->IncreaseState(m_xAccessible.get(), state); + break; + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::BUSY: + case AccessibleStateType::FOCUSABLE: + case AccessibleStateType::OFFSCREEN: + pAgent->IncreaseState(m_xAccessible.get(), state); + pAgent->NotifyAccEvent(UM_EVENT_STATE_BUSY, m_xAccessible.get()); + break; + case AccessibleStateType::SHOWING: + // UNO !SHOWING == MSAA OFFSCREEN + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + default: + break; + } + } + else + { + // old value + switch(state) + { + case AccessibleStateType::SELECTED: + pAgent->DecreaseState(m_xAccessible.get(), state); + break; + case AccessibleStateType::BUSY: + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::FOCUSABLE: + case AccessibleStateType::OFFSCREEN: + pAgent->DecreaseState(m_xAccessible.get(), state); + pAgent->NotifyAccEvent(UM_EVENT_STATE_BUSY, m_xAccessible.get()); + break; + case AccessibleStateType::SHOWING: + // UNO !SHOWING == MSAA OFFSCREEN + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + default: + break; + } + } +} + +/** + * handle the focused event + * @param enable true if get focus, false if lose focus + */ +void AccContainerEventListener::FireStateFocusedChange(bool enable) +{ + if(enable) + { + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + //if the acc role is MENU_BAR, MSAA UM_EVENT_MENU_START event should be sent + //if the acc role is POPUP_MENU, MSAA UM_EVENT_MENUPOPUPSTART event should be sent + short role = GetRole(); + if(role == AccessibleRole::MENU_BAR) + { + pAgent->NotifyAccEvent(UM_EVENT_MENU_START, m_xAccessible.get()); + } + else if (role == AccessibleRole::POPUP_MENU) + pAgent->NotifyAccEvent(UM_EVENT_MENUPOPUPSTART, m_xAccessible.get()); + //Disable the focused event on option_pane and Panel. + //only disable option_pane for toolbar has panel to get focus + else if (role == AccessibleRole::PANEL || role == AccessibleRole::OPTION_PANE ) + { + //don't send focused event on PANEL & OPTION_PANE if the parent is not toolbar + short parentRole = GetParentRole(); + if (parentRole == AccessibleRole::TOOL_BAR + || parentRole == AccessibleRole::SCROLL_PANE // sidebar + || parentRole == AccessibleRole::PANEL) // sidebar + pAgent->NotifyAccEvent(UM_EVENT_STATE_FOCUSED, m_xAccessible.get()); + } + //to update ComboBox's description + else if (role == AccessibleRole::COMBO_BOX ) + { + pAgent->UpdateDescription(m_xAccessible.get()); + //for editable combobox, send focus event on only edit control, + bool bSendFocusOnCombobox = true; + //send focused event to the first text child + Reference<XAccessibleContext> mxContext = m_xAccessible->getAccessibleContext(); + if(mxContext.is()) + { + Reference<XAccessible> mxChild = mxContext->getAccessibleChild(0); + if(mxChild.is()) + { + Reference<XAccessibleContext> mxChildContext = mxChild->getAccessibleContext(); + short childrole = mxChildContext->getAccessibleRole(); + if (childrole == AccessibleRole::TEXT) + { + if (IsEditable(mxChildContext)) + { + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + pAgent->IncreaseState( mxChild.get(), AccessibleStateType::FOCUSED); + pAgent->NotifyAccEvent(UM_EVENT_STATE_FOCUSED, mxChild.get()); + bSendFocusOnCombobox = false; + } + } + } + } + if (bSendFocusOnCombobox) + pAgent->NotifyAccEvent(UM_EVENT_STATE_FOCUSED, m_xAccessible.get()); + } + else + pAgent->NotifyAccEvent(UM_EVENT_STATE_FOCUSED, m_xAccessible.get()); + } + else + { + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + //if the acc role is MENU_BAR, MSAA UM_EVENT_MENU_END event should be sent + //if the acc role is POPUP_MENU, MSAA UM_EVENT_MENUPOPUPEND event should be sent + if (GetRole() == AccessibleRole::MENU_BAR) + { + pAgent->NotifyAccEvent(UM_EVENT_MENU_END, m_xAccessible.get()); + } + else if (GetRole() == AccessibleRole::POPUP_MENU) + { + pAgent->NotifyAccEvent(UM_EVENT_MENUPOPUPEND, m_xAccessible.get()); + } + } +} + +/** + * handle the VALUE_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccContainerEventListener::HandleValueChangedEvent(Any, Any) +{ + pAgent->UpdateValue(m_xAccessible.get()); + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_VALUECHANGE, m_xAccessible.get()); +} + +bool AccContainerEventListener::IsEditable(Reference<XAccessibleContext> const & xContext) +{ + Reference< XAccessibleStateSet > pRState = xContext->getAccessibleStateSet(); + if( !pRState.is() ) + return false; + + Sequence<short> pStates = pRState->getStates(); + int count = pStates.getLength(); + for( int iIndex = 0;iIndex < count;iIndex++ ) + { + if(pStates[iIndex] == AccessibleStateType::EDITABLE) + return true; + } + return false; +} + +bool AccContainerEventListener::NotifyChildEvent(short nWinEvent,const Any &Value) +{ + Reference< XAccessible > xChild; + if(Value >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->NotifyAccEvent(nWinEvent, pAcc); + return true; + } + } + return false; +} + +void AccContainerEventListener::HandleSelectionChangedAddEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if(NotifyChildEvent(UM_EVENT_SELECTION_CHANGED_ADD,newValue)) + { + return ; + } + pAgent->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED_ADD, m_xAccessible.get()); +} + +void AccContainerEventListener::HandleSelectionChangedRemoveEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if(NotifyChildEvent(UM_EVENT_SELECTION_CHANGED_REMOVE,newValue)) + { + return ; + } + pAgent->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED_REMOVE, m_xAccessible.get()); +} + +void AccContainerEventListener::HandleSelectionChangedWithinEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if(NotifyChildEvent(UM_EVENT_SELECTION_CHANGED_WITHIN,newValue)) + { + return ; + } + pAgent->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED_WITHIN, m_xAccessible.get()); +} + +void AccContainerEventListener::UpdateAllChildrenState(XAccessible* pXAccessible) +{ + Reference<css::accessibility::XAccessibleContext> xContext = pXAccessible->getAccessibleContext(); + if(!xContext.is()) + { + return; + } + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + if(pAccessibleContext == nullptr) + { + return; + } + + if (pAgent && pAgent->IsStateManageDescendant(pXAccessible)) + { + return; + } + + int count = pAccessibleContext->getAccessibleChildCount(); + for (int i=0;i<count;i++) + { + Reference<css::accessibility::XAccessible> mxAccessible + = pAccessibleContext->getAccessibleChild(i); + + css::accessibility::XAccessible* mpAccessible = mxAccessible.get(); + if(mpAccessible != nullptr) + { + pAgent->UpdateState(mpAccessible); + UpdateAllChildrenState(mpAccessible); + } + } +} + +void AccContainerEventListener::HandlePageChangedEvent(const Any& /*oldValue*/, const Any& /*newValue*/) +{ + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_PAGECHANGED, m_xAccessible.get()); +} + +void AccContainerEventListener::HandleSectionChangedEvent(const Any& /*oldValue*/, const Any& /*newValue*/ ) +{ + pAgent->NotifyAccEvent(UM_EVENT_SECTION_CHANGED, m_xAccessible.get()); +} + +void AccContainerEventListener::HandleColumnChangedEvent(const Any& /*oldValue*/, const Any& /*newValue*/) +{ + pAgent->NotifyAccEvent(UM_EVENT_COLUMN_CHANGED, m_xAccessible.get()); +} + +void AccContainerEventListener::HandleNameChangedEvent( Any name ) +{ + if (GetRole() == AccessibleRole::COMBO_BOX) + { + Reference<XAccessibleContext> mxContext(m_xAccessible->getAccessibleContext()); + if(mxContext.is()) + { + Reference<XAccessible> mxChild = mxContext->getAccessibleChild(0); + if(mxChild.is()) + { + Reference<XAccessibleContext> mxChildContext = mxChild->getAccessibleContext(); + short childrole = mxChildContext->getAccessibleRole(); + if (childrole == AccessibleRole::TEXT) + { + pAgent->UpdateAccName(mxChild.get(), name); + } + } + } + } + AccEventListener::HandleNameChangedEvent(name); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccDescendantManagerEventListener.cxx b/winaccessibility/source/service/AccDescendantManagerEventListener.cxx new file mode 100644 index 000000000..c8fc771ae --- /dev/null +++ b/winaccessibility/source/service/AccDescendantManagerEventListener.cxx @@ -0,0 +1,223 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccDescendantManagerEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccDescendantManagerEventListener::AccDescendantManagerEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + : AccComponentEventListener(pAcc, Agent) +{ +} + +AccDescendantManagerEventListener::~AccDescendantManagerEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccDescendantManagerEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::SELECTION_CHANGED: + HandleSelectionChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::CHILD: + HandleChildChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS: + HandleChildChangedNoFocusEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_ADD: + HandleSelectionChangedAddEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_REMOVE: + HandleSelectionChangedRemoveEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_WITHIN: + HandleSelectionChangedWithinEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccComponentEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the CHILD event + * @param oldValue the child to be deleted + * @param newValue the child to be added + */ +void AccDescendantManagerEventListener::HandleChildChangedEvent(Any oldValue, Any newValue) +{ + + Reference< XAccessible > xChild; + if( newValue >>= xChild) + { + //create a new child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->InsertAccObj(pAcc, m_xAccessible.get()); + pAgent->InsertChildrenAccObj(pAcc); + + pAgent->NotifyAccEvent(UM_EVENT_CHILD_ADDED, pAcc); + + } + } + + if (oldValue >>= xChild) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + + pAgent->NotifyAccEvent(UM_EVENT_CHILD_REMOVED, pAcc); + pAgent->DeleteChildrenAccObj( pAcc ); + pAgent->DeleteAccObj( pAcc ); + } + } + +} + +/** + * handle the SELECTION_CHANGED event + */ +void AccDescendantManagerEventListener::HandleSelectionChangedEvent(Any oldValue, Any newValue) +{ + bool bSend =false; + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + //if the Role is the SC cell ,don't add the selected state. + if (pAgent->GetRole(pAcc) != AccessibleRole::TABLE_CELL) + { + pAgent->IncreaseState( pAcc, AccessibleStateType::SELECTED); + } + + pAgent->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED, pAcc); + bSend=true; + } + } + if(oldValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->DecreaseState( pAcc, AccessibleStateType::SELECTED); + } + } + if (!bSend) + { + pAgent->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED, m_xAccessible.get()); + } +} + + +void AccDescendantManagerEventListener::HandleChildChangedNoFocusEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + + pAgent->InsertAccObj(pAcc, m_xAccessible.get()); + pAgent->InsertChildrenAccObj(pAcc); + } + } + if (oldValue >>= xChild) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->DeleteChildrenAccObj( pAcc ); + pAgent->DeleteAccObj( pAcc ); + } + } +} + +bool AccDescendantManagerEventListener::NotifyChildEvent(short nWinEvent,const Any &Value) +{ + Reference< XAccessible > xChild; + if(Value >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->NotifyAccEvent(nWinEvent, pAcc); + + if (pAgent->IsStateManageDescendant(m_xAccessible.get()) + && (nWinEvent == UM_EVENT_SELECTION_CHANGED_REMOVE)) + { + pAgent->DeleteAccObj( pAcc ); + } + return true; + } + } + return false; +} +void AccDescendantManagerEventListener::HandleSelectionChangedAddEvent(const Any& /*oldValue*/, const Any &newValue) +{ + if(NotifyChildEvent(UM_EVENT_SELECTION_CHANGED_ADD,newValue)) + { + return ; + } + pAgent->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED_ADD, m_xAccessible.get()); +} + +void AccDescendantManagerEventListener::HandleSelectionChangedRemoveEvent(const Any& /*oldValue*/, const Any &newValue) +{ + if(NotifyChildEvent(UM_EVENT_SELECTION_CHANGED_REMOVE,newValue)) + { + return ; + } + pAgent->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED_REMOVE, m_xAccessible.get()); +} + +void AccDescendantManagerEventListener::HandleSelectionChangedWithinEvent(const Any& /*oldValue*/, const Any &newValue) +{ + if(NotifyChildEvent(UM_EVENT_SELECTION_CHANGED_WITHIN,newValue)) + { + return ; + } + pAgent->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED_WITHIN, m_xAccessible.get()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccDialogEventListener.cxx b/winaccessibility/source/service/AccDialogEventListener.cxx new file mode 100644 index 000000000..1b9ce3cb7 --- /dev/null +++ b/winaccessibility/source/service/AccDialogEventListener.cxx @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccDialogEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccDialogEventListener::AccDialogEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccEventListener(pAcc, Agent) +{} +AccDialogEventListener::~AccDialogEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccDialogEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::CHILD: + HandleChildChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the CHILD event + * @param oldValue the child to be deleted + * @param newValue the child to be added + */ +void AccDialogEventListener::HandleChildChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if( newValue >>= xChild) + { + //create a new child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + //add this child + pAgent->InsertAccObj(pAcc, m_xAccessible.get()); + //add all oldValue's existing children + pAgent->InsertChildrenAccObj(pAcc); + pAgent->NotifyAccEvent(UM_EVENT_CHILD_ADDED, pAcc); + } + } + else if (oldValue >>= xChild) + { + //delete an existing child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->NotifyAccEvent(UM_EVENT_CHILD_REMOVED, pAcc); + //delete all oldValue's existing children + pAgent->DeleteChildrenAccObj( pAcc ); + //delete this child + pAgent->DeleteAccObj( pAcc ); + } + } + +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccDialogEventListener::SetComponentState(short state, bool enable) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::ICONIFIED: + // no msaa state mapping + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + if( enable ) + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + else + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccEventListener.cxx b/winaccessibility/source/service/AccEventListener.cxx new file mode 100644 index 000000000..e2be5cce1 --- /dev/null +++ b/winaccessibility/source/service/AccEventListener.cxx @@ -0,0 +1,267 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <cppuhelper/bootstrap.hxx> +#include <com/sun/star/bridge/XUnoUrlResolver.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include <vcl/svapp.hxx> + +#include <toolkit/awt/vclxwindow.hxx> + +#include <AccEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> + +#include <stdio.h> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; +using namespace cppu; + +AccEventListener::AccEventListener(css::accessibility::XAccessible* pAcc, + AccObjectManagerAgent* Agent) + : m_xAccessible(pAcc) + , pAgent(Agent) +{} + +AccEventListener::~AccEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::NAME_CHANGED: + HandleNameChangedEvent(aEvent.NewValue); + break; + case AccessibleEventId::DESCRIPTION_CHANGED: + HandleDescriptionChangedEvent(aEvent.NewValue); + break; + case AccessibleEventId::STATE_CHANGED: + HandleStateChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + break; + } +} + +/** + * handle the NAME_CHANGED event + * @param name the new name with changed. + */ +void AccEventListener::HandleNameChangedEvent(Any name) +{ + if (pAgent->IsTopWinAcc(m_xAccessible.get())) + { + XAccessible* pAccDoc = pAgent->GetAccDocByAccTopWin(m_xAccessible.get()); + if ( pAccDoc ) + { + pAgent->UpdateAccName(pAccDoc); + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_NAMECHANGE, pAccDoc); + } + } + + pAgent->UpdateAccName(m_xAccessible.get(), name); + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_NAMECHANGE, m_xAccessible.get()); +} + +/** + * handle the DESCRIPTION_CHANGED event + * @param desc the new description + */ +void AccEventListener::HandleDescriptionChangedEvent(Any desc) +{ + pAgent->UpdateDescription(m_xAccessible.get(), desc); + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_DESCRIPTIONCHANGE, m_xAccessible.get()); +} + +/** + * handle the BOUNDRECT_CHANGED event + */ +void AccEventListener::HandleBoundrectChangedEvent() +{ + AccObjectManagerAgent::UpdateLocation(m_xAccessible.get()); + pAgent->NotifyAccEvent(UM_EVENT_BOUNDRECT_CHANGED, m_xAccessible.get()); +} + +/** + * handle the VISIBLE_DATA_CHANGED event + */ +void AccEventListener::HandleVisibleDataChangedEvent() +{ + pAgent->UpdateValue(m_xAccessible.get()); + pAgent->NotifyAccEvent(UM_EVENT_VISIBLE_DATA_CHANGED, m_xAccessible.get()); +} + +/** + * handle the STATE_CHANGED event + * @param oldValue the old state of the source of event + * @param newValue the new state of the source of event + */ +void AccEventListener::HandleStateChangedEvent(Any oldValue, Any newValue) +{ + short newV, oldV; + if( newValue >>= newV) + { + SetComponentState(newV, true); + } + else if (oldValue >>= oldV) + { + SetComponentState(oldV, false); + } +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccEventListener::SetComponentState(short state, bool enable ) +{ + switch (state) + { + case AccessibleStateType::FOCUSED: + FireStateFocusedChange(enable); + break; + default: + FireStatePropertyChange(state, enable); + break; + } +} + +/** + * handle the focused event + * @param enable true if get focus, false if lose focus + */ +void AccEventListener::FireStateFocusedChange(bool enable) +{ + if(enable) + { + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + pAgent->NotifyAccEvent(UM_EVENT_STATE_FOCUSED, m_xAccessible.get()); + } + else + { + // no focus lost event in MSAA + } +} + + +/** + * fire the MSAA state changed event + * @param state the state id + * @param set true if state is set, false if state is unset + */ +void AccEventListener::FireStatePropertyChange(short /*state*/, bool set ) +{ + if( set ) + { + //get new state + } + else + { + //lose old state + } +} + +/** + * get the role of accessible object which is observed + */ +short AccEventListener::GetRole() +{ + css::uno::Reference<css::accessibility::XAccessibleContext> const + xContext(m_xAccessible->getAccessibleContext()); + if(xContext.is()) + { + return xContext->getAccessibleRole(); + } + return -1; +} + +/** + * get the role of accessible parent object which is observed + */ +short AccEventListener::GetParentRole() +{ + if (m_xAccessible.is()) + { + return pAgent->GetParentRole(m_xAccessible.get()); + } + return -1; +} +/** + * remove the listener from accessible object + */ +void AccEventListener::RemoveMeFromBroadcaster() +{ + try + { + if (!m_xAccessible.is()) + { + return; + } + try + { + css::uno::Reference<XAccessibleEventBroadcaster> const xBroadcaster( + m_xAccessible->getAccessibleContext(), UNO_QUERY); + if (xBroadcaster.is()) + { + //remove the lister from accessible object + xBroadcaster->removeAccessibleEventListener(this); + } + } + catch (Exception const&) + { // may throw if it's already disposed - ignore that + } + pAgent->NotifyDestroy(m_xAccessible.get()); + m_xAccessible.clear(); // release cyclic reference + } + catch(...) + { + return; + } + +} + +/** + * this method is invoked before listener is disposed + */ +void AccEventListener::disposing( const css::lang::EventObject& /*Source*/ ) +{ + SolarMutexGuard g; + + RemoveMeFromBroadcaster(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccFrameEventListener.cxx b/winaccessibility/source/service/AccFrameEventListener.cxx new file mode 100644 index 000000000..2d31bdffb --- /dev/null +++ b/winaccessibility/source/service/AccFrameEventListener.cxx @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccFrameEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +#include <vcl/window.hxx> +#include <toolkit/awt/vclxwindow.hxx> +#include <vcl/sysdata.hxx> + +AccFrameEventListener::AccFrameEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccEventListener(pAcc, Agent) +{ +} + +AccFrameEventListener::~AccFrameEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccFrameEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::CHILD: + HandleChildChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the CHILD event + * @param oldValue the child to be deleted + * @param newValue the child to be added + */ +void AccFrameEventListener::HandleChildChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if( newValue >>= xChild) + { + //create a new child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + + VCLXWindow* pvclwindow = dynamic_cast<VCLXWindow*>(m_xAccessible.get()); + assert(pvclwindow); + const SystemEnvData* systemdata + = pvclwindow->GetWindow()->GetSystemData(); + + //add this child + pAgent->InsertAccObj(pAcc, m_xAccessible.get(), + reinterpret_cast<sal_Int64>(systemdata->hWnd)); + //add all oldValue's existing children + pAgent->InsertChildrenAccObj(pAcc); + pAgent->NotifyAccEvent(UM_EVENT_CHILD_ADDED, pAcc); + } + } + else if (oldValue >>= xChild) + { + //delete an existing child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->NotifyAccEvent(UM_EVENT_CHILD_REMOVED, pAcc); + //delete all oldValue's existing children + pAgent->DeleteChildrenAccObj( pAcc ); + //delete this child + pAgent->DeleteAccObj( pAcc ); + } + } + +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccFrameEventListener::SetComponentState(short state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::ICONIFIED: + // no msaa state + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + if( enable ) + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + else + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccListEventListener.cxx b/winaccessibility/source/service/AccListEventListener.cxx new file mode 100644 index 000000000..9852fe810 --- /dev/null +++ b/winaccessibility/source/service/AccListEventListener.cxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccListEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccListEventListener::AccListEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccDescendantManagerEventListener(pAcc, Agent) +{ +} + +AccListEventListener::~AccListEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccListEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + HandleActiveDescendantChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::INVALIDATE_ALL_CHILDREN: + // Since List items a transient a child events are mostly used + // to attach/detach listeners, it is safe to ignore it here + //TODO: investigate again + break; + case AccessibleEventId::VALUE_CHANGED: + HandleValueChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccDescendantManagerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the ACTIVE_DESCENDANT_CHANGED event + * @param oldValue the child to lose active + * @param newValue the child to get active + */ +void AccListEventListener::HandleActiveDescendantChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + + // Valueset has cache the child item xacc,Update state if no insert obj + bool bHasCache = pAgent->InsertAccObj(pAcc, m_xAccessible.get()); + if (!bHasCache) + { + pAgent->UpdateState(pAcc); + } + + pAgent->IncreaseState( pAcc, AccessibleStateType::FOCUSED); + + pAgent->NotifyAccEvent(UM_EVENT_ACTIVE_DESCENDANT_CHANGED, pAcc); + } + } + if (oldValue >>= xChild) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->DeleteAccObj( pAcc ); + } + } +} + +/** + * handle the VALUE_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccListEventListener::HandleValueChangedEvent(Any, Any) +{ + //to enable value changed event + if (GetParentRole() == AccessibleRole::COMBO_BOX) + { + XAccessible* pParentAcc = + pAgent->GetParentXAccessible(m_xAccessible.get()); + pAgent->UpdateValue(pParentAcc); + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_VALUECHANGE, pParentAcc); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccMenuEventListener.cxx b/winaccessibility/source/service/AccMenuEventListener.cxx new file mode 100644 index 000000000..623997177 --- /dev/null +++ b/winaccessibility/source/service/AccMenuEventListener.cxx @@ -0,0 +1,147 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccMenuEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccMenuEventListener::AccMenuEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccComponentEventListener(pAcc, Agent) +{} +AccMenuEventListener::~AccMenuEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccMenuEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::CHILD: + HandleChildChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED: + //don't need to process anything,just same as word behavior + //handleSelectionChangedEvent(); + break; + default: + AccComponentEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the CHILD event + * @param oldValue the child to be deleted + * @param newValue the child to be added + */ +void AccMenuEventListener::HandleChildChangedEvent(Any oldValue, Any newValue) +{ + + Reference< XAccessible > xChild; + if( newValue >>= xChild) + { + //create a new child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + //add this child + pAgent->InsertAccObj(pAcc, m_xAccessible.get()); + //add all oldValue's existing children + pAgent->InsertChildrenAccObj(pAcc); + pAgent->NotifyAccEvent(UM_EVENT_CHILD_ADDED, pAcc); + } + } + else if (oldValue >>= xChild) + { + //delete an existing child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->NotifyAccEvent(UM_EVENT_CHILD_REMOVED, pAcc); + //delete all oldValue's existing children + pAgent->DeleteChildrenAccObj( pAcc ); + //delete this child + pAgent->DeleteAccObj( pAcc ); + } + } + +} + +/** + * handle the SELECTION_CHANGED event + */ +void AccMenuEventListener::HandleSelectionChangedEventNoArgs() +{ + pAgent->NotifyAccEvent(UM_EVENT_SELECTION_CHANGED, m_xAccessible.get()); +} + +/** + * handle the Menu_popup event + */ +void AccMenuEventListener::FireStatePropertyChange(short state, bool set) +{ + if( set ) + { + // new value + switch(state) + { + //for sub menu is popup, there is a menu selected event. + case AccessibleStateType::SELECTED: + pAgent->IncreaseState(m_xAccessible.get(), state); + pAgent->UpdateChildState(m_xAccessible.get()); + break; + default: + AccComponentEventListener::FireStatePropertyChange(state, set); + break; + } + } + else + { + switch(state) + { + //for sub menu is popup, there is a menu selected event. + case AccessibleStateType::SELECTED: + pAgent->DecreaseState(m_xAccessible.get(), state); + + break; + default: + AccComponentEventListener::FireStatePropertyChange(state, set); + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccObject.cxx b/winaccessibility/source/service/AccObject.cxx new file mode 100644 index 000000000..f64605228 --- /dev/null +++ b/winaccessibility/source/service/AccObject.cxx @@ -0,0 +1,1195 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleValue.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleText.hpp> + +#include <o3tl/char16_t2wchar_t.hxx> +#include <o3tl/safeint.hxx> + +#include <stdlib.h> +#include <memory.h> +#include <stdio.h> +#include <algorithm> +#include <assert.h> + +#include <AccObject.hxx> +#include <AccEventListener.hxx> + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra-tokens" + // "#endif !_MIDL_USE_GUIDDEF_" in midl-generated code +#endif +#include <UAccCOM_i.c> +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +using namespace std; +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; +using namespace com::sun::star::accessibility::AccessibleRole; +using namespace com::sun::star::accessibility::AccessibleStateType; + +//Role mapping table,left side is UNO role, right side is MSAA role +const short ROLE_TABLE[][2] = + { + {UNKNOWN, IA2_ROLE_UNKNOWN}, + {ALERT , ROLE_SYSTEM_DIALOG}, + {COLUMN_HEADER , ROLE_SYSTEM_COLUMNHEADER}, + //{CANVAS , ROLE_SYSTEM_CLIENT}, + {CANVAS , IA2_ROLE_CANVAS}, + {CHECK_BOX , ROLE_SYSTEM_CHECKBUTTON}, + {CHECK_MENU_ITEM , IA2_ROLE_CHECK_MENU_ITEM}, + {COLOR_CHOOSER, IA2_ROLE_COLOR_CHOOSER}, + {COMBO_BOX , ROLE_SYSTEM_COMBOBOX}, + {DATE_EDITOR , IA2_ROLE_DATE_EDITOR}, + {DESKTOP_ICON , IA2_ROLE_DESKTOP_ICON}, + {DESKTOP_PANE, IA2_ROLE_DESKTOP_PANE}, + {DIRECTORY_PANE, IA2_ROLE_DIRECTORY_PANE}, + {DIALOG, ROLE_SYSTEM_DIALOG}, + {DOCUMENT, ROLE_SYSTEM_DOCUMENT}, + {EMBEDDED_OBJECT , IA2_ROLE_EMBEDDED_OBJECT }, + {END_NOTE , IA2_ROLE_ENDNOTE }, + {FILE_CHOOSER , IA2_ROLE_FILE_CHOOSER }, + {FILLER, ROLE_SYSTEM_WHITESPACE}, + {FONT_CHOOSER, IA2_ROLE_FONT_CHOOSER}, + {FOOTER, IA2_ROLE_FOOTER}, + {FOOTNOTE, IA2_ROLE_FOOTNOTE}, + //{FRAME, IA2_ROLE_FRAME}, + {FRAME, ROLE_SYSTEM_DIALOG}, + {GLASS_PANE , IA2_ROLE_GLASS_PANE}, + {GRAPHIC , ROLE_SYSTEM_GRAPHIC}, + {GROUP_BOX, ROLE_SYSTEM_GROUPING}, + {HEADER , IA2_ROLE_HEADER}, + {HEADING , IA2_ROLE_HEADING}, + {HYPER_LINK , ROLE_SYSTEM_TEXT}, + {ICON , IA2_ROLE_ICON}, + {INTERNAL_FRAME, IA2_ROLE_INTERNAL_FRAME}, + {LABEL, ROLE_SYSTEM_STATICTEXT}, + {LAYERED_PANE , IA2_ROLE_LAYERED_PANE}, + {LIST , ROLE_SYSTEM_LIST}, + {LIST_ITEM , ROLE_SYSTEM_LISTITEM}, + //{MENU , ROLE_SYSTEM_MENUPOPUP}, + {MENU, ROLE_SYSTEM_MENUITEM}, + {MENU_BAR, ROLE_SYSTEM_MENUBAR}, + {MENU_ITEM, ROLE_SYSTEM_MENUITEM}, + {OPTION_PANE , IA2_ROLE_OPTION_PANE}, + {PAGE_TAB, ROLE_SYSTEM_PAGETAB}, + {PAGE_TAB_LIST, ROLE_SYSTEM_PAGETABLIST}, + {PANEL, IA2_ROLE_OPTION_PANE}, + {PARAGRAPH, IA2_ROLE_PARAGRAPH}, + {PASSWORD_TEXT, ROLE_SYSTEM_TEXT}, + {POPUP_MENU, ROLE_SYSTEM_MENUPOPUP}, + {PUSH_BUTTON, ROLE_SYSTEM_PUSHBUTTON}, + {PROGRESS_BAR, ROLE_SYSTEM_PROGRESSBAR}, + {RADIO_BUTTON, ROLE_SYSTEM_RADIOBUTTON}, + {RADIO_MENU_ITEM, IA2_ROLE_RADIO_MENU_ITEM}, + {ROW_HEADER , ROLE_SYSTEM_ROWHEADER}, + {ROOT_PANE, IA2_ROLE_ROOT_PANE}, + {SCROLL_BAR , ROLE_SYSTEM_SCROLLBAR}, + {SCROLL_PANE , IA2_ROLE_SCROLL_PANE}, + {SHAPE, IA2_ROLE_SHAPE}, + {SEPARATOR , ROLE_SYSTEM_SEPARATOR}, + {SLIDER , ROLE_SYSTEM_SLIDER}, + {SPIN_BOX , ROLE_SYSTEM_SPINBUTTON}, + {SPLIT_PANE, IA2_ROLE_SPLIT_PANE}, + {STATUS_BAR, ROLE_SYSTEM_STATUSBAR}, + {TABLE, ROLE_SYSTEM_TABLE}, + {TABLE_CELL , ROLE_SYSTEM_CELL}, + {TEXT, ROLE_SYSTEM_TEXT}, + {TEXT_FRAME , IA2_ROLE_TEXT_FRAME}, + //for change toggle button to push button for jaws + {TOGGLE_BUTTON, ROLE_SYSTEM_PUSHBUTTON}, + + {TOOL_BAR, ROLE_SYSTEM_TOOLBAR}, + {TOOL_TIP, ROLE_SYSTEM_TOOLTIP}, + {TREE , ROLE_SYSTEM_OUTLINE}, + {VIEW_PORT , IA2_ROLE_VIEW_PORT}, + {WINDOW, ROLE_SYSTEM_WINDOW}, + {BUTTON_DROPDOWN, ROLE_SYSTEM_BUTTONDROPDOWN}, + {BUTTON_MENU, ROLE_SYSTEM_BUTTONMENU}, + {CAPTION, IA2_ROLE_CAPTION}, + {CHART, IA2_ROLE_SHAPE}, + {EDIT_BAR, IA2_ROLE_EDITBAR}, + {FORM, IA2_ROLE_FORM}, + {IMAGE_MAP , IA2_ROLE_IMAGE_MAP}, + {NOTE, IA2_ROLE_NOTE}, + {PAGE, IA2_ROLE_PAGE}, + {RULER , IA2_ROLE_RULER}, + {SECTION, IA2_ROLE_SECTION}, + {TREE_ITEM , ROLE_SYSTEM_OUTLINEITEM}, + {TREE_TABLE, ROLE_SYSTEM_OUTLINE}, + {COMMENT, IA2_ROLE_TEXT_FRAME }, + {COMMENT_END, IA2_ROLE_TEXT_FRAME }, + {DOCUMENT_PRESENTATION, ROLE_SYSTEM_DOCUMENT }, + {DOCUMENT_SPREADSHEET, ROLE_SYSTEM_DOCUMENT }, + {DOCUMENT_TEXT, ROLE_SYSTEM_DOCUMENT }, + {STATIC, IA2_ROLE_TEXT_FRAME } + }; + + +/** + * Constructor. + * @param pXAcc Uno XAccessible interface of control. + * @param Agent The agent kept in all listeners,it's the sole interface by which + * listener communicate with windows manager. + * @param listener listener that registers in UNO system. + * @return. + */ +AccObject::AccObject(XAccessible* pAcc, AccObjectManagerAgent* pAgent, + AccEventListener* pListener) : + m_resID (NULL), + m_pParantID (nullptr), + m_bShouldDestroy(false), + m_pIMAcc (nullptr), + m_pParentObj(nullptr), + m_pListener (pListener), + m_xAccRef( pAcc ) +{ + ImplInitializeCreateObj(); + + m_xAccContextRef = m_xAccRef->getAccessibleContext(); + m_xAccActionRef.set(m_xAccContextRef,UNO_QUERY); + m_accRole = m_xAccContextRef -> getAccessibleRole(); + if( m_pIMAcc ) + { + m_pIMAcc->SetXAccessible(reinterpret_cast<hyper>(m_xAccRef.get())); + m_pIMAcc->Put_XAccAgent(reinterpret_cast<hyper>(pAgent)); + m_pIMAcc->SetDefaultAction(reinterpret_cast<hyper>(m_xAccActionRef.get())); + } +} +/** + * Destructor. + * @param + * @return + */ +AccObject::~AccObject() +{ + m_pIMAcc = nullptr; + m_xAccRef = nullptr; + m_xAccActionRef = nullptr; + m_xAccContextRef = nullptr; +} + + +/** + * Insert a child element. + * @param pChild Child element that should be inserted into child list. + * @param pos Insert position. + * @return + */ +void AccObject::InsertChild( AccObject* pChild,short pos ) +{ + + std::vector<AccObject*>::iterator iter; + iter = std::find(m_childrenList.begin(),m_childrenList.end(),pChild); + if(iter!=m_childrenList.end()) + return; + if(LAST_CHILD==pos) + { + m_childrenList.push_back(pChild); + } + else + { + iter=m_childrenList.begin()+pos; + m_childrenList.insert(iter,pChild); + } + + pChild->SetParentObj(this); +} + +/** + * Delete a child element + * @param pChild Child element that should be inserted into child list. + * @param pos Insert position. + * @return + */ +void AccObject::DeleteChild( AccObject* pChild ) +{ + std::vector<AccObject*>::iterator iter; + iter = std::find(m_childrenList.begin(),m_childrenList.end(),pChild); + if(iter!=m_childrenList.end()) + { + m_childrenList.erase(iter); + if(m_pIMAcc) + pChild->SetParentObj(nullptr); + } +} + +/** + * In order to windows API WindowFromAccessibleObject, we sometimes to set a pure + * top window accessible object created by windows system as top ancestor. + * @param. + * @return + */ +void AccObject::UpdateValidWindow() +{ + if(m_pIMAcc) + m_pIMAcc->Put_XAccWindowHandle(m_pParantID); +} + +/** + * Translate all UNO basic information into MSAA com information. + * @param + * @return If the method is correctly processed. + */ +void AccObject::ImplInitializeCreateObj() +{ + m_pIMAcc = UAccCOMCreateInstance(); + + assert(m_pIMAcc); +} + +/** + * Update name property to com object. + * @param + * @return + */ +void AccObject::UpdateName( ) +{ + if (!m_pIMAcc) + { + return; + } + + if( ( TEXT_FRAME == m_accRole ) && ( m_pParentObj !=nullptr )&& ( SCROLL_PANE == m_pParentObj -> m_accRole ) ) + m_pIMAcc->Put_XAccName( o3tl::toW(m_pParentObj->m_xAccContextRef->getAccessibleName().getStr()) ); + //IAccessibility2 Implementation 2009----- + if ( PARAGRAPH == m_accRole) + { + m_pIMAcc->Put_XAccName(L""); + } + //-----IAccessibility2 Implementation 2009 + else + m_pIMAcc->Put_XAccName(o3tl::toW(m_xAccContextRef->getAccessibleName().getStr())); + + return ; +} +/** + * Update description property to com object. + * no content for update description + * @param + * @return + */ +void AccObject::UpdateDescription() +{ + if (!m_pIMAcc) + { + return; + } + + m_pIMAcc->Put_XAccDescription(o3tl::toW(m_xAccContextRef->getAccessibleDescription().getStr())); + return ; +} + +/** + * Update default action property to com object. + * @param + * @return + */ +void AccObject::UpdateAction() +{ + m_xAccActionRef.set(m_xAccContextRef,UNO_QUERY); + + if( m_xAccActionRef.is() && m_pIMAcc ) + { + if( m_xAccActionRef->getAccessibleActionCount() > 0 ) + { + UpdateDefaultAction( ); + m_pIMAcc->SetDefaultAction( + reinterpret_cast<hyper>(m_xAccActionRef.get())); + } + } +} + +/** + * Update value property to com object. + * @param + * @return + */ +void AccObject::UpdateValue() +{ + if( nullptr == m_pIMAcc || !m_xAccContextRef.is() ) + { + assert(false); + return ; + } + + Reference< XAccessibleValue > pRValue(m_xAccContextRef,UNO_QUERY); + Any pAny; + if( pRValue.is() ) + { + pAny = pRValue->getCurrentValue(); + } + + SetValue( pAny ); +} + +/** + * Set special default action description string via UNO role. + * @param Role UNO role + * @return + */ +void AccObject::UpdateDefaultAction( ) +{ + if(!m_xAccActionRef.is()) + return ; + + switch(m_accRole) + { + case PUSH_BUTTON: + case TOGGLE_BUTTON: + case RADIO_BUTTON: + case MENU_ITEM: + case RADIO_MENU_ITEM: + case CHECK_MENU_ITEM: + case LIST_ITEM: + case CHECK_BOX: + case TREE_ITEM: + case BUTTON_DROPDOWN: + m_pIMAcc->Put_ActionDescription( o3tl::toW(m_xAccActionRef->getAccessibleActionDescription(sal_Int32(0)).getStr()) ); + return; + } +} + +/** + * Set value property via pAny. + * @param pAny New value. + * @return + */ +void AccObject::SetValue( Any pAny ) +{ + if( nullptr == m_pIMAcc || !m_xAccContextRef.is() ) + { + assert(false); + return ; + } + Reference< XAccessibleText > pRText(m_xAccContextRef,UNO_QUERY); + OUString val; + switch(m_accRole) + { + case SPIN_BOX: + // 3. date editor's msaa value should be the same as spinbox + case DATE_EDITOR: + case TEXT: + case PARAGRAPH: + case HEADING: + case TABLE_CELL: + + if(pRText.get()) + { + val = pRText->getText(); + } + m_pIMAcc->Put_XAccValue( o3tl::toW(val.getStr()) ); + break; + case TREE_ITEM: + //case CHECK_BOX: //Commented by Li Xing to disable the value for general checkbox + case COMBO_BOX: + case NOTE: + case SCROLL_BAR: + m_pIMAcc->Put_XAccValue( o3tl::toW(GetMAccessibleValueFromAny(pAny).getStr()) ); + break ; + // Added by Li Xing, only the checkbox in tree should have the value. + case CHECK_BOX: + if( ( m_pParentObj !=nullptr ) && (TREE == m_pParentObj->m_accRole || TREE_ITEM == m_pParentObj->m_accRole )) + m_pIMAcc->Put_XAccValue( o3tl::toW(GetMAccessibleValueFromAny(pAny).getStr()) ); + break; + default: + break; + } + + return; +} + +OUString AccObject::GetMAccessibleValueFromAny(Any pAny) +{ + OUString strValue; + + if(nullptr == m_pIMAcc) + return strValue; + + if(pAny.getValueType() == cppu::UnoType<cppu::UnoUnsignedShortType>::get() ) + { + sal_uInt16 val; + if (pAny >>= val) + { + strValue=OUString::number(val); + + } + } + else if(pAny.getValueType() == cppu::UnoType<OUString>::get()) + { + + pAny >>= strValue ; + + } + else if(pAny.getValueType() == cppu::UnoType<Sequence< OUString >>::get()) + { + Sequence< OUString > val; + if (pAny >>= val) + { + + int count = val.getLength(); + + for( int iIndex = 0;iIndex < count;iIndex++ ) + { + strValue += val[iIndex]; + } + + } + } + else if(pAny.getValueType() == cppu::UnoType<double>::get()) + { + double val; + if (pAny >>= val) + { + strValue=OUString::number(val); + } + } + else if(pAny.getValueType() == cppu::UnoType<sal_Int32>::get()) + { + sal_Int32 val; + if (pAny >>= val) + { + strValue=OUString::number(val); + } + } + else if (pAny.getValueType() == cppu::UnoType<css::accessibility::TextSegment>::get()) + { + css::accessibility::TextSegment val; + if (pAny >>= val) + { + OUString realVal(val.SegmentText); + strValue = realVal; + + } + } + + return strValue; +} +/** + * Set name property via pAny. + * @param pAny New accessible name. + * @return + */ +void AccObject::SetName( Any pAny) +{ + if( nullptr == m_pIMAcc ) + return ; + + m_pIMAcc->Put_XAccName( o3tl::toW(GetMAccessibleValueFromAny(pAny).getStr()) ); + +} + +/** + * Set description property via pAny. + * @param pAny New accessible description. + * @return + */ +void AccObject::SetDescription( Any pAny ) +{ + if( nullptr == m_pIMAcc ) + return ; + m_pIMAcc->Put_XAccDescription( o3tl::toW(GetMAccessibleValueFromAny(pAny).getStr()) ); +} + +/** + * Set role property via pAny + * @param Role New accessible role. + * @return + */ +void AccObject::SetRole( short Role ) +{ + if( nullptr == m_pIMAcc ) + return ; + m_pIMAcc->Put_XAccRole( Role ); +} + +/** +* Get role property via pAny +* @param +* @return accessible role +*/ +short AccObject::GetRole() const +{ + return m_accRole; +} + +/** + * Get MSAA state from UNO state + * @Role xState UNO state. + * @return + */ +DWORD AccObject::GetMSAAStateFromUNO(short xState) +{ + DWORD IState = UNO_MSAA_UNMAPPING; + + if( !m_xAccContextRef.is() ) + { + assert(false); + return IState; + } + short Role = m_accRole; + + switch( xState ) + { + case BUSY: + IState = STATE_SYSTEM_BUSY; + break; + case CHECKED: + if( Role == PUSH_BUTTON || Role == TOGGLE_BUTTON ) + { + IState = STATE_SYSTEM_PRESSED; + } + else + IState = STATE_SYSTEM_CHECKED; + break; + case DEFUNC: + IState = STATE_SYSTEM_UNAVAILABLE; + break; + case EXPANDED: + IState = STATE_SYSTEM_EXPANDED; + break; + case FOCUSABLE: + IState = STATE_SYSTEM_FOCUSABLE; + break; + case FOCUSED: + IState = STATE_SYSTEM_FOCUSED; + break; + case INDETERMINATE: + IState = STATE_SYSTEM_MIXED; + break; + case MULTI_SELECTABLE: + IState = STATE_SYSTEM_MULTISELECTABLE; + break; + case PRESSED: + IState = STATE_SYSTEM_PRESSED; + break; + case RESIZABLE: + IState = STATE_SYSTEM_SIZEABLE; + break; + case SELECTABLE: + if( m_accRole == MENU || m_accRole == MENU_ITEM) + { + IState = UNO_MSAA_UNMAPPING; + } + else + { + IState = STATE_SYSTEM_SELECTABLE; + } + break; + case SELECTED: + if( m_accRole == MENU || m_accRole == MENU_ITEM ) + { + IState = UNO_MSAA_UNMAPPING; + } + else + { + IState = STATE_SYSTEM_SELECTED; + } + break; + case ARMED: + IState = STATE_SYSTEM_FOCUSED; + break; + case EXPANDABLE: + { + sal_Bool isExpanded = true; + sal_Bool isExpandable = true; + if( Role == PUSH_BUTTON || Role == TOGGLE_BUTTON || BUTTON_DROPDOWN == Role ) + { + IState = STATE_SYSTEM_HASPOPUP; + } + else + { + GetExpandedState(&isExpandable,&isExpanded); + if(!isExpanded) + IState = STATE_SYSTEM_COLLAPSED; + } + } + break; + //Remove the SENSITIVE state mapping. There is no corresponding MSAA state. + //case SENSITIVE: + // IState = STATE_SYSTEM_PROTECTED; + case EDITABLE: + if( m_pIMAcc ) + { + m_pIMAcc->DecreaseState( STATE_SYSTEM_READONLY ); + } + break; + case OFFSCREEN: + IState = STATE_SYSTEM_OFFSCREEN; + break; + case MOVEABLE: + IState = STATE_SYSTEM_MOVEABLE; + break; + case COLLAPSE: + IState = STATE_SYSTEM_COLLAPSED; + break; + case DEFAULT: + IState = STATE_SYSTEM_DEFAULT; + break; + default: + break; + } + + return IState; +} + +/** + * Decrease state of com object + * @param xState The lost state. + * @return + */ +void AccObject::DecreaseState( short xState ) +{ + if( nullptr == m_pIMAcc ) + { + return; + } + + if( xState == FOCUSABLE) + { + short Role = m_accRole ; + if(Role == MENU_ITEM + || Role == RADIO_MENU_ITEM + || Role == CHECK_MENU_ITEM) + return; + else + { + if (Role == TOGGLE_BUTTON || Role == PUSH_BUTTON || BUTTON_DROPDOWN == Role) + { + if( ( m_pParentObj !=nullptr ) && (TOOL_BAR == m_pParentObj->m_accRole ) ) + return; + } + } + } + + else if( xState == AccessibleStateType::VISIBLE ) + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_INVISIBLE ); + } + else if( xState == AccessibleStateType::SHOWING ) + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_OFFSCREEN ); + } + + DWORD msState = GetMSAAStateFromUNO(xState); + if(msState!=UNO_MSAA_UNMAPPING) + m_pIMAcc->DecreaseState(msState); +} + +/** + * Increase state of com object + * @param xState The new state. + * @return + */ +void AccObject::IncreaseState( short xState ) +{ + if( nullptr == m_pIMAcc ) + { + assert(false); + return; + } + + + if( xState == AccessibleStateType::VISIBLE ) + { + m_pIMAcc->DecreaseState( STATE_SYSTEM_INVISIBLE ); + } + else if( xState == AccessibleStateType::SHOWING ) + { + m_pIMAcc->DecreaseState( STATE_SYSTEM_OFFSCREEN ); + } + + + DWORD msState = GetMSAAStateFromUNO(xState); + if(msState!=UNO_MSAA_UNMAPPING) + m_pIMAcc->IncreaseState( msState ); +} + +/** + * Get next child element + * @param + * @return AccObject Object interface. + */ +AccObject* AccObject::NextChild() +{ + IAccChildList::iterator pInd = m_childrenList.begin(); + if( pInd != m_childrenList.end() ) + return *pInd; + return nullptr; +} +/** + * update action description desc + * @param + * @return + */ +void AccObject::UpdateActionDesc() +{ + if (!m_pIMAcc) + { + return; + } + + OUString pXString = m_xAccContextRef->getAccessibleDescription(); + m_pIMAcc->Put_XAccDescription(o3tl::toW(pXString.getStr())); + long Role = m_accRole; + + if( Role == PUSH_BUTTON || Role == RADIO_BUTTON || Role == MENU_ITEM || + Role == LIST_ITEM || Role == CHECK_BOX || Role == TREE_ITEM || + Role == CHECK_MENU_ITEM || Role == RADIO_MENU_ITEM ) + { + UpdateDefaultAction( ); + } + else + { + + if( m_xAccActionRef.is() ) + { + if( m_xAccActionRef->getAccessibleActionCount() > 0 ) + { + if (!(Role == SPIN_BOX || Role == COMBO_BOX || Role == DATE_EDITOR || + Role == EDIT_BAR || Role == PASSWORD_TEXT || Role == TEXT)) + { + pXString = m_xAccActionRef->getAccessibleActionDescription( 0 ); + //Solution: if string length is more than zero, action is set. + if( pXString.getLength() > 0) + m_pIMAcc->Put_ActionDescription( o3tl::toW(pXString.getStr()) ); + } + } + } + } + +} +/** + * update role information from uno to com + * @param + * @return + */ +void AccObject::UpdateRole() +{ + if (!m_pIMAcc) + { + return; + } + + XAccessibleContext* pContext = m_xAccContextRef.get(); + m_pIMAcc->Put_XAccRole( ROLE_SYSTEM_WINDOW ); + sal_Int16 iRoleIndex = pContext->getAccessibleRole(); + if ((0 <= iRoleIndex) && (o3tl::make_unsigned(iRoleIndex) < SAL_N_ELEMENTS(ROLE_TABLE))) + { + short iIA2Role = ROLE_TABLE[iRoleIndex][1] ; + m_pIMAcc->Put_XAccRole( iIA2Role ); + } + +} +/** + * update state information from uno to com + * @param + * @return + */ +void AccObject::UpdateState() +{ + if (!m_pIMAcc) + { + return; + } + + XAccessibleContext* pContext = m_xAccContextRef.get(); + Reference< XAccessibleStateSet > pRState = pContext->getAccessibleStateSet(); + if( !pRState.is() ) + { + assert(false); + return ; + } + + m_pIMAcc->SetState(0); + + if ( m_accRole == POPUP_MENU ) + { + return; + } + + Sequence<short> pStates = pRState->getStates(); + int count = pStates.getLength(); + + bool isEnable = false; + bool isShowing = false; + bool isEditable = false; + bool isVisible = false; + bool isFocusable = false; + + for( int iIndex = 0;iIndex < count;iIndex++ ) + { + if( pStates[iIndex] == ENABLED ) + isEnable = true; + else if( pStates[iIndex] == SHOWING) + isShowing = true; + else if( pStates[iIndex] == VISIBLE) + isVisible = true; + else if( pStates[iIndex] == EDITABLE ) + isEditable = true; + else if (pStates[iIndex] == FOCUSABLE) + isFocusable = true; + IncreaseState( pStates[iIndex]); + } + bool bIsMenuItem = m_accRole == MENU_ITEM || m_accRole == RADIO_MENU_ITEM || m_accRole == CHECK_MENU_ITEM; + + if(bIsMenuItem) + { + if(!(isShowing && isVisible) ) + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_INVISIBLE ); + m_pIMAcc->DecreaseState( STATE_SYSTEM_FOCUSABLE ); + } + } + else + { + if(!(isShowing || isVisible) ) + m_pIMAcc->IncreaseState( STATE_SYSTEM_INVISIBLE ); + } + + short Role = m_accRole; + + switch(m_accRole) + { + case LABEL: + case STATIC: + m_pIMAcc->IncreaseState( STATE_SYSTEM_READONLY ); + break; + case TEXT: + // 2. editable combobox -> readonly ------ bridge + case EMBEDDED_OBJECT: + case END_NOTE: + case FOOTER: + case FOOTNOTE: + case GRAPHIC: + case HEADER: + case HEADING: + + //Image Map + case PARAGRAPH: + case PASSWORD_TEXT: + case SHAPE: + case SPIN_BOX: + case TABLE: + case TABLE_CELL: + case TEXT_FRAME: + case DATE_EDITOR: + case DOCUMENT: + case COLUMN_HEADER: + { + if(!isEditable) + m_pIMAcc->IncreaseState( STATE_SYSTEM_READONLY ); + } + break; + default: + break; + } + + if( isEnable ) + { + + if(!(Role == FILLER || Role == END_NOTE || Role == FOOTER || Role == FOOTNOTE || Role == GROUP_BOX || Role == RULER + || Role == HEADER || Role == ICON || Role == INTERNAL_FRAME || Role == LABEL || Role == LAYERED_PANE + || Role == SCROLL_BAR || Role == SCROLL_PANE || Role == SPLIT_PANE || Role == STATIC || Role == STATUS_BAR + || Role == TOOL_TIP)) + { + if( SEPARATOR == Role ) + { + if( ( m_pParentObj != nullptr ) && ( MENU == m_pParentObj->m_accRole || POPUP_MENU == m_pParentObj->m_accRole )) + IncreaseState( FOCUSABLE ); + } + + else if (TABLE_CELL == Role || TABLE == Role || PANEL == Role || OPTION_PANE == Role || + COLUMN_HEADER == Role) + { + if (isFocusable) + IncreaseState( FOCUSABLE ); + } + else + { + if(bIsMenuItem) + { + if ( isShowing && isVisible) + { + IncreaseState( FOCUSABLE ); + } + } + else + { + IncreaseState( FOCUSABLE ); + } + } + } + } + else + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_UNAVAILABLE ); + if( !((Role == MENU_ITEM) || + (Role == RADIO_MENU_ITEM) || + (Role == CHECK_MENU_ITEM)) ) + { + if ( Role == TOGGLE_BUTTON || Role == PUSH_BUTTON || BUTTON_DROPDOWN == Role) + { + if(( m_pParentObj != nullptr )&& (TOOL_BAR == m_pParentObj->m_accRole ) ) + IncreaseState( FOCUSABLE ); + else + DecreaseState( FOCUSABLE ); + } + else + DecreaseState( FOCUSABLE ); + } + else if( isShowing || isVisible ) + { + IncreaseState( FOCUSABLE ); + } + } + + switch(m_accRole) + { + case POPUP_MENU: + case MENU: + if( pContext->getAccessibleChildCount() > 0 ) + m_pIMAcc->IncreaseState( STATE_SYSTEM_HASPOPUP ); + break; + case PASSWORD_TEXT: + m_pIMAcc->IncreaseState( STATE_SYSTEM_PROTECTED ); + break; + default: + break; + } +} + +/** + * update location information from uno to com + * @param + * @return + */ +void AccObject::UpdateLocation() +{ + if (!m_pIMAcc) + { + return; + } + XAccessibleContext* pContext = m_xAccContextRef.get(); + + Reference< XAccessibleComponent > pRComponent(pContext,UNO_QUERY); + if( pRComponent.is() ) + { + css::awt::Point pCPoint = pRComponent->getLocationOnScreen(); + css::awt::Size pCSize = pRComponent->getSize(); + Location tempLocation; + tempLocation.m_dLeft = pCPoint.X; + tempLocation.m_dTop = pCPoint.Y; + tempLocation.m_dWidth = pCSize.Width; + tempLocation.m_dHeight = pCSize.Height; + m_pIMAcc->Put_XAccLocation( tempLocation ); + } + +} + + +/** + * Public method to mapping information between MSAA and UNO. + * @param + * @return If the method is correctly processed. + */ +bool AccObject:: UpdateAccessibleInfoFromUnoToMSAA ( ) +{ + if( nullptr == m_pIMAcc || !m_xAccContextRef.is() ) + { + assert(false); + return false; + } + + UpdateName(); + + UpdateValue(); + + UpdateActionDesc(); + + UpdateRole(); + + UpdateLocation(); + + UpdateState(); + + return true; +} + +/* + * Add a child selected element. + * @param pAccObj Child object pointer. + * @return + */ +void AccObject::AddSelect( long index, AccObject* accObj) +{ + m_selectionList.emplace(index,accObj); +} + +IAccSelectionList& AccObject::GetSelection() +{ + return m_selectionList; +} + + +/** + * Set self to focus object in parent child list + * @param + * @return + */ +void AccObject::setFocus() +{ + if(m_pIMAcc) + { + IncreaseState(FOCUSED); + m_pIMAcc->Put_XAccFocus(CHILDID_SELF); + + UpdateRole(); + } +} + +/** + * Unset self from focus object in parent child list. + * @param + * @return + */ +void AccObject::unsetFocus() +{ + if(m_pIMAcc) + { + DecreaseState( FOCUSED ); + m_pIMAcc->Put_XAccFocus(UACC_NO_FOCUS); + } +} + +void AccObject::GetExpandedState( sal_Bool* isExpandable, sal_Bool* isExpanded) +{ + *isExpanded = false; + *isExpandable = false; + + if( !m_xAccContextRef.is() ) + { + return; + } + Reference< XAccessibleStateSet > pRState = m_xAccContextRef->getAccessibleStateSet(); + if( !pRState.is() ) + { + return; + } + + Sequence<short> pStates = pRState->getStates(); + int count = pStates.getLength(); + + for( int iIndex = 0;iIndex < count;iIndex++ ) + { + if( EXPANDED == pStates[iIndex] ) + { + *isExpanded = true; + } + else if( EXPANDABLE == pStates[iIndex] ) + { + *isExpandable = true; + } + } +} + +void AccObject::NotifyDestroy(bool ifDelete) +{ + m_bShouldDestroy=ifDelete; + if(m_pIMAcc) + m_pIMAcc->NotifyDestroy(m_bShouldDestroy); +} + +void AccObject::SetParentObj(AccObject* pParentAccObj) +{ + m_pParentObj = pParentAccObj; + + if(m_pIMAcc) + { + if(m_pParentObj) + { + m_pIMAcc->Put_XAccParent(m_pParentObj->GetIMAccessible()); + } + else + { + m_pIMAcc->Put_XAccParent(nullptr); + } + } +} +//ResID means ChildID in MSAA +void AccObject::SetResID(long id) +{ + m_resID = id; + if(m_pIMAcc) + m_pIMAcc->Put_XAccChildID(m_resID); +} +//return COM interface in acc object +IMAccessible* AccObject::GetIMAccessible() +{ + return m_pIMAcc; +} + +Reference<XAccessible> const& AccObject::GetXAccessible() +{ + return m_xAccRef; +} + +void AccObject::SetParentHWND(HWND hWnd) +{ + m_pParantID = hWnd; +} + +void AccObject::SetListener(rtl::Reference<AccEventListener> const& pListener) +{ + m_pListener = pListener; +} + +AccEventListener* AccObject::getListener() +{ + return m_pListener.get(); +} + +long AccObject::GetResID() +{ + return m_resID; +} + +HWND AccObject::GetParentHWND() +{ + return m_pParantID; +} + +AccObject* AccObject::GetParentObj() +{ + return m_pParentObj; +} +bool AccObject::ifShouldDestroy() +{ + return m_bShouldDestroy; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccObjectContainerEventListener.cxx b/winaccessibility/source/service/AccObjectContainerEventListener.cxx new file mode 100644 index 000000000..ccda6df4e --- /dev/null +++ b/winaccessibility/source/service/AccObjectContainerEventListener.cxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// AccObjectContainerEventListener.cpp: implementation of the AccContainerEventListener class. + + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <AccObjectContainerEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccObjectContainerEventListener::AccObjectContainerEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccContainerEventListener(pAcc, Agent) +{} +AccObjectContainerEventListener::~AccObjectContainerEventListener() +{ +} + +/** + * handle the STATE_CHANGED event + */ +void AccObjectContainerEventListener::HandleStateChangedEvent(Any oldValue, Any newValue) +{ + //set the accessible name before process for there is no NAME_CHANGED event when change + //the text in drawing objects. + short newV; + if( newValue >>= newV) + { + if (newV == AccessibleStateType::FOCUSED) + { + pAgent->UpdateAccName(m_xAccessible.get()); + pAgent->UpdateDescription(m_xAccessible.get()); + } + } + AccContainerEventListener::HandleStateChangedEvent(oldValue, newValue); +} +/** + * handle the VISIBLE_DATA_CHANGED event + * For SHAPES, the visible_data_changed event should be mapped to LOCATION_CHANGED event + */ +void AccObjectContainerEventListener::HandleVisibleDataChangedEvent() +{ + AccContainerEventListener::HandleBoundrectChangedEvent(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccObjectManagerAgent.cxx b/winaccessibility/source/service/AccObjectManagerAgent.cxx new file mode 100644 index 000000000..abc75f71c --- /dev/null +++ b/winaccessibility/source/service/AccObjectManagerAgent.cxx @@ -0,0 +1,404 @@ +/* -*- 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 <AccObjectManagerAgent.hxx> +#include <AccObjectWinManager.hxx> + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnon-virtual-dtor" +#endif +#include <UAccCOM.h> +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +/** + * Construction/Destruction. + * @param + * @return + */ +AccObjectManagerAgent::AccObjectManagerAgent() + : pWinManager(new AccObjectWinManager(this)) +{ +} + +AccObjectManagerAgent::~AccObjectManagerAgent() +{ +} + +/** + * Interface of updating MSAA name when UNO name_changed event occurs. + * @param pXAcc Uno XAccessible interface of control. + * @return + */ +void AccObjectManagerAgent::UpdateAccName( XAccessible* pXAcc ) +{ + if( pWinManager ) + pWinManager->UpdateAccName( pXAcc ); +} + +/** + * Interface of updating MSAA name when UNO action changed event occurs. + * @param pXAcc Uno XAccessible interface of control. + * @return + */ +void AccObjectManagerAgent::UpdateAction( XAccessible* pXAcc ) +{ + if( pWinManager ) + pWinManager->UpdateAction( pXAcc ); +} + +/** + * Interface of updating MSAA value when UNO value_changed event occurs. + * @param pXAcc Uno XAccessible interface of control. + * @param pAny New value. + * @return + */ +void AccObjectManagerAgent::UpdateValue( XAccessible* pXAcc, Any pAny ) +{ + if( pWinManager ) + pWinManager->SetValue( pXAcc, pAny ); +} + +/** + * Interface of updating MSAA value when UNO value_changed event occurs. If we can not + * find new value, we'll get new value from pXAcc to update com value. + * @param pXAcc Uno XAccessible interface of control. + * @return + */ +void AccObjectManagerAgent::UpdateValue( XAccessible* pXAcc ) +{ + if( pWinManager ) + pWinManager->UpdateValue( pXAcc ); +} + +/** + * Interface of updating MSAA name when UNO name_changed event occurs. + * @param pXAcc Uno XAccessible interface of control. + * @param newName New UNO accessible name. + * @return + */ +void AccObjectManagerAgent::UpdateAccName( XAccessible* pXAcc, Any newName) +{ + if( pWinManager ) + pWinManager->SetAccName( pXAcc, newName ); +} + + +/** + * Interface of updating MSAA location when UNO location_changed event occurs. + * @param pXAcc Uno XAccessible interface of control. + * @param pXAcc Uno The top position of new location. + * @param pXAcc Uno The left position of new location. + * @param pXAcc Uno The width of new location. + * @param pXAcc Uno The width of new location. + * @return + */ +void AccObjectManagerAgent::UpdateLocation( XAccessible* /* pXAcc */, long /*top*/, long /*left*/, long /*width*/, long /*height*/ ) +{ +#ifdef _IMPL_WIN + if( pWinManager ) + pWinManager->SetLocation( pXAcc, top, left, width, height ); +#endif +} + +/** + * Interface of updating MSAA name when UNO description_changed event occurs. + * @param pXAcc Uno XAccessible interface of control. + * @param newDesc New UNO accessible description. + * @return + */ +void AccObjectManagerAgent::UpdateDescription( XAccessible* pXAcc, Any newDesc ) +{ + if( pWinManager ) + pWinManager->SetDescription( pXAcc, newDesc ); +} + +/** + * When a new UNO XAccessible object is found by listener, we create a corresponding + * com object and insert it to our manager list. + * @param pXAcc Uno XAccessible interface of control. + * @param pWnd The top window handle containing control. + * @return If the method is correctly processed. + */ +bool AccObjectManagerAgent::InsertAccObj( + XAccessible* pXAcc, XAccessible* pParentXAcc, sal_Int64 nWnd) +{ + if( pWinManager ) + return pWinManager->InsertAccObj(pXAcc, pParentXAcc, + static_cast<HWND>(reinterpret_cast<void*>(nWnd))); + + return false; +} + +/** + * save the pair <topwindowhandle, XAccessible> + * @param hWnd, top window handle + * @param pXAcc XAccessible interface for top window + * @return void + */ +void +AccObjectManagerAgent::SaveTopWindowHandle(sal_Int64 hWnd, XAccessible* pXAcc) +{ + if( pWinManager ) + pWinManager->SaveTopWindowHandle( + static_cast<HWND>(reinterpret_cast<void*>(hWnd)), pXAcc); +} + + +/** + * When a UNO XAccessible object's new children are found by listener, we create + * corresponding com objects and insert them to our manager list. + * @param pXAcc Uno XAccessible interface of control. + * @param pWnd The top window handle containing control. + * @return If the method is correctly processed. + */ +bool +AccObjectManagerAgent::InsertChildrenAccObj(XAccessible* pXAcc, sal_Int64 pWnd) +{ + if( pWinManager ) + return pWinManager->InsertChildrenAccObj( pXAcc, HWND(reinterpret_cast<void*>(pWnd)) ); + + return false; +} + +/** + * When a new UNO XAccessible object is destroyed, we delete its corresponding + * com object and remove it from our manager list. + * @param pXAcc Uno XAccessible interface of control. + * @return + */ +void AccObjectManagerAgent::DeleteAccObj( XAccessible* pXAcc ) +{ + if( pWinManager ) + pWinManager->DeleteAccObj( pXAcc ); +} + +/** + * When new UNO children XAccessible objects are destroyed, we delete their + * corresponding com objects and remove them from our manager list. + * @param pXAcc Uno XAccessible interface of control. + * @return + */ +void AccObjectManagerAgent::DeleteChildrenAccObj( XAccessible* pXAcc ) +{ + if( pWinManager ) + pWinManager->DeleteChildrenAccObj( pXAcc ); +} + +/** + * Interface of decreasing MSAA state when some UNO state is decreased. + * @param pXAcc Uno XAccessible interface of control. + * @param pState The lost state of control. + * @return + */ +void AccObjectManagerAgent::DecreaseState( XAccessible* pXAcc,unsigned short pState ) +{ + if(pWinManager) + { + pWinManager->DecreaseState( pXAcc, pState ); + } +} + +/** + * Interface of increasing MSAA name when some UNO state is increased. + * @param pXAcc Uno XAccessible interface of control. + * @param pState The new state of control. + * @return + */ +void AccObjectManagerAgent::IncreaseState( XAccessible* pXAcc,unsigned short pState ) +{ + if(pWinManager) + { + pWinManager->IncreaseState( pXAcc, pState ); + } +} + +void AccObjectManagerAgent::UpdateState( css::accessibility::XAccessible* pXAcc ) +{ + if(pWinManager) + pWinManager->UpdateState(pXAcc); +} + +/** + * Interface of notify MSAA event when some UNO event occurred. + * @param pXAcc Uno XAccessible interface of control. + * @param pEvent UNO event ID. + * @return If the method is correctly processed. + */ +bool AccObjectManagerAgent::NotifyAccEvent(short pEvent, XAccessible* pXAcc) +{ + if(pWinManager) + return pWinManager->NotifyAccEvent(pXAcc,pEvent); + + return false; +} + +/** + * Judge whether a XAccessible object is a container object. + * @param pXAcc Uno XAccessible interface of control. + * @return If the method is correctly processed. + */ +bool AccObjectManagerAgent::IsContainer( XAccessible* pXAcc ) +{ + if(pWinManager) + return AccObjectWinManager::IsContainer(pXAcc); + + return false; +} + +/** + * Return com object interface by querying XAccessible interface. + * @param pXAcc Uno XAccessible interface of control. + * @return Com interface. + */ +IMAccessible* AccObjectManagerAgent::GetIMAccByXAcc(XAccessible* pXAcc) +{ + if(pWinManager) + return pWinManager->GetIMAccByXAcc(pXAcc); + + return nullptr; +} + +/** + * Notify manager when a XAccessible object is destroying. + * @param pXAcc Uno XAccessible interface of control. + * @return. + */ +void AccObjectManagerAgent::NotifyDestroy(XAccessible* pXAcc) +{ + if(pWinManager) + pWinManager->NotifyDestroy(pXAcc); +} + +/** + * Return com object interface by querying child id. + * @param pXAcc Uno XAccessible interface of control. + * @return Com interface. + */ +void AccObjectManagerAgent::GetIAccessibleFromResID(long childID,IMAccessible** pIMAcc) +{ + if(pWinManager) + *pIMAcc = pWinManager->GetIAccessibleFromResID(childID); +} + +/** + * Return object interface by querying interface. + * @param pXAcc Uno XAccessible interface of control. + * @return Com interface. + */ +bool AccObjectManagerAgent::GetIAccessibleFromXAccessible( + XAccessible* pXAcc, IAccessible** ppXI) +{ + if(pWinManager) + { + *ppXI = reinterpret_cast<IAccessible*>(pWinManager->GetIMAccByXAcc(pXAcc)); + if(*ppXI) + return true; + } + return false; +} + +XAccessible* AccObjectManagerAgent::GetParentXAccessible( XAccessible* pXAcc ) +{ + if(pWinManager) + return pWinManager->GetParentXAccessible( pXAcc ); + + return nullptr; +} + +short AccObjectManagerAgent::GetParentRole( XAccessible* pXAcc ) +{ + if(pWinManager) + return pWinManager->GetParentRole( pXAcc ); + + return -1; +} + +void AccObjectManagerAgent::UpdateDescription( XAccessible* pXAcc ) +{ + if(pWinManager) + pWinManager->UpdateDescription( pXAcc ); +} + +void AccObjectManagerAgent::UpdateChildState(XAccessible* pXAcc) +{ + if(pWinManager) + pWinManager->UpdateChildState( pXAcc ); +} + + +bool AccObjectManagerAgent::IsSpecialToolboItem(XAccessible* pXAcc) +{ + if(pWinManager) + return pWinManager->IsSpecialToolboItem( pXAcc ); + + return false; +} + +short AccObjectManagerAgent::GetRole(XAccessible* pXAcc) +{ + if(pWinManager) + return AccObjectWinManager::GetRole( pXAcc ); + + return -1; +} + +XAccessible* AccObjectManagerAgent::GetAccDocByAccTopWin( XAccessible* pXAcc ) +{ + if (pWinManager) + { + return pWinManager->GetAccDocByAccTopWin( pXAcc ); + } + return nullptr; +} +bool AccObjectManagerAgent::IsTopWinAcc(XAccessible* pXAcc) +{ + if (pWinManager) + { + return pWinManager->IsTopWinAcc( pXAcc ); + } + return NULL; +} + +bool AccObjectManagerAgent::IsStateManageDescendant(XAccessible* pXAcc) +{ + if(pWinManager) + return AccObjectWinManager::IsStateManageDescendant( pXAcc ); + + return false; +} + +/** + * Implementation of interface XMSAAService's method getAccObjectPtr() + * that returns the corresponding COM interface with the MS event. + * @return Com interface. + */ +sal_Int64 AccObjectManagerAgent::Get_ToATInterface( + sal_Int64 hWnd, sal_Int64 lParam, sal_Int64 wParam) +{ + return static_cast<sal_Int64>(pWinManager->Get_ToATInterface( + static_cast<HWND>(reinterpret_cast<void*>(hWnd)), lParam, wParam)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccObjectWinManager.cxx b/winaccessibility/source/service/AccObjectWinManager.cxx new file mode 100644 index 000000000..b56db56d4 --- /dev/null +++ b/winaccessibility/source/service/AccObjectWinManager.cxx @@ -0,0 +1,1244 @@ +/* -*- 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/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 std; +using namespace com::sun::star::accessibility; +using namespace com::sun::star::accessibility::AccessibleRole; +using namespace com::sun::star::accessibility::AccessibleStateType; +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(); +#ifdef ACC_DEBUG + + fclose( pFile ); +#endif +} + + +/** + * 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 = static_cast<XAccessible*>(iterResult->second); + return GetAccObjByXAcc(pXAcc); +} + +/** + * Simulate MSAA event via XAccessible interface and event type. + * @param pXAcc XAccessible interface. + * @param state Customize Interface + * @return The terminate result that identifies if the call is successful. + */ +bool AccObjectWinManager::NotifyAccEvent(XAccessible* pXAcc,short state) +{ + 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(state) + { + case UM_EVENT_STATE_FOCUSED: + { + UpdateAccFocus(pXAcc); + selfAccObj->UpdateDefaultAction( ); + UpdateValue(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + } + case UM_EVENT_STATE_BUSY: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_STATE_CHECKED: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_STATE_PRESSED: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + + //Removed fire out selected event + //case UM_EVENT_STATE_SELECTED: + // NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + // break; + case UM_EVENT_STATE_ARMED: + UpdateAccFocus(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_MENU_START: + NotifyWinEvent( EVENT_SYSTEM_MENUSTART,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_MENU_END: + NotifyWinEvent( EVENT_SYSTEM_MENUEND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_MENUPOPUPSTART: + NotifyWinEvent( EVENT_SYSTEM_MENUPOPUPSTART,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_MENUPOPUPEND: + NotifyWinEvent( EVENT_SYSTEM_MENUPOPUPEND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SELECTION_CHANGED: + NotifyWinEvent( EVENT_OBJECT_SELECTION,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SELECTION_CHANGED_ADD: + NotifyWinEvent( EVENT_OBJECT_SELECTIONADD,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SELECTION_CHANGED_REMOVE: + NotifyWinEvent( EVENT_OBJECT_SELECTIONREMOVE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SELECTION_CHANGED_WITHIN: + NotifyWinEvent( EVENT_OBJECT_SELECTIONWITHIN,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_VALUECHANGE: + UpdateValue(pXAcc); + NotifyWinEvent( EVENT_OBJECT_VALUECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_NAMECHANGE: + NotifyWinEvent( EVENT_OBJECT_NAMECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_DESCRIPTIONCHANGE: + NotifyWinEvent( EVENT_OBJECT_DESCRIPTIONCHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_DEFACTIONCHANGE: + NotifyWinEvent( IA2_EVENT_ACTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_CARETCHANGE: + NotifyWinEvent( IA2_EVENT_TEXT_CARET_MOVED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_TEXTCHANGE: + NotifyWinEvent( IA2_EVENT_TEXT_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_ACTIVE_DESCENDANT_CHANGED: + UpdateAccFocus(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_BOUNDRECT_CHANGED: + NotifyWinEvent( EVENT_OBJECT_LOCATIONCHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_VISIBLE_DATA_CHANGED: + NotifyWinEvent( IA2_EVENT_VISIBLE_DATA_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SHOW : + NotifyWinEvent( EVENT_OBJECT_SHOW,hAcc, OBJID_CLIENT,dChildID ); + NotifyWinEvent( EVENT_SYSTEM_FOREGROUND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_CAPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_CAPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_COLUMN_HEADER_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_MODEL_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_MODEL_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_ROW_HEADER_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_ROW_HEADER_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_SUMMARY_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_SUMMARY_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TABLE_ROW_DESCRIPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_REORDER: + NotifyWinEvent( EVENT_OBJECT_REORDER,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_PAGE_CHANGED: + NotifyWinEvent( IA2_EVENT_PAGE_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_CHILD_REMOVED: + NotifyWinEvent( EVENT_OBJECT_DESTROY,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_CHILD_ADDED: + NotifyWinEvent( EVENT_OBJECT_CREATE ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_OBJECT_PAGECHANGED: + NotifyWinEvent( IA2_EVENT_PAGE_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_TEXT_SELECTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TEXT_SELECTION_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_SECTION_CHANGED: + NotifyWinEvent( IA2_EVENT_SECTION_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UM_EVENT_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); + DeleteFromHwndXAcc(pXAcc); + if( accObj.GetRole() == DOCUMENT || + accObj.GetRole() == DOCUMENT_PRESENTATION || + accObj.GetRole() == DOCUMENT_SPREADSHEET || + accObj.GetRole() == 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() == DOCUMENT || + pObj.GetRole() == DOCUMENT_PRESENTATION || + pObj.GetRole() == DOCUMENT_SPREADSHEET || + pObj.GetRole() == 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.get()); + 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 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(); +} + +void AccObjectWinManager::UpdateDescription( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if ( pAccObj ) + pAccObj->UpdateDescription(); +} + +/** + * 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 ); +} + +/** + * Set corresponding com object's description via XAccessible interface and new description. + * @param pXAcc XAccessible interface. + * @param newDesc new description + * @return + */ +void AccObjectWinManager::SetDescription( XAccessible* pXAcc, Any newDesc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->SetDescription( newDesc ); +} + +/** + * Set corresponding com object's role via XAccessible interface and new role. + * @param pXAcc XAccessible interface. + * @param Role new role + * @return + */ +void AccObjectWinManager::SetRole( XAccessible* pXAcc, long Role ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->SetRole( static_cast<short>(Role) ); +} + +/** + * 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; + break; + case /*AccessibleRole::*/COLUMN_HEADER: + case /*AccessibleRole::*/TABLE: + if(!IsStateManageDescendant(pAccessible)) + return true; + break; + case /*AccessibleRole::*/MENU: + return true; + break; + 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; + + Sequence<short> pStates = pRState->getStates(); + int count = pStates.getLength(); + for( int iIndex = 0;iIndex < count;iIndex++ ) + { + if(pStates[iIndex] == /*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(true); + } +} + + +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::IsSpecialToolboItem(css::accessibility::XAccessible* pXAcc) +{ + if (pXAcc && oldFocus != pXAcc) + { + if(GetParentRole(pXAcc) == TOOL_BAR) + { + Reference< XAccessibleContext > pRContext(pXAcc->getAccessibleContext()); + if (pRContext.is()) + { + if(pRContext->getAccessibleRole() == TOGGLE_BUTTON) + { + return true; + } + } + } + } + return false; +} + +short AccObjectWinManager::GetRole(css::accessibility::XAccessible* pXAcc) +{ + assert(pXAcc != nullptr); + Reference<css::accessibility::XAccessibleContext> xContext = pXAcc->getAccessibleContext(); + if(xContext.is()) + { + return xContext->getAccessibleRole(); + } + return -1; +} + +XAccessible* AccObjectWinManager::GetAccDocByHWND(HWND pWnd) +{ + XHWNDToDocumentHash::iterator aIter; + aIter = XHWNDDocList.find( pWnd ); + if ( aIter != XHWNDDocList.end() ) + { + return aIter->second; + } + + return nullptr; +} + +XAccessible* AccObjectWinManager::GetAccDocByAccTopWin( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + HWND hWnd = pAccObj->GetParentHWND(); + return GetAccDocByHWND(hWnd); +} + +bool AccObjectWinManager::IsTopWinAcc( css::accessibility::XAccessible* pXAcc ) +{ + bool bRet = false; + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if ( pAccObj ) + { + bRet = ( pAccObj->GetParentObj() == nullptr ); + } + return bRet; +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccParagraphEventListener.cxx b/winaccessibility/source/service/AccParagraphEventListener.cxx new file mode 100644 index 000000000..55d7eecf7 --- /dev/null +++ b/winaccessibility/source/service/AccParagraphEventListener.cxx @@ -0,0 +1,131 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccParagraphEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccParagraphEventListener::AccParagraphEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccContainerEventListener(pAcc, Agent) +{} +AccParagraphEventListener::~AccParagraphEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccParagraphEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::CARET_CHANGED: + HandleCaretChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + //Added for paragraph selected state. + case AccessibleEventId::STATE_CHANGED: + { + short State; + if( (aEvent.NewValue >>= State) && (State == AccessibleStateType::SELECTED) ) + { + pAgent->IncreaseState(m_xAccessible.get(), State); + break; + } + else if( (aEvent.OldValue >>= State) && (State == AccessibleStateType::SELECTED) ) + { + pAgent->DecreaseState(m_xAccessible.get(), State); + break; + } + + AccContainerEventListener::notifyEvent(aEvent); + break; + } + + case AccessibleEventId::TEXT_SELECTION_CHANGED: + HandleTextSelectionChangedEvent(); + break; + + default: + AccContainerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the CARET_CHANGED event + * @param oldValue in UNO, this parameter is always NULL + * @param newValue in UNO, this parameter is always NULL + */ +void AccParagraphEventListener::HandleCaretChangedEvent(Any, Any) +{ + AccObjectManagerAgent::UpdateLocation(m_xAccessible.get()); + pAgent->NotifyAccEvent(UM_EVENT_OBJECT_CARETCHANGE, m_xAccessible.get()); +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccParagraphEventListener::SetComponentState(short state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::EDITABLE: + // no msaa state + break; + case AccessibleStateType::MULTI_LINE: + // no msaa state mapping + break; + case AccessibleStateType::SINGLE_LINE: + // no msaa state mapping + break; + default: + AccContainerEventListener::SetComponentState(state, enable); + break; + } +} + +void AccParagraphEventListener::HandleTextSelectionChangedEvent() +{ + pAgent->NotifyAccEvent(UM_EVENT_TEXT_SELECTION_CHANGED, m_xAccessible.get()); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTableEventListener.cxx b/winaccessibility/source/service/AccTableEventListener.cxx new file mode 100644 index 000000000..7e8add454 --- /dev/null +++ b/winaccessibility/source/service/AccTableEventListener.cxx @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp> + +#include <vcl/svapp.hxx> + +#include <AccTableEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccTableEventListener::AccTableEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccDescendantManagerEventListener(pAcc, Agent) +{} +AccTableEventListener::~AccTableEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccTableEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + HandleActiveDescendantChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + + case AccessibleEventId::TABLE_CAPTION_CHANGED: + { + + pAgent->NotifyAccEvent(UM_EVENT_TABLE_CAPTION_CHANGED, m_xAccessible.get()); + break; + } + case AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED: + { + + pAgent->NotifyAccEvent(UM_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED, m_xAccessible.get()); + break; + } + case AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED: + { + + pAgent->NotifyAccEvent(UM_EVENT_TABLE_COLUMN_HEADER_CHANGED, m_xAccessible.get()); + break; + } + case AccessibleEventId::TABLE_ROW_HEADER_CHANGED: + { + + pAgent->NotifyAccEvent(UM_EVENT_TABLE_ROW_HEADER_CHANGED, m_xAccessible.get()); + break; + } + case AccessibleEventId::TABLE_MODEL_CHANGED: + { + + HandleTableModelChangeEvent(aEvent.NewValue); + break; + } + case AccessibleEventId::TABLE_SUMMARY_CHANGED: + { + + pAgent->NotifyAccEvent(UM_EVENT_TABLE_SUMMARY_CHANGED, m_xAccessible.get()); + break; + } + case AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED: + { + + pAgent->NotifyAccEvent(UM_EVENT_TABLE_ROW_DESCRIPTION_CHANGED, m_xAccessible.get()); + break; + } + default: + AccDescendantManagerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the ACTIVE_DESCENDANT_CHANGED event + * @param oldValue the child to lose active + * @param newValue the child to get active + */ +void AccTableEventListener::HandleActiveDescendantChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->InsertAccObj(pAcc, m_xAccessible.get()); + pAgent->NotifyAccEvent(UM_EVENT_ACTIVE_DESCENDANT_CHANGED, pAcc); + } + } + else if (oldValue >>= xChild) + { + //delete an existing child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->DeleteAccObj( pAcc ); + } + } + +} +void AccTableEventListener::HandleTableModelChangeEvent(Any newValue) +{ + AccessibleTableModelChange aModelChange; + if (newValue >>= aModelChange) + { + if (m_xAccessible.is()) + { + //delete all oldValue's existing children + pAgent->DeleteChildrenAccObj(m_xAccessible.get()); + //add all oldValue's existing children + pAgent->InsertChildrenAccObj(m_xAccessible.get()); + } + pAgent->NotifyAccEvent(UM_EVENT_TABLE_MODEL_CHANGED, m_xAccessible.get()); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTextComponentEventListener.cxx b/winaccessibility/source/service/AccTextComponentEventListener.cxx new file mode 100644 index 000000000..1a185b0d8 --- /dev/null +++ b/winaccessibility/source/service/AccTextComponentEventListener.cxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccTextComponentEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccTextComponentEventListener::AccTextComponentEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccComponentEventListener(pAcc, Agent) +{} +AccTextComponentEventListener::~AccTextComponentEventListener() +{ +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccTextComponentEventListener::SetComponentState(short state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::EDITABLE: + // no msaa state mapping + break; + case AccessibleStateType::MULTI_LINE: + // no msaa state mapping + break; + case AccessibleStateType::SINGLE_LINE: + // no msaa state mapping + break; + default: + AccComponentEventListener::SetComponentState(state, enable); + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTopWindowListener.cxx b/winaccessibility/source/service/AccTopWindowListener.cxx new file mode 100644 index 000000000..bcb821771 --- /dev/null +++ b/winaccessibility/source/service/AccTopWindowListener.cxx @@ -0,0 +1,256 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <sal/log.hxx> +#include <vcl/window.hxx> +#include <toolkit/awt/vclxaccessiblecomponent.hxx> +#include <toolkit/awt/vclxwindow.hxx> + +#include <vcl/sysdata.hxx> +#include <vcl/svapp.hxx> + +#include <AccTopWindowListener.hxx> +#include <unomsaaevent.hxx> + +#include <com/sun/star/accessibility/AccessibleRole.hpp> + +using namespace com::sun::star::uno; + +/** + * For the new opened window, generate all the UNO accessible's object, COM object and add + * accessible listener to monitor all these objects. + * @param pAccessible the accessible of the new opened window + */ +void AccTopWindowListener::HandleWindowOpened( css::accessibility::XAccessible* pAccessible ) +{ + //get SystemData from window + VclPtr<vcl::Window> window; + if (auto pvclwindow = dynamic_cast<VCLXWindow*>(pAccessible)) + window = pvclwindow->GetWindow(); + else if (auto pvclxcomponent = dynamic_cast<VCLXAccessibleComponent*>(pAccessible)) + window = pvclxcomponent->GetWindow(); + assert(window); + // The SalFrame of window may be destructed at this time + const SystemEnvData* systemdata = nullptr; + try + { + systemdata = window->GetSystemData(); + } + catch(...) + { + systemdata = nullptr; + } + Reference<css::accessibility::XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(!xContext.is()) + return; + + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + //Only AccessibleContext exist, add all listeners + if(pAccessibleContext != nullptr && systemdata != nullptr) + { + accManagerAgent.SaveTopWindowHandle( + reinterpret_cast<sal_Int64>(systemdata->hWnd), pAccessible); + + AddAllListeners(pAccessible,nullptr,systemdata->hWnd); + + if( window->GetStyle() & WB_MOVEABLE ) + accManagerAgent.IncreaseState( pAccessible, static_cast<unsigned short>(-1) /* U_MOVEBLE */ ); + + short role = pAccessibleContext->getAccessibleRole(); + + if (role == css::accessibility::AccessibleRole::POPUP_MENU || + role == css::accessibility::AccessibleRole::MENU ) + { + accManagerAgent.NotifyAccEvent(UM_EVENT_MENUPOPUPSTART, pAccessible); + } + + if (role == css::accessibility::AccessibleRole::FRAME || + role == css::accessibility::AccessibleRole::DIALOG || + role == css::accessibility::AccessibleRole::WINDOW || + role == css::accessibility::AccessibleRole::ALERT) + { + accManagerAgent.NotifyAccEvent(UM_EVENT_SHOW, pAccessible); + } + } +} + +AccTopWindowListener::AccTopWindowListener() + : accManagerAgent() +{ +} + +AccTopWindowListener::~AccTopWindowListener() +{ +} + +/** + * It is invoked when a new window is opened, the source of this EventObject is the window + */ +void AccTopWindowListener::windowOpened( const css::lang::EventObject& e ) +{ + SAL_INFO( "iacc2", "windowOpened triggered" ); + + if ( !e.Source.is()) + return; + + Reference< css::accessibility::XAccessible > xAccessible ( e.Source, UNO_QUERY ); + css::accessibility::XAccessible* pAccessible = xAccessible.get(); + if ( !pAccessible ) + return; + + SolarMutexGuard g; + + HandleWindowOpened( pAccessible ); +} + +/** + * Add the accessible event listener to object and all its children objects. + * @param pAccessible the accessible object + * @param pParentXAcc the parent of current accessible object + * @param pWND the handle of top window which current object resides + */ +void AccTopWindowListener::AddAllListeners(css::accessibility::XAccessible* pAccessible, css::accessibility::XAccessible* pParentXAcc, HWND pWND) +{ + Reference<css::accessibility::XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(!xContext.is()) + { + return; + } + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + if(pAccessibleContext == nullptr) + { + return; + } + + accManagerAgent.InsertAccObj(pAccessible, pParentXAcc, + reinterpret_cast<sal_Int64>(pWND)); + + if (!accManagerAgent.IsContainer(pAccessible)) + { + return; + } + + + short role = pAccessibleContext->getAccessibleRole(); + if(css::accessibility::AccessibleRole::DOCUMENT == role || + css::accessibility::AccessibleRole::DOCUMENT_PRESENTATION == role || + css::accessibility::AccessibleRole::DOCUMENT_SPREADSHEET == role || + css::accessibility::AccessibleRole::DOCUMENT_TEXT == role) + { + if(accManagerAgent.IsStateManageDescendant(pAccessible)) + { + return ; + } + } + + + int count = pAccessibleContext->getAccessibleChildCount(); + for (int i=0;i<count;i++) + { + Reference<css::accessibility::XAccessible> mxAccessible + = pAccessibleContext->getAccessibleChild(i); + + css::accessibility::XAccessible* mpAccessible = mxAccessible.get(); + if(mpAccessible != nullptr) + { + Reference<css::accessibility::XAccessibleContext> mxAccessibleContext + = mpAccessible->getAccessibleContext(); + css::accessibility::XAccessibleContext* mpContext = mxAccessibleContext.get(); + if(mpContext != nullptr) + AddAllListeners( mpAccessible, pAccessible, pWND); + } + } +} + +void AccTopWindowListener::windowClosing( const css::lang::EventObject& ) +{ + SAL_INFO( "iacc2", "windowClosing triggered" ); +} + +/** + * Invoke this method when the top window is closed, remove all the objects and its children + * from current manager's cache, and remove the COM object and the accessible event listener + * assigned to the accessible objects. + */ +void AccTopWindowListener::windowClosed( const css::lang::EventObject& e ) +{ + SAL_INFO( "iacc2", "windowClosed triggered" ); + + if ( !e.Source.is()) + return; + + Reference< css::accessibility::XAccessible > xAccessible ( e.Source, UNO_QUERY ); + css::accessibility::XAccessible* pAccessible = xAccessible.get(); + if ( pAccessible == nullptr) + return; + + Reference<css::accessibility::XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(!xContext.is()) + { + return; + } + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + + short role = -1; + if(pAccessibleContext != nullptr) + { + role = pAccessibleContext->getAccessibleRole(); + + if (role == css::accessibility::AccessibleRole::POPUP_MENU || + role == css::accessibility::AccessibleRole::MENU) + { + accManagerAgent.NotifyAccEvent(UM_EVENT_MENUPOPUPEND, pAccessible); + } + } + + + accManagerAgent.DeleteChildrenAccObj( pAccessible ); + if( role != css::accessibility::AccessibleRole::POPUP_MENU ) + accManagerAgent.DeleteAccObj( pAccessible ); + +} + +void AccTopWindowListener::windowMinimized( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::windowNormalized( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::windowActivated( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::windowDeactivated( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::disposing( const css::lang::EventObject& ) +{ +} + +sal_Int64 AccTopWindowListener::GetMSComPtr( + sal_Int64 hWnd, sal_Int64 lParam, sal_Int64 wParam) +{ + return accManagerAgent.Get_ToATInterface(hWnd, lParam, wParam); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTreeEventListener.cxx b/winaccessibility/source/service/AccTreeEventListener.cxx new file mode 100644 index 000000000..bf5aceb8d --- /dev/null +++ b/winaccessibility/source/service/AccTreeEventListener.cxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccTreeEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccTreeEventListener::AccTreeEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccDescendantManagerEventListener(pAcc, Agent) +{} +AccTreeEventListener::~AccTreeEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccTreeEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + HandleActiveDescendantChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccDescendantManagerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the ACTIVE_DESCENDANT_CHANGED event + * @param oldValue the child to lose active + * @param newValue the child to get active + */ +void AccTreeEventListener::HandleActiveDescendantChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->InsertAccObj(pAcc, m_xAccessible.get()); + pAgent->NotifyAccEvent(UM_EVENT_ACTIVE_DESCENDANT_CHANGED, pAcc); + } + } + if (oldValue >>= xChild) + { + //delete an existing child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->DeleteAccObj( pAcc ); + } + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccWindowEventListener.cxx b/winaccessibility/source/service/AccWindowEventListener.cxx new file mode 100644 index 000000000..c079cc6ed --- /dev/null +++ b/winaccessibility/source/service/AccWindowEventListener.cxx @@ -0,0 +1,136 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccWindowEventListener.hxx> +#include <AccObjectManagerAgent.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccWindowEventListener::AccWindowEventListener(css::accessibility::XAccessible* pAcc, AccObjectManagerAgent* Agent) + :AccEventListener(pAcc, Agent) +{} +AccWindowEventListener::~AccWindowEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject: the event object which contains information about event + */ +void AccWindowEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::CHILD: + HandleChildChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the CHILD event + * @param oldValue the child to be deleted + * @param newValue the child to be added + */ +void AccWindowEventListener::HandleChildChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if( newValue >>= xChild) + { + //create a new child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + //add this child + pAgent->InsertAccObj(pAcc, m_xAccessible.get()); + //add all oldValue's existing children + pAgent->InsertChildrenAccObj(pAcc); + pAgent->NotifyAccEvent(UM_EVENT_CHILD_ADDED, pAcc); + } + } + else if (oldValue >>= xChild) + { + //delete an existing child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + pAgent->NotifyAccEvent(UM_EVENT_CHILD_REMOVED, pAcc); + pAgent->DeleteChildrenAccObj( pAcc ); + //delete this child + pAgent->DeleteAccObj( pAcc ); + } + } +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccWindowEventListener::SetComponentState(short state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::ICONIFIED: + // no msaa state + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + if( enable ) + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + else + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + case AccessibleStateType::SHOWING: + // UNO !SHOWING == MSAA OFFSCREEN + if( enable ) + { + pAgent->IncreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + } + else + pAgent->DecreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/ResIDGenerator.cxx b/winaccessibility/source/service/ResIDGenerator.cxx new file mode 100644 index 000000000..fafb236c7 --- /dev/null +++ b/winaccessibility/source/service/ResIDGenerator.cxx @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ResIDGenerator.hxx> + +#include <cassert> + +ResIDGenerator::~ResIDGenerator() +{ +} + +/** + * SubList stores those IDs that were ever generated and deleted, the method + * return the ID from subList first if subList is not empty,else return ++max. + * Add the obsolete IDs by calling SetSub method + * + * @param + * @return new resource ID. + */ +long ResIDGenerator::GenerateNewResID() +{ + if (!subList.empty()) + { + long nRes = *(subList.begin()); + subList.pop_front(); + return nRes; + } + assert(max < LONG_MAX); + return -(++max); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/msaaservice_impl.cxx b/winaccessibility/source/service/msaaservice_impl.cxx new file mode 100644 index 000000000..02ac891f5 --- /dev/null +++ b/winaccessibility/source/service/msaaservice_impl.cxx @@ -0,0 +1,314 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <rtl/ref.hxx> +#include <sal/log.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/accessibility/XMSAAService.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> + +#include <com/sun/star/awt/XExtendedToolkit.hpp> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> + +#include <prewin.h> +#include <postwin.h> + +using namespace ::com::sun::star; // for odk interfaces +using namespace ::com::sun::star::uno; // for basic types +using namespace ::com::sun::star::accessibility; + +using namespace ::com::sun::star::awt; + +#include <AccTopWindowListener.hxx> + +namespace my_sc_impl +{ + +static Sequence< OUString > getSupportedServiceNames_MSAAServiceImpl() +{ + Sequence< OUString > seqNames { "com.sun.star.accessibility.MSAAService" }; + return seqNames; +} + +static OUString getImplementationName_MSAAServiceImpl() +{ + return "com.sun.star.accessibility.my_sc_implementation.MSAAService"; +} + +namespace { + +class MSAAServiceImpl : public ::cppu::WeakImplHelper< + XMSAAService, lang::XServiceInfo > +{ +private: + rtl::Reference<AccTopWindowListener> m_pTopWindowListener; + +public: + MSAAServiceImpl (); + + // XComponent - as used by VCL to lifecycle manage this bridge. + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& ) override + { /* dummy */ } + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& ) override + { /* dummy */ } + + // XMSAAService + virtual sal_Int64 SAL_CALL getAccObjectPtr( + sal_Int64 hWnd, sal_Int64 lParam, sal_Int64 wParam) override; + virtual void SAL_CALL handleWindowOpened(sal_Int64) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +} + +/** + * Implementation of getAccObjectPtr. + * @param + * @return Com interface. + */ +sal_Int64 MSAAServiceImpl::getAccObjectPtr( + sal_Int64 hWnd, sal_Int64 lParam, sal_Int64 wParam) +{ + SolarMutexGuard g; + + if (!m_pTopWindowListener.is()) + { + return 0; + } + return m_pTopWindowListener->GetMSComPtr(hWnd, lParam, wParam); +} + +/** + * Implementation of handleWindowOpened, the method will be invoked when a + * top window is opened and AT starts up. + * @param + * @return + */ +void MSAAServiceImpl::handleWindowOpened(sal_Int64 nAcc) +{ + SolarMutexGuard g; + + SAL_INFO( "iacc2", "Window opened " << nAcc ); + + if (m_pTopWindowListener.is() && nAcc) + { + m_pTopWindowListener->HandleWindowOpened( + static_cast<css::accessibility::XAccessible*>( + reinterpret_cast<void*>(nAcc))); + } +} + +OUString MSAAServiceImpl::getImplementationName() +{ + return getImplementationName_MSAAServiceImpl(); +} + +/** + * Implementation of XServiceInfo, return support service name. + * @param Service name. + * @return If the service name is supported. + */ +sal_Bool MSAAServiceImpl::supportsService( OUString const & serviceName ) +{ + return cppu::supportsService(this, serviceName); +} + +/** + * Implementation of XServiceInfo, return all service names. + * @param. + * @return service name sequence. + */ +Sequence< OUString > MSAAServiceImpl::getSupportedServiceNames() +{ + return getSupportedServiceNames_MSAAServiceImpl(); +} + +static void AccessBridgeHandleExistingWindow(const Reference< XMSAAService > &xAccMgr, + vcl::Window *pWindow, bool bShow) +{ + if ( pWindow ) + { + css::uno::Reference< css::accessibility::XAccessible > xAccessible; + + SAL_INFO( "iacc2", "Decide whether to register existing window with IAccessible2" ); + + // Test for combo box - drop down floating windows first + vcl::Window * pParentWindow = pWindow->GetParent(); + + if ( pParentWindow ) + { + try + { + // The parent window of a combo box floating window should have the role COMBO_BOX + css::uno::Reference< css::accessibility::XAccessible > xParentAccessible(pParentWindow->GetAccessible()); + if ( xParentAccessible.is() ) + { + css::uno::Reference< css::accessibility::XAccessibleContext > xParentAC( xParentAccessible->getAccessibleContext() ); + if ( xParentAC.is() && (css::accessibility::AccessibleRole::COMBO_BOX == xParentAC->getAccessibleRole()) ) + { + // O.k. - this is a combo box floating window corresponding to the child of role LIST of the parent. + // Let's not rely on a specific child order, just search for the child with the role LIST + sal_Int32 nCount = xParentAC->getAccessibleChildCount(); + for ( sal_Int32 n = 0; (n < nCount) && !xAccessible.is(); n++) + { + css::uno::Reference< css::accessibility::XAccessible > xChild = xParentAC->getAccessibleChild(n); + if ( xChild.is() ) + { + css::uno::Reference< css::accessibility::XAccessibleContext > xChildAC = xChild->getAccessibleContext(); + if ( xChildAC.is() && (css::accessibility::AccessibleRole::LIST == xChildAC->getAccessibleRole()) ) + { + xAccessible = xChild; + } + } + } + } + } + } + catch (css::uno::RuntimeException const&) + { + // Ignore show events that throw DisposedExceptions in getAccessibleContext(), + // but keep revoking these windows in hide(s). + if (bShow) + return; + } + } + + // We have to rely on the fact that Window::GetAccessible()->getAccessibleContext() returns a valid XAccessibleContext + // also for other menus than menubar or toplevel popup window. Otherwise we had to traverse the hierarchy to find the + // context object to this menu floater. This makes the call to Window->IsMenuFloatingWindow() obsolete. + if ( ! xAccessible.is() ) + xAccessible = pWindow->GetAccessible(); + + assert( xAccMgr.is() ); + if ( xAccessible.is() ) + { + xAccMgr->handleWindowOpened( + reinterpret_cast<sal_Int64>(xAccessible.get())); + SAL_INFO( "iacc2", "Decide whether to register existing window with IAccessible2" ); + } + } +} + +/* + * Setup and notify the OS of Accessible peers for all existing windows. + */ +static void AccessBridgeUpdateOldTopWindows( const Reference< XMSAAService > &xAccMgr ) +{ + sal_uInt16 nTopWindowCount = static_cast<sal_uInt16>(Application::GetTopWindowCount()); + + for ( sal_uInt16 i = 0; i < nTopWindowCount; i++ ) + { + vcl::Window* pTopWindow = Application::GetTopWindow( i ); + css::uno::Reference< css::accessibility::XAccessible > xAccessible = pTopWindow->GetAccessible(); + if ( xAccessible.is() ) + { + css::uno::Reference< css::accessibility::XAccessibleContext > xAC( xAccessible->getAccessibleContext() ); + if ( xAC.is()) + { + if ( !xAC->getAccessibleName().isEmpty() ) + AccessBridgeHandleExistingWindow( xAccMgr, pTopWindow, true ); + } + } + } +} + +/** + * Static method that can create an entity of our MSAA Service + * @param xContext No use here. + * @return The object interface. + */ +static Reference< XInterface > create_MSAAServiceImpl( Reference< XComponentContext > const & /*xContext*/ ) +{ + Reference< XMSAAService > xAccMgr( new MSAAServiceImpl() ); + + AccessBridgeUpdateOldTopWindows( xAccMgr ); + + SAL_INFO("iacc2", "Created new IAccessible2 service impl."); + + return xAccMgr; +} + +MSAAServiceImpl::MSAAServiceImpl() +{ + Reference< XExtendedToolkit > xToolkit(Application::GetVCLToolkit(), UNO_QUERY); + + if( xToolkit.is() ) + { + m_pTopWindowListener.set(new AccTopWindowListener()); + Reference<XTopWindowListener> const xRef(m_pTopWindowListener.get()); + xToolkit->addTopWindowListener( xRef ); + SAL_INFO( "iacc2", "successfully connected to the toolkit event hose" ); + } + else + SAL_WARN( "iacc2", "No VCL toolkit interface to listen to for events"); +} + +void MSAAServiceImpl::dispose() +{ + SolarMutexGuard g; + + // As all folders and streams contain references to their parents, + // we must remove these references so that they will be deleted when + // the hash_map of the root folder is cleared, releasing all subfolders + // and substreams which in turn release theirs, etc. When xRootFolder is + // released when this destructor completes, the folder tree should be + // deleted fully (and automagically). + m_pTopWindowListener.clear(); +} + +} + +/* shared lib exports implemented without helpers in service_impl1.cxx */ +namespace my_sc_impl +{ +static struct ::cppu::ImplementationEntry s_component_entries [] = + { + { + create_MSAAServiceImpl, getImplementationName_MSAAServiceImpl, + getSupportedServiceNames_MSAAServiceImpl, + ::cppu::createSingleComponentFactory, + nullptr, 0 + }, + { nullptr, nullptr, nullptr, nullptr, nullptr, 0 } + }; +} + +extern "C" +{ + SAL_DLLPUBLIC_EXPORT void * iacc2_component_getFactory( + sal_Char const * implName, lang::XMultiServiceFactory * xMgr, + registry::XRegistryKey * xRegistry ) + { + return ::cppu::component_getFactoryHelper( + implName, xMgr, xRegistry, ::my_sc_impl::s_component_entries ); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/winaccessibility.component b/winaccessibility/source/service/winaccessibility.component new file mode 100644 index 000000000..8c61403e0 --- /dev/null +++ b/winaccessibility/source/service/winaccessibility.component @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + prefix="iacc2" xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.accessibility.my_sc_implementation.MSAAService"> + <service name="com.sun.star.accessibility.MSAAService"/> + </implementation> +</component> |