diff options
Diffstat (limited to 'winaccessibility/source/service')
20 files changed, 5255 insertions, 0 deletions
diff --git a/winaccessibility/source/service/AccComponentEventListener.cxx b/winaccessibility/source/service/AccComponentEventListener.cxx new file mode 100644 index 0000000000..e63317b59e --- /dev/null +++ b/winaccessibility/source/service/AccComponentEventListener.cxx @@ -0,0 +1,327 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccComponentEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccComponentEventListener::AccComponentEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccEventListener(pAcc, pManager) +{ +} + +AccComponentEventListener::~AccComponentEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * + * @param AccessibleEventObject the event object which contains information about event + */ +void AccComponentEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::VALUE_CHANGED: + HandleValueChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::ACTION_CHANGED: + HandleActionChangedEvent(); + break; + case AccessibleEventId::TEXT_CHANGED: + HandleTextChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::CARET_CHANGED: + HandleCaretChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + case AccessibleEventId::SELECTION_CHANGED: + HandleSelectionChangedEventNoArgs(); + break; + //to add TEXT_SELECTION_CHANGED event + case AccessibleEventId::TEXT_SELECTION_CHANGED: + HandleTextSelectionChangedEvent(); + break; + //End + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the VALUE_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccComponentEventListener::HandleValueChangedEvent(Any, Any) +{ + m_pObjManager->UpdateValue(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_VALUECHANGE); +} + +/** + * handle the NAME_CHANGED event + */ +void AccComponentEventListener::HandleActionChangedEvent() +{ + m_pObjManager->UpdateAction(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_DEFACTIONCHANGE); +} + +/** + * handle the TEXT_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccComponentEventListener::HandleTextChangedEvent(Any, Any newValue) +{ + m_pObjManager->SetValue(m_xAccessible.get(), newValue); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_VALUECHANGE); +} + +/** + * handle the CARET_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccComponentEventListener::HandleCaretChangedEvent(Any, Any) +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_CARETCHANGE); +} + +/** + * set the new state and fire the MSAA event + * + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccComponentEventListener::SetComponentState(sal_Int64 state, bool enable) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::CHECKED: + case AccessibleStateType::PRESSED: + case AccessibleStateType::SELECTED: + case AccessibleStateType::ARMED: + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::SHOWING: + FireStatePropertyChange(state, enable); + break; + case AccessibleStateType::VISIBLE: + if (GetRole() == AccessibleRole::MENU_ITEM) + { + if(enable) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + else + { + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + } + else + { + FireStatePropertyChange(state, enable); + } + break; + case AccessibleStateType::FOCUSED: + FireStateFocusedChange(enable); + break; + case AccessibleStateType::ENABLED: + if(enable) + { + m_pObjManager->UpdateState(m_xAccessible.get()); + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + // 8. label should have no FOCUSABLE state, Firefox has READONLY state, we can also have. + if ( GetRole() != AccessibleRole::LABEL + && GetRole() != AccessibleRole::STATIC + && GetRole() != AccessibleRole::NOTIFICATION + && GetRole() != AccessibleRole::SCROLL_BAR) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + } + else + { + m_pObjManager->UpdateState(m_xAccessible.get()); + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + } + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + break; + default: + break; + } +} + +/** + * fire the MSAA state changed event + * + * @param state the state id + * @param set true if state is set, false if state is unset + */ +void AccComponentEventListener::FireStatePropertyChange(sal_Int64 state, bool set) +{ + if( set) + { + // new value + switch(state) + { + case AccessibleStateType::CHECKED: + case AccessibleStateType::INDETERMINATE: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + m_pObjManager->UpdateAction(m_xAccessible.get()); + + if (!m_pObjManager->IsSpecialToolbarItem(m_xAccessible.get())) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_CHECKED); + } + break; + case AccessibleStateType::PRESSED: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_PRESSED); + break; + case AccessibleStateType::SELECTED: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + break; + case AccessibleStateType::ARMED: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_ARMED); + break; + case AccessibleStateType::SHOWING: + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + // UNO !SHOWING == MSAA OFFSCREEN + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING ); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_SHOWING); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE ); + break; + default: + break; + } + } + else + { + // old value + switch(state) + { + case AccessibleStateType::CHECKED: + case AccessibleStateType::INDETERMINATE: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + m_pObjManager->UpdateAction(m_xAccessible.get()); + + if (!m_pObjManager->IsSpecialToolbarItem(m_xAccessible.get())) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_CHECKED); + } + break; + case AccessibleStateType::PRESSED: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_PRESSED); + break; + case AccessibleStateType::SELECTED: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + //if the state is unset, no need to send MSAA SELECTION event + //m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_SELECTED); + break; + case AccessibleStateType::ARMED: + { + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + //if the state is unset, no need to send MSAA MENU event + //m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_ARMED); + } + break; + case AccessibleStateType::SHOWING: + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + // UNO !SHOWING == MSAA OFFSCREEN + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + + default: + break; + } + } +} + +/** + * handle the focused event + * + * @param enable true if get focus, false if lose focus + */ +void AccComponentEventListener::FireStateFocusedChange(bool enable) +{ + if(enable) + { + if (GetParentRole() != AccessibleRole::COMBO_BOX) + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_FOCUSED); + } + else + { + //if lose focus, no need to send MSAA FOCUS event + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + } +} + +void AccComponentEventListener::HandleSelectionChangedEventNoArgs() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED); +} + +//add TEXT_SELECTION_CHANGED event +void AccComponentEventListener::HandleTextSelectionChangedEvent() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TEXT_SELECTION_CHANGED); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccContainerEventListener.cxx b/winaccessibility/source/service/AccContainerEventListener.cxx new file mode 100644 index 0000000000..d05b9f5a27 --- /dev/null +++ b/winaccessibility/source/service/AccContainerEventListener.cxx @@ -0,0 +1,498 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccContainerEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccContainerEventListener::AccContainerEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccEventListener(pAcc, pManager) +{ +} + +AccContainerEventListener::~AccContainerEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * + * @param AccessibleEventObject the event object which contains information about event + */ +void AccContainerEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::SELECTION_CHANGED: + HandleSelectionChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::INVALIDATE_ALL_CHILDREN: + HandleAllChildrenChangedEvent(); + break; + case AccessibleEventId::TEXT_CHANGED: + HandleTextChangedEvent(aEvent.OldValue, aEvent.NewValue); + [[fallthrough]]; //TODO ??? + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + case AccessibleEventId::STATE_CHANGED: + HandleStateChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VALUE_CHANGED: + HandleValueChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_ADD: + HandleSelectionChangedAddEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_REMOVE: + HandleSelectionChangedRemoveEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_WITHIN: + HandleSelectionChangedWithinEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::PAGE_CHANGED: + HandlePageChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SECTION_CHANGED: + HandleSectionChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::COLUMN_CHANGED: + HandleColumnChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +void AccContainerEventListener::HandleStateChangedEvent(Any oldValue, Any newValue) +{ + sal_Int64 State; + if( newValue >>= State) + { + SetComponentState(State, true); + } + else if (oldValue >>= State) + { + SetComponentState(State, false); + } + +} + +/** + * handle the SELECTION_CHANGED event + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccContainerEventListener::HandleSelectionChangedEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED, newValue)) + { + return ; + } + + //menu bar does not process selection change event,just same as word behavior + if (GetRole()!=AccessibleRole::MENU_BAR) + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED); +} + +/** + * handle the INVALIDATE_ALL_CHILDREN event + */ +void AccContainerEventListener::HandleAllChildrenChangedEvent() +{ + //TODO: update all the children + if (m_xAccessible.is()) + { + //delete all oldValue's existing children + m_pObjManager->DeleteChildrenAccObj(m_xAccessible.get()); + //add all oldValue's existing children + m_pObjManager->InsertChildrenAccObj(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_REORDER); + } +} + +/** + * handle the TEXT_CHANGED event + */ +void AccContainerEventListener::HandleTextChangedEvent(Any, Any newValue) +{ + m_pObjManager->SetValue(m_xAccessible.get(), newValue); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_TEXTCHANGE); +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccContainerEventListener::SetComponentState(sal_Int64 state, bool enable ) +{ + // only the following state can be fired state event. + + switch (state) + { + case AccessibleStateType::SELECTED: + case AccessibleStateType::BUSY: + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::OFFSCREEN: + case AccessibleStateType::FOCUSABLE: + case AccessibleStateType::SHOWING: + case AccessibleStateType::VISIBLE: + FireStatePropertyChange(state, enable); + break; + case AccessibleStateType::FOCUSED: + FireStateFocusedChange(enable); + break; + case AccessibleStateType::ENABLED: + if(enable) + { + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + m_pObjManager->UpdateState(m_xAccessible.get()); + + UpdateAllChildrenState(m_xAccessible.get()); + } + else + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::DEFUNC); + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSABLE); + m_pObjManager->UpdateState(m_xAccessible.get()); + + UpdateAllChildrenState(m_xAccessible.get()); + } + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + //for PAGE_TAB_LIST, there will be ACTIVE state, then it should be converted to FOCUSED event. + if (GetRole() == AccessibleRole::PAGE_TAB_LIST) + { + if (!enable) /* get the active state */ + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + } + + else /* lose the active state */ + { + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + } + } + break; + + case AccessibleStateType::EXPANDED: + case AccessibleStateType::COLLAPSE: + case AccessibleStateType::CHECKED: + { + m_pObjManager->UpdateState(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_BUSY); + break; + } + + default: + break; + } +} + +/** + * fire the MSAA state changed event + * @param state the state id + * @param set true if state is set, false if state is unset + */ +void AccContainerEventListener::FireStatePropertyChange(sal_Int64 state, bool set) +{ + if( set ) + { + // new value + switch(state) + { + case AccessibleStateType::SELECTED: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + break; + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::BUSY: + case AccessibleStateType::FOCUSABLE: + case AccessibleStateType::OFFSCREEN: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_BUSY); + break; + case AccessibleStateType::SHOWING: + // UNO !SHOWING == MSAA OFFSCREEN + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + default: + break; + } + } + else + { + // old value + switch(state) + { + case AccessibleStateType::SELECTED: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + break; + case AccessibleStateType::BUSY: + case AccessibleStateType::INDETERMINATE: + case AccessibleStateType::FOCUSABLE: + case AccessibleStateType::OFFSCREEN: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_BUSY); + break; + case AccessibleStateType::SHOWING: + // UNO !SHOWING == MSAA OFFSCREEN + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + default: + break; + } + } +} + +/** + * handle the focused event + * @param enable true if get focus, false if lose focus + */ +void AccContainerEventListener::FireStateFocusedChange(bool enable) +{ + if(enable) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + // if the acc role is MENU_BAR, UnoMSAAEvent::MENU_START event should be sent + // if the acc role is POPUP_MENU, UnoMSAAEvent::MENUPOPUPSTART event should be sent + short role = GetRole(); + if(role == AccessibleRole::MENU_BAR) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::MENU_START); + } + else if (role == AccessibleRole::POPUP_MENU) + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::MENUPOPUPSTART); + //Disable the focused event on option_pane and Panel. + //only disable option_pane for toolbar has panel to get focus + else if (role == AccessibleRole::PANEL || role == AccessibleRole::OPTION_PANE ) + { + //don't send focused event on PANEL & OPTION_PANE if the parent is not toolbar + short parentRole = GetParentRole(); + if (parentRole == AccessibleRole::TOOL_BAR + || parentRole == AccessibleRole::SCROLL_PANE // sidebar + || parentRole == AccessibleRole::PANEL) // sidebar + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_FOCUSED); + } + else if (role == AccessibleRole::COMBO_BOX ) + { + //for editable combobox, send focus event on only edit control, + bool bSendFocusOnCombobox = true; + //send focused event to the first text child + Reference<XAccessibleContext> mxContext = m_xAccessible->getAccessibleContext(); + if(mxContext.is()) + { + Reference<XAccessible> mxChild = mxContext->getAccessibleChild(0); + if(mxChild.is()) + { + Reference<XAccessibleContext> mxChildContext = mxChild->getAccessibleContext(); + short childrole = mxChildContext->getAccessibleRole(); + if (childrole == AccessibleRole::TEXT) + { + if (IsEditable(mxChildContext)) + { + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + m_pObjManager->IncreaseState( mxChild.get(), AccessibleStateType::FOCUSED); + m_pObjManager->NotifyAccEvent(mxChild.get(), UnoMSAAEvent::STATE_FOCUSED); + bSendFocusOnCombobox = false; + } + } + } + } + if (bSendFocusOnCombobox) + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_FOCUSED); + } + else + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_FOCUSED); + } + else + { + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + // if the acc role is MENU_BAR, UnoMSAAEvent::MENU_END event should be sent + // if the acc role is POPUP_MENU, UnoMSAAEvent::MENUPOPUPEND event should be sent + if (GetRole() == AccessibleRole::MENU_BAR) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::MENU_END); + } + else if (GetRole() == AccessibleRole::POPUP_MENU) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::MENUPOPUPEND); + } + } +} + +/** + * handle the VALUE_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccContainerEventListener::HandleValueChangedEvent(Any, Any) +{ + m_pObjManager->UpdateValue(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_VALUECHANGE); +} + +bool AccContainerEventListener::IsEditable(Reference<XAccessibleContext> const & xContext) +{ + sal_Int64 nRState = xContext->getAccessibleStateSet(); + return nRState & AccessibleStateType::EDITABLE; +} + +bool AccContainerEventListener::NotifyChildEvent(UnoMSAAEvent eWinEvent, const Any& Value) +{ + Reference< XAccessible > xChild; + if(Value >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->NotifyAccEvent(pAcc, eWinEvent); + return true; + } + } + return false; +} + +void AccContainerEventListener::HandleSelectionChangedAddEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_ADD, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_ADD); +} + +void AccContainerEventListener::HandleSelectionChangedRemoveEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_REMOVE, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_REMOVE); +} + +void AccContainerEventListener::HandleSelectionChangedWithinEvent(const Any& /*oldValue*/, const Any& newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_WITHIN, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_WITHIN); +} + +void AccContainerEventListener::UpdateAllChildrenState(XAccessible* pXAccessible) +{ + Reference<css::accessibility::XAccessibleContext> xContext = pXAccessible->getAccessibleContext(); + if(!xContext.is()) + { + return; + } + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + if(pAccessibleContext == nullptr) + { + return; + } + + if (AccObjectWinManager::IsStateManageDescendant(pXAccessible)) + { + return; + } + + const sal_Int64 nCount = pAccessibleContext->getAccessibleChildCount(); + for (sal_Int64 i = 0; i < nCount; i++) + { + Reference<css::accessibility::XAccessible> mxAccessible + = pAccessibleContext->getAccessibleChild(i); + + css::accessibility::XAccessible* mpAccessible = mxAccessible.get(); + if(mpAccessible != nullptr) + { + m_pObjManager->UpdateState(mpAccessible); + UpdateAllChildrenState(mpAccessible); + } + } +} + +void AccContainerEventListener::HandlePageChangedEvent(const Any& /*oldValue*/, const Any& /*newValue*/) +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_PAGECHANGED); +} + +void AccContainerEventListener::HandleSectionChangedEvent(const Any& /*oldValue*/, const Any& /*newValue*/ ) +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SECTION_CHANGED); +} + +void AccContainerEventListener::HandleColumnChangedEvent(const Any& /*oldValue*/, const Any& /*newValue*/) +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::COLUMN_CHANGED); +} + +void AccContainerEventListener::HandleNameChangedEvent( Any name ) +{ + if (GetRole() == AccessibleRole::COMBO_BOX) + { + Reference<XAccessibleContext> mxContext(m_xAccessible->getAccessibleContext()); + if(mxContext.is()) + { + Reference<XAccessible> mxChild = mxContext->getAccessibleChild(0); + if(mxChild.is()) + { + Reference<XAccessibleContext> mxChildContext = mxChild->getAccessibleContext(); + short childrole = mxChildContext->getAccessibleRole(); + if (childrole == AccessibleRole::TEXT) + { + m_pObjManager->SetAccName(mxChild.get(), name); + } + } + } + } + AccEventListener::HandleNameChangedEvent(name); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccDescendantManagerEventListener.cxx b/winaccessibility/source/service/AccDescendantManagerEventListener.cxx new file mode 100644 index 0000000000..d3fcb2d0fe --- /dev/null +++ b/winaccessibility/source/service/AccDescendantManagerEventListener.cxx @@ -0,0 +1,198 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccDescendantManagerEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccDescendantManagerEventListener::AccDescendantManagerEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + : AccComponentEventListener(pAcc, pManager) +{ +} + +AccDescendantManagerEventListener::~AccDescendantManagerEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccDescendantManagerEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::SELECTION_CHANGED: + HandleSelectionChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS: + HandleChildChangedNoFocusEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_ADD: + HandleSelectionChangedAddEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_REMOVE: + HandleSelectionChangedRemoveEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::SELECTION_CHANGED_WITHIN: + HandleSelectionChangedWithinEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccComponentEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the SELECTION_CHANGED event + */ +void AccDescendantManagerEventListener::HandleSelectionChangedEvent(Any oldValue, Any newValue) +{ + bool bSend =false; + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + Reference<css::accessibility::XAccessibleContext> xContext = pAcc->getAccessibleContext(); + //if the Role is the SC cell ,don't add the selected state. + if (xContext.is() && xContext->getAccessibleRole() != AccessibleRole::TABLE_CELL) + { + m_pObjManager->IncreaseState( pAcc, AccessibleStateType::SELECTED); + } + + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::SELECTION_CHANGED); + bSend=true; + } + } + if(oldValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->DecreaseState( pAcc, AccessibleStateType::SELECTED); + } + } + if (!bSend) + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED); + } +} + + +void AccDescendantManagerEventListener::HandleChildChangedNoFocusEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + + m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get()); + m_pObjManager->InsertChildrenAccObj(pAcc); + } + } + if (oldValue >>= xChild) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->DeleteChildrenAccObj( pAcc ); + m_pObjManager->DeleteAccObj( pAcc ); + } + } +} + +bool AccDescendantManagerEventListener::NotifyChildEvent(UnoMSAAEvent eWinEvent, const Any& Value) +{ + Reference< XAccessible > xChild; + if(Value >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->NotifyAccEvent(pAcc, eWinEvent); + + if (AccObjectWinManager::IsStateManageDescendant(m_xAccessible.get())) + { + if (eWinEvent == UnoMSAAEvent::SELECTION_CHANGED_REMOVE) + { + // The object has just been sent in a SELECTION_CHANGED_REMOVE event + // and accessibility tools may query for the object and call methods on + // it as a response to this. + // Therefore, don't delete the object yet, but remember it for deletion + // once the next event of a different type occurs. + m_aUnselectedChildrenForDeletion.push_back(pAcc); + } + else + { + // handle any pending deletions for objects previously removed from selection + for (XAccessible* pAcc2 : m_aUnselectedChildrenForDeletion) + m_pObjManager->DeleteAccObj(pAcc2); + m_aUnselectedChildrenForDeletion.clear(); + } + } + return true; + } + } + return false; +} +void AccDescendantManagerEventListener::HandleSelectionChangedAddEvent(const Any& /*oldValue*/, const Any &newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_ADD, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_ADD); +} + +void AccDescendantManagerEventListener::HandleSelectionChangedRemoveEvent(const Any& /*oldValue*/, const Any &newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_REMOVE, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_REMOVE); +} + +void AccDescendantManagerEventListener::HandleSelectionChangedWithinEvent(const Any& /*oldValue*/, const Any &newValue) +{ + if (NotifyChildEvent(UnoMSAAEvent::SELECTION_CHANGED_WITHIN, newValue)) + { + return ; + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED_WITHIN); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccDialogEventListener.cxx b/winaccessibility/source/service/AccDialogEventListener.cxx new file mode 100644 index 0000000000..1236fc458a --- /dev/null +++ b/winaccessibility/source/service/AccDialogEventListener.cxx @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccDialogEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccDialogEventListener::AccDialogEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccEventListener(pAcc, pManager) +{} +AccDialogEventListener::~AccDialogEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccDialogEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccDialogEventListener::SetComponentState(sal_Int64 state, bool enable) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::ICONIFIED: + // no msaa state mapping + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + if( enable ) + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + else + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccEventListener.cxx b/winaccessibility/source/service/AccEventListener.cxx new file mode 100644 index 0000000000..d8e6223403 --- /dev/null +++ b/winaccessibility/source/service/AccEventListener.cxx @@ -0,0 +1,296 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <cppuhelper/bootstrap.hxx> +#include <com/sun/star/bridge/XUnoUrlResolver.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> + +#include <vcl/svapp.hxx> + +#include <AccEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> + +#include <stdio.h> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; +using namespace cppu; + +AccEventListener::AccEventListener(css::accessibility::XAccessible* pAcc, + AccObjectWinManager* pManager) + : m_xAccessible(pAcc) + , m_pObjManager(pManager) +{ +} + +AccEventListener::~AccEventListener() {} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccEventListener::notifyEvent(const css::accessibility::AccessibleEventObject& aEvent) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::CHILD: + HandleChildChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::NAME_CHANGED: + HandleNameChangedEvent(aEvent.NewValue); + break; + case AccessibleEventId::DESCRIPTION_CHANGED: + HandleDescriptionChangedEvent(); + break; + case AccessibleEventId::STATE_CHANGED: + HandleStateChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + break; + } +} + +/** + * handle the NAME_CHANGED event + * @param name the new name with changed. + */ +void AccEventListener::HandleNameChangedEvent(Any name) +{ + if (m_pObjManager->IsTopWinAcc(m_xAccessible.get())) + { + XAccessible* pAccDoc = m_pObjManager->GetAccDocByAccTopWin(m_xAccessible.get()); + if (pAccDoc) + { + m_pObjManager->UpdateAccName(pAccDoc); + m_pObjManager->NotifyAccEvent(pAccDoc, UnoMSAAEvent::OBJECT_NAMECHANGE); + } + } + + m_pObjManager->SetAccName(m_xAccessible.get(), name); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_NAMECHANGE); +} + +/** + * Handle the CHILD event + * @param oldValue the child to be deleted + * @param newValue the child to be added + */ +void AccEventListener::HandleChildChangedEvent(com::sun::star::uno::Any oldValue, + com::sun::star::uno::Any newValue) +{ + Reference<XAccessible> xChild; + if (newValue >>= xChild) + { + if (xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get()); + m_pObjManager->InsertChildrenAccObj(pAcc); + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::CHILD_ADDED); + } + } + else if (oldValue >>= xChild) + { + if (xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::CHILD_REMOVED); + m_pObjManager->DeleteChildrenAccObj(pAcc); + m_pObjManager->DeleteAccObj(pAcc); + } + } +} + +/** + * handle the DESCRIPTION_CHANGED event + */ +void AccEventListener::HandleDescriptionChangedEvent() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_DESCRIPTIONCHANGE); +} + +/** + * handle the BOUNDRECT_CHANGED event + */ +void AccEventListener::HandleBoundrectChangedEvent() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::BOUNDRECT_CHANGED); +} + +/** + * handle the VISIBLE_DATA_CHANGED event + */ +void AccEventListener::HandleVisibleDataChangedEvent() +{ + m_pObjManager->UpdateValue(m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::VISIBLE_DATA_CHANGED); +} + +/** + * handle the STATE_CHANGED event + * @param oldValue the old state of the source of event + * @param newValue the new state of the source of event + */ +void AccEventListener::HandleStateChangedEvent(Any oldValue, Any newValue) +{ + sal_Int64 newV, oldV; + if (newValue >>= newV) + { + SetComponentState(newV, true); + } + else if (oldValue >>= oldV) + { + SetComponentState(oldV, false); + } +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccEventListener::SetComponentState(sal_Int64 state, bool enable) +{ + switch (state) + { + case AccessibleStateType::FOCUSED: + FireStateFocusedChange(enable); + break; + default: + FireStatePropertyChange(state, enable); + break; + } +} + +/** + * handle the focused event + * @param enable true if get focus, false if lose focus + */ +void AccEventListener::FireStateFocusedChange(bool enable) +{ + if (enable) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::FOCUSED); + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_FOCUSED); + } + else + { + // no focus lost event in MSAA + } +} + +/** + * fire the MSAA state changed event + * @param state the state id + * @param set true if state is set, false if state is unset + */ +void AccEventListener::FireStatePropertyChange(sal_Int64 /*state*/, bool set) +{ + if (set) + { + //get new state + } + else + { + //lose old state + } +} + +/** + * get the role of accessible object which is observed + */ +short AccEventListener::GetRole() +{ + css::uno::Reference<css::accessibility::XAccessibleContext> const xContext( + m_xAccessible->getAccessibleContext()); + if (xContext.is()) + { + return xContext->getAccessibleRole(); + } + return -1; +} + +/** + * get the role of accessible parent object which is observed + */ +short AccEventListener::GetParentRole() +{ + if (m_xAccessible.is()) + { + return m_pObjManager->GetParentRole(m_xAccessible.get()); + } + return -1; +} +/** + * remove the listener from accessible object + */ +void AccEventListener::RemoveMeFromBroadcaster(bool const isNotifyDestroy) +{ + try + { + if (!m_xAccessible.is()) + { + return; + } + try + { + css::uno::Reference<XAccessibleEventBroadcaster> const xBroadcaster( + m_xAccessible->getAccessibleContext(), UNO_QUERY); + if (xBroadcaster.is()) + { + //remove the lister from accessible object + xBroadcaster->removeAccessibleEventListener(this); + } + } + catch (Exception const&) + { // may throw if it's already disposed - ignore that + } + if (isNotifyDestroy) + { + m_pObjManager->NotifyDestroy(m_xAccessible.get()); + } + m_xAccessible.clear(); // release cyclic reference + } + catch (...) + { + return; + } +} + +/** + * this method is invoked before listener is disposed + */ +void AccEventListener::disposing(const css::lang::EventObject& /*Source*/) +{ + SolarMutexGuard g; + + RemoveMeFromBroadcaster(true); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccFrameEventListener.cxx b/winaccessibility/source/service/AccFrameEventListener.cxx new file mode 100644 index 0000000000..55ecf24792 --- /dev/null +++ b/winaccessibility/source/service/AccFrameEventListener.cxx @@ -0,0 +1,128 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccFrameEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +#include <vcl/window.hxx> +#include <toolkit/awt/vclxwindow.hxx> +#include <vcl/sysdata.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccFrameEventListener::AccFrameEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccEventListener(pAcc, pManager) +{ +} + +AccFrameEventListener::~AccFrameEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccFrameEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the CHILD event + * @param oldValue the child to be deleted + * @param newValue the child to be added + */ +void AccFrameEventListener::HandleChildChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if( newValue >>= xChild) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + VCLXWindow* pvclwindow = dynamic_cast<VCLXWindow*>(m_xAccessible.get()); + assert(pvclwindow); + const SystemEnvData* systemdata + = pvclwindow->GetWindow()->GetSystemData(); + + m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get(), systemdata->hWnd); + m_pObjManager->InsertChildrenAccObj(pAcc); + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::CHILD_ADDED); + } + } + else if (oldValue >>= xChild) + { + AccEventListener::HandleChildChangedEvent(oldValue, newValue); + } +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccFrameEventListener::SetComponentState(sal_Int64 state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::ICONIFIED: + // no msaa state + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + if( enable ) + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + else + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + case AccessibleStateType::ACTIVE: + // Only frames should be active + // no msaa state mapping + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccListEventListener.cxx b/winaccessibility/source/service/AccListEventListener.cxx new file mode 100644 index 0000000000..9eaab9fd0c --- /dev/null +++ b/winaccessibility/source/service/AccListEventListener.cxx @@ -0,0 +1,126 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccListEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccListEventListener::AccListEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccDescendantManagerEventListener(pAcc, pManager) +{ +} + +AccListEventListener::~AccListEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccListEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + HandleActiveDescendantChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::INVALIDATE_ALL_CHILDREN: + // Since List items a transient a child events are mostly used + // to attach/detach listeners, it is safe to ignore it here + //TODO: investigate again + break; + case AccessibleEventId::VALUE_CHANGED: + HandleValueChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccDescendantManagerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the ACTIVE_DESCENDANT_CHANGED event + * @param oldValue the child to lose active + * @param newValue the child to get active + */ +void AccListEventListener::HandleActiveDescendantChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + + // Valueset has cache the child item xacc,Update state if no insert obj + bool bHasCache = m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get()); + if (!bHasCache) + { + m_pObjManager->UpdateState(pAcc); + } + + m_pObjManager->IncreaseState( pAcc, AccessibleStateType::FOCUSED); + + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::ACTIVE_DESCENDANT_CHANGED); + } + } + if (oldValue >>= xChild) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->DeleteAccObj( pAcc ); + } + } +} + +/** + * handle the VALUE_CHANGED event + * + * @param oldValue the old value of the source of event + * @param newValue the new value of the source of event + */ +void AccListEventListener::HandleValueChangedEvent(Any, Any) +{ + //to enable value changed event + if (GetParentRole() == AccessibleRole::COMBO_BOX) + { + XAccessible* pParentAcc = + m_pObjManager->GetParentXAccessible(m_xAccessible.get()); + m_pObjManager->UpdateValue(pParentAcc); + m_pObjManager->NotifyAccEvent(pParentAcc, UnoMSAAEvent::OBJECT_VALUECHANGE); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccMenuEventListener.cxx b/winaccessibility/source/service/AccMenuEventListener.cxx new file mode 100644 index 0000000000..25b347ebc8 --- /dev/null +++ b/winaccessibility/source/service/AccMenuEventListener.cxx @@ -0,0 +1,106 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccMenuEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccMenuEventListener::AccMenuEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccComponentEventListener(pAcc, pManager) +{} +AccMenuEventListener::~AccMenuEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccMenuEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::SELECTION_CHANGED: + //don't need to process anything,just same as word behavior + //handleSelectionChangedEvent(); + break; + default: + AccComponentEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the SELECTION_CHANGED event + */ +void AccMenuEventListener::HandleSelectionChangedEventNoArgs() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::SELECTION_CHANGED); +} + +/** + * handle the Menu_popup event + */ +void AccMenuEventListener::FireStatePropertyChange(sal_Int64 state, bool set) +{ + if( set ) + { + // new value + switch(state) + { + //for sub menu is popup, there is a menu selected event. + case AccessibleStateType::SELECTED: + m_pObjManager->IncreaseState(m_xAccessible.get(), state); + m_pObjManager->UpdateChildState(m_xAccessible.get()); + break; + default: + AccComponentEventListener::FireStatePropertyChange(state, set); + break; + } + } + else + { + switch(state) + { + //for sub menu is popup, there is a menu selected event. + case AccessibleStateType::SELECTED: + m_pObjManager->DecreaseState(m_xAccessible.get(), state); + + break; + default: + AccComponentEventListener::FireStatePropertyChange(state, set); + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccObject.cxx b/winaccessibility/source/service/AccObject.cxx new file mode 100644 index 0000000000..51d04ec18d --- /dev/null +++ b/winaccessibility/source/service/AccObject.cxx @@ -0,0 +1,1164 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleValue.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/XAccessibleText.hpp> + +#include <o3tl/char16_t2wchar_t.hxx> +#include <o3tl/safeint.hxx> +#include <sal/log.hxx> + +#include <stdlib.h> +#include <memory.h> +#include <stdio.h> +#include <algorithm> +#include <assert.h> + +#include <AccObject.hxx> +#include <AccEventListener.hxx> + +#if defined __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra-tokens" + // "#endif !_MIDL_USE_GUIDDEF_" in midl-generated code +#endif +#include <UAccCOM_i.c> +#if defined __clang__ +#pragma clang diagnostic pop +#endif + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; +using namespace com::sun::star::accessibility::AccessibleRole; +using namespace com::sun::star::accessibility::AccessibleStateType; + +namespace { + +/** + * Map a UNO accessible role to an IAccessible2 role. + * @param nUnoRole The UNO role (css::accessibility::AccessibleRole). + * @return IAccessible2 role. + */ +short lcl_mapToIAccessible2Role(sal_Int16 nUnoRole) +{ + switch(nUnoRole) + { + case css::accessibility::AccessibleRole::UNKNOWN: + return IA2_ROLE_UNKNOWN; + case css::accessibility::AccessibleRole::ALERT: + return ROLE_SYSTEM_DIALOG; + case css::accessibility::AccessibleRole::BLOCK_QUOTE: + return IA2_ROLE_BLOCK_QUOTE; + case css::accessibility::AccessibleRole::COLUMN_HEADER: + return ROLE_SYSTEM_COLUMNHEADER; + case css::accessibility::AccessibleRole::CANVAS: + return IA2_ROLE_CANVAS; + case css::accessibility::AccessibleRole::CHECK_BOX: + return ROLE_SYSTEM_CHECKBUTTON; + case css::accessibility::AccessibleRole::CHECK_MENU_ITEM: + return IA2_ROLE_CHECK_MENU_ITEM; + case css::accessibility::AccessibleRole::COLOR_CHOOSER: + return IA2_ROLE_COLOR_CHOOSER; + case css::accessibility::AccessibleRole::COMBO_BOX: + return ROLE_SYSTEM_COMBOBOX; + case css::accessibility::AccessibleRole::DATE_EDITOR: + return IA2_ROLE_DATE_EDITOR; + case css::accessibility::AccessibleRole::DESKTOP_ICON: + return IA2_ROLE_DESKTOP_ICON; + case css::accessibility::AccessibleRole::DESKTOP_PANE: + return IA2_ROLE_DESKTOP_PANE; + case css::accessibility::AccessibleRole::DIRECTORY_PANE: + return IA2_ROLE_DIRECTORY_PANE; + case css::accessibility::AccessibleRole::DIALOG: + return ROLE_SYSTEM_DIALOG; + case css::accessibility::AccessibleRole::DOCUMENT: + return ROLE_SYSTEM_DOCUMENT; + case css::accessibility::AccessibleRole::EMBEDDED_OBJECT: + return IA2_ROLE_EMBEDDED_OBJECT; + case css::accessibility::AccessibleRole::END_NOTE: + return IA2_ROLE_ENDNOTE; + case css::accessibility::AccessibleRole::FILE_CHOOSER: + return IA2_ROLE_FILE_CHOOSER; + case css::accessibility::AccessibleRole::FILLER: + return ROLE_SYSTEM_WHITESPACE; + case css::accessibility::AccessibleRole::FONT_CHOOSER: + return IA2_ROLE_FONT_CHOOSER; + case css::accessibility::AccessibleRole::FOOTER: + return IA2_ROLE_FOOTER; + case css::accessibility::AccessibleRole::FOOTNOTE: + return IA2_ROLE_FOOTNOTE; + case css::accessibility::AccessibleRole::FRAME: + return IA2_ROLE_FRAME; + case css::accessibility::AccessibleRole::GLASS_PANE: + return IA2_ROLE_GLASS_PANE; + case css::accessibility::AccessibleRole::GRAPHIC: + return ROLE_SYSTEM_GRAPHIC; + case css::accessibility::AccessibleRole::GROUP_BOX: + return ROLE_SYSTEM_GROUPING; + case css::accessibility::AccessibleRole::HEADER: + return IA2_ROLE_HEADER; + case css::accessibility::AccessibleRole::HEADING: + return IA2_ROLE_HEADING; + case css::accessibility::AccessibleRole::HYPER_LINK: + return ROLE_SYSTEM_TEXT; + case css::accessibility::AccessibleRole::ICON: + return IA2_ROLE_ICON; + case css::accessibility::AccessibleRole::INTERNAL_FRAME: + return IA2_ROLE_INTERNAL_FRAME; + case css::accessibility::AccessibleRole::LABEL: + return ROLE_SYSTEM_STATICTEXT; + case css::accessibility::AccessibleRole::LAYERED_PANE: + return IA2_ROLE_LAYERED_PANE; + case css::accessibility::AccessibleRole::LIST: + return ROLE_SYSTEM_LIST; + case css::accessibility::AccessibleRole::LIST_ITEM: + return ROLE_SYSTEM_LISTITEM; + case css::accessibility::AccessibleRole::MENU: + return ROLE_SYSTEM_MENUITEM; + case css::accessibility::AccessibleRole::MENU_BAR: + return ROLE_SYSTEM_MENUBAR; + case css::accessibility::AccessibleRole::MENU_ITEM: + return ROLE_SYSTEM_MENUITEM; + case css::accessibility::AccessibleRole::OPTION_PANE: + return IA2_ROLE_OPTION_PANE; + case css::accessibility::AccessibleRole::PAGE_TAB: + return ROLE_SYSTEM_PAGETAB; + case css::accessibility::AccessibleRole::PAGE_TAB_LIST: + return ROLE_SYSTEM_PAGETABLIST; + case css::accessibility::AccessibleRole::PANEL: + return IA2_ROLE_OPTION_PANE; + case css::accessibility::AccessibleRole::PARAGRAPH: + return IA2_ROLE_PARAGRAPH; + case css::accessibility::AccessibleRole::PASSWORD_TEXT: + return ROLE_SYSTEM_TEXT; + case css::accessibility::AccessibleRole::POPUP_MENU: + return ROLE_SYSTEM_MENUPOPUP; + case css::accessibility::AccessibleRole::PUSH_BUTTON: + return ROLE_SYSTEM_PUSHBUTTON; + case css::accessibility::AccessibleRole::PROGRESS_BAR: + return ROLE_SYSTEM_PROGRESSBAR; + case css::accessibility::AccessibleRole::RADIO_BUTTON: + return ROLE_SYSTEM_RADIOBUTTON; + case css::accessibility::AccessibleRole::RADIO_MENU_ITEM: + return IA2_ROLE_RADIO_MENU_ITEM; + case css::accessibility::AccessibleRole::ROW_HEADER: + return ROLE_SYSTEM_ROWHEADER; + case css::accessibility::AccessibleRole::ROOT_PANE: + return IA2_ROLE_ROOT_PANE; + case css::accessibility::AccessibleRole::SCROLL_BAR: + return ROLE_SYSTEM_SCROLLBAR; + case css::accessibility::AccessibleRole::SCROLL_PANE: + return IA2_ROLE_SCROLL_PANE; + case css::accessibility::AccessibleRole::SHAPE: + return IA2_ROLE_SHAPE; + case css::accessibility::AccessibleRole::SEPARATOR: + return ROLE_SYSTEM_SEPARATOR; + case css::accessibility::AccessibleRole::SLIDER: + return ROLE_SYSTEM_SLIDER; + case css::accessibility::AccessibleRole::SPIN_BOX: + return ROLE_SYSTEM_SPINBUTTON; + case css::accessibility::AccessibleRole::SPLIT_PANE: + return IA2_ROLE_SPLIT_PANE; + case css::accessibility::AccessibleRole::STATUS_BAR: + return ROLE_SYSTEM_STATUSBAR; + case css::accessibility::AccessibleRole::TABLE: + return ROLE_SYSTEM_TABLE; + case css::accessibility::AccessibleRole::TABLE_CELL: + return ROLE_SYSTEM_CELL; + case css::accessibility::AccessibleRole::TEXT: + return ROLE_SYSTEM_TEXT; + case css::accessibility::AccessibleRole::TEXT_FRAME: + return IA2_ROLE_TEXT_FRAME; + case css::accessibility::AccessibleRole::TOGGLE_BUTTON: + return ROLE_SYSTEM_PUSHBUTTON; + case css::accessibility::AccessibleRole::TOOL_BAR: + return ROLE_SYSTEM_TOOLBAR; + case css::accessibility::AccessibleRole::TOOL_TIP: + return ROLE_SYSTEM_TOOLTIP; + case css::accessibility::AccessibleRole::TREE: + return ROLE_SYSTEM_OUTLINE; + case css::accessibility::AccessibleRole::VIEW_PORT: + return IA2_ROLE_VIEW_PORT; + case css::accessibility::AccessibleRole::WINDOW: + return ROLE_SYSTEM_WINDOW; + case css::accessibility::AccessibleRole::BUTTON_DROPDOWN: + return ROLE_SYSTEM_BUTTONDROPDOWN; + case css::accessibility::AccessibleRole::BUTTON_MENU: + return ROLE_SYSTEM_BUTTONMENU; + case css::accessibility::AccessibleRole::CAPTION: + return IA2_ROLE_CAPTION; + case css::accessibility::AccessibleRole::CHART: + return IA2_ROLE_SHAPE; + case css::accessibility::AccessibleRole::EDIT_BAR: + return IA2_ROLE_EDITBAR; + case css::accessibility::AccessibleRole::FORM: + return IA2_ROLE_FORM; + case css::accessibility::AccessibleRole::IMAGE_MAP: + return IA2_ROLE_IMAGE_MAP; + case css::accessibility::AccessibleRole::NOTE: + return IA2_ROLE_NOTE; + case css::accessibility::AccessibleRole::PAGE: + return IA2_ROLE_PAGE; + case css::accessibility::AccessibleRole::RULER: + return IA2_ROLE_RULER; + case css::accessibility::AccessibleRole::SECTION: + return IA2_ROLE_SECTION; + case css::accessibility::AccessibleRole::TREE_ITEM: + return ROLE_SYSTEM_OUTLINEITEM; + case css::accessibility::AccessibleRole::TREE_TABLE: + return ROLE_SYSTEM_OUTLINE; + case css::accessibility::AccessibleRole::COMMENT: + return IA2_ROLE_TEXT_FRAME; + case css::accessibility::AccessibleRole::COMMENT_END: + return IA2_ROLE_TEXT_FRAME; + case css::accessibility::AccessibleRole::DOCUMENT_PRESENTATION: + return ROLE_SYSTEM_DOCUMENT; + case css::accessibility::AccessibleRole::DOCUMENT_SPREADSHEET: + return ROLE_SYSTEM_DOCUMENT; + case css::accessibility::AccessibleRole::DOCUMENT_TEXT: + return ROLE_SYSTEM_DOCUMENT; + case css::accessibility::AccessibleRole::STATIC: + return ROLE_SYSTEM_STATICTEXT; + case css::accessibility::AccessibleRole::NOTIFICATION: + return ROLE_SYSTEM_ALERT; + default: + SAL_WARN("iacc2", "Unmapped role: " << nUnoRole); + return IA2_ROLE_UNKNOWN; + } +} +}; + + +/** + * Constructor. + * @param pXAcc Uno XAccessible interface of control. + * @param pManager The accessible object manager kept in all listeners. + * @param listener listener that registers in UNO system. + * @return. + */ +AccObject::AccObject(XAccessible* pAcc, AccObjectWinManager* pManager, + AccEventListener* pListener) : + m_resID (0), + m_pParantID (nullptr), + m_pIMAcc (UAccCOMCreateInstance()), + m_pParentObj(nullptr), + m_pListener (pListener), + m_xAccRef( pAcc ) +{ + ImplInitializeCreateObj(); + + m_xAccContextRef = m_xAccRef->getAccessibleContext(); + m_xAccActionRef.set(m_xAccContextRef,UNO_QUERY); + m_accRole = m_xAccContextRef -> getAccessibleRole(); + if( m_pIMAcc ) + { + m_pIMAcc->SetXAccessible(reinterpret_cast<hyper>(m_xAccRef.get())); + m_pIMAcc->Put_XAccObjectManager(reinterpret_cast<hyper>(pManager)); + m_pIMAcc->SetDefaultAction(reinterpret_cast<hyper>(m_xAccActionRef.get())); + } +} +/** + * Destructor. + * @param + * @return + */ +AccObject::~AccObject() +{ + m_xAccRef = nullptr; + m_xAccActionRef = nullptr; + m_xAccContextRef = nullptr; +} + + +/** + * Insert a child element. + * @param pChild Child element that should be inserted into child list. + * @param pos Insert position. + * @return + */ +void AccObject::InsertChild( AccObject* pChild,short pos ) +{ + + std::vector<AccObject*>::iterator iter; + iter = std::find(m_childrenList.begin(),m_childrenList.end(),pChild); + if(iter!=m_childrenList.end()) + return; + if(LAST_CHILD==pos) + { + m_childrenList.push_back(pChild); + } + else + { + iter=m_childrenList.begin()+pos; + m_childrenList.insert(iter,pChild); + } + + pChild->SetParentObj(this); +} + +/** + * Delete a child element + * @param pChild Child element that should be inserted into child list. + * @param pos Insert position. + * @return + */ +void AccObject::DeleteChild( AccObject* pChild ) +{ + std::vector<AccObject*>::iterator iter; + iter = std::find(m_childrenList.begin(),m_childrenList.end(),pChild); + if(iter!=m_childrenList.end()) + { + m_childrenList.erase(iter); + if(m_pIMAcc) + pChild->SetParentObj(nullptr); + } +} + +/** + * In order to windows API WindowFromAccessibleObject, we sometimes to set a pure + * top window accessible object created by windows system as top ancestor. + * @param. + * @return + */ +void AccObject::UpdateValidWindow() +{ + if(m_pIMAcc) + m_pIMAcc->Put_XAccWindowHandle(m_pParantID); +} + +/** + * Translate all UNO basic information into MSAA com information. + * @param + * @return If the method is correctly processed. + */ +void AccObject::ImplInitializeCreateObj() +{ + assert(m_pIMAcc); +} + +/** + * Update name property to com object. + * @param + * @return + */ +void AccObject::UpdateName( ) +{ + if (!m_pIMAcc) + { + return; + } + + if( ( TEXT_FRAME == m_accRole ) && ( m_pParentObj !=nullptr )&& ( SCROLL_PANE == m_pParentObj -> m_accRole ) ) + m_pIMAcc->Put_XAccName( o3tl::toW(m_pParentObj->m_xAccContextRef->getAccessibleName().getStr()) ); + //IAccessibility2 Implementation 2009----- + if (m_accRole == AccessibleRole::PARAGRAPH || m_accRole == AccessibleRole::BLOCK_QUOTE) + { + m_pIMAcc->Put_XAccName(L""); + } + //-----IAccessibility2 Implementation 2009 + else + m_pIMAcc->Put_XAccName(o3tl::toW(m_xAccContextRef->getAccessibleName().getStr())); + + return ; +} + +/** + * Update default action property to com object. + * @param + * @return + */ +void AccObject::UpdateAction() +{ + m_xAccActionRef.set(m_xAccContextRef,UNO_QUERY); + + if( m_xAccActionRef.is() && m_pIMAcc ) + { + if( m_xAccActionRef->getAccessibleActionCount() > 0 ) + { + UpdateDefaultAction( ); + m_pIMAcc->SetDefaultAction( + reinterpret_cast<hyper>(m_xAccActionRef.get())); + } + } +} + +/** + * Update value property to com object. + * @param + * @return + */ +void AccObject::UpdateValue() +{ + if( nullptr == m_pIMAcc || !m_xAccContextRef.is() ) + { + assert(false); + return ; + } + + Reference< XAccessibleValue > pRValue(m_xAccContextRef,UNO_QUERY); + Any pAny; + if( pRValue.is() ) + { + pAny = pRValue->getCurrentValue(); + } + + SetValue( pAny ); +} + +/** + * Set special default action description string via UNO role. + * @param Role UNO role + * @return + */ +void AccObject::UpdateDefaultAction( ) +{ + if(!m_xAccActionRef.is()) + return ; + + switch(m_accRole) + { + case PUSH_BUTTON: + case TOGGLE_BUTTON: + case RADIO_BUTTON: + case MENU_ITEM: + case RADIO_MENU_ITEM: + case CHECK_MENU_ITEM: + case LIST_ITEM: + case CHECK_BOX: + case TREE_ITEM: + case BUTTON_DROPDOWN: + m_pIMAcc->Put_ActionDescription( o3tl::toW(m_xAccActionRef->getAccessibleActionDescription(sal_Int32(0)).getStr()) ); + return; + } +} + +/** + * Set value property via pAny. + * @param pAny New value. + * @return + */ +void AccObject::SetValue( Any pAny ) +{ + if( nullptr == m_pIMAcc || !m_xAccContextRef.is() ) + { + assert(false); + return ; + } + Reference< XAccessibleText > pRText(m_xAccContextRef,UNO_QUERY); + OUString val; + switch(m_accRole) + { + case SPIN_BOX: + // 3. date editor's msaa value should be the same as spinbox + case DATE_EDITOR: + case TEXT: + case BLOCK_QUOTE: + case PARAGRAPH: + case HEADING: + case TABLE_CELL: + + if(pRText) + { + val = pRText->getText(); + } + m_pIMAcc->Put_XAccValue( o3tl::toW(val.getStr()) ); + break; + case TREE_ITEM: + //case CHECK_BOX: //Commented by Li Xing to disable the value for general checkbox + case COMBO_BOX: + case NOTE: + case SCROLL_BAR: + m_pIMAcc->Put_XAccValue( o3tl::toW(GetMAccessibleValueFromAny(pAny).getStr()) ); + break ; + // Added by Li Xing, only the checkbox in tree should have the value. + case CHECK_BOX: + if( ( m_pParentObj !=nullptr ) && (TREE == m_pParentObj->m_accRole || TREE_ITEM == m_pParentObj->m_accRole )) + m_pIMAcc->Put_XAccValue( o3tl::toW(GetMAccessibleValueFromAny(pAny).getStr()) ); + break; + default: + break; + } + + return; +} + +OUString AccObject::GetMAccessibleValueFromAny(Any pAny) +{ + OUString strValue; + + if(nullptr == m_pIMAcc) + return strValue; + + if(pAny.getValueType() == cppu::UnoType<cppu::UnoUnsignedShortType>::get() ) + { + sal_uInt16 val; + if (pAny >>= val) + { + strValue=OUString::number(val); + + } + } + else if(pAny.getValueType() == cppu::UnoType<OUString>::get()) + { + + pAny >>= strValue ; + + } + else if(pAny.getValueType() == cppu::UnoType<Sequence< OUString >>::get()) + { + Sequence< OUString > val; + if (pAny >>= val) + { + for (const OUString& rElem : val) + strValue += rElem; + } + } + else if(pAny.getValueType() == cppu::UnoType<double>::get()) + { + double val; + if (pAny >>= val) + { + strValue=OUString::number(val); + } + } + else if(pAny.getValueType() == cppu::UnoType<sal_Int32>::get()) + { + sal_Int32 val; + if (pAny >>= val) + { + strValue=OUString::number(val); + } + } + else if (pAny.getValueType() == cppu::UnoType<css::accessibility::TextSegment>::get()) + { + css::accessibility::TextSegment val; + if (pAny >>= val) + { + OUString realVal(val.SegmentText); + strValue = realVal; + + } + } + + return strValue; +} +/** + * Set name property via pAny. + * @param pAny New accessible name. + * @return + */ +void AccObject::SetName( Any pAny) +{ + if( nullptr == m_pIMAcc ) + return ; + + m_pIMAcc->Put_XAccName( o3tl::toW(GetMAccessibleValueFromAny(pAny).getStr()) ); + +} + +/** +* Get role property via pAny +* @param +* @return accessible role +*/ +short AccObject::GetRole() const +{ + return m_accRole; +} + +/** + * Get MSAA state from UNO state + * @Role nState UNO state. + * @return + */ +DWORD AccObject::GetMSAAStateFromUNO(sal_Int64 nState) +{ + DWORD IState = UNO_MSAA_UNMAPPING; + + if( !m_xAccContextRef.is() ) + { + assert(false); + return IState; + } + + switch( nState ) + { + case BUSY: + IState = STATE_SYSTEM_BUSY; + break; + case CHECKED: + if (m_accRole == PUSH_BUTTON || m_accRole == TOGGLE_BUTTON) + { + IState = STATE_SYSTEM_PRESSED; + } + else + IState = STATE_SYSTEM_CHECKED; + break; + case DEFUNC: + IState = STATE_SYSTEM_UNAVAILABLE; + break; + case EXPANDED: + IState = STATE_SYSTEM_EXPANDED; + break; + case FOCUSABLE: + IState = STATE_SYSTEM_FOCUSABLE; + break; + case FOCUSED: + IState = STATE_SYSTEM_FOCUSED; + break; + case INDETERMINATE: + IState = STATE_SYSTEM_MIXED; + break; + case MULTI_SELECTABLE: + IState = STATE_SYSTEM_MULTISELECTABLE; + break; + case PRESSED: + IState = STATE_SYSTEM_PRESSED; + break; + case RESIZABLE: + IState = STATE_SYSTEM_SIZEABLE; + break; + case SELECTABLE: + if( m_accRole == MENU || m_accRole == MENU_ITEM) + { + IState = UNO_MSAA_UNMAPPING; + } + else + { + IState = STATE_SYSTEM_SELECTABLE; + } + break; + case SELECTED: + if( m_accRole == MENU || m_accRole == MENU_ITEM ) + { + IState = UNO_MSAA_UNMAPPING; + } + else + { + IState = STATE_SYSTEM_SELECTED; + } + break; + case ARMED: + IState = STATE_SYSTEM_FOCUSED; + break; + case EXPANDABLE: + { + sal_Bool isExpanded = true; + sal_Bool isExpandable = true; + if (m_accRole == PUSH_BUTTON || m_accRole == TOGGLE_BUTTON || m_accRole == BUTTON_DROPDOWN) + { + IState = STATE_SYSTEM_HASPOPUP; + } + else + { + GetExpandedState(&isExpandable,&isExpanded); + if(!isExpanded) + IState = STATE_SYSTEM_COLLAPSED; + } + } + break; + //Remove the SENSITIVE state mapping. There is no corresponding MSAA state. + //case SENSITIVE: + // IState = STATE_SYSTEM_PROTECTED; + case EDITABLE: + if( m_pIMAcc ) + { + m_pIMAcc->DecreaseState( STATE_SYSTEM_READONLY ); + } + break; + case OFFSCREEN: + IState = STATE_SYSTEM_OFFSCREEN; + break; + case MOVEABLE: + IState = STATE_SYSTEM_MOVEABLE; + break; + case COLLAPSE: + IState = STATE_SYSTEM_COLLAPSED; + break; + case DEFAULT: + IState = STATE_SYSTEM_DEFAULT; + break; + default: + break; + } + + return IState; +} + +/** + * Decrease state of com object + * @param xState The lost state. + * @return + */ +void AccObject::DecreaseState( sal_Int64 xState ) +{ + if( nullptr == m_pIMAcc ) + { + return; + } + + if( xState == FOCUSABLE) + { + if (m_accRole == MENU_ITEM || m_accRole == RADIO_MENU_ITEM || m_accRole == CHECK_MENU_ITEM) + return; + else + { + if (m_accRole == TOGGLE_BUTTON || m_accRole == PUSH_BUTTON || m_accRole == BUTTON_DROPDOWN) + { + if( ( m_pParentObj !=nullptr ) && (TOOL_BAR == m_pParentObj->m_accRole ) ) + return; + } + } + } + + else if( xState == AccessibleStateType::VISIBLE ) + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_INVISIBLE ); + } + else if( xState == AccessibleStateType::SHOWING ) + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_OFFSCREEN ); + } + + DWORD msState = GetMSAAStateFromUNO(xState); + if(msState!=UNO_MSAA_UNMAPPING) + m_pIMAcc->DecreaseState(msState); +} + +/** + * Increase state of com object + * @param xState The new state. + * @return + */ +void AccObject::IncreaseState( sal_Int64 xState ) +{ + if( nullptr == m_pIMAcc ) + { + assert(false); + return; + } + + + if( xState == AccessibleStateType::VISIBLE ) + { + m_pIMAcc->DecreaseState( STATE_SYSTEM_INVISIBLE ); + } + else if( xState == AccessibleStateType::SHOWING ) + { + m_pIMAcc->DecreaseState( STATE_SYSTEM_OFFSCREEN ); + } + + + DWORD msState = GetMSAAStateFromUNO(xState); + if(msState!=UNO_MSAA_UNMAPPING) + m_pIMAcc->IncreaseState( msState ); +} + +/** + * Get next child element + * @param + * @return AccObject Object interface. + */ +AccObject* AccObject::NextChild() +{ + IAccChildList::iterator pInd = m_childrenList.begin(); + if( pInd != m_childrenList.end() ) + return *pInd; + return nullptr; +} +/** + * update action description desc + * @param + * @return + */ +void AccObject::UpdateActionDesc() +{ + if (!m_pIMAcc) + return; + + long Role = m_accRole; + + if( Role == PUSH_BUTTON || Role == RADIO_BUTTON || Role == MENU_ITEM || + Role == LIST_ITEM || Role == CHECK_BOX || Role == TREE_ITEM || + Role == CHECK_MENU_ITEM || Role == RADIO_MENU_ITEM ) + { + UpdateDefaultAction( ); + } + else + { + + if( m_xAccActionRef.is() ) + { + if( m_xAccActionRef->getAccessibleActionCount() > 0 ) + { + if (!(Role == SPIN_BOX || Role == COMBO_BOX || Role == DATE_EDITOR || + Role == EDIT_BAR || Role == PASSWORD_TEXT || Role == TEXT)) + { + const OUString sActionDesc = m_xAccActionRef->getAccessibleActionDescription(0); + // if string is non-empty, action is set. + if (!sActionDesc.isEmpty()) + m_pIMAcc->Put_ActionDescription(o3tl::toW(sActionDesc.getStr())); + } + } + } + } + +} +/** + * update role information from uno to com + * @param + * @return + */ +void AccObject::UpdateRole() +{ + if (!m_pIMAcc) + { + return; + } + + const sal_Int16 nUnoRole = m_xAccContextRef->getAccessibleRole(); + short nIA2Role = lcl_mapToIAccessible2Role(nUnoRole); + m_pIMAcc->Put_XAccRole(nIA2Role); +} + +/** + * update state information from uno to com + * @param + * @return + */ +void AccObject::UpdateState() +{ + if (!m_pIMAcc) + { + return; + } + + XAccessibleContext* pContext = m_xAccContextRef.get(); + sal_Int64 nRState = pContext->getAccessibleStateSet(); + + m_pIMAcc->SetState(0); + + if ( m_accRole == POPUP_MENU ) + { + return; + } + + bool isEnable = false; + bool isShowing = false; + bool isEditable = false; + bool isVisible = false; + bool isFocusable = false; + + for (int i=0; i<63; ++i) + { + sal_Int64 nState = sal_Int64(1) << i; + if (!(nState & nRState)) + continue; + if (nState == ENABLED) + isEnable = true; + else if (nState == SHOWING) + isShowing = true; + else if (nState == VISIBLE) + isVisible = true; + else if (nState == EDITABLE) + isEditable = true; + else if (nState == FOCUSABLE) + isFocusable = true; + IncreaseState(nState); + } + + bool bIsMenuItem = m_accRole == MENU_ITEM || m_accRole == RADIO_MENU_ITEM || m_accRole == CHECK_MENU_ITEM; + + if(bIsMenuItem) + { + if(!(isShowing && isVisible) ) + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_INVISIBLE ); + m_pIMAcc->DecreaseState( STATE_SYSTEM_FOCUSABLE ); + } + } + else + { + if(!(isShowing || isVisible) ) + m_pIMAcc->IncreaseState( STATE_SYSTEM_INVISIBLE ); + } + + switch(m_accRole) + { + case LABEL: + case STATIC: + case NOTIFICATION: + m_pIMAcc->IncreaseState( STATE_SYSTEM_READONLY ); + break; + case TEXT: + // 2. editable combobox -> readonly ------ bridge + case EMBEDDED_OBJECT: + case END_NOTE: + case FOOTER: + case FOOTNOTE: + case GRAPHIC: + case HEADER: + case HEADING: + + //Image Map + case BLOCK_QUOTE: + case PARAGRAPH: + case PASSWORD_TEXT: + case SHAPE: + case SPIN_BOX: + case TABLE: + case TABLE_CELL: + case TEXT_FRAME: + case DATE_EDITOR: + case DOCUMENT: + case COLUMN_HEADER: + { + if(!isEditable) + m_pIMAcc->IncreaseState( STATE_SYSTEM_READONLY ); + } + break; + default: + break; + } + + if( isEnable ) + { + + if (!(m_accRole == FILLER || m_accRole == END_NOTE || m_accRole == FOOTER || m_accRole == FOOTNOTE || m_accRole == GROUP_BOX || m_accRole == RULER + || m_accRole == HEADER || m_accRole == ICON || m_accRole == INTERNAL_FRAME || m_accRole == LABEL || m_accRole == LAYERED_PANE + || m_accRole == SCROLL_BAR || m_accRole == SCROLL_PANE || m_accRole == SPLIT_PANE || m_accRole == STATIC || m_accRole == STATUS_BAR + || m_accRole == TOOL_TIP || m_accRole == NOTIFICATION)) + { + if (m_accRole == SEPARATOR) + { + if( ( m_pParentObj != nullptr ) && ( MENU == m_pParentObj->m_accRole || POPUP_MENU == m_pParentObj->m_accRole )) + IncreaseState( FOCUSABLE ); + } + + else if (m_accRole == TABLE_CELL || m_accRole == TABLE || m_accRole == PANEL || m_accRole == OPTION_PANE || + m_accRole == COLUMN_HEADER) + { + if (isFocusable) + IncreaseState( FOCUSABLE ); + } + else + { + if(bIsMenuItem) + { + if ( isShowing && isVisible) + { + IncreaseState( FOCUSABLE ); + } + } + else + { + IncreaseState( FOCUSABLE ); + } + } + } + } + else + { + m_pIMAcc->IncreaseState( STATE_SYSTEM_UNAVAILABLE ); + if( !((m_accRole == MENU_ITEM) || + (m_accRole == RADIO_MENU_ITEM) || + (m_accRole == CHECK_MENU_ITEM)) ) + { + if (m_accRole == TOGGLE_BUTTON || m_accRole == PUSH_BUTTON || m_accRole == BUTTON_DROPDOWN) + { + if(( m_pParentObj != nullptr )&& (TOOL_BAR == m_pParentObj->m_accRole ) ) + IncreaseState( FOCUSABLE ); + else + DecreaseState( FOCUSABLE ); + } + else + DecreaseState( FOCUSABLE ); + } + else if( isShowing || isVisible ) + { + IncreaseState( FOCUSABLE ); + } + } + + switch(m_accRole) + { + case POPUP_MENU: + case MENU: + if( pContext->getAccessibleChildCount() > 0 ) + m_pIMAcc->IncreaseState( STATE_SYSTEM_HASPOPUP ); + break; + case PASSWORD_TEXT: + m_pIMAcc->IncreaseState( STATE_SYSTEM_PROTECTED ); + break; + default: + break; + } +} + +/** + * Public method to mapping information between MSAA and UNO. + * @param + * @return If the method is correctly processed. + */ +bool AccObject::UpdateAccessibleInfoFromUnoToMSAA() +{ + if( nullptr == m_pIMAcc || !m_xAccContextRef.is() ) + { + assert(false); + return false; + } + + UpdateName(); + + UpdateValue(); + + UpdateActionDesc(); + + UpdateRole(); + + UpdateState(); + + return true; +} + + +/** + * Set self to focus object in parent child list + * @param + * @return + */ +void AccObject::setFocus() +{ + if(m_pIMAcc) + { + IncreaseState(FOCUSED); + m_pIMAcc->Put_XAccFocus(CHILDID_SELF); + + UpdateRole(); + } +} + +/** + * Unset self from focus object in parent child list. + * @param + * @return + */ +void AccObject::unsetFocus() +{ + if(m_pIMAcc) + { + DecreaseState( FOCUSED ); + m_pIMAcc->Put_XAccFocus(UACC_NO_FOCUS); + } +} + +void AccObject::GetExpandedState( sal_Bool* isExpandable, sal_Bool* isExpanded) +{ + *isExpanded = false; + *isExpandable = false; + + if( !m_xAccContextRef.is() ) + { + return; + } + sal_Int64 nRState = m_xAccContextRef->getAccessibleStateSet(); + + if (nRState & EXPANDED) + *isExpanded = true; + if (nRState & EXPANDABLE) + *isExpandable = true; +} + +void AccObject::NotifyDestroy() +{ + if(m_pIMAcc) + m_pIMAcc->NotifyDestroy(); +} + +void AccObject::SetParentObj(AccObject* pParentAccObj) +{ + m_pParentObj = pParentAccObj; + + if(m_pIMAcc) + { + if(m_pParentObj) + { + m_pIMAcc->Put_XAccParent(m_pParentObj->GetIMAccessible()); + } + else + { + m_pIMAcc->Put_XAccParent(nullptr); + } + } +} +//ResID means ChildID in MSAA +void AccObject::SetResID(long id) +{ + m_resID = id; + if(m_pIMAcc) + m_pIMAcc->Put_XAccChildID(m_resID); +} +//return COM interface in acc object +IMAccessible* AccObject::GetIMAccessible() +{ + return m_pIMAcc; +} + +Reference<XAccessible> const& AccObject::GetXAccessible() +{ + return m_xAccRef; +} + +void AccObject::SetParentHWND(HWND hWnd) +{ + m_pParantID = hWnd; +} + +rtl::Reference<AccEventListener> AccObject::SetListener(rtl::Reference<AccEventListener> const& pListener) +{ + rtl::Reference<AccEventListener> pRet(m_pListener); + m_pListener = pListener; + return pRet; +} + +AccEventListener* AccObject::getListener() +{ + return m_pListener.get(); +} + +long AccObject::GetResID() +{ + return m_resID; +} + +HWND AccObject::GetParentHWND() +{ + return m_pParantID; +} + +AccObject* AccObject::GetParentObj() +{ + return m_pParentObj; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccObjectContainerEventListener.cxx b/winaccessibility/source/service/AccObjectContainerEventListener.cxx new file mode 100644 index 0000000000..137b498a2c --- /dev/null +++ b/winaccessibility/source/service/AccObjectContainerEventListener.cxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +// AccObjectContainerEventListener.cpp: implementation of the AccContainerEventListener class. + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <AccObjectContainerEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccObjectContainerEventListener::AccObjectContainerEventListener( + css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + : AccContainerEventListener(pAcc, pManager) +{ +} +AccObjectContainerEventListener::~AccObjectContainerEventListener() {} + +/** + * handle the STATE_CHANGED event + */ +void AccObjectContainerEventListener::HandleStateChangedEvent(Any oldValue, Any newValue) +{ + //set the accessible name before process for there is no NAME_CHANGED event when change + //the text in drawing objects. + sal_Int64 newV; + if (newValue >>= newV) + { + if (newV == AccessibleStateType::FOCUSED) + { + m_pObjManager->UpdateAccName(m_xAccessible.get()); + } + } + AccContainerEventListener::HandleStateChangedEvent(oldValue, newValue); +} +/** + * handle the VISIBLE_DATA_CHANGED event + * For SHAPES, the visible_data_changed event should be mapped to LOCATION_CHANGED event + */ +void AccObjectContainerEventListener::HandleVisibleDataChangedEvent() +{ + AccContainerEventListener::HandleBoundrectChangedEvent(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccObjectWinManager.cxx b/winaccessibility/source/service/AccObjectWinManager.cxx new file mode 100644 index 0000000000..24deb8150c --- /dev/null +++ b/winaccessibility/source/service/AccObjectWinManager.cxx @@ -0,0 +1,1125 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <cassert> + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/XAccessibleEventListener.hpp> +#include <com/sun/star/accessibility/XAccessibleComponent.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> + +#include <oleacc.h> +#include <AccObjectWinManager.hxx> +#include <AccEventListener.hxx> +#include <AccComponentEventListener.hxx> +#include <AccContainerEventListener.hxx> +#include <AccDialogEventListener.hxx> +#include <AccWindowEventListener.hxx> +#include <AccFrameEventListener.hxx> +#include <AccMenuEventListener.hxx> +#include <AccObjectContainerEventListener.hxx> +#include <AccParagraphEventListener.hxx> +#include <AccTextComponentEventListener.hxx> +#include <AccListEventListener.hxx> +#include <AccTreeEventListener.hxx> +#include <AccTableEventListener.hxx> +#include <AccObject.hxx> +#include <unomsaaevent.hxx> + + +using namespace com::sun::star::accessibility; +using namespace com::sun::star::uno; + +AccObjectWinManager::AccObjectWinManager(): + oldFocus(nullptr) +{ +} + +/** + * Destructor,clear all resource. + * @param + * @return + */ +AccObjectWinManager::~AccObjectWinManager() +{ + { + std::scoped_lock l(m_Mutex); + + XIdAccList.clear(); + HwndXAcc.clear(); + } + XResIdAccList.clear(); + XHWNDDocList.clear(); +} + + +/** + * Get valid com object interface when notifying some MSAA event + * @param pWND The top window handle that contains that event control. + * @param wParam Windows system interface. + * @return Com interface with event. + */ + +sal_Int64 +AccObjectWinManager::Get_ToATInterface(sal_Int64 nHWnd, long lParam, WPARAM wParam) +{ + IMAccessible* pRetIMAcc = nullptr; + + if(lParam == OBJID_CLIENT ) + { + HWND hWnd = reinterpret_cast<HWND>(nHWnd); + pRetIMAcc = GetTopWindowIMAccessible(hWnd); + } + + if ( pRetIMAcc && lParam == OBJID_CLIENT ) + { + LRESULT result = LresultFromObject(IID_IAccessible, wParam, pRetIMAcc); + pRetIMAcc->Release(); + return static_cast<sal_Int64>(result); + } + return 0; +} + +/** + * Search AccObject by XAccessible pointer from our container. + * @param pXAcc XAccessible interface. + * @return Pointer of accObject that is found. + */ +AccObject* AccObjectWinManager::GetAccObjByXAcc( XAccessible* pXAcc) +{ + if( pXAcc == nullptr) + return nullptr; + + std::scoped_lock l(m_Mutex); + + XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( pXAcc ); + if ( pIndTemp == XIdAccList.end() ) + return nullptr; + + return &(pIndTemp->second); +} + +/** + * get acc object of top window by its handle + * @param hWnd, top window handle + * @return pointer to AccObject + */ +IMAccessible * AccObjectWinManager::GetTopWindowIMAccessible(HWND hWnd) +{ + std::scoped_lock l(m_Mutex); // tdf#155794 for HwndXAcc and XIdAccList + + XHWNDToXAccHash::iterator iterResult =HwndXAcc.find(hWnd); + if(iterResult == HwndXAcc.end()) + return nullptr; + XAccessible* pXAcc = iterResult->second; + AccObject *const pAccObject(GetAccObjByXAcc(pXAcc)); + if (!pAccObject) + { + return nullptr; + } + IMAccessible *const pRet(pAccObject->GetIMAccessible()); + if (!pRet) + { + return nullptr; + } + pRet->AddRef(); + return pRet; +} + +/** + * Simulate MSAA event via XAccessible interface and event type. + * @param pXAcc XAccessible interface. + * @param eEvent event type + * @return The terminate result that identifies if the call is successful. + */ +bool AccObjectWinManager::NotifyAccEvent(XAccessible* pXAcc, UnoMSAAEvent eEvent) +{ + Reference< XAccessibleContext > pRContext; + + if( pXAcc == nullptr) + return false; + + + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return false; + + + AccObject* selfAccObj= GetAccObjByXAcc(pXAcc); + + if(selfAccObj==nullptr) + return false; + + long dChildID = selfAccObj->GetResID(); + HWND hAcc = selfAccObj->GetParentHWND(); + + switch(eEvent) + { + case UnoMSAAEvent::STATE_FOCUSED: + { + UpdateAccFocus(pXAcc); + selfAccObj->UpdateDefaultAction( ); + UpdateValue(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + } + case UnoMSAAEvent::STATE_BUSY: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::STATE_CHECKED: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::STATE_PRESSED: + NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + + //Removed fire out selected event + //case UnoMSAAEvent::STATE_SELECTED: + // NotifyWinEvent( EVENT_OBJECT_STATECHANGE,hAcc, OBJID_CLIENT,dChildID ); + // break; + case UnoMSAAEvent::STATE_ARMED: + UpdateAccFocus(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::STATE_SHOWING: + // send EVENT_SYSTEM_ALERT when notification gets shown + if (pRContext->getAccessibleRole() == AccessibleRole::NOTIFICATION) + NotifyWinEvent(EVENT_SYSTEM_ALERT, hAcc, OBJID_CLIENT, dChildID); + break; + case UnoMSAAEvent::MENU_START: + NotifyWinEvent( EVENT_SYSTEM_MENUSTART,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::MENU_END: + NotifyWinEvent( EVENT_SYSTEM_MENUEND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::MENUPOPUPSTART: + NotifyWinEvent( EVENT_SYSTEM_MENUPOPUPSTART,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::MENUPOPUPEND: + NotifyWinEvent( EVENT_SYSTEM_MENUPOPUPEND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SELECTION_CHANGED: + NotifyWinEvent( EVENT_OBJECT_SELECTION,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SELECTION_CHANGED_ADD: + NotifyWinEvent( EVENT_OBJECT_SELECTIONADD,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SELECTION_CHANGED_REMOVE: + NotifyWinEvent( EVENT_OBJECT_SELECTIONREMOVE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SELECTION_CHANGED_WITHIN: + NotifyWinEvent( EVENT_OBJECT_SELECTIONWITHIN,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_VALUECHANGE: + UpdateValue(pXAcc); + NotifyWinEvent( EVENT_OBJECT_VALUECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_NAMECHANGE: + NotifyWinEvent( EVENT_OBJECT_NAMECHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_DESCRIPTIONCHANGE: + NotifyWinEvent( EVENT_OBJECT_DESCRIPTIONCHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_DEFACTIONCHANGE: + NotifyWinEvent( IA2_EVENT_ACTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_CARETCHANGE: + NotifyWinEvent( IA2_EVENT_TEXT_CARET_MOVED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_TEXTCHANGE: + NotifyWinEvent( IA2_EVENT_TEXT_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::ACTIVE_DESCENDANT_CHANGED: + UpdateAccFocus(pXAcc); + NotifyWinEvent( EVENT_OBJECT_FOCUS,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::BOUNDRECT_CHANGED: + NotifyWinEvent( EVENT_OBJECT_LOCATIONCHANGE,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::VISIBLE_DATA_CHANGED: + NotifyWinEvent( IA2_EVENT_VISIBLE_DATA_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SHOW : + NotifyWinEvent( EVENT_OBJECT_SHOW,hAcc, OBJID_CLIENT,dChildID ); + NotifyWinEvent( EVENT_SYSTEM_FOREGROUND,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_CAPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_CAPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_COLUMN_DESCRIPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_COLUMN_DESCRIPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_COLUMN_HEADER_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_COLUMN_HEADER_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_MODEL_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_MODEL_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_ROW_HEADER_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_ROW_HEADER_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_SUMMARY_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_SUMMARY_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TABLE_ROW_DESCRIPTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TABLE_ROW_DESCRIPTION_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_REORDER: + NotifyWinEvent( EVENT_OBJECT_REORDER,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::PAGE_CHANGED: + NotifyWinEvent( IA2_EVENT_PAGE_CHANGED,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::CHILD_REMOVED: + NotifyWinEvent( EVENT_OBJECT_DESTROY,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::CHILD_ADDED: + NotifyWinEvent( EVENT_OBJECT_CREATE ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::OBJECT_PAGECHANGED: + NotifyWinEvent( IA2_EVENT_PAGE_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::TEXT_SELECTION_CHANGED: + NotifyWinEvent( IA2_EVENT_TEXT_SELECTION_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::SECTION_CHANGED: + NotifyWinEvent( IA2_EVENT_SECTION_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + case UnoMSAAEvent::COLUMN_CHANGED: + NotifyWinEvent( IA2_EVENT_TEXT_COLUMN_CHANGED ,hAcc, OBJID_CLIENT,dChildID ); + break; + default: + break; + } + + return true; +} + +/** + * Get Parent XAccessible interface by XAccessible interface. + * @param pXAcc XAccessible interface. + * @return Parent XAccessible interface. + */ +XAccessible* AccObjectWinManager::GetParentXAccessible( XAccessible* pXAcc ) +{ + AccObject* pObj= GetAccObjByXAcc(pXAcc); + if( pObj ==nullptr ) + return nullptr; + if(pObj->GetParentObj()) + { + pObj = pObj->GetParentObj(); + return pObj->GetXAccessible().get(); + } + return nullptr; +} + +/** + * Get Parent role by XAccessible interface. + * @param pXAcc XAccessible interface. + * @return Parent role. + */ +short AccObjectWinManager::GetParentRole( XAccessible* pXAcc ) +{ + AccObject* pObj= GetAccObjByXAcc(pXAcc); + if( pObj ==nullptr ) + return -1; + if(pObj->GetParentObj()) + { + pObj = pObj->GetParentObj(); + if(pObj->GetXAccessible().is()) + { + Reference< XAccessibleContext > pRContext = pObj->GetXAccessible()->getAccessibleContext(); + if(pRContext.is()) + return pRContext->getAccessibleRole(); + } + } + return -1; +} + +/** + * Update focus object by new focused XAccessible interface. + * @param newFocus New XAccessible interface that gets focus. + * @return + */ +void AccObjectWinManager::UpdateAccFocus(XAccessible* newFocus) +{ + AccObject* pAccObjNew = GetAccObjByXAcc(newFocus); + if(pAccObjNew) + { + AccObject* pAccObjOld = GetAccObjByXAcc(oldFocus); + oldFocus = newFocus; + pAccObjNew->setFocus(); + //if old == new, the pAccObjNew will be without focused state + if (pAccObjOld && pAccObjOld != pAccObjNew) + pAccObjOld->unsetFocus(); + } +} + +/** + * Delete child element from children list. + * @param pObj Child element that should be removed from parent child list. + * @return + */ +void AccObjectWinManager::DeleteAccChildNode( AccObject* pObj ) +{ + AccObject *parentAccObj = pObj->GetParentObj(); + if( parentAccObj ) + parentAccObj->DeleteChild( pObj ); +} + +/** + * Delete XAccessible items in top window handle hashtable + * @param pXAcc XAccessible interface. + * @return + */ +void AccObjectWinManager::DeleteFromHwndXAcc(XAccessible const * pXAcc ) +{ + std::scoped_lock l(m_Mutex); + + auto iter = std::find_if(HwndXAcc.begin(), HwndXAcc.end(), + [&pXAcc](XHWNDToXAccHash::value_type& rEntry) { return rEntry.second == pXAcc; }); + if (iter != HwndXAcc.end()) + HwndXAcc.erase(iter); +} + +/** + * Delete all children with the tree root of XAccessible pointer + * @param pXAcc Tree root XAccessible interface. + * @return + */ +void AccObjectWinManager::DeleteChildrenAccObj(XAccessible* pXAcc) +{ + AccObject* currentObj=nullptr; + AccObject* childObj=nullptr; + + currentObj = GetAccObjByXAcc( pXAcc); + if(currentObj) + { + childObj = currentObj->NextChild(); + while(childObj) + { + XAccessible *const pTmpXAcc = childObj->GetXAccessible().get(); + if(pTmpXAcc) + { + DeleteChildrenAccObj(pTmpXAcc); + DeleteAccObj(pTmpXAcc); + } + childObj = currentObj->NextChild(); + } + } +} + +/** + * Delete Acc object self. + * @param pXAcc The XAccessible interface. + * @return + */ +void AccObjectWinManager::DeleteAccObj( XAccessible* pXAcc ) +{ + if( pXAcc == nullptr ) + return; + + rtl::Reference<AccEventListener> pListener; + + { + std::scoped_lock l(m_Mutex); + + XIdToAccObjHash::iterator temp = XIdAccList.find(pXAcc); + if( temp != XIdAccList.end() ) + { + ResIdGen.SetSub( temp->second.GetResID() ); + } + else + { + return; + } + + AccObject& accObj = temp->second; + DeleteAccChildNode( &accObj ); + pListener = DeleteAccListener(&accObj); + accObj.NotifyDestroy(); + if( accObj.GetIMAccessible() ) + { + accObj.GetIMAccessible()->Release(); + } + size_t i = XResIdAccList.erase(accObj.GetResID()); + assert(i != 0); + (void) i; + DeleteFromHwndXAcc(pXAcc); + if (accObj.GetRole() == AccessibleRole::DOCUMENT || + accObj.GetRole() == AccessibleRole::DOCUMENT_PRESENTATION || + accObj.GetRole() == AccessibleRole::DOCUMENT_SPREADSHEET || + accObj.GetRole() == AccessibleRole::DOCUMENT_TEXT) + { + XHWNDDocList.erase(accObj.GetParentHWND()); + } + XIdAccList.erase(pXAcc); // note: this invalidates accObj so do it last! + } + if (pListener) + { + pListener->RemoveMeFromBroadcaster(false); + } +} + +/** + * Delete listener that inspects some XAccessible object + * @param pAccObj Accobject pointer. + * @return + */ +rtl::Reference<AccEventListener> AccObjectWinManager::DeleteAccListener( AccObject* pAccObj ) +{ + return pAccObj->SetListener(nullptr); +} + +/** + * Generate a child ID, which is used for AT + * @param + * @return New resource ID. + */ +inline long AccObjectWinManager::ImpleGenerateResID() +{ + return ResIdGen.GenerateNewResID(); +} + +/** + * Insert all children of the current acc object + * @param pXAcc XAccessible interface + * @param pWnd Top Window handle + * @return The calling result. + */ +bool AccObjectWinManager::InsertChildrenAccObj( css::accessibility::XAccessible* pXAcc, + HWND pWnd) +{ + if(!IsContainer(pXAcc)) + return false; + + Reference< XAccessibleContext > pRContext; + + if( pXAcc == nullptr) + return false; + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return false; + + short role = pRContext->getAccessibleRole(); + + if(css::accessibility::AccessibleRole::DOCUMENT == role || + css::accessibility::AccessibleRole::DOCUMENT_PRESENTATION == role || + css::accessibility::AccessibleRole::DOCUMENT_SPREADSHEET == role || + css::accessibility::AccessibleRole::DOCUMENT_TEXT == role) + { + if(IsStateManageDescendant(pXAcc)) + { + return true; + } + } + + const sal_Int64 nCount = pRContext->getAccessibleChildCount(); + for (sal_Int64 i = 0; i < nCount; i++) + { + Reference<XAccessible> mxAccessible + = pRContext->getAccessibleChild(i); + XAccessible* mpAccessible = mxAccessible.get(); + if(mpAccessible != nullptr) + { + InsertAccObj( mpAccessible,pXAcc,pWnd ); + InsertChildrenAccObj(mpAccessible,pWnd); + } + } + + return true; +} + +/** + * Insert child object. + * @param pCurObj The child object + * @param pParentObj The parent object + * @param pWnd Top window handle. + * @return + */ +void AccObjectWinManager::InsertAccChildNode( AccObject* pCurObj, AccObject* pParentObj, HWND /* pWnd */ ) +{ + if(pCurObj) + { + if(pParentObj) + { + pParentObj->InsertChild(pCurObj); + } + else + { + pCurObj->UpdateValidWindow(); + } + } +} + +/** + * Insert child object. + * @param pCurObj The child object + * @param pParentObj The parent object + * @param pWnd Top window handle. + * @return + */ +bool AccObjectWinManager::InsertAccObj( XAccessible* pXAcc,XAccessible* pParentXAcc,HWND pWnd ) +{ + Reference< XAccessibleContext > pRContext; + + if( pXAcc == nullptr) + return false; + + pRContext = pXAcc->getAccessibleContext(); + if( !pRContext.is() ) + return false; + + { + short nCurRole = GetRole(pXAcc); + + std::scoped_lock l(m_Mutex); + + XIdToAccObjHash::iterator itXacc = XIdAccList.find( pXAcc ); + if (itXacc != XIdAccList.end() ) + { + if (AccessibleRole::SHAPE == nCurRole) + { + AccObject &objXacc = itXacc->second; + AccObject *pObjParent = objXacc.GetParentObj(); + if (pObjParent && + pObjParent->GetXAccessible().is() && + pObjParent->GetXAccessible().get() != pParentXAcc) + { + XIdToAccObjHash::iterator itXaccParent = XIdAccList.find( pParentXAcc ); + if(itXaccParent != XIdAccList.end()) + { + objXacc.SetParentObj(&(itXaccParent->second)); + } + } + } + return false; + } + } + + if( pWnd == nullptr ) + { + if(pParentXAcc) + { + AccObject* pObj = GetAccObjByXAcc(pParentXAcc); + if(pObj) + pWnd = pObj->GetParentHWND(); + } + if( pWnd == nullptr ) + return false; + } + + AccObject pObj(pXAcc, this); + if( pObj.GetIMAccessible() == nullptr ) + return false; + pObj.SetResID( this->ImpleGenerateResID()); + pObj.SetParentHWND( pWnd ); + + //for file name support + if (pObj.GetRole() == AccessibleRole::DOCUMENT || + pObj.GetRole() == AccessibleRole::DOCUMENT_PRESENTATION || + pObj.GetRole() == AccessibleRole::DOCUMENT_SPREADSHEET || + pObj.GetRole() == AccessibleRole::DOCUMENT_TEXT) + { + XHWNDToDocumentHash::iterator aIter = XHWNDDocList.find(pWnd); + if ( aIter != XHWNDDocList.end() ) + { + XHWNDDocList.erase( aIter ); + } + XHWNDDocList.emplace( pWnd, pXAcc ); + } + //end of file name + + ::rtl::Reference<AccEventListener> const pListener = + CreateAccEventListener(pXAcc); + if (!pListener.is()) + return false; + Reference<XAccessibleComponent> xComponent(pRContext,UNO_QUERY); + Reference<XAccessibleEventBroadcaster> broadcaster(xComponent,UNO_QUERY); + if (broadcaster.is()) + { + Reference<XAccessibleEventListener> const xListener(pListener); + broadcaster->addAccessibleEventListener(xListener); + } + else + return false; + + { + std::scoped_lock l(m_Mutex); + + XIdAccList.emplace(pXAcc, pObj); + XIdToAccObjHash::iterator pIndTemp = XIdAccList.find( pXAcc ); + XResIdAccList.emplace(pObj.GetResID(),&(pIndTemp->second)); + } + + AccObject* pCurObj = GetAccObjByXAcc(pXAcc); + if( pCurObj ) + { + pCurObj->SetListener(pListener); + } + + AccObject* pParentObj = GetAccObjByXAcc(pParentXAcc); + InsertAccChildNode(pCurObj,pParentObj,pWnd); + if( pCurObj ) + pCurObj->UpdateAccessibleInfoFromUnoToMSAA(); + return true; +} + + +/** + * save the pair <topwindowhandle, XAccessible> + * @param hWnd, top window handle + * @param pXAcc XAccessible interface for top window + * @return void + */ +void AccObjectWinManager::SaveTopWindowHandle(HWND hWnd, css::accessibility::XAccessible* pXAcc) +{ + std::scoped_lock l(m_Mutex); + + HwndXAcc.emplace(hWnd,pXAcc); +} + + +/** Create the corresponding listener. + * @param pXAcc XAccessible interface. + */ +::rtl::Reference<AccEventListener> +AccObjectWinManager::CreateAccEventListener(XAccessible* pXAcc) +{ + ::rtl::Reference<AccEventListener> pRet; + Reference<XAccessibleContext> xContext = pXAcc->getAccessibleContext(); + if(xContext.is()) + { + switch( xContext->getAccessibleRole() ) + { + case AccessibleRole::DIALOG: + pRet = new AccDialogEventListener(pXAcc, this); + break; + case AccessibleRole::FRAME: + pRet = new AccFrameEventListener(pXAcc, this); + break; + case AccessibleRole::WINDOW: + pRet = new AccWindowEventListener(pXAcc, this); + break; + case AccessibleRole::ROOT_PANE: + pRet = new AccFrameEventListener(pXAcc, this); + break; + //Container + case AccessibleRole::CANVAS: + case AccessibleRole::COMBO_BOX: + case AccessibleRole::DOCUMENT: + case AccessibleRole::DOCUMENT_PRESENTATION: + case AccessibleRole::DOCUMENT_SPREADSHEET: + case AccessibleRole::DOCUMENT_TEXT: + case AccessibleRole::END_NOTE: + case AccessibleRole::FILLER: + case AccessibleRole::FOOTNOTE: + case AccessibleRole::FOOTER: + case AccessibleRole::HEADER: + case AccessibleRole::LAYERED_PANE: + case AccessibleRole::MENU_BAR: + case AccessibleRole::POPUP_MENU: + case AccessibleRole::OPTION_PANE: + case AccessibleRole::PAGE_TAB: + case AccessibleRole::PAGE_TAB_LIST: + case AccessibleRole::PANEL: + case AccessibleRole::SCROLL_PANE: + case AccessibleRole::SPLIT_PANE: + case AccessibleRole::STATUS_BAR: + case AccessibleRole::TABLE_CELL: + case AccessibleRole::TOOL_BAR: + case AccessibleRole::VIEW_PORT: + pRet = new AccContainerEventListener(pXAcc, this); + break; + case AccessibleRole::BLOCK_QUOTE: + case AccessibleRole::PARAGRAPH: + case AccessibleRole::HEADING: + pRet = new AccParagraphEventListener(pXAcc, this); + break; + //Component + case AccessibleRole::CHECK_BOX: + case AccessibleRole::ICON: + case AccessibleRole::LABEL: + case AccessibleRole::STATIC: + case AccessibleRole::NOTIFICATION: + case AccessibleRole::MENU_ITEM: + case AccessibleRole::CHECK_MENU_ITEM: + case AccessibleRole::RADIO_MENU_ITEM: + case AccessibleRole::PUSH_BUTTON: + case AccessibleRole::RADIO_BUTTON: + case AccessibleRole::SCROLL_BAR: + case AccessibleRole::SEPARATOR: + case AccessibleRole::TOGGLE_BUTTON: + case AccessibleRole::BUTTON_DROPDOWN: + case AccessibleRole::TOOL_TIP: + case AccessibleRole::SPIN_BOX: + case AccessibleRole::DATE_EDITOR: + pRet = new AccComponentEventListener(pXAcc, this); + break; + //text component + case AccessibleRole::TEXT: + pRet = new AccTextComponentEventListener(pXAcc, this); + break; + //menu + case AccessibleRole::MENU: + pRet = new AccMenuEventListener(pXAcc, this); + break; + //object container + case AccessibleRole::SHAPE: + + case AccessibleRole::EMBEDDED_OBJECT: + case AccessibleRole::GRAPHIC: + case AccessibleRole::TEXT_FRAME: + pRet = new AccObjectContainerEventListener(pXAcc, this); + break; + //descendmanager + case AccessibleRole::LIST: + pRet = new AccListEventListener(pXAcc, this); + break; + case AccessibleRole::TREE: + pRet = new AccTreeEventListener(pXAcc, this); + break; + //special + case AccessibleRole::COLUMN_HEADER: + case AccessibleRole::TABLE: + pRet = new AccTableEventListener(pXAcc, this); + break; + default: + pRet = new AccContainerEventListener(pXAcc, this); + break; + } + } + return pRet; +} + +/** + * state is a combination integer, each bit of which represents a single state, + * such as focused,1 for the state on,0 for the state off. Here call COM interface + * to modify the state value, including DecreaseState. + * @param pXAcc XAccessible interface. + * @param pState Changed state. + * @return + */ +void AccObjectWinManager::DecreaseState(XAccessible* pXAcc, sal_Int64 nState) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->DecreaseState(nState); +} + +/** + * state is a combination integer, each bit of which represents a single state,such as focused,1 for + * the state on,0 for the state off. Here call COM interface to modify the state value, including + * IncreaseState. + * @param pXAcc XAccessible interface. + * @param pState Changed state. + * @return + */ +void AccObjectWinManager::IncreaseState(XAccessible* pXAcc, sal_Int64 nState) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->IncreaseState(nState); +} + +void AccObjectWinManager::UpdateState( css::accessibility::XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateState( ); +} + +/** + * Set corresponding com object's accessible name via XAccessible interface and new + * name + * @param pXAcc XAccessible interface. + * @return + */ +void AccObjectWinManager::UpdateAccName( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateName(); +} + +void AccObjectWinManager::UpdateAction( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateAction(); +} + +/** + * Set corresponding com object's value via XAccessible interface and new value. + * @param pXAcc XAccessible interface. + * @param pAny new value. + * @return + */ +void AccObjectWinManager::SetValue( XAccessible* pXAcc, Any pAny ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->SetValue( pAny ); +} + +/** + * Set corresponding com object's value via XAccessible interface. + * @param pXAcc XAccessible interface. + * @return + */ +void AccObjectWinManager::UpdateValue( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->UpdateValue(); +} + +/** + * Set corresponding com object's name via XAccessible interface and new name. + * @param pXAcc XAccessible interface. + * @param newName new name + * @return + */ +void AccObjectWinManager::SetAccName( XAccessible* pXAcc, Any newName) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if( pAccObj ) + pAccObj->SetName( newName ); +} + +/** + * Judge if a XAccessible object is a container object. + * @param pAccessible XAccessible interface. + * @return If XAccessible object is container. + */ +bool AccObjectWinManager::IsContainer(XAccessible* pAccessible) +{ + try + { + if(pAccessible) + { + Reference<XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(xContext.is()) + { + switch( xContext->getAccessibleRole() ) + { + case AccessibleRole::DIALOG: + case AccessibleRole::FRAME: + case AccessibleRole::WINDOW: + case AccessibleRole::ROOT_PANE: + case AccessibleRole::CANVAS: + case AccessibleRole::COMBO_BOX: + case AccessibleRole::DOCUMENT: + case AccessibleRole::DOCUMENT_PRESENTATION: + case AccessibleRole::DOCUMENT_SPREADSHEET: + case AccessibleRole::DOCUMENT_TEXT: + case AccessibleRole::EMBEDDED_OBJECT: + case AccessibleRole::END_NOTE: + case AccessibleRole::FILLER: + case AccessibleRole::FOOTNOTE: + case AccessibleRole::FOOTER: + case AccessibleRole::GRAPHIC: + case AccessibleRole::GROUP_BOX: + case AccessibleRole::HEADER: + case AccessibleRole::LAYERED_PANE: + case AccessibleRole::MENU_BAR: + case AccessibleRole::POPUP_MENU: + case AccessibleRole::OPTION_PANE: + case AccessibleRole::PAGE_TAB: + case AccessibleRole::PAGE_TAB_LIST: + case AccessibleRole::PANEL: + case AccessibleRole::SCROLL_PANE: + case AccessibleRole::SPLIT_PANE: + case AccessibleRole::STATUS_BAR: + case AccessibleRole::TABLE_CELL: + case AccessibleRole::TEXT_FRAME: + case AccessibleRole::TOOL_BAR: + case AccessibleRole::VIEW_PORT: + case AccessibleRole::SHAPE: + return true; + case AccessibleRole::COLUMN_HEADER: + case AccessibleRole::TABLE: + if(!IsStateManageDescendant(pAccessible)) + return true; + break; + case AccessibleRole::MENU: + return true; + default: + return false; + } + } + } + } + catch(...) + { + return false; + } + return false; +} + +/** + * Judge if a XAccessible object has ManageDescendant event. + * @param pAccessible XAccessible interface. + * @return If XAccessible object is managedescendant. + */ +bool AccObjectWinManager::IsStateManageDescendant(XAccessible* pAccessible) +{ + if(pAccessible) + { + Reference<XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(xContext.is()) + { + sal_Int64 nRState = xContext->getAccessibleStateSet(); + return nRState & AccessibleStateType::MANAGES_DESCENDANTS; + } + } + return false; +} + +/** + * Query and get IAccessible interface by XAccessible interface from list. + * @param pXAcc XAccessible interface. + * @return Com accobject interface. + */ +IMAccessible* AccObjectWinManager::GetIAccessibleFromXAccessible(XAccessible* pXAcc) +{ + AccObject* pAccObj = GetAccObjByXAcc(pXAcc); + if (pAccObj) + return pAccObj->GetIMAccessible(); + + return nullptr; +} + +/** + * Query and get IAccessible interface by child id from list. + * @param resID, childID. + * @return Com accobject interface. + */ +IMAccessible * AccObjectWinManager::GetIAccessibleFromResID(long resID) +{ + XResIdToAccObjHash::iterator pIndTemp = XResIdAccList.find( resID ); + if ( pIndTemp == XResIdAccList.end() ) + return nullptr; + + AccObject* pObj = pIndTemp->second; + + if(pObj->GetIMAccessible()) + return pObj->GetIMAccessible(); + return nullptr; +} +/** + * Notify some object will be destroyed. + * @param pXAcc XAccessible interface. + * @return Com accobject interface. + */ +void AccObjectWinManager::NotifyDestroy(XAccessible* pXAcc) +{ + AccObject* accObj = GetAccObjByXAcc(pXAcc); + if(accObj) + { + accObj->NotifyDestroy(); + } +} + + +void AccObjectWinManager::UpdateChildState(css::accessibility::XAccessible* pAccSubMenu) +{ + Reference<css::accessibility::XAccessibleContext> xContext(pAccSubMenu,UNO_QUERY); + if (!xContext.is()) + { + return; + } + const sal_Int64 nCount = xContext->getAccessibleChildCount(); + for (sal_Int64 i = 0 ; i < nCount; ++i) + { + Reference<css::accessibility::XAccessible> xChild = xContext->getAccessibleChild(i); + if (xChild.is()) + { + AccObject *pObj = GetAccObjByXAcc(xChild.get()); + if (pObj) + { + pObj->UpdateState(); + } + } + } +} + + +bool AccObjectWinManager::IsSpecialToolbarItem(css::accessibility::XAccessible* pXAcc) +{ + if (pXAcc && oldFocus != pXAcc) + { + if (GetParentRole(pXAcc) == AccessibleRole::TOOL_BAR) + { + Reference< XAccessibleContext > pRContext(pXAcc->getAccessibleContext()); + if (pRContext.is()) + { + if (pRContext->getAccessibleRole() == AccessibleRole::TOGGLE_BUTTON) + { + return true; + } + } + } + } + return false; +} + +short AccObjectWinManager::GetRole(css::accessibility::XAccessible* pXAcc) +{ + assert(pXAcc != nullptr); + Reference<css::accessibility::XAccessibleContext> xContext = pXAcc->getAccessibleContext(); + if(xContext.is()) + { + return xContext->getAccessibleRole(); + } + return -1; +} + +XAccessible* AccObjectWinManager::GetAccDocByHWND(HWND pWnd) +{ + XHWNDToDocumentHash::iterator aIter; + aIter = XHWNDDocList.find( pWnd ); + if ( aIter != XHWNDDocList.end() ) + { + return aIter->second; + } + + return nullptr; +} + +XAccessible* AccObjectWinManager::GetAccDocByAccTopWin( XAccessible* pXAcc ) +{ + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + HWND hWnd = pAccObj->GetParentHWND(); + return GetAccDocByHWND(hWnd); +} + +bool AccObjectWinManager::IsTopWinAcc( css::accessibility::XAccessible* pXAcc ) +{ + bool bRet = false; + AccObject* pAccObj = GetAccObjByXAcc( pXAcc ); + if ( pAccObj ) + { + bRet = ( pAccObj->GetParentObj() == nullptr ); + } + return bRet; +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccParagraphEventListener.cxx b/winaccessibility/source/service/AccParagraphEventListener.cxx new file mode 100644 index 0000000000..fe7504901f --- /dev/null +++ b/winaccessibility/source/service/AccParagraphEventListener.cxx @@ -0,0 +1,130 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccParagraphEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccParagraphEventListener::AccParagraphEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccContainerEventListener(pAcc, pManager) +{} +AccParagraphEventListener::~AccParagraphEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccParagraphEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::CARET_CHANGED: + HandleCaretChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + //Added for paragraph selected state. + case AccessibleEventId::STATE_CHANGED: + { + sal_Int64 State; + if( (aEvent.NewValue >>= State) && (State == AccessibleStateType::SELECTED) ) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), State); + break; + } + else if( (aEvent.OldValue >>= State) && (State == AccessibleStateType::SELECTED) ) + { + m_pObjManager->DecreaseState(m_xAccessible.get(), State); + break; + } + + AccContainerEventListener::notifyEvent(aEvent); + break; + } + + case AccessibleEventId::TEXT_SELECTION_CHANGED: + HandleTextSelectionChangedEvent(); + break; + + default: + AccContainerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the CARET_CHANGED event + * @param oldValue in UNO, this parameter is always NULL + * @param newValue in UNO, this parameter is always NULL + */ +void AccParagraphEventListener::HandleCaretChangedEvent(Any, Any) +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::OBJECT_CARETCHANGE); +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccParagraphEventListener::SetComponentState(sal_Int64 state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::EDITABLE: + // no msaa state + break; + case AccessibleStateType::MULTI_LINE: + // no msaa state mapping + break; + case AccessibleStateType::SINGLE_LINE: + // no msaa state mapping + break; + default: + AccContainerEventListener::SetComponentState(state, enable); + break; + } +} + +void AccParagraphEventListener::HandleTextSelectionChangedEvent() +{ + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TEXT_SELECTION_CHANGED); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTableEventListener.cxx b/winaccessibility/source/service/AccTableEventListener.cxx new file mode 100644 index 0000000000..ccc67690a6 --- /dev/null +++ b/winaccessibility/source/service/AccTableEventListener.cxx @@ -0,0 +1,142 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> +#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp> + +#include <vcl/svapp.hxx> + +#include <AccTableEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccTableEventListener::AccTableEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccDescendantManagerEventListener(pAcc, pManager) +{} +AccTableEventListener::~AccTableEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccTableEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + HandleActiveDescendantChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + + case AccessibleEventId::TABLE_CAPTION_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_CAPTION_CHANGED); + break; + } + case AccessibleEventId::TABLE_COLUMN_DESCRIPTION_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_COLUMN_DESCRIPTION_CHANGED); + break; + } + case AccessibleEventId::TABLE_COLUMN_HEADER_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_COLUMN_HEADER_CHANGED); + break; + } + case AccessibleEventId::TABLE_ROW_HEADER_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_ROW_HEADER_CHANGED); + break; + } + case AccessibleEventId::TABLE_MODEL_CHANGED: + { + HandleTableModelChangeEvent(aEvent.NewValue); + break; + } + case AccessibleEventId::TABLE_SUMMARY_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_SUMMARY_CHANGED); + break; + } + case AccessibleEventId::TABLE_ROW_DESCRIPTION_CHANGED: + { + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_ROW_DESCRIPTION_CHANGED); + break; + } + default: + AccDescendantManagerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the ACTIVE_DESCENDANT_CHANGED event + * @param oldValue the child to lose active + * @param newValue the child to get active + */ +void AccTableEventListener::HandleActiveDescendantChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::ACTIVE_DESCENDANT_CHANGED); + } + } + else if (oldValue >>= xChild) + { + //delete an existing child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->DeleteAccObj( pAcc ); + } + } + +} +void AccTableEventListener::HandleTableModelChangeEvent(Any newValue) +{ + AccessibleTableModelChange aModelChange; + if (newValue >>= aModelChange) + { + if (m_xAccessible.is()) + { + //delete all oldValue's existing children + m_pObjManager->DeleteChildrenAccObj(m_xAccessible.get()); + //add all oldValue's existing children + m_pObjManager->InsertChildrenAccObj(m_xAccessible.get()); + } + m_pObjManager->NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::TABLE_MODEL_CHANGED); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTextComponentEventListener.cxx b/winaccessibility/source/service/AccTextComponentEventListener.cxx new file mode 100644 index 0000000000..05643016ea --- /dev/null +++ b/winaccessibility/source/service/AccTextComponentEventListener.cxx @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccTextComponentEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccTextComponentEventListener::AccTextComponentEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccComponentEventListener(pAcc, pManager) +{} +AccTextComponentEventListener::~AccTextComponentEventListener() +{ +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccTextComponentEventListener::SetComponentState(sal_Int64 state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::EDITABLE: + // no msaa state mapping + break; + case AccessibleStateType::MULTI_LINE: + // no msaa state mapping + break; + case AccessibleStateType::SINGLE_LINE: + // no msaa state mapping + break; + default: + AccComponentEventListener::SetComponentState(state, enable); + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTopWindowListener.cxx b/winaccessibility/source/service/AccTopWindowListener.cxx new file mode 100644 index 0000000000..12cb20f85a --- /dev/null +++ b/winaccessibility/source/service/AccTopWindowListener.cxx @@ -0,0 +1,253 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <sal/log.hxx> +#include <vcl/window.hxx> +#include <toolkit/awt/vclxaccessiblecomponent.hxx> +#include <toolkit/awt/vclxwindow.hxx> + +#include <vcl/sysdata.hxx> +#include <vcl/svapp.hxx> + +#include <AccTopWindowListener.hxx> +#include <unomsaaevent.hxx> + +#include <com/sun/star/accessibility/AccessibleRole.hpp> + +using namespace com::sun::star::uno; + +/** + * For the new opened window, generate all the UNO accessible's object, COM object and add + * accessible listener to monitor all these objects. + * @param pAccessible the accessible of the new opened window + */ +void AccTopWindowListener::HandleWindowOpened( css::accessibility::XAccessible* pAccessible ) +{ + //get SystemData from window + VclPtr<vcl::Window> window; + if (auto pvclwindow = dynamic_cast<VCLXWindow*>(pAccessible)) + window = pvclwindow->GetWindow(); + else if (auto pvclxcomponent = dynamic_cast<VCLXAccessibleComponent*>(pAccessible)) + window = pvclxcomponent->GetWindow(); + assert(window); + // The SalFrame of window may be destructed at this time + const SystemEnvData* systemdata = nullptr; + try + { + systemdata = window->GetSystemData(); + } + catch(...) + { + systemdata = nullptr; + } + Reference<css::accessibility::XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(!xContext.is()) + return; + + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + //Only AccessibleContext exist, add all listeners + if(pAccessibleContext != nullptr && systemdata != nullptr) + { + m_aAccObjectManager.SaveTopWindowHandle(systemdata->hWnd, pAccessible); + + AddAllListeners(pAccessible,nullptr,systemdata->hWnd); + + if( window->GetStyle() & WB_MOVEABLE ) + m_aAccObjectManager.IncreaseState( pAccessible, static_cast<unsigned short>(-1) /* U_MOVEBLE */ ); + + short role = pAccessibleContext->getAccessibleRole(); + + if (role == css::accessibility::AccessibleRole::POPUP_MENU || + role == css::accessibility::AccessibleRole::MENU ) + { + m_aAccObjectManager.NotifyAccEvent(pAccessible, UnoMSAAEvent::MENUPOPUPSTART); + } + + if (role == css::accessibility::AccessibleRole::FRAME || + role == css::accessibility::AccessibleRole::DIALOG || + role == css::accessibility::AccessibleRole::WINDOW || + role == css::accessibility::AccessibleRole::ALERT) + { + m_aAccObjectManager.NotifyAccEvent(pAccessible, UnoMSAAEvent::SHOW); + } + } +} + +AccTopWindowListener::AccTopWindowListener() + : m_aAccObjectManager() +{ +} + +AccTopWindowListener::~AccTopWindowListener() +{ +} + +/** + * It is invoked when a new window is opened, the source of this EventObject is the window + */ +void AccTopWindowListener::windowOpened( const css::lang::EventObject& e ) +{ + SAL_INFO( "iacc2", "windowOpened triggered" ); + + if ( !e.Source.is()) + return; + + Reference< css::accessibility::XAccessible > xAccessible ( e.Source, UNO_QUERY ); + css::accessibility::XAccessible* pAccessible = xAccessible.get(); + if ( !pAccessible ) + return; + + SolarMutexGuard g; + + HandleWindowOpened( pAccessible ); +} + +/** + * Add the accessible event listener to object and all its children objects. + * @param pAccessible the accessible object + * @param pParentXAcc the parent of current accessible object + * @param pWND the handle of top window which current object resides + */ +void AccTopWindowListener::AddAllListeners(css::accessibility::XAccessible* pAccessible, css::accessibility::XAccessible* pParentXAcc, HWND pWND) +{ + Reference<css::accessibility::XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(!xContext.is()) + { + return; + } + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + if(pAccessibleContext == nullptr) + { + return; + } + + m_aAccObjectManager.InsertAccObj(pAccessible, pParentXAcc, pWND); + + if (!AccObjectWinManager::IsContainer(pAccessible)) + { + return; + } + + + short role = pAccessibleContext->getAccessibleRole(); + if(css::accessibility::AccessibleRole::DOCUMENT == role || + css::accessibility::AccessibleRole::DOCUMENT_PRESENTATION == role || + css::accessibility::AccessibleRole::DOCUMENT_SPREADSHEET == role || + css::accessibility::AccessibleRole::DOCUMENT_TEXT == role) + { + if(AccObjectWinManager::IsStateManageDescendant(pAccessible)) + { + return ; + } + } + + sal_Int64 nCount = pAccessibleContext->getAccessibleChildCount(); + for (sal_Int64 i = 0; i < nCount; i++) + { + Reference<css::accessibility::XAccessible> mxAccessible + = pAccessibleContext->getAccessibleChild(i); + + css::accessibility::XAccessible* mpAccessible = mxAccessible.get(); + if(mpAccessible != nullptr) + { + Reference<css::accessibility::XAccessibleContext> mxAccessibleContext + = mpAccessible->getAccessibleContext(); + css::accessibility::XAccessibleContext* mpContext = mxAccessibleContext.get(); + if(mpContext != nullptr) + AddAllListeners( mpAccessible, pAccessible, pWND); + } + } +} + +void AccTopWindowListener::windowClosing( const css::lang::EventObject& ) +{ + SAL_INFO( "iacc2", "windowClosing triggered" ); +} + +/** + * Invoke this method when the top window is closed, remove all the objects and its children + * from current manager's cache, and remove the COM object and the accessible event listener + * assigned to the accessible objects. + */ +void AccTopWindowListener::windowClosed( const css::lang::EventObject& e ) +{ + SAL_INFO( "iacc2", "windowClosed triggered" ); + + if ( !e.Source.is()) + return; + + Reference< css::accessibility::XAccessible > xAccessible ( e.Source, UNO_QUERY ); + css::accessibility::XAccessible* pAccessible = xAccessible.get(); + if ( pAccessible == nullptr) + return; + + Reference<css::accessibility::XAccessibleContext> xContext = pAccessible->getAccessibleContext(); + if(!xContext.is()) + { + return; + } + css::accessibility::XAccessibleContext* pAccessibleContext = xContext.get(); + + short role = -1; + if(pAccessibleContext != nullptr) + { + role = pAccessibleContext->getAccessibleRole(); + + if (role == css::accessibility::AccessibleRole::POPUP_MENU || + role == css::accessibility::AccessibleRole::MENU) + { + m_aAccObjectManager.NotifyAccEvent(pAccessible, UnoMSAAEvent::MENUPOPUPEND); + } + } + + + m_aAccObjectManager.DeleteChildrenAccObj( pAccessible ); + if( role != css::accessibility::AccessibleRole::POPUP_MENU ) + m_aAccObjectManager.DeleteAccObj( pAccessible ); + +} + +void AccTopWindowListener::windowMinimized( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::windowNormalized( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::windowActivated( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::windowDeactivated( const css::lang::EventObject& ) +{ +} + +void AccTopWindowListener::disposing( const css::lang::EventObject& ) +{ +} + +sal_Int64 AccTopWindowListener::GetMSComPtr( + sal_Int64 hWnd, sal_Int64 lParam, sal_Int64 wParam) +{ + return m_aAccObjectManager.Get_ToATInterface(hWnd, lParam, wParam); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccTreeEventListener.cxx b/winaccessibility/source/service/AccTreeEventListener.cxx new file mode 100644 index 0000000000..b7c80b2d1f --- /dev/null +++ b/winaccessibility/source/service/AccTreeEventListener.cxx @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccTreeEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccTreeEventListener::AccTreeEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccDescendantManagerEventListener(pAcc, pManager) +{} +AccTreeEventListener::~AccTreeEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject the event object which contains information about event + */ +void AccTreeEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::ACTIVE_DESCENDANT_CHANGED: + HandleActiveDescendantChangedEvent(aEvent.OldValue, aEvent.NewValue); + break; + default: + AccDescendantManagerEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * handle the ACTIVE_DESCENDANT_CHANGED event + * @param oldValue the child to lose active + * @param newValue the child to get active + */ +void AccTreeEventListener::HandleActiveDescendantChangedEvent(Any oldValue, Any newValue) +{ + Reference< XAccessible > xChild; + if(newValue >>= xChild ) + { + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->InsertAccObj(pAcc, m_xAccessible.get()); + m_pObjManager->NotifyAccEvent(pAcc, UnoMSAAEvent::ACTIVE_DESCENDANT_CHANGED); + } + } + if (oldValue >>= xChild) + { + //delete an existing child + if(xChild.is()) + { + XAccessible* pAcc = xChild.get(); + m_pObjManager->DeleteAccObj(pAcc); + } + } + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/AccWindowEventListener.cxx b/winaccessibility/source/service/AccWindowEventListener.cxx new file mode 100644 index 0000000000..5a96914ea5 --- /dev/null +++ b/winaccessibility/source/service/AccWindowEventListener.cxx @@ -0,0 +1,98 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <com/sun/star/accessibility/XAccessible.hpp> +#include <com/sun/star/accessibility/AccessibleStateType.hpp> +#include <com/sun/star/accessibility/AccessibleEventId.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> +#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp> + +#include <vcl/svapp.hxx> + +#include <AccWindowEventListener.hxx> +#include <AccObjectWinManager.hxx> +#include <unomsaaevent.hxx> + +using namespace com::sun::star::uno; +using namespace com::sun::star::accessibility; + +AccWindowEventListener::AccWindowEventListener(css::accessibility::XAccessible* pAcc, AccObjectWinManager* pManager) + :AccEventListener(pAcc, pManager) +{} +AccWindowEventListener::~AccWindowEventListener() +{ +} + +/** + * Uno's event notifier when event is captured + * @param AccessibleEventObject: the event object which contains information about event + */ +void AccWindowEventListener::notifyEvent( const css::accessibility::AccessibleEventObject& aEvent ) +{ + SolarMutexGuard g; + + switch (aEvent.EventId) + { + case AccessibleEventId::VISIBLE_DATA_CHANGED: + HandleVisibleDataChangedEvent(); + break; + case AccessibleEventId::BOUNDRECT_CHANGED: + HandleBoundrectChangedEvent(); + break; + default: + AccEventListener::notifyEvent(aEvent); + break; + } +} + +/** + * set the new state and fire the MSAA event + * @param state new state id + * @param enable true if state is set, false if state is unset + */ +void AccWindowEventListener::SetComponentState(sal_Int64 state, bool enable ) +{ + // only the following state can be fired state event. + switch (state) + { + case AccessibleStateType::ICONIFIED: + // no msaa state + break; + case AccessibleStateType::VISIBLE: + // UNO !VISIBLE == MSAA INVISIBLE + if( enable ) + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + else + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::VISIBLE); + break; + case AccessibleStateType::SHOWING: + // UNO !SHOWING == MSAA OFFSCREEN + if( enable ) + { + m_pObjManager->IncreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + } + else + m_pObjManager->DecreaseState(m_xAccessible.get(), AccessibleStateType::SHOWING); + break; + default: + break; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/ResIDGenerator.cxx b/winaccessibility/source/service/ResIDGenerator.cxx new file mode 100644 index 0000000000..7498380300 --- /dev/null +++ b/winaccessibility/source/service/ResIDGenerator.cxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ResIDGenerator.hxx> + +#include <cassert> + +ResIDGenerator::~ResIDGenerator() {} + +/** + * SubList stores those IDs that were ever generated and deleted, the method + * return the ID from subList first if subList is not empty, else return m_nMin--. + * Add the obsolete IDs by calling SetSub method + * + * @param + * @return new resource ID. + */ +long ResIDGenerator::GenerateNewResID() +{ + if (!subList.empty()) + { + long nRes = *(subList.begin()); + subList.pop_front(); + return nRes; + } + assert(m_nMin > LONG_MIN); + return m_nMin--; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/msaaservice_impl.cxx b/winaccessibility/source/service/msaaservice_impl.cxx new file mode 100644 index 0000000000..3891b6df48 --- /dev/null +++ b/winaccessibility/source/service/msaaservice_impl.cxx @@ -0,0 +1,275 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <rtl/ref.hxx> +#include <sal/log.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/implementationentry.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/accessibility/XMSAAService.hpp> +#include <com/sun/star/accessibility/AccessibleRole.hpp> + +#include <com/sun/star/awt/XExtendedToolkit.hpp> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> + +#include <prewin.h> +#include <postwin.h> + +#include <AccTopWindowListener.hxx> + +using namespace ::com::sun::star; // for odk interfaces +using namespace ::com::sun::star::uno; // for basic types +using namespace ::com::sun::star::accessibility; + +using namespace ::com::sun::star::awt; + +namespace my_sc_impl +{ + +namespace { + +class MSAAServiceImpl : public ::cppu::WeakImplHelper< + XMSAAService, lang::XServiceInfo > +{ +private: + rtl::Reference<AccTopWindowListener> m_pTopWindowListener; + +public: + MSAAServiceImpl (); + + // XComponent - as used by VCL to lifecycle manage this bridge. + virtual void SAL_CALL dispose() override; + virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& ) override + { /* dummy */ } + virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& ) override + { /* dummy */ } + + // XMSAAService + virtual sal_Int64 SAL_CALL getAccObjectPtr( + sal_Int64 hWnd, sal_Int64 lParam, sal_Int64 wParam) override; + virtual void SAL_CALL handleWindowOpened(sal_Int64) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( OUString const & serviceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; +}; + +} + +/** + * Implementation of getAccObjectPtr. + * @param + * @return Com interface. + */ +sal_Int64 MSAAServiceImpl::getAccObjectPtr( + sal_Int64 hWnd, sal_Int64 lParam, sal_Int64 wParam) +{ + // tdf#155794: this must complete without taking SolarMutex + + if (!m_pTopWindowListener.is()) + { + return 0; + } + return m_pTopWindowListener->GetMSComPtr(hWnd, lParam, wParam); +} + +/** + * Implementation of handleWindowOpened, the method will be invoked when a + * top window is opened and AT starts up. + * @param + * @return + */ +void MSAAServiceImpl::handleWindowOpened(sal_Int64 nAcc) +{ + SolarMutexGuard g; + + SAL_INFO( "iacc2", "Window opened " << nAcc ); + + if (m_pTopWindowListener.is() && nAcc) + { + m_pTopWindowListener->HandleWindowOpened( + static_cast<css::accessibility::XAccessible*>( + reinterpret_cast<void*>(nAcc))); + } +} + +OUString MSAAServiceImpl::getImplementationName() +{ + return "com.sun.star.accessibility.my_sc_implementation.MSAAService"; +} + +/** + * Implementation of XServiceInfo, return support service name. + * @param Service name. + * @return If the service name is supported. + */ +sal_Bool MSAAServiceImpl::supportsService( OUString const & serviceName ) +{ + return cppu::supportsService(this, serviceName); +} + +/** + * Implementation of XServiceInfo, return all service names. + * @param. + * @return service name sequence. + */ +Sequence< OUString > MSAAServiceImpl::getSupportedServiceNames() +{ + return { "com.sun.star.accessibility.MSAAService" }; +} + +static void AccessBridgeHandleExistingWindow(const Reference< XMSAAService > &xAccMgr, + vcl::Window *pWindow, bool bShow) +{ + if ( pWindow ) + { + css::uno::Reference< css::accessibility::XAccessible > xAccessible; + + SAL_INFO( "iacc2", "Decide whether to register existing window with IAccessible2" ); + + // Test for combo box - drop down floating windows first + vcl::Window * pParentWindow = pWindow->GetParent(); + + if ( pParentWindow ) + { + try + { + // The parent window of a combo box floating window should have the role COMBO_BOX + css::uno::Reference< css::accessibility::XAccessible > xParentAccessible(pParentWindow->GetAccessible()); + if ( xParentAccessible.is() ) + { + css::uno::Reference< css::accessibility::XAccessibleContext > xParentAC( xParentAccessible->getAccessibleContext() ); + if ( xParentAC.is() && (css::accessibility::AccessibleRole::COMBO_BOX == xParentAC->getAccessibleRole()) ) + { + // O.k. - this is a combo box floating window corresponding to the child of role LIST of the parent. + // Let's not rely on a specific child order, just search for the child with the role LIST + sal_Int64 nCount = xParentAC->getAccessibleChildCount(); + for (sal_Int64 n = 0; (n < nCount) && !xAccessible.is(); n++) + { + css::uno::Reference< css::accessibility::XAccessible > xChild = xParentAC->getAccessibleChild(n); + if ( xChild.is() ) + { + css::uno::Reference< css::accessibility::XAccessibleContext > xChildAC = xChild->getAccessibleContext(); + if ( xChildAC.is() && (css::accessibility::AccessibleRole::LIST == xChildAC->getAccessibleRole()) ) + { + xAccessible = xChild; + } + } + } + } + } + } + catch (css::uno::RuntimeException const&) + { + // Ignore show events that throw DisposedExceptions in getAccessibleContext(), + // but keep revoking these windows in hide(s). + if (bShow) + return; + } + } + + // We have to rely on the fact that Window::GetAccessible()->getAccessibleContext() returns a valid XAccessibleContext + // also for other menus than menubar or toplevel popup window. Otherwise we had to traverse the hierarchy to find the + // context object to this menu floater. This makes the call to Window->IsMenuFloatingWindow() obsolete. + if ( ! xAccessible.is() ) + xAccessible = pWindow->GetAccessible(); + + assert( xAccMgr.is() ); + if ( xAccessible.is() ) + { + xAccMgr->handleWindowOpened( + reinterpret_cast<sal_Int64>(xAccessible.get())); + SAL_INFO( "iacc2", "Decide whether to register existing window with IAccessible2" ); + } + } +} + +/* + * Setup and notify the OS of Accessible peers for all existing windows. + */ +static void AccessBridgeUpdateOldTopWindows( const Reference< XMSAAService > &xAccMgr ) +{ + sal_uInt16 nTopWindowCount = static_cast<sal_uInt16>(Application::GetTopWindowCount()); + + for ( sal_uInt16 i = 0; i < nTopWindowCount; i++ ) + { + vcl::Window* pTopWindow = Application::GetTopWindow( i ); + css::uno::Reference< css::accessibility::XAccessible > xAccessible = pTopWindow->GetAccessible(); + if ( xAccessible.is() ) + { + css::uno::Reference< css::accessibility::XAccessibleContext > xAC( xAccessible->getAccessibleContext() ); + if ( xAC.is()) + { + if ( !xAC->getAccessibleName().isEmpty() ) + AccessBridgeHandleExistingWindow( xAccMgr, pTopWindow, true ); + } + } + } +} + +MSAAServiceImpl::MSAAServiceImpl() +{ + Reference< XExtendedToolkit > xToolkit(Application::GetVCLToolkit(), UNO_QUERY); + + if( xToolkit.is() ) + { + m_pTopWindowListener.set(new AccTopWindowListener()); + Reference<XTopWindowListener> const xRef(m_pTopWindowListener); + xToolkit->addTopWindowListener( xRef ); + SAL_INFO( "iacc2", "successfully connected to the toolkit event hose" ); + } + else + SAL_WARN( "iacc2", "No VCL toolkit interface to listen to for events"); +} + +void MSAAServiceImpl::dispose() +{ + SolarMutexGuard g; + + // As all folders and streams contain references to their parents, + // we must remove these references so that they will be deleted when + // the hash_map of the root folder is cleared, releasing all subfolders + // and substreams which in turn release theirs, etc. When xRootFolder is + // released when this destructor completes, the folder tree should be + // deleted fully (and automagically). + m_pTopWindowListener.clear(); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +winaccessibility_MSAAServiceImpl_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + Reference< XMSAAService > xAccMgr( new MSAAServiceImpl() ); + + AccessBridgeUpdateOldTopWindows( xAccMgr ); + + SAL_INFO("iacc2", "Created new IAccessible2 service impl."); + + xAccMgr->acquire(); + return xAccMgr.get(); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/winaccessibility/source/service/winaccessibility.component b/winaccessibility/source/service/winaccessibility.component new file mode 100644 index 0000000000..fe26e40e20 --- /dev/null +++ b/winaccessibility/source/service/winaccessibility.component @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + --> +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.accessibility.my_sc_implementation.MSAAService" + constructor="winaccessibility_MSAAServiceImpl_get_implementation"> + <service name="com.sun.star.accessibility.MSAAService"/> + </implementation> +</component> |