Browse Source

Windows Accessibility: Improved support for read-only text interfaces and fixed issue causing text past 1000 characters to not be read out by Narrator

v6.1.6
ed 4 years ago
parent
commit
963fd79e6a
4 changed files with 58 additions and 23 deletions
  1. +6
    -9
      modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp
  2. +3
    -2
      modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h
  3. +49
    -6
      modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h
  4. +0
    -6
      modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h

+ 6
- 9
modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp View File

@@ -158,16 +158,18 @@ JUCE_COMRESULT AccessibilityNativeHandle::GetPatternProvider (PATTERNID pId, IUn
case UIA_TextPatternId: case UIA_TextPatternId:
case UIA_TextPattern2Id: case UIA_TextPattern2Id:
{ {
if (accessibilityHandler.getTextInterface() != nullptr)
if (accessibilityHandler.getTextInterface() != nullptr
|| isReadOnlyText (accessibilityHandler))
{
return new UIATextProvider (this); return new UIATextProvider (this);
}
break; break;
} }
case UIA_ValuePatternId: case UIA_ValuePatternId:
{ {
if (accessibilityHandler.getValueInterface() != nullptr if (accessibilityHandler.getValueInterface() != nullptr
|| isEditableText (accessibilityHandler)
|| nameIsAccessibilityValue (role))
|| isEditableText (accessibilityHandler))
{ {
return new UIAValueProvider (this); return new UIAValueProvider (this);
} }
@@ -539,12 +541,7 @@ JUCE_COMRESULT AccessibilityNativeHandle::GetFocus (IRawElementProviderFragment*
//============================================================================== //==============================================================================
String AccessibilityNativeHandle::getElementName() const String AccessibilityNativeHandle::getElementName() const
{ {
const auto role = accessibilityHandler.getRole();
if (nameIsAccessibilityValue (role))
return {};
if (role == AccessibilityRole::tooltip)
if (accessibilityHandler.getRole() == AccessibilityRole::tooltip)
return accessibilityHandler.getDescription(); return accessibilityHandler.getDescription();
auto name = accessibilityHandler.getTitle(); auto name = accessibilityHandler.getTitle();


+ 3
- 2
modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h View File

@@ -106,9 +106,10 @@ inline bool isEditableText (const AccessibilityHandler& handler)
&& handler.getTextInterface() != nullptr; && handler.getTextInterface() != nullptr;
} }
inline bool nameIsAccessibilityValue (AccessibilityRole role)
inline bool isReadOnlyText (const AccessibilityHandler& handler)
{ {
return role == AccessibilityRole::staticText;
return handler.getRole() == AccessibilityRole::staticText
&& handler.getValueInterface() != nullptr;
} }
} // namespace juce } // namespace juce

+ 49
- 6
modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h View File

@@ -34,6 +34,10 @@ public:
explicit UIATextProvider (AccessibilityNativeHandle* nativeHandle) explicit UIATextProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle) : UIAProviderBase (nativeHandle)
{ {
const auto& handler = getHandler();
if (isReadOnlyText (handler))
readOnlyTextInterface = std::make_unique<ReadOnlyTextInterface> (handler.getValueInterface()->getCurrentValueAsString());
} }
//============================================================================== //==============================================================================
@@ -63,7 +67,9 @@ public:
{ {
return withCheckedComArgs (pRetVal, *this, [&] return withCheckedComArgs (pRetVal, *this, [&]
{ {
*pRetVal = SupportedTextSelection_Single;
*pRetVal = (readOnlyTextInterface != nullptr ? SupportedTextSelection_None
: SupportedTextSelection_Single);
return S_OK; return S_OK;
}); });
} }
@@ -163,6 +169,15 @@ public:
}); });
} }
//==============================================================================
AccessibilityTextInterface* getTextInterface() const
{
if (readOnlyTextInterface != nullptr)
return readOnlyTextInterface.get();
return getHandler().getTextInterface();
}
private: private:
//============================================================================== //==============================================================================
template <typename Value, typename Callback> template <typename Value, typename Callback>
@@ -170,7 +185,7 @@ private:
{ {
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{ {
if (auto* textInterface = getHandler().getTextInterface())
if (auto* textInterface = getTextInterface())
return callback (*textInterface); return callback (*textInterface);
return UIA_E_NOTSUPPORTED; return UIA_E_NOTSUPPORTED;
@@ -243,7 +258,7 @@ private:
if (! isElementValid()) if (! isElementValid())
return UIA_E_ELEMENTNOTAVAILABLE; return UIA_E_ELEMENTNOTAVAILABLE;
if (auto* textInterface = getHandler().getTextInterface())
if (auto* textInterface = owner->getTextInterface())
{ {
auto numCharacters = textInterface->getTotalNumCharacters(); auto numCharacters = textInterface->getTotalNumCharacters();
@@ -468,7 +483,7 @@ private:
if (! isElementValid()) if (! isElementValid())
return UIA_E_ELEMENTNOTAVAILABLE; return UIA_E_ELEMENTNOTAVAILABLE;
if (auto* textInterface = getHandler().getTextInterface())
if (auto* textInterface = owner->getTextInterface())
{ {
auto otherRange = static_cast<UIATextRangeProvider*> (targetRange)->getSelectionRange(); auto otherRange = static_cast<UIATextRangeProvider*> (targetRange)->getSelectionRange();
auto targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start ? otherRange.getStart() auto targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start ? otherRange.getStart()
@@ -552,7 +567,7 @@ private:
if (! isElementValid()) if (! isElementValid())
return UIA_E_ELEMENTNOTAVAILABLE; return UIA_E_ELEMENTNOTAVAILABLE;
if (auto* textInterface = getHandler().getTextInterface())
if (auto* textInterface = owner->getTextInterface())
{ {
textInterface->setSelection ({}); textInterface->setSelection ({});
return S_OK; return S_OK;
@@ -574,7 +589,7 @@ private:
if (! isElementValid()) if (! isElementValid())
return UIA_E_ELEMENTNOTAVAILABLE; return UIA_E_ELEMENTNOTAVAILABLE;
if (auto* textInterface = getHandler().getTextInterface())
if (auto* textInterface = owner->getTextInterface())
{ {
textInterface->setSelection ({}); textInterface->setSelection ({});
textInterface->setSelection (selectionRange); textInterface->setSelection (selectionRange);
@@ -635,6 +650,34 @@ private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIATextRangeProvider) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIATextRangeProvider)
}; };
//==============================================================================
class ReadOnlyTextInterface : public AccessibilityTextInterface
{
public:
explicit ReadOnlyTextInterface (const String& t)
: text (t)
{
}
bool isDisplayingProtectedText() const override { return false; }
int getTotalNumCharacters() const { return text.length(); }
Range<int> getSelection() const override { return selection; }
void setSelection (Range<int> s) override { selection = s; }
int getTextInsertionOffset() const override { return 0; }
String getText (Range<int> range) const override { return text.substring (range.getStart(), range.getEnd()); }
void setText (const String&) override {}
RectangleList<int> getTextBounds (Range<int>) const override { return {}; }
int getOffsetAtPoint (Point<int>) const override { return 0; }
private:
const String text;
Range<int> selection;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReadOnlyTextInterface)
};
std::unique_ptr<ReadOnlyTextInterface> readOnlyTextInterface;
//============================================================================== //==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIATextProvider) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIATextProvider)
}; };


+ 0
- 6
modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h View File

@@ -44,9 +44,6 @@ public:
const auto& handler = getHandler(); const auto& handler = getHandler();
if (nameIsAccessibilityValue (handler.getRole()))
return UIA_E_NOTSUPPORTED;
const auto sendValuePropertyChangeMessage = [&]() const auto sendValuePropertyChangeMessage = [&]()
{ {
VARIANT newValue; VARIANT newValue;
@@ -112,9 +109,6 @@ private:
{ {
const auto& handler = getHandler(); const auto& handler = getHandler();
if (nameIsAccessibilityValue (handler.getRole()))
return handler.getTitle();
if (isEditableText (handler)) if (isEditableText (handler))
if (auto* textInterface = getHandler().getTextInterface()) if (auto* textInterface = getHandler().getTextInterface())
return textInterface->getText ({ 0, textInterface->getTotalNumCharacters() }); return textInterface->getText ({ 0, textInterface->getTotalNumCharacters() });


Loading…
Cancel
Save