tdf#160695 wina11y: Send status change events for toolbar buttons

When the checked or indeterminate state of a toolbar button
changes, forward the corresponding UNO a11y event as
a corresponding MSAA event.

For roles `AccessibleRole::PUSH_BUTTON` and
`AccessibleRole::TOGGLE_BUTTON`, `AccObject::GetMSAAStateFromUNO`
uses `STATE_SYSTEM_PRESSED` instead of
`STATE_SYSTEM_CHECKED`, so also use
`UnoMSAAEvent::STATE_PRESSED` for the event.

It's unclear why sending of such events would generally
be omitted for "special toolbar items" previously.

The events can be used to implement announcement of
toggled font attributes in NVDA, e.g. when the "Bold"
button in the formatting toolbar is toggled via a keyboard
shortcut, similar to how Orca does it (s. tdf#123864).

Related NVDA issue for which I plan to submit a PR: [1]

[1] https://github.com/nvaccess/nvda/issues/4248

Change-Id: Ic2846e338802c3cb7656de5b77e4df23bd5b0703
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166155
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
This commit is contained in:
Michael Weghorn 2024-04-16 19:02:30 +02:00
parent d304fdb336
commit 0425b6eb47
3 changed files with 19 additions and 30 deletions

View file

@ -132,8 +132,6 @@ public:
void UpdateChildState(css::accessibility::XAccessible* pXAcc);
bool IsSpecialToolbarItem(css::accessibility::XAccessible* pXAcc);
static short GetRole(css::accessibility::XAccessible* pXAcc);
css::accessibility::XAccessible* GetAccDocByAccTopWin( css::accessibility::XAccessible* pXAcc );

View file

@ -207,6 +207,19 @@ void AccComponentEventListener::SetComponentState(sal_Int64 state, bool enable)
*/
void AccComponentEventListener::FireStatePropertyChange(sal_Int64 state, bool set)
{
if (!m_xAccessible.is())
return;
css::uno::Reference<css::accessibility::XAccessibleContext> xAccContext = m_xAccessible->getAccessibleContext();
if (!xAccContext.is())
return;
const sal_Int16 nRole = xAccContext->getAccessibleRole();
// for these button roles, MSAA state STATE_SYSTEM_PRESSED is used instead of
// STATE_SYSTEM_CHECKED (s. AccObject::GetMSAAStateFromUNO)
const bool bPressedInsteadOfChecked
= (nRole == AccessibleRole::PUSH_BUTTON) || (nRole == AccessibleRole::TOGGLE_BUTTON);
if( set)
{
// new value
@ -216,11 +229,10 @@ void AccComponentEventListener::FireStatePropertyChange(sal_Int64 state, bool se
case AccessibleStateType::INDETERMINATE:
m_rObjManager.IncreaseState(m_xAccessible.get(), state);
m_rObjManager.UpdateAction(m_xAccessible.get());
if (!m_rObjManager.IsSpecialToolbarItem(m_xAccessible.get()))
{
if (bPressedInsteadOfChecked)
m_rObjManager.NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_PRESSED);
else
m_rObjManager.NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_CHECKED);
}
break;
case AccessibleStateType::PRESSED:
m_rObjManager.IncreaseState(m_xAccessible.get(), state);
@ -256,11 +268,10 @@ void AccComponentEventListener::FireStatePropertyChange(sal_Int64 state, bool se
case AccessibleStateType::INDETERMINATE:
m_rObjManager.DecreaseState(m_xAccessible.get(), state);
m_rObjManager.UpdateAction(m_xAccessible.get());
if (!m_rObjManager.IsSpecialToolbarItem(m_xAccessible.get()))
{
if (bPressedInsteadOfChecked)
m_rObjManager.NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_PRESSED);
else
m_rObjManager.NotifyAccEvent(m_xAccessible.get(), UnoMSAAEvent::STATE_CHECKED);
}
break;
case AccessibleStateType::PRESSED:
m_rObjManager.DecreaseState(m_xAccessible.get(), state);

View file

@ -1062,26 +1062,6 @@ void AccObjectWinManager::UpdateChildState(css::accessibility::XAccessible* pAcc
}
}
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);