vcl/inc/qt5/QtAccessibleEventListener.hxx |    3 
 vcl/qt5/QtAccessibleEventListener.cxx     |  115 +++++++++++++++++++++++++++++-
 2 files changed, 116 insertions(+), 2 deletions(-)

New commits:
commit 8c3e8af0e60865ec6d38e2117efdb4ed2f10a20c
Author:     Michael Weghorn <m.wegh...@posteo.de>
AuthorDate: Fri Jun 17 17:29:19 2022 +0200
Commit:     Michael Weghorn <m.wegh...@posteo.de>
CommitDate: Fri Jun 17 19:30:29 2022 +0200

    qt a11y: Forward STATE_CHANGED event as such
    
    Handle `AccessibleEventId::STATE_CHANGED` by
    sending a corresponding `QAccessibleStateChangeEvent`.
    
    The previous way of sending a `QAccessible::ForegroundChanged`
    event looked rather arbitrary and had no effect in practice,
    since that type of event is currently ignored in Qt's AT-SPI adapter
    anyway.
    
    At this point in time, the Qt library doesn't forward
    changes of all states to the AT-SPI layer. Most notably,
    it ignores changes to the focused state.
    (Qt itself uses events of type `QAccessible::Focus`
    instead of `QAccessibleStateChangeEvent` with the `focused`
    state set to notify about focus changes, but that's not exactly the
    same, and e.g. causes Orca to ignore some focus changes).
    I have submitted a change to Qt to implement
    forwarding of `QAccessibleStateChangeEvent`s for the
    focused state to the AT-SPI layer, currently awaiting
    review. [1]
    
    With that Qt change in place, Orca still ignored these
    events in LibreOffice message dialogs, since those
    use a11y role `ALERT`, which wasn't previously considered
    when trying to retrieve a potential dialog that an
    a11y object belonged to.
    The corresponding Orca merge request [2] has just been merged.
    
    With these two in place, Orca now announces the focused
    button when switching focus using the tab key
    e.g. in the "Save document?" dialog when using the qt6 VCL plugin.
    (Most other things in the LO UI are still usually not announced.)
    
    For some reason, forwarding changes to state `AccessibleStateType::ACTIVE`
    resulted in Orca becoming unresponsive (stop talking) quite quickly.
    That needs further analysis, so that state change isn't forwarded
    to Qt for now.
    
    [1] https://codereview.qt-project.org/c/qt/qtbase/+/416510
    [2] https://gitlab.gnome.org/GNOME/orca/-/merge_requests/127
    
    Change-Id: I81c9a0f5ec8c74f95943d3073bba5b304f995d31
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136057
    Tested-by: Jenkins
    Reviewed-by: Michael Weghorn <m.wegh...@posteo.de>

diff --git a/vcl/inc/qt5/QtAccessibleEventListener.hxx 
b/vcl/inc/qt5/QtAccessibleEventListener.hxx
index a73f6d31f2f8..1103dc9da598 100644
--- a/vcl/inc/qt5/QtAccessibleEventListener.hxx
+++ b/vcl/inc/qt5/QtAccessibleEventListener.hxx
@@ -33,6 +33,9 @@ public:
 private:
     css::uno::Reference<css::accessibility::XAccessible> m_xAccessible;
     QtAccessibleWidget* m_pAccessibleWidget;
+
+    static void HandleStateChangedEvent(QAccessibleInterface* 
pQAccessibleInterface,
+                                        const 
css::accessibility::AccessibleEventObject& rEvent);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qt5/QtAccessibleEventListener.cxx 
b/vcl/qt5/QtAccessibleEventListener.cxx
index 515584351c74..ee9acc651599 100644
--- a/vcl/qt5/QtAccessibleEventListener.cxx
+++ b/vcl/qt5/QtAccessibleEventListener.cxx
@@ -23,6 +23,7 @@
 #include <sal/log.hxx>
 
 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
 #include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
 #include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
 #include <com/sun/star/accessibility/TextSegment.hpp>
@@ -41,6 +42,117 @@ QtAccessibleEventListener::QtAccessibleEventListener(const 
Reference<XAccessible
 {
 }
 
+void QtAccessibleEventListener::HandleStateChangedEvent(
+    QAccessibleInterface* pQAccessibleInterface,
+    const css::accessibility::AccessibleEventObject& rEvent)
+{
+    QAccessible::State aState;
+
+    short nState = 0;
+    rEvent.NewValue >>= nState;
+    // States in 'QAccessibleStateChangeEvent' indicate what states have 
changed, so if e.g.
+    // an object loses focus (not just if it gains it), 'focus' state needs to 
be set to 'true',
+    // so retrieve the old/previous value from the event if necessary.
+    if (nState == AccessibleStateType::INVALID)
+        rEvent.OldValue >>= nState;
+
+    switch (nState)
+    {
+        case AccessibleStateType::ACTIVE:
+            // ignore for now, since it somehow causes Orca to become 
unresponsive quite quickly
+            // TODO: analyze further and fix root cause
+            /*
+            aState.active = true;
+            break;
+            */
+            return;
+        case AccessibleStateType::BUSY:
+            aState.busy = true;
+            break;
+        case AccessibleStateType::CHECKED:
+            aState.checked = true;
+            break;
+        case AccessibleStateType::COLLAPSE:
+            aState.collapsed = true;
+            break;
+        case AccessibleStateType::DEFAULT:
+            aState.defaultButton = true;
+            break;
+        case AccessibleStateType::ENABLED:
+            aState.disabled = true;
+            break;
+        case AccessibleStateType::EDITABLE:
+            aState.editable = true;
+            break;
+        case AccessibleStateType::EXPANDABLE:
+            aState.expandable = true;
+            break;
+        case AccessibleStateType::EXPANDED:
+            aState.expanded = true;
+            break;
+        case AccessibleStateType::FOCUSABLE:
+            aState.focusable = true;
+            break;
+        case AccessibleStateType::FOCUSED:
+            aState.focused = true;
+            break;
+        case AccessibleStateType::INVALID:
+            aState.invalid = true;
+            break;
+        case AccessibleStateType::VISIBLE:
+            aState.invisible = true;
+            break;
+        case AccessibleStateType::MODAL:
+            aState.modal = true;
+            break;
+        case AccessibleStateType::MOVEABLE:
+            aState.movable = true;
+            break;
+        case AccessibleStateType::MULTI_LINE:
+        // comment in Qt's qaccessible.h has this:
+        // "// quint64 singleLine : 1; // we have multi line, this is 
redundant."
+        case AccessibleStateType::SINGLE_LINE:
+            aState.multiLine = true;
+            break;
+        case AccessibleStateType::MULTI_SELECTABLE:
+            aState.multiSelectable = true;
+            break;
+        case AccessibleStateType::OFFSCREEN:
+            aState.offscreen = true;
+            break;
+        case AccessibleStateType::PRESSED:
+            aState.pressed = true;
+            break;
+        case AccessibleStateType::RESIZABLE:
+            aState.sizeable = true;
+            break;
+        case AccessibleStateType::SELECTABLE:
+            aState.selectable = true;
+            break;
+        case AccessibleStateType::SELECTED:
+            aState.selected = true;
+            break;
+        // These don't seem to have a matching Qt equivalent
+        case AccessibleStateType::ARMED:
+        case AccessibleStateType::DEFUNC:
+        case AccessibleStateType::HORIZONTAL:
+        case AccessibleStateType::ICONIFIED:
+        case AccessibleStateType::INDETERMINATE:
+        case AccessibleStateType::MANAGES_DESCENDANTS:
+        case AccessibleStateType::OPAQUE:
+        case AccessibleStateType::SENSITIVE:
+        case AccessibleStateType::SHOWING:
+        case AccessibleStateType::STALE:
+        case AccessibleStateType::TRANSIENT:
+        case AccessibleStateType::VERTICAL:
+        default:
+            return;
+    }
+
+    QAccessible::updateAccessibility(
+        new QAccessibleStateChangeEvent(pQAccessibleInterface, aState));
+}
+
 void QtAccessibleEventListener::notifyEvent(const 
css::accessibility::AccessibleEventObject& aEvent)
 {
     QAccessibleInterface* pQAccessibleInterface = m_pAccessibleWidget;
@@ -211,8 +323,7 @@ void QtAccessibleEventListener::notifyEvent(const 
css::accessibility::Accessible
                 new QAccessibleEvent(pQAccessibleInterface, 
QAccessible::LocationChanged));
             return;
         case AccessibleEventId::STATE_CHANGED:
-            QAccessible::updateAccessibility(
-                new QAccessibleEvent(pQAccessibleInterface, 
QAccessible::ForegroundChanged));
+            HandleStateChangedEvent(pQAccessibleInterface, aEvent);
             return;
         case AccessibleEventId::VALUE_CHANGED:
         {

Reply via email to