diff --git a/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityRole.h b/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityRole.h index b4354934a1..d58549537e 100644 --- a/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityRole.h +++ b/modules/juce_gui_basics/accessibility/enums/juce_AccessibilityRole.h @@ -41,6 +41,7 @@ enum class AccessibilityRole comboBox, image, slider, + label, staticText, editableText, menuItem, diff --git a/modules/juce_gui_basics/accessibility/interfaces/juce_AccessibilityTextInterface.h b/modules/juce_gui_basics/accessibility/interfaces/juce_AccessibilityTextInterface.h index b77d6ca8b1..ea5a8944c1 100644 --- a/modules/juce_gui_basics/accessibility/interfaces/juce_AccessibilityTextInterface.h +++ b/modules/juce_gui_basics/accessibility/interfaces/juce_AccessibilityTextInterface.h @@ -46,6 +46,9 @@ public: */ virtual bool isDisplayingProtectedText() const = 0; + /** Returns true if the text being displayed is read-only or false if editable. */ + virtual bool isReadOnly() const = 0; + /** Returns the total number of characters in the text element. */ virtual int getTotalNumCharacters() const = 0; diff --git a/modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm b/modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm index 9351a5296f..cbc5eb1276 100644 --- a/modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm +++ b/modules/juce_gui_basics/native/accessibility/juce_mac_Accessibility.mm @@ -170,7 +170,8 @@ private: static bool hasEditableText (AccessibilityHandler& handler) noexcept { return handler.getRole() == AccessibilityRole::editableText - && handler.getTextInterface() != nullptr; + && handler.getTextInterface() != nullptr + && ! handler.getTextInterface()->isReadOnly(); } static bool isSelectable (AccessibleState state) noexcept @@ -396,6 +397,7 @@ private: case AccessibilityRole::comboBox: return NSAccessibilityPopUpButtonRole; case AccessibilityRole::image: return NSAccessibilityImageRole; case AccessibilityRole::slider: return NSAccessibilitySliderRole; + case AccessibilityRole::label: return NSAccessibilityStaticTextRole; case AccessibilityRole::staticText: return NSAccessibilityStaticTextRole; case AccessibilityRole::editableText: return NSAccessibilityTextAreaRole; case AccessibilityRole::menuItem: return NSAccessibilityMenuItemRole; @@ -504,11 +506,8 @@ private: { if (auto* handler = getHandler (self)) { - if (hasEditableText (*handler)) - { - auto* textInterface = handler->getTextInterface(); + if (auto* textInterface = handler->getTextInterface()) return juceStringToNS (textInterface->getText ({ 0, textInterface->getTotalNumCharacters() })); - } if (handler->getCurrentState().isCheckable()) return handler->getCurrentState().isChecked() ? @(1) : @(0); diff --git a/modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp b/modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp index e440483227..6968218fce 100644 --- a/modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp +++ b/modules/juce_gui_basics/native/accessibility/juce_win32_AccessibilityElement.cpp @@ -60,6 +60,7 @@ static long roleToControlTypeId (AccessibilityRole roleType) case AccessibilityRole::comboBox: return UIA_ComboBoxControlTypeId; case AccessibilityRole::image: return UIA_ImageControlTypeId; case AccessibilityRole::slider: return UIA_SliderControlTypeId; + case AccessibilityRole::label: return UIA_TextControlTypeId; case AccessibilityRole::staticText: return UIA_TextControlTypeId; case AccessibilityRole::editableText: return UIA_EditControlTypeId; case AccessibilityRole::menuItem: return UIA_MenuItemControlTypeId; @@ -160,21 +161,15 @@ JUCE_COMRESULT AccessibilityNativeHandle::GetPatternProvider (PATTERNID pId, IUn case UIA_TextPatternId: case UIA_TextPattern2Id: { - if (accessibilityHandler.getTextInterface() != nullptr - || isReadOnlyText (accessibilityHandler)) - { + if (accessibilityHandler.getTextInterface() != nullptr) return new UIATextProvider (this); - } break; } case UIA_ValuePatternId: { - if (accessibilityHandler.getValueInterface() != nullptr - || isEditableText (accessibilityHandler)) - { + if (accessibilityHandler.getValueInterface() != nullptr) return new UIAValueProvider (this); - } break; } diff --git a/modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h b/modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h index 6934c88125..6538ca37b6 100644 --- a/modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h +++ b/modules/juce_gui_basics/native/accessibility/juce_win32_UIAHelpers.h @@ -102,16 +102,4 @@ inline JUCE_COMRESULT withCheckedComArgs (Value* pRetVal, Object& handle, Callba return callback(); } -inline bool isEditableText (const AccessibilityHandler& handler) -{ - return handler.getRole() == AccessibilityRole::editableText - && handler.getTextInterface() != nullptr; -} - -inline bool isReadOnlyText (const AccessibilityHandler& handler) -{ - return handler.getRole() == AccessibilityRole::staticText - && handler.getValueInterface() != nullptr; -} - } // namespace juce diff --git a/modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h b/modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h index b6e6b69f86..ed9131822c 100644 --- a/modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h +++ b/modules/juce_gui_basics/native/accessibility/juce_win32_UIATextProvider.h @@ -34,10 +34,6 @@ public: explicit UIATextProvider (AccessibilityNativeHandle* nativeHandle) : UIAProviderBase (nativeHandle) { - const auto& handler = getHandler(); - - if (isReadOnlyText (handler)) - readOnlyTextInterface = std::make_unique (handler.getValueInterface()->getCurrentValueAsString()); } //============================================================================== @@ -71,9 +67,7 @@ public: { return withCheckedComArgs (pRetVal, *this, [&] { - *pRetVal = (readOnlyTextInterface != nullptr ? SupportedTextSelection_None - : SupportedTextSelection_Single); - + *pRetVal = SupportedTextSelection_Single; return S_OK; }); } @@ -173,15 +167,6 @@ public: }); } - //============================================================================== - AccessibilityTextInterface* getTextInterface() const - { - if (readOnlyTextInterface != nullptr) - return readOnlyTextInterface.get(); - - return getHandler().getTextInterface(); - } - private: //============================================================================== template @@ -189,7 +174,7 @@ private: { return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT { - if (auto* textInterface = getTextInterface()) + if (auto* textInterface = getHandler().getTextInterface()) return callback (*textInterface); return (HRESULT) UIA_E_NOTSUPPORTED; @@ -262,7 +247,7 @@ private: if (! isElementValid()) return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE; - if (auto* textInterface = owner->getTextInterface()) + if (auto* textInterface = owner->getHandler().getTextInterface()) { auto numCharacters = textInterface->getTotalNumCharacters(); @@ -340,23 +325,14 @@ private: { VariantHelpers::clear (pRetVal); - const auto& handler = getHandler(); - switch (attributeId) { case UIA_IsReadOnlyAttributeId: { - const auto readOnly = [&] - { - if (auto* valueInterface = handler.getValueInterface()) - return valueInterface->isReadOnly(); - - return false; - }(); - - VariantHelpers::setBool (readOnly, pRetVal); + VariantHelpers::setBool (textInterface.isReadOnly(), pRetVal); break; } + case UIA_CaretPositionAttributeId: { auto cursorPos = textInterface.getTextInsertionOffset(); @@ -491,7 +467,7 @@ private: if (! isElementValid()) return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE; - if (auto* textInterface = owner->getTextInterface()) + if (auto* textInterface = owner->getHandler().getTextInterface()) { auto otherRange = static_cast (targetRange)->getSelectionRange(); auto targetPoint = (targetEndpoint == TextPatternRangeEndpoint_Start ? otherRange.getStart() @@ -575,7 +551,7 @@ private: if (! isElementValid()) return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE; - if (auto* textInterface = owner->getTextInterface()) + if (auto* textInterface = owner->getHandler().getTextInterface()) { textInterface->setSelection ({}); return S_OK; @@ -597,7 +573,7 @@ private: if (! isElementValid()) return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE; - if (auto* textInterface = owner->getTextInterface()) + if (auto* textInterface = owner->getHandler().getTextInterface()) { textInterface->setSelection ({}); textInterface->setSelection (selectionRange); @@ -658,34 +634,6 @@ private: 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 override { return text.length(); } - Range getSelection() const override { return selection; } - void setSelection (Range s) override { selection = s; } - int getTextInsertionOffset() const override { return 0; } - String getText (Range range) const override { return text.substring (range.getStart(), range.getEnd()); } - void setText (const String&) override {} - RectangleList getTextBounds (Range) const override { return {}; } - int getOffsetAtPoint (Point) const override { return 0; } - - private: - const String text; - Range selection; - - JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReadOnlyTextInterface) - }; - - std::unique_ptr readOnlyTextInterface; - //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIATextProvider) }; diff --git a/modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h b/modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h index e191780130..05ce7ba57a 100644 --- a/modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h +++ b/modules/juce_gui_basics/native/accessibility/juce_win32_UIAValueProvider.h @@ -43,44 +43,28 @@ public: return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE; const auto& handler = getHandler(); + auto& valueInterface = *handler.getValueInterface(); - const auto sendValuePropertyChangeMessage = [&]() - { - VARIANT newValue; - VariantHelpers::setString (getCurrentValueString(), &newValue); + if (valueInterface.isReadOnly()) + return (HRESULT) UIA_E_NOTSUPPORTED; - sendAccessibilityPropertyChangedEvent (handler, UIA_ValueValuePropertyId, newValue); - }; + valueInterface.setValueAsString (String (val)); - if (isEditableText (handler)) - { - handler.getTextInterface()->setText (String (val)); - sendValuePropertyChangeMessage(); + VARIANT newValue; + VariantHelpers::setString (valueInterface.getCurrentValueAsString(), &newValue); - return S_OK; - } + sendAccessibilityPropertyChangedEvent (handler, UIA_ValueValuePropertyId, newValue); - if (auto* valueInterface = handler.getValueInterface()) - { - if (! valueInterface->isReadOnly()) - { - valueInterface->setValueAsString (String (val)); - sendValuePropertyChangeMessage(); - - return S_OK; - } - } - - return (HRESULT) UIA_E_NOTSUPPORTED; + return S_OK; } JUCE_COMRESULT get_Value (BSTR* pRetVal) override { return withCheckedComArgs (pRetVal, *this, [&] { - auto currentValue = getCurrentValueString(); + auto currentValueString = getHandler().getValueInterface()->getCurrentValueAsString(); - *pRetVal = SysAllocString ((const OLECHAR*) currentValue.toWideCharPointer()); + *pRetVal = SysAllocString ((const OLECHAR*) currentValueString.toWideCharPointer()); return S_OK; }); } @@ -89,37 +73,12 @@ public: { return withCheckedComArgs (pRetVal, *this, [&] { - *pRetVal = true; - - const auto& handler = getHandler(); - - if (isEditableText (handler) - || (handler.getValueInterface() != nullptr - && ! handler.getValueInterface()->isReadOnly())) - { - *pRetVal = false; - } - + *pRetVal = getHandler().getValueInterface()->isReadOnly(); return S_OK; }); } private: - String getCurrentValueString() const - { - const auto& handler = getHandler(); - - if (isEditableText (handler)) - if (auto* textInterface = getHandler().getTextInterface()) - return textInterface->getText ({ 0, textInterface->getTotalNumCharacters() }); - - if (auto* valueInterface = getHandler().getValueInterface()) - return valueInterface->getCurrentValueAsString(); - - jassertfalse; - return {}; - } - //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAValueProvider) }; diff --git a/modules/juce_gui_basics/widgets/juce_Label.cpp b/modules/juce_gui_basics/widgets/juce_Label.cpp index 5882cf56c3..11fb9264cd 100644 --- a/modules/juce_gui_basics/widgets/juce_Label.cpp +++ b/modules/juce_gui_basics/widgets/juce_Label.cpp @@ -523,7 +523,7 @@ class LabelAccessibilityHandler : public AccessibilityHandler public: explicit LabelAccessibilityHandler (Label& labelToWrap) : AccessibilityHandler (labelToWrap, - AccessibilityRole::staticText, + AccessibilityRole::label, getAccessibilityActions (labelToWrap), { std::make_unique (labelToWrap) }), label (labelToWrap) diff --git a/modules/juce_gui_basics/widgets/juce_TextEditor.cpp b/modules/juce_gui_basics/widgets/juce_TextEditor.cpp index a62b82573d..fbae68c90c 100644 --- a/modules/juce_gui_basics/widgets/juce_TextEditor.cpp +++ b/modules/juce_gui_basics/widgets/juce_TextEditor.cpp @@ -2700,27 +2700,11 @@ public: : AccessibilityHandler (textEditorToWrap, textEditorToWrap.isReadOnly() ? AccessibilityRole::staticText : AccessibilityRole::editableText, {}, - makeInterfaces (textEditorToWrap)) + { std::make_unique (textEditorToWrap) }) { } private: - class TextEditorValueInterface : public AccessibilityTextValueInterface - { - public: - explicit TextEditorValueInterface (TextEditor& textEditorToWrap) - : textEditor (textEditorToWrap) - { - } - - bool isReadOnly() const override { return true; } - String getCurrentValueAsString() const override { return textEditor.getText(); } - void setValueAsString (const String&) override {} - - private: - TextEditor& textEditor; - }; - class TextEditorTextInterface : public AccessibilityTextInterface { public: @@ -2730,6 +2714,7 @@ private: } bool isDisplayingProtectedText() const override { return textEditor.getPasswordCharacter() != 0; } + bool isReadOnly() const override { return textEditor.isReadOnly(); } int getTotalNumCharacters() const override { return textEditor.getText().length(); } Range getSelection() const override { return textEditor.getHighlightedRegion(); } @@ -2772,14 +2757,6 @@ private: TextEditor& textEditor; }; - static AccessibilityHandler::Interfaces makeInterfaces (TextEditor& textEditor) - { - if (textEditor.isReadOnly()) - return { std::make_unique (textEditor) }; - - return { std::make_unique (textEditor) }; - } - //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextEditorAccessibilityHandler) }; diff --git a/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp b/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp index 96ba2483ae..30199fbca8 100644 --- a/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp +++ b/modules/juce_gui_extra/code_editor/juce_CodeEditorComponent.cpp @@ -35,27 +35,11 @@ public: codeEditorComponentToWrap.isReadOnly() ? AccessibilityRole::staticText : AccessibilityRole::editableText, {}, - makeInterfaces (codeEditorComponentToWrap)) + { std::make_unique (codeEditorComponentToWrap) }) { } private: - class CodeEditorComponentValueInterface : public AccessibilityTextValueInterface - { - public: - explicit CodeEditorComponentValueInterface (CodeEditorComponent& codeEditorComponentToWrap) - : codeEditorComponent (codeEditorComponentToWrap) - { - } - - bool isReadOnly() const override { return true; } - String getCurrentValueAsString() const override { return codeEditorComponent.document.getAllContent(); } - void setValueAsString (const String&) override {} - - private: - CodeEditorComponent& codeEditorComponent; - }; - class CodeEditorComponentTextInterface : public AccessibilityTextInterface { public: @@ -69,6 +53,11 @@ private: return false; } + bool isReadOnly() const override + { + return codeEditorComponent.isReadOnly(); + } + int getTotalNumCharacters() const override { return codeEditorComponent.document.getAllContent().length(); @@ -152,14 +141,6 @@ private: CodeEditorComponent& codeEditorComponent; }; - static AccessibilityHandler::Interfaces makeInterfaces (CodeEditorComponent& codeEditorComponent) - { - if (codeEditorComponent.isReadOnly()) - return { std::make_unique (codeEditorComponent) }; - - return { std::make_unique (codeEditorComponent) }; - } - //============================================================================== JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CodeEditorAccessibilityHandler) };