migrating to the latest JUCE version

This commit is contained in:
2022-11-04 23:11:33 +01:00
committed by Nikolai Rodionov
parent 4257a0f8ba
commit faf8f18333
2796 changed files with 888518 additions and 784244 deletions

View File

@ -1,111 +1,302 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace AccessibilityTextHelpers
{
enum class BoundaryType
{
character,
word,
line,
document
};
enum class Direction
{
forwards,
backwards
};
static int findTextBoundary (const AccessibilityTextInterface& textInterface,
int currentPosition,
BoundaryType boundary,
Direction direction)
{
const auto numCharacters = textInterface.getTotalNumCharacters();
const auto isForwards = (direction == Direction::forwards);
auto offsetWithDirecton = [isForwards] (int input) { return isForwards ? input : -input; };
switch (boundary)
{
case BoundaryType::character:
return jlimit (0, numCharacters, currentPosition + offsetWithDirecton (1));
case BoundaryType::word:
case BoundaryType::line:
{
const auto text = [&]() -> String
{
if (isForwards)
return textInterface.getText ({ currentPosition, textInterface.getTotalNumCharacters() });
const auto str = textInterface.getText ({ 0, currentPosition });
auto start = str.getCharPointer();
auto end = start.findTerminatingNull();
const auto size = getAddressDifference (end.getAddress(), start.getAddress());
String reversed;
if (size > 0)
{
reversed.preallocateBytes ((size_t) size);
auto destPtr = reversed.getCharPointer();
for (;;)
{
destPtr.write (*--end);
if (end == start)
break;
}
destPtr.writeNull();
}
return reversed;
}();
auto tokens = (boundary == BoundaryType::line ? StringArray::fromLines (text)
: StringArray::fromTokens (text, false));
return currentPosition + offsetWithDirecton (tokens[0].length());
}
case BoundaryType::document:
return isForwards ? numCharacters : 0;
}
jassertfalse;
return -1;
}
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
struct AccessibilityTextHelpers
{
/* Wraps a CharPtr into a stdlib-compatible iterator.
MSVC's std::reverse_iterator requires the wrapped iterator to be default constructible
when building in C++20 mode, but I don't really want to add public default constructors to
the CharPtr types. Instead, we add a very basic default constructor here which sets the
wrapped CharPtr to nullptr.
*/
template <typename CharPtr>
class CharPtrIteratorAdapter
{
public:
using difference_type = int;
using value_type = decltype (*std::declval<CharPtr>());
using pointer = value_type*;
using reference = value_type;
using iterator_category = std::bidirectional_iterator_tag;
CharPtrIteratorAdapter() = default;
constexpr explicit CharPtrIteratorAdapter (CharPtr arg) : ptr (arg) {}
constexpr auto operator*() const { return *ptr; }
constexpr CharPtrIteratorAdapter& operator++()
{
++ptr;
return *this;
}
constexpr CharPtrIteratorAdapter& operator--()
{
--ptr;
return *this;
}
constexpr bool operator== (const CharPtrIteratorAdapter& other) const { return ptr == other.ptr; }
constexpr bool operator!= (const CharPtrIteratorAdapter& other) const { return ptr != other.ptr; }
constexpr auto operator+ (difference_type offset) const { return CharPtrIteratorAdapter { ptr + offset }; }
constexpr auto operator- (difference_type offset) const { return CharPtrIteratorAdapter { ptr - offset }; }
private:
CharPtr ptr { {} };
};
template <typename CharPtr>
static auto makeCharPtrIteratorAdapter (CharPtr ptr)
{
return CharPtrIteratorAdapter<CharPtr> { ptr };
}
enum class BoundaryType
{
character,
word,
line,
document
};
enum class Direction
{
forwards,
backwards
};
enum class ExtendSelection
{
no,
yes
};
/* Indicates whether a function may return the current text position, in the case that the
position already falls on a text unit boundary.
*/
enum class IncludeThisBoundary
{
no, //< Always search for the following boundary, even if the current position falls on a boundary
yes //< Return the current position if it falls on a boundary
};
/* Indicates whether a word boundary should include any whitespaces that follow the
non-whitespace characters.
*/
enum class IncludeWhitespaceAfterWords
{
no, //< The word ends on the first whitespace character
yes //< The word ends after the last whitespace character
};
/* Like std::distance, but always does an O(N) count rather than an O(1) count, and doesn't
require the iterators to have any member type aliases.
*/
template <typename Iter>
static int countDifference (Iter from, Iter to)
{
int distance = 0;
while (from != to)
{
++from;
++distance;
}
return distance;
}
/* Returns the number of characters between ptr and the next word end in a specific
direction.
If ptr is inside a word, the result will be the distance to the end of the same
word.
*/
template <typename CharPtr>
static int findNextWordEndOffset (CharPtr beginIn,
CharPtr endIn,
CharPtr ptrIn,
Direction direction,
IncludeThisBoundary includeBoundary,
IncludeWhitespaceAfterWords includeWhitespace)
{
const auto begin = makeCharPtrIteratorAdapter (beginIn);
const auto end = makeCharPtrIteratorAdapter (endIn);
const auto ptr = makeCharPtrIteratorAdapter (ptrIn);
const auto move = [&] (auto b, auto e, auto iter)
{
const auto isSpace = [] (juce_wchar c) { return CharacterFunctions::isWhitespace (c); };
const auto start = [&]
{
if (iter == b && includeBoundary == IncludeThisBoundary::yes)
return b;
const auto nudged = iter - (iter != b && includeBoundary == IncludeThisBoundary::yes ? 1 : 0);
return includeWhitespace == IncludeWhitespaceAfterWords::yes
? std::find_if (nudged, e, isSpace)
: std::find_if_not (nudged, e, isSpace);
}();
const auto found = includeWhitespace == IncludeWhitespaceAfterWords::yes
? std::find_if_not (start, e, isSpace)
: std::find_if (start, e, isSpace);
return countDifference (iter, found);
};
return direction == Direction::forwards ? move (begin, end, ptr)
: -move (std::make_reverse_iterator (end),
std::make_reverse_iterator (begin),
std::make_reverse_iterator (ptr));
}
/* Returns the number of characters between ptr and the beginning of the next line in a
specific direction.
*/
template <typename CharPtr>
static int findNextLineOffset (CharPtr beginIn,
CharPtr endIn,
CharPtr ptrIn,
Direction direction,
IncludeThisBoundary includeBoundary)
{
const auto begin = makeCharPtrIteratorAdapter (beginIn);
const auto end = makeCharPtrIteratorAdapter (endIn);
const auto ptr = makeCharPtrIteratorAdapter (ptrIn);
const auto findNewline = [] (auto from, auto to) { return std::find (from, to, juce_wchar { '\n' }); };
if (direction == Direction::forwards)
{
if (ptr != begin && includeBoundary == IncludeThisBoundary::yes && *(ptr - 1) == '\n')
return 0;
const auto newline = findNewline (ptr, end);
return countDifference (ptr, newline) + (newline == end ? 0 : 1);
}
const auto rbegin = std::make_reverse_iterator (ptr);
const auto rend = std::make_reverse_iterator (begin);
return -countDifference (rbegin, findNewline (rbegin + (rbegin == rend || includeBoundary == IncludeThisBoundary::yes ? 0 : 1), rend));
}
/* Unfortunately, the method of computing end-points of text units depends on context, and on
the current platform.
Some examples of different behaviour:
- On Android, updating the cursor/selection always searches for the next text unit boundary;
but on Windows, ExpandToEnclosingUnit() should not move the starting point of the
selection if it already at a unit boundary. This means that we need both inclusive and
exclusive methods for finding the next text boundary.
- On Android, moving the cursor by 'words' should move to the first space following a
non-space character in the requested direction. On Windows, a 'word' includes trailing
whitespace, but not preceding whitespace. This means that we need a way of specifying
whether whitespace should be included when navigating by words.
*/
static int findTextBoundary (const AccessibilityTextInterface& textInterface,
int currentPosition,
BoundaryType boundary,
Direction direction,
IncludeThisBoundary includeBoundary,
IncludeWhitespaceAfterWords includeWhitespace)
{
const auto numCharacters = textInterface.getTotalNumCharacters();
const auto isForwards = (direction == Direction::forwards);
const auto currentClamped = jlimit (0, numCharacters, currentPosition);
switch (boundary)
{
case BoundaryType::character:
{
const auto offset = includeBoundary == IncludeThisBoundary::yes ? 0
: (isForwards ? 1 : -1);
return jlimit (0, numCharacters, currentPosition + offset);
}
case BoundaryType::word:
{
const auto str = textInterface.getText ({ 0, numCharacters });
return currentClamped + findNextWordEndOffset (str.begin(),
str.end(),
str.begin() + currentClamped,
direction,
includeBoundary,
includeWhitespace);
}
case BoundaryType::line:
{
const auto str = textInterface.getText ({ 0, numCharacters });
return currentClamped + findNextLineOffset (str.begin(),
str.end(),
str.begin() + currentClamped,
direction,
includeBoundary);
}
case BoundaryType::document:
return isForwards ? numCharacters : 0;
}
jassertfalse;
return -1;
}
/* Adjusts the current text selection range, using an algorithm appropriate for cursor movement
on Android.
*/
static Range<int> findNewSelectionRangeAndroid (const AccessibilityTextInterface& textInterface,
BoundaryType boundaryType,
ExtendSelection extend,
Direction direction)
{
const auto oldPos = textInterface.getTextInsertionOffset();
const auto cursorPos = findTextBoundary (textInterface,
oldPos,
boundaryType,
direction,
IncludeThisBoundary::no,
IncludeWhitespaceAfterWords::no);
if (extend == ExtendSelection::no)
return { cursorPos, cursorPos };
const auto currentSelection = textInterface.getSelection();
const auto start = currentSelection.getStart();
const auto end = currentSelection.getEnd();
return Range<int>::between (cursorPos, oldPos == start ? end : start);
}
};
} // namespace juce

View File

@ -0,0 +1,155 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
struct AccessibilityTextHelpersTest : public UnitTest
{
AccessibilityTextHelpersTest()
: UnitTest ("AccessibilityTextHelpers", UnitTestCategories::gui) {}
void runTest() override
{
using ATH = AccessibilityTextHelpers;
beginTest ("Android find word end");
{
const auto testMultiple = [this] (String str,
int start,
const std::vector<int>& collection)
{
auto it = collection.begin();
for (const auto direction : { ATH::Direction::forwards, ATH::Direction::backwards })
{
for (const auto includeBoundary : { ATH::IncludeThisBoundary::no, ATH::IncludeThisBoundary::yes })
{
for (const auto includeWhitespace : { ATH::IncludeWhitespaceAfterWords::no, ATH::IncludeWhitespaceAfterWords::yes })
{
const auto actual = ATH::findNextWordEndOffset (str.begin(), str.end(), str.begin() + start, direction, includeBoundary, includeWhitespace);
const auto expected = *it++;
expect (expected == actual);
}
}
}
};
// Character Indices 0 3 56 13 50 51
// | | || | | |
const auto string = String ("hello world \r\n with some spaces in this sentence ") + String (CharPointer_UTF8 ("\xe2\x88\xae E\xe2\x8b\x85""da = Q"));
// Direction forwards forwards forwards forwards backwards backwards backwards backwards
// IncludeBoundary no no yes yes no no yes yes
// IncludeWhitespace no yes no yes no yes no yes
testMultiple (string, 0, { 5, 6, 5, 0, 0, 0, 0, 0 });
testMultiple (string, 3, { 2, 3, 2, 3, -3, -3, -3, -3 });
testMultiple (string, 5, { 6, 1, 0, 1, -5, -5, -5, 0 });
testMultiple (string, 6, { 5, 9, 5, 0, -6, -1, 0, -1 });
testMultiple (string, 13, { 6, 2, 6, 2, -7, -2, -7, -2 });
testMultiple (string, 50, { 1, 2, 1, 0, -9, -1, 0, -1 });
testMultiple (string, 51, { 5, 1, 0, 1, -1, -2, -1, 0 });
testMultiple (" a b ", 0, { 3, 2, 0, 2, 0, 0, 0, 0 });
testMultiple (" a b ", 1, { 2, 1, 2, 1, -1, -1, -1, -1 });
}
beginTest ("Android text range adjustment");
{
const auto testMultiple = [this] (String str,
Range<int> initial,
auto boundary,
const std::vector<Range<int>>& collection)
{
auto it = collection.begin();
for (auto extend : { ATH::ExtendSelection::no, ATH::ExtendSelection::yes })
{
for (auto direction : { ATH::Direction::forwards, ATH::Direction::backwards })
{
for (auto insert : { CursorPosition::begin, CursorPosition::end })
{
const MockAccessibilityTextInterface mock { str, initial, insert };
const auto actual = ATH::findNewSelectionRangeAndroid (mock, boundary, extend, direction);
const auto expected = *it++;
expect (expected == actual);
}
}
}
};
// Extend no no no no yes yes yes yes
// Direction forwards forwards backwards backwards forwards forwards backwards backwards
// Insert begin end begin end begin end begin end
testMultiple ("hello world", { 5, 5 }, ATH::BoundaryType::character, { { 6, 6 }, { 6, 6 }, { 4, 4 }, { 4, 4 }, { 5, 6 }, { 5, 6 }, { 4, 5 }, { 4, 5 } });
testMultiple ("hello world", { 0, 0 }, ATH::BoundaryType::character, { { 1, 1 }, { 1, 1 }, { 0, 0 }, { 0, 0 }, { 0, 1 }, { 0, 1 }, { 0, 0 }, { 0, 0 } });
testMultiple ("hello world", { 11, 11 }, ATH::BoundaryType::character, { { 11, 11 }, { 11, 11 }, { 10, 10 }, { 10, 10 }, { 11, 11 }, { 11, 11 }, { 10, 11 }, { 10, 11 } });
testMultiple ("hello world", { 4, 5 }, ATH::BoundaryType::character, { { 5, 5 }, { 6, 6 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 4, 6 }, { 3, 5 }, { 4, 4 } });
testMultiple ("hello world", { 0, 1 }, ATH::BoundaryType::character, { { 1, 1 }, { 2, 2 }, { 0, 0 }, { 0, 0 }, { 1, 1 }, { 0, 2 }, { 0, 1 }, { 0, 0 } });
testMultiple ("hello world", { 10, 11 }, ATH::BoundaryType::character, { { 11, 11 }, { 11, 11 }, { 9, 9 }, { 10, 10 }, { 11, 11 }, { 10, 11 }, { 9, 11 }, { 10, 10 } });
testMultiple ("foo bar baz", { 0, 0 }, ATH::BoundaryType::word, { { 3, 3 }, { 3, 3 }, { 0, 0 }, { 0, 0 }, { 0, 3 }, { 0, 3 }, { 0, 0 }, { 0, 0 } });
testMultiple ("foo bar baz", { 1, 6 }, ATH::BoundaryType::word, { { 3, 3 }, { 8, 8 }, { 0, 0 }, { 5, 5 }, { 3, 6 }, { 1, 8 }, { 0, 6 }, { 1, 5 } });
testMultiple ("foo bar baz", { 3, 3 }, ATH::BoundaryType::word, { { 8, 8 }, { 8, 8 }, { 0, 0 }, { 0, 0 }, { 3, 8 }, { 3, 8 }, { 0, 3 }, { 0, 3 } });
testMultiple ("foo bar baz", { 3, 5 }, ATH::BoundaryType::word, { { 8, 8 }, { 8, 8 }, { 0, 0 }, { 0, 0 }, { 5, 8 }, { 3, 8 }, { 0, 5 }, { 0, 3 } });
testMultiple ("foo bar\n\n\na b\nc d e", { 0, 0 }, ATH::BoundaryType::line, { { 8, 8 }, { 8, 8 }, { 0, 0 }, { 0, 0 }, { 0, 8 }, { 0, 8 }, { 0, 0 }, { 0, 0 } });
testMultiple ("foo bar\n\n\na b\nc d e", { 7, 7 }, ATH::BoundaryType::line, { { 8, 8 }, { 8, 8 }, { 0, 0 }, { 0, 0 }, { 7, 8 }, { 7, 8 }, { 0, 7 }, { 0, 7 } });
testMultiple ("foo bar\n\n\na b\nc d e", { 8, 8 }, ATH::BoundaryType::line, { { 9, 9 }, { 9, 9 }, { 0, 0 }, { 0, 0 }, { 8, 9 }, { 8, 9 }, { 0, 8 }, { 0, 8 } });
testMultiple ("foo bar\r\na b\r\nxyz", { 0, 0 }, ATH::BoundaryType::line, { { 9, 9 }, { 9, 9 }, { 0, 0 }, { 0, 0 }, { 0, 9 }, { 0, 9 }, { 0, 0 }, { 0, 0 } });
testMultiple ("foo bar\r\na b\r\nxyz", { 10, 10 }, ATH::BoundaryType::line, { { 14, 14 }, { 14, 14 }, { 9, 9 }, { 9, 9 }, { 10, 14 }, { 10, 14 }, { 9, 10 }, { 9, 10 } });
}
}
enum class CursorPosition { begin, end };
class MockAccessibilityTextInterface : public AccessibilityTextInterface
{
public:
MockAccessibilityTextInterface (String stringIn, Range<int> selectionIn, CursorPosition insertIn)
: string (stringIn), selection (selectionIn), insert (insertIn) {}
bool isDisplayingProtectedText() const override { return false; }
bool isReadOnly() const override { return false; }
int getTotalNumCharacters() const override { return string.length(); }
Range<int> getSelection() const override { return selection; }
int getTextInsertionOffset() const override { return insert == CursorPosition::begin ? selection.getStart() : selection.getEnd(); }
String getText (Range<int> range) const override { return string.substring (range.getStart(), range.getEnd()); }
RectangleList<int> getTextBounds (Range<int>) const override { return {}; }
int getOffsetAtPoint (Point<int>) const override { return 0; }
void setSelection (Range<int> newRange) override { selection = newRange; }
void setText (const String& newText) override { string = newText; }
private:
String string;
Range<int> selection;
CursorPosition insert;
};
};
static AccessibilityTextHelpersTest accessibilityTextHelpersTest;
} // namespace juce

View File

@ -2,15 +2,15 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-6-licence
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
@ -37,60 +37,47 @@ static void juceFreeAccessibilityPlatformSpecificData (UIAccessibilityElement* e
namespace juce
{
#if (defined (__IPHONE_11_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_11_0)
#define JUCE_IOS_CONTAINER_API_AVAILABLE 1
#endif
constexpr auto juceUIAccessibilityContainerTypeNone =
#if JUCE_IOS_CONTAINER_API_AVAILABLE
UIAccessibilityContainerTypeNone;
#else
0;
#endif
constexpr auto juceUIAccessibilityContainerTypeDataTable =
#if JUCE_IOS_CONTAINER_API_AVAILABLE
UIAccessibilityContainerTypeDataTable;
#else
1;
#endif
constexpr auto juceUIAccessibilityContainerTypeList =
#if JUCE_IOS_CONTAINER_API_AVAILABLE
UIAccessibilityContainerTypeList;
#else
2;
#endif
#define JUCE_NATIVE_ACCESSIBILITY_INCLUDED 1
//==============================================================================
static NSArray* getContainerAccessibilityElements (AccessibilityHandler& handler)
{
const auto children = handler.getChildren();
template <typename> struct Signature;
NSMutableArray* accessibleChildren = [NSMutableArray arrayWithCapacity: (NSUInteger) children.size()];
template <typename Result, typename... Args>
struct Signature<Result (Args...)> {};
[accessibleChildren addObject: (id) handler.getNativeImplementation()];
for (auto* childHandler : children)
{
id accessibleElement = [&childHandler]
{
id native = (id) childHandler->getNativeImplementation();
if (childHandler->getChildren().size() > 0)
return [native accessibilityContainer];
return native;
}();
if (accessibleElement != nil)
[accessibleChildren addObject: accessibleElement];
}
return accessibleChildren;
}
// @selector isn't constexpr, so the 'sel' members are functions rather than static constexpr data members
struct SignatureHasText : Signature<BOOL()> { static auto sel() { return @selector (hasText); } };
struct SignatureSetSelectedTextRange : Signature<void (UITextRange*)> { static auto sel() { return @selector (setSelectedTextRange:); } };
struct SignatureSelectedTextRange : Signature<UITextRange*()> { static auto sel() { return @selector (selectedTextRange); } };
struct SignatureMarkedTextRange : Signature<UITextRange*()> { static auto sel() { return @selector (markedTextRange); } };
struct SignatureSetMarkedTextSelectedRange : Signature<void (NSString*, NSRange)> { static auto sel() { return @selector (setMarkedText:selectedRange:); } };
struct SignatureUnmarkText : Signature<void()> { static auto sel() { return @selector (unmarkText); } };
struct SignatureMarkedTextStyle : Signature<NSDictionary<NSAttributedStringKey, id>*()> { static auto sel() { return @selector (markedTextStyle); } };
struct SignatureSetMarkedTextStyle : Signature<void (NSDictionary<NSAttributedStringKey, id>*)> { static auto sel() { return @selector (setMarkedTextStyle:); } };
struct SignatureBeginningOfDocument : Signature<UITextPosition*()> { static auto sel() { return @selector (beginningOfDocument); } };
struct SignatureEndOfDocument : Signature<UITextPosition*()> { static auto sel() { return @selector (endOfDocument); } };
struct SignatureTokenizer : Signature<id<UITextInputTokenizer>()> { static auto sel() { return @selector (tokenizer); } };
struct SignatureBaseWritingDirection : Signature<NSWritingDirection (UITextPosition*, UITextStorageDirection)> { static auto sel() { return @selector (baseWritingDirectionForPosition:inDirection:); } };
struct SignatureCaretRectForPosition : Signature<CGRect (UITextPosition*)> { static auto sel() { return @selector (caretRectForPosition:); } };
struct SignatureCharacterRangeByExtending : Signature<UITextRange* (UITextPosition*, UITextLayoutDirection)> { static auto sel() { return @selector (characterRangeByExtendingPosition:inDirection:); } };
struct SignatureCharacterRangeAtPoint : Signature<UITextRange* (CGPoint)> { static auto sel() { return @selector (characterRangeAtPoint:); } };
struct SignatureClosestPositionToPoint : Signature<UITextPosition* (CGPoint)> { static auto sel() { return @selector (closestPositionToPoint:); } };
struct SignatureClosestPositionToPointInRange : Signature<UITextPosition* (CGPoint, UITextRange*)> { static auto sel() { return @selector (closestPositionToPoint:withinRange:); } };
struct SignatureComparePositionToPosition : Signature<NSComparisonResult (UITextPosition*, UITextPosition*)> { static auto sel() { return @selector (comparePosition:toPosition:); } };
struct SignatureOffsetFromPositionToPosition : Signature<NSInteger (UITextPosition*, UITextPosition*)> { static auto sel() { return @selector (offsetFromPosition:toPosition:); } };
struct SignaturePositionFromPositionInDirection : Signature<UITextPosition* (UITextPosition*, UITextLayoutDirection, NSInteger)> { static auto sel() { return @selector (positionFromPosition:inDirection:offset:); } };
struct SignaturePositionFromPositionOffset : Signature<UITextPosition* (UITextPosition*, NSInteger)> { static auto sel() { return @selector (positionFromPosition:offset:); } };
struct SignatureFirstRectForRange : Signature<CGRect (UITextRange*)> { static auto sel() { return @selector (firstRectForRange:); } };
struct SignatureSelectionRectsForRange : Signature<NSArray<UITextSelectionRect*>* (UITextRange*)> { static auto sel() { return @selector (selectionRectsForRange:); } };
struct SignaturePositionWithinRange : Signature<UITextPosition* (UITextRange*, UITextLayoutDirection)> { static auto sel() { return @selector (positionWithinRange:farthestInDirection:); } };
struct SignatureReplaceRangeWithText : Signature<void (UITextRange*, NSString*)> { static auto sel() { return @selector (replaceRange:withText:); } };
struct SignatureSetBaseWritingDirection : Signature<void (NSWritingDirection, UITextRange*)> { static auto sel() { return @selector (setBaseWritingDirection:forRange:); } };
struct SignatureTextInRange : Signature<NSString* (UITextRange*)> { static auto sel() { return @selector (textInRange:); } };
struct SignatureTextRangeFromPosition : Signature<UITextRange* (UITextPosition*, UITextPosition*)> { static auto sel() { return @selector (textRangeFromPosition:toPosition:); } };
struct SignatureSetInputDelegate : Signature<void (id)> { static auto sel() { return @selector (setInputDelegate:); } };
struct SignatureInputDelegate : Signature<id()> { static auto sel() { return @selector (inputDelegate); } };
struct SignatureKeyboardType : Signature<UIKeyboardType()> { static auto sel() { return @selector (keyboardType); } };
struct SignatureAutocapitalizationType : Signature<UITextAutocapitalizationType()> { static auto sel() { return @selector (autocapitalizationType); } };
struct SignatureAutocorrectionType : Signature<UITextAutocorrectionType()> { static auto sel() { return @selector (autocorrectionType); } };
//==============================================================================
class AccessibilityHandler::AccessibilityNativeImpl
@ -108,73 +95,131 @@ public:
private:
//==============================================================================
class AccessibilityContainer : public ObjCClass<UIAccessibilityElement>
class AccessibilityContainer : public AccessibleObjCClass<NSObject>
{
public:
AccessibilityContainer()
: ObjCClass ("JUCEUIAccessibilityElementContainer_")
: AccessibleObjCClass ("JUCEUIAccessibilityContainer_")
{
addMethod (@selector (isAccessibilityElement), getIsAccessibilityElement, "c@:");
addMethod (@selector (accessibilityFrame), getAccessibilityFrame, @encode (CGRect), "@:");
addMethod (@selector (accessibilityElements), getAccessibilityElements, "@@:");
addMethod (@selector (accessibilityContainerType), getAccessibilityContainerType, "i@:");
addMethod (@selector (isAccessibilityElement), [] (id, SEL) { return false; });
addIvar<AccessibilityHandler*> ("handler");
addMethod (@selector (accessibilityFrame), [] (id self, SEL)
{
if (auto* handler = getHandler (self))
return convertToCGRect (handler->getComponent().getScreenBounds());
return CGRectZero;
});
addMethod (@selector (accessibilityElements), [] (id self, SEL) -> NSArray*
{
if (auto* handler = getHandler (self))
return getContainerAccessibilityElements (*handler);
return nil;
});
if (@available (iOS 11.0, *))
{
addMethod (@selector (accessibilityDataTableCellElementForRow:column:), [] (id self, SEL, NSUInteger row, NSUInteger column) -> id
{
if (auto* tableHandler = getEnclosingHandlerWithInterface (getHandler (self), &AccessibilityHandler::getTableInterface))
if (auto* tableInterface = tableHandler->getTableInterface())
if (auto* cellHandler = tableInterface->getCellHandler ((int) row, (int) column))
if (auto* parent = getAccessibleParent (cellHandler))
return static_cast<id> (parent->getNativeImplementation());
return nil;
});
addMethod (@selector (accessibilityRowCount), getAccessibilityRowCount);
addMethod (@selector (accessibilityColumnCount), getAccessibilityColumnCount);
addMethod (@selector (accessibilityHeaderElementsForColumn:), [] (id self, SEL, NSUInteger column) -> NSArray*
{
if (auto* tableHandler = getEnclosingHandlerWithInterface (getHandler (self), &AccessibilityHandler::getTableInterface))
{
if (auto* tableInterface = tableHandler->getTableInterface())
{
if (auto* header = tableInterface->getHeaderHandler())
{
if (isPositiveAndBelow (column, header->getChildren().size()))
{
auto* result = [NSMutableArray new];
[result addObject: static_cast<id> (header->getChildren()[(size_t) column]->getNativeImplementation())];
return result;
}
}
}
}
return nullptr;
});
addProtocol (@protocol (UIAccessibilityContainerDataTable));
addMethod (@selector (accessibilityContainerType), [] (id self, SEL) -> NSInteger
{
if (auto* handler = getHandler (self))
{
if (handler->getTableInterface() != nullptr)
{
if (@available (iOS 11.0, *))
return UIAccessibilityContainerTypeDataTable;
return 1; // UIAccessibilityContainerTypeDataTable
}
const auto handlerRole = handler->getRole();
if (handlerRole == AccessibilityRole::popupMenu
|| handlerRole == AccessibilityRole::list
|| handlerRole == AccessibilityRole::tree)
{
if (@available (iOS 11.0, *))
return UIAccessibilityContainerTypeList;
return 2; // UIAccessibilityContainerTypeList
}
}
if (@available (iOS 11.0, *))
return UIAccessibilityContainerTypeNone;
return 0; // UIAccessibilityContainerTypeNone
});
}
registerClass();
}
private:
static const AccessibilityHandler* getAccessibleParent (const AccessibilityHandler* h)
{
if (h == nullptr)
return nullptr;
if ([static_cast<id> (h->getNativeImplementation()) isAccessibilityElement])
return h;
return getAccessibleParent (h->getParent());
}
static AccessibilityHandler* getHandler (id self)
{
return getIvar<AccessibilityHandler*> (self, "handler");
}
static BOOL getIsAccessibilityElement (id, SEL)
{
return NO;
}
static CGRect getAccessibilityFrame (id self, SEL)
{
if (auto* handler = getHandler (self))
return convertToCGRect (handler->getComponent().getScreenBounds());
return CGRectZero;
}
static NSArray* getAccessibilityElements (id self, SEL)
{
if (auto* handler = getHandler (self))
return getContainerAccessibilityElements (*handler);
return nil;
}
static NSInteger getAccessibilityContainerType (id self, SEL)
{
if (auto* handler = getHandler (self))
{
if (handler->getTableInterface() != nullptr)
return juceUIAccessibilityContainerTypeDataTable;
const auto role = handler->getRole();
if (role == AccessibilityRole::popupMenu
|| role == AccessibilityRole::list
|| role == AccessibilityRole::tree)
{
return juceUIAccessibilityContainerTypeList;
}
}
return juceUIAccessibilityContainerTypeNone;
}
};
//==============================================================================
class AccessibilityElement : public AccessibleObjCClass<UIAccessibilityElement>
{
template <typename Func, typename... Items>
static constexpr void forEach (Func&& func, Items&&... items)
{
(void) std::initializer_list<int> { ((void) func (std::forward<Items> (items)), 0)... };
}
public:
enum class Type { defaultElement, textElement };
@ -185,49 +230,282 @@ private:
id instance = (hasEditableText (handler) ? textCls : cls).createInstance();
Holder element ([instance initWithAccessibilityContainer: (id) handler.getComponent().getWindowHandle()]);
Holder element ([instance initWithAccessibilityContainer: static_cast<id> (handler.getComponent().getWindowHandle())]);
object_setInstanceVariable (element.get(), "handler", &handler);
return element;
}
AccessibilityElement (Type elementType)
{
addMethod (@selector (isAccessibilityElement), getIsAccessibilityElement, "c@:");
addMethod (@selector (accessibilityContainer), getAccessibilityContainer, "@@:");
addMethod (@selector (accessibilityFrame), getAccessibilityFrame, @encode (CGRect), "@:");
addMethod (@selector (accessibilityTraits), getAccessibilityTraits, "i@:");
addMethod (@selector (accessibilityLabel), getAccessibilityTitle, "@@:");
addMethod (@selector (accessibilityHint), getAccessibilityHelp, "@@:");
addMethod (@selector (accessibilityValue), getAccessibilityValue, "@@:");
addMethod (@selector (setAccessibilityValue:), setAccessibilityValue, "v@:@");
addMethod (@selector (isAccessibilityElement), [] (id self, SEL)
{
auto* handler = getHandler (self);
addMethod (@selector (accessibilityElementDidBecomeFocused), onFocusGain, "v@:");
addMethod (@selector (accessibilityElementDidLoseFocus), onFocusLoss, "v@:");
addMethod (@selector (accessibilityElementIsFocused), isFocused, "c@:");
addMethod (@selector (accessibilityViewIsModal), getIsAccessibilityModal, "c@:");
const auto hasAccessiblePropertiesOrIsTableCell = [] (auto& handlerRef)
{
const auto isTableCell = [&]
{
if (auto* tableHandler = getEnclosingHandlerWithInterface (&handlerRef, &AccessibilityHandler::getTableInterface))
{
if (auto* tableInterface = tableHandler->getTableInterface())
{
return tableInterface->getRowSpan (handlerRef).hasValue()
&& tableInterface->getColumnSpan (handlerRef).hasValue();
}
}
addMethod (@selector (accessibilityActivate), accessibilityPerformActivate, "c@:");
addMethod (@selector (accessibilityIncrement), accessibilityPerformIncrement, "c@:");
addMethod (@selector (accessibilityDecrement), accessibilityPerformDecrement, "c@:");
addMethod (@selector (accessibilityPerformEscape), accessibilityEscape, "c@:");
return false;
};
addMethod (@selector (accessibilityDataTableCellElementForRow:column:), getAccessibilityDataTableCellElementForRowColumn, "@@:ii");
addMethod (@selector (accessibilityRowCount), getAccessibilityRowCount, "i@:");
addMethod (@selector (accessibilityColumnCount), getAccessibilityColumnCount, "i@:");
addProtocol (@protocol (UIAccessibilityContainerDataTable));
return handlerRef.getTitle().isNotEmpty()
|| handlerRef.getHelp().isNotEmpty()
|| handlerRef.getTextInterface() != nullptr
|| handlerRef.getValueInterface() != nullptr
|| isTableCell();
};
addMethod (@selector (accessibilityRowRange), getAccessibilityRowIndexRange, @encode (NSRange), "@:");
addMethod (@selector (accessibilityColumnRange), getAccessibilityColumnIndexRange, @encode (NSRange), "@:");
addProtocol (@protocol (UIAccessibilityContainerDataTableCell));
return handler != nullptr
&& ! handler->isIgnored()
&& handler->getRole() != AccessibilityRole::window
&& hasAccessiblePropertiesOrIsTableCell (*handler);
});
addMethod (@selector (accessibilityContainer), [] (id self, SEL) -> id
{
if (auto* handler = getHandler (self))
{
if (handler->getComponent().isOnDesktop())
return static_cast<id> (handler->getComponent().getWindowHandle());
if (! handler->getChildren().empty())
{
if (UIAccessibilityElement* container = getContainer (self))
return container;
static AccessibilityContainer cls;
id container = cls.createInstance();
object_setInstanceVariable (container, "handler", handler);
object_setInstanceVariable (self, "container", container);
return container;
}
if (auto* parent = handler->getParent())
return [static_cast<id> (parent->getNativeImplementation()) accessibilityContainer];
}
return nil;
});
addMethod (@selector (accessibilityFrame), [] (id self, SEL)
{
if (auto* handler = getHandler (self))
return convertToCGRect (handler->getComponent().getScreenBounds());
return CGRectZero;
});
addMethod (@selector (accessibilityTraits), [] (id self, SEL)
{
auto traits = UIAccessibilityTraits{};
if (auto* handler = getHandler (self))
{
traits |= [&handler]
{
switch (handler->getRole())
{
case AccessibilityRole::button:
case AccessibilityRole::toggleButton:
case AccessibilityRole::radioButton:
case AccessibilityRole::comboBox: return UIAccessibilityTraitButton;
case AccessibilityRole::label:
case AccessibilityRole::staticText: return UIAccessibilityTraitStaticText;
case AccessibilityRole::image: return UIAccessibilityTraitImage;
case AccessibilityRole::tableHeader: return UIAccessibilityTraitHeader;
case AccessibilityRole::hyperlink: return UIAccessibilityTraitLink;
case AccessibilityRole::ignored: return UIAccessibilityTraitNotEnabled;
case AccessibilityRole::editableText: return UIAccessibilityTraitKeyboardKey;
case AccessibilityRole::slider:
case AccessibilityRole::menuItem:
case AccessibilityRole::menuBar:
case AccessibilityRole::popupMenu:
case AccessibilityRole::table:
case AccessibilityRole::column:
case AccessibilityRole::row:
case AccessibilityRole::cell:
case AccessibilityRole::list:
case AccessibilityRole::listItem:
case AccessibilityRole::tree:
case AccessibilityRole::treeItem:
case AccessibilityRole::progressBar:
case AccessibilityRole::group:
case AccessibilityRole::dialogWindow:
case AccessibilityRole::window:
case AccessibilityRole::scrollBar:
case AccessibilityRole::tooltip:
case AccessibilityRole::splashScreen:
case AccessibilityRole::unspecified: break;
}
return UIAccessibilityTraitNone;
}();
const auto state = handler->getCurrentState();
if (state.isSelected() || state.isChecked())
traits |= UIAccessibilityTraitSelected;
if (auto* valueInterface = getValueInterface (self))
if (! valueInterface->isReadOnly() && valueInterface->getRange().isValid())
traits |= UIAccessibilityTraitAdjustable;
}
return traits | sendSuperclassMessage<UIAccessibilityTraits> (self, @selector (accessibilityTraits));
});
addMethod (@selector (accessibilityLabel), getAccessibilityTitle);
addMethod (@selector (accessibilityHint), getAccessibilityHelp);
addMethod (@selector (accessibilityValue), [] (id self, SEL) -> NSString*
{
if (auto* handler = getHandler (self))
{
if (handler->getCurrentState().isCheckable())
return handler->getCurrentState().isChecked() ? @"1" : @"0";
return (NSString*) getAccessibilityValueFromInterfaces (*handler);
}
return nil;
});
addMethod (@selector (setAccessibilityValue:), setAccessibilityValue);
addMethod (@selector (accessibilityElementDidBecomeFocused), [] (id self, SEL)
{
if (auto* handler = getHandler (self))
{
const WeakReference<Component> safeComponent (&handler->getComponent());
performActionIfSupported (self, AccessibilityActionType::focus);
if (safeComponent != nullptr)
handler->grabFocus();
}
});
addMethod (@selector (accessibilityElementDidLoseFocus), [] (id self, SEL)
{
if (auto* handler = getHandler (self))
handler->giveAwayFocus();
});
addMethod (@selector (accessibilityElementIsFocused), [] (id self, SEL) -> BOOL
{
if (auto* handler = getHandler (self))
return handler->hasFocus (false);
return NO;
});
addMethod (@selector (accessibilityViewIsModal), getIsAccessibilityModal);
addMethod (@selector (accessibilityActivate), [] (id self, SEL)
{
if (auto* handler = getHandler (self))
{
// Occasionally VoiceOver sends accessibilityActivate to the wrong element, so we first query
// which element it thinks has focus and forward the event on to that element if it differs
id focusedElement = UIAccessibilityFocusedElement (UIAccessibilityNotificationVoiceOverIdentifier);
if (focusedElement != nullptr && ! [static_cast<id> (handler->getNativeImplementation()) isEqual: focusedElement])
return [focusedElement accessibilityActivate];
if (handler->hasFocus (false))
return accessibilityPerformPress (self, {});
}
return NO;
});
addMethod (@selector (accessibilityIncrement), accessibilityPerformIncrement);
addMethod (@selector (accessibilityDecrement), accessibilityPerformDecrement);
addMethod (@selector (accessibilityPerformEscape), [] (id self, SEL)
{
if (auto* handler = getHandler (self))
{
if (auto* modal = Component::getCurrentlyModalComponent())
{
if (auto* modalHandler = modal->getAccessibilityHandler())
{
if (modalHandler == handler || modalHandler->isParentOf (handler))
{
modal->exitModalState (0);
return YES;
}
}
}
}
return NO;
});
if (elementType == Type::textElement)
{
addMethod (@selector (accessibilityLineNumberForPoint:), getAccessibilityLineNumberForPoint, "i@:", @encode (CGPoint));
addMethod (@selector (accessibilityContentForLineNumber:), getAccessibilityContentForLineNumber, "@@:i");
addMethod (@selector (accessibilityFrameForLineNumber:), getAccessibilityFrameForLineNumber, @encode (CGRect), "@:i");
addMethod (@selector (accessibilityPageContent), getAccessibilityPageContent, "@@:");
addMethod (@selector (deleteBackward), [] (id, SEL) {});
addMethod (@selector (insertText:), [] (id, SEL, NSString*) {});
addProtocol (@protocol (UIAccessibilityReadingContent));
forEach ([this] (auto signature) { addPassthroughMethodWithSignature (signature); },
SignatureHasText{},
SignatureSetSelectedTextRange{},
SignatureSelectedTextRange{},
SignatureMarkedTextRange{},
SignatureSetMarkedTextSelectedRange{},
SignatureUnmarkText{},
SignatureMarkedTextStyle{},
SignatureSetMarkedTextStyle{},
SignatureBeginningOfDocument{},
SignatureEndOfDocument{},
SignatureTokenizer{},
SignatureBaseWritingDirection{},
SignatureCaretRectForPosition{},
SignatureCharacterRangeByExtending{},
SignatureCharacterRangeAtPoint{},
SignatureClosestPositionToPoint{},
SignatureClosestPositionToPointInRange{},
SignatureComparePositionToPosition{},
SignatureOffsetFromPositionToPosition{},
SignaturePositionFromPositionInDirection{},
SignaturePositionFromPositionOffset{},
SignatureFirstRectForRange{},
SignatureSelectionRectsForRange{},
SignaturePositionWithinRange{},
SignatureReplaceRangeWithText{},
SignatureSetBaseWritingDirection{},
SignatureTextInRange{},
SignatureTextRangeFromPosition{},
SignatureSetInputDelegate{},
SignatureInputDelegate{},
SignatureKeyboardType{},
SignatureAutocapitalizationType{},
SignatureAutocorrectionType{});
addProtocol (@protocol (UITextInput));
}
if (@available (iOS 11.0, *))
{
addMethod (@selector (accessibilityRowRange), getAccessibilityRowIndexRange);
addMethod (@selector (accessibilityColumnRange), getAccessibilityColumnIndexRange);
addProtocol (@protocol (UIAccessibilityContainerDataTableCell));
}
addIvar<UIAccessibilityElement*> ("container");
@ -236,246 +514,65 @@ private:
}
private:
//==============================================================================
template <typename Result>
static auto getResult (NSInvocation* invocation, detail::Tag<Result>)
{
Result result{};
[invocation getReturnValue: &result];
return result;
}
static void getResult (NSInvocation*, detail::Tag<void>) {}
template <typename HasSelector, typename Result, typename... Args>
auto makePassthroughCallback (HasSelector, Signature<Result (Args...)>)
{
return [] (id self, SEL, Args... args) -> Result
{
if (auto* input = getPeerTextInput (self))
{
const auto s = detail::makeCompileTimeStr (@encode (Result), @encode (id), @encode (SEL), @encode (Args)...);
const auto signature = [NSMethodSignature signatureWithObjCTypes: s.data()];
const auto invocation = [NSInvocation invocationWithMethodSignature: signature];
invocation.selector = HasSelector::sel();
// Indices 0 and 1 are 'id self' and 'SEL _cmd' respectively
auto counter = 2;
forEach ([&] (auto& arg) { [invocation setArgument: &arg atIndex: counter++]; }, args...);
[invocation invokeWithTarget: input];
return getResult (invocation, detail::Tag<Result>{});
}
jassertfalse;
return {};
};
}
template <typename Signature>
void addPassthroughMethodWithSignature (Signature signature)
{
addMethod (Signature::sel(), makePassthroughCallback (signature, signature));
}
static UIAccessibilityElement* getContainer (id self)
{
return getIvar<UIAccessibilityElement*> (self, "container");
}
//==============================================================================
static id getAccessibilityContainer (id self, SEL)
static UIViewComponentPeer* getPeer (id self)
{
if (auto* handler = getHandler (self))
{
if (handler->getComponent().isOnDesktop())
return (id) handler->getComponent().getWindowHandle();
if (handler->getChildren().size() > 0)
{
if (UIAccessibilityElement* container = getContainer (self))
return container;
static AccessibilityContainer cls;
id windowHandle = (id) handler->getComponent().getWindowHandle();
UIAccessibilityElement* container = [cls.createInstance() initWithAccessibilityContainer: windowHandle];
[container retain];
object_setInstanceVariable (container, "handler", handler);
object_setInstanceVariable (self, "container", container);
return container;
}
if (auto* parent = handler->getParent())
return [(id) parent->getNativeImplementation() accessibilityContainer];
}
return static_cast<UIViewComponentPeer*> (handler->getComponent().getPeer());
return nil;
}
static CGRect getAccessibilityFrame (id self, SEL)
static JuceTextView* getPeerTextInput (id self)
{
if (auto* handler = getHandler (self))
return convertToCGRect (handler->getComponent().getScreenBounds());
return CGRectZero;
}
static UIAccessibilityTraits getAccessibilityTraits (id self, SEL)
{
auto traits = UIAccessibilityTraits{};
if (auto* handler = getHandler (self))
{
traits |= [&handler]
{
switch (handler->getRole())
{
case AccessibilityRole::button:
case AccessibilityRole::toggleButton:
case AccessibilityRole::radioButton:
case AccessibilityRole::comboBox: return UIAccessibilityTraitButton;
case AccessibilityRole::label:
case AccessibilityRole::staticText: return UIAccessibilityTraitStaticText;
case AccessibilityRole::image: return UIAccessibilityTraitImage;
case AccessibilityRole::tableHeader: return UIAccessibilityTraitHeader;
case AccessibilityRole::hyperlink: return UIAccessibilityTraitLink;
case AccessibilityRole::editableText: return UIAccessibilityTraitKeyboardKey;
case AccessibilityRole::ignored: return UIAccessibilityTraitNotEnabled;
case AccessibilityRole::slider:
case AccessibilityRole::menuItem:
case AccessibilityRole::menuBar:
case AccessibilityRole::popupMenu:
case AccessibilityRole::table:
case AccessibilityRole::column:
case AccessibilityRole::row:
case AccessibilityRole::cell:
case AccessibilityRole::list:
case AccessibilityRole::listItem:
case AccessibilityRole::tree:
case AccessibilityRole::treeItem:
case AccessibilityRole::progressBar:
case AccessibilityRole::group:
case AccessibilityRole::dialogWindow:
case AccessibilityRole::window:
case AccessibilityRole::scrollBar:
case AccessibilityRole::tooltip:
case AccessibilityRole::splashScreen:
case AccessibilityRole::unspecified: break;
}
return UIAccessibilityTraitNone;
}();
const auto state = handler->getCurrentState();
if (state.isSelected() || state.isChecked())
traits |= UIAccessibilityTraitSelected;
if (auto* valueInterface = getValueInterface (self))
if (! valueInterface->isReadOnly() && valueInterface->getRange().isValid())
traits |= UIAccessibilityTraitAdjustable;
}
return traits | sendSuperclassMessage<UIAccessibilityTraits> (self, @selector (accessibilityTraits));
}
static NSString* getAccessibilityValue (id self, SEL)
{
if (auto* handler = getHandler (self))
{
if (handler->getCurrentState().isCheckable())
return handler->getCurrentState().isChecked() ? @"1" : @"0";
return (NSString*) getAccessibilityValueFromInterfaces (*handler);
}
return nil;
}
static void onFocusGain (id self, SEL)
{
if (auto* handler = getHandler (self))
{
const WeakReference<Component> safeComponent (&handler->getComponent());
performActionIfSupported (self, AccessibilityActionType::focus);
if (safeComponent != nullptr)
handler->grabFocus();
}
}
static void onFocusLoss (id self, SEL)
{
if (auto* handler = getHandler (self))
handler->giveAwayFocus();
}
static BOOL isFocused (id self, SEL)
{
if (auto* handler = getHandler (self))
return handler->hasFocus (false);
return NO;
}
static BOOL accessibilityPerformActivate (id self, SEL)
{
if (auto* handler = getHandler (self))
{
// occasionaly VoiceOver sends accessibilityActivate to the wrong element, so we first query
// which element it thinks has focus and forward the event on to that element if it differs
id focusedElement = UIAccessibilityFocusedElement (UIAccessibilityNotificationVoiceOverIdentifier);
if (! [(id) handler->getNativeImplementation() isEqual: focusedElement])
return [focusedElement accessibilityActivate];
if (handler->hasFocus (false))
return accessibilityPerformPress (self, {});
}
return NO;
}
static BOOL accessibilityEscape (id self, SEL)
{
if (auto* handler = getHandler (self)) {
// HACK - look for parent that is a CalloutBox and dismiss it
if (CallOutBox* const cb = handler->getComponent().findParentComponentOfClass<CallOutBox>()) {
cb->dismiss();
return YES;
}
}
return NO;
}
static id getAccessibilityDataTableCellElementForRowColumn (id self, SEL, NSUInteger row, NSUInteger column)
{
if (auto* tableInterface = getTableInterface (self))
if (auto* cellHandler = tableInterface->getCellHandler ((int) row, (int) column))
return (id) cellHandler->getNativeImplementation();
return nil;
}
static NSInteger getAccessibilityLineNumberForPoint (id self, SEL, CGPoint point)
{
if (auto* handler = getHandler (self))
{
if (auto* textInterface = handler->getTextInterface())
{
auto pointInt = roundToIntPoint (point);
if (handler->getComponent().getScreenBounds().contains (pointInt))
{
auto textBounds = textInterface->getTextBounds ({ 0, textInterface->getTotalNumCharacters() });
for (int i = 0; i < textBounds.getNumRectangles(); ++i)
if (textBounds.getRectangle (i).contains (pointInt))
return (NSInteger) i;
}
}
}
return NSNotFound;
}
static NSString* getAccessibilityContentForLineNumber (id self, SEL, NSInteger lineNumber)
{
if (auto* textInterface = getTextInterface (self))
{
auto lines = StringArray::fromLines (textInterface->getText ({ 0, textInterface->getTotalNumCharacters() }));
if ((int) lineNumber < lines.size())
return juceStringToNS (lines[(int) lineNumber]);
}
return nil;
}
static CGRect getAccessibilityFrameForLineNumber (id self, SEL, NSInteger lineNumber)
{
if (auto* textInterface = getTextInterface (self))
{
auto textBounds = textInterface->getTextBounds ({ 0, textInterface->getTotalNumCharacters() });
if (lineNumber < textBounds.getNumRectangles())
return convertToCGRect (textBounds.getRectangle ((int) lineNumber));
}
return CGRectZero;
}
static NSString* getAccessibilityPageContent (id self, SEL)
{
if (auto* textInterface = getTextInterface (self))
return juceStringToNS (textInterface->getText ({ 0, textInterface->getTotalNumCharacters() }));
if (auto* peer = getPeer (self))
return peer->hiddenTextInput.get();
return nil;
}
@ -535,9 +632,8 @@ void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, Inte
const bool moveToHandler = (eventType == InternalAccessibilityEvent::focusChanged && handler.hasFocus (false));
sendAccessibilityEvent (notification,
moveToHandler ? (id) handler.getNativeImplementation() : nil);
moveToHandler ? static_cast<id> (handler.getNativeImplementation()) : nil);
}
}
void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventType) const
@ -559,7 +655,7 @@ void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventTyp
}();
if (notification != UIAccessibilityNotifications{})
sendAccessibilityEvent (notification, (id) getNativeImplementation());
sendAccessibilityEvent (notification, static_cast<id> (getNativeImplementation()));
}
void AccessibilityHandler::postAnnouncement (const String& announcementString, AnnouncementPriority)

View File

@ -2,15 +2,15 @@
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-6-licence
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
@ -46,7 +46,9 @@ public:
using Holder = std::unique_ptr<Base, AccessibleObjCClassDeleter>;
protected:
AccessibleObjCClass() : ObjCClass<Base> ("JUCEAccessibilityElement_")
AccessibleObjCClass() : AccessibleObjCClass ("JUCEAccessibilityElement_") {}
explicit AccessibleObjCClass (const char* name) : ObjCClass<Base> (name)
{
ObjCClass<Base>::template addIvar<AccessibilityHandler*> ("handler");
}
@ -93,8 +95,7 @@ protected:
static BOOL getIsAccessibilityElement (id self, SEL)
{
if (auto* handler = getHandler (self))
return ! handler->isIgnored()
&& handler->getRole() != AccessibilityRole::window;
return ! handler->isIgnored() && handler->getRole() != AccessibilityRole::window;
return NO;
}
@ -126,6 +127,10 @@ protected:
static BOOL accessibilityPerformPress (id self, SEL)
{
if (auto* handler = getHandler (self))
if (handler->getCurrentState().isCheckable() && handler->getActions().invoke (AccessibilityActionType::toggle))
return YES;
return performActionIfSupported (self, AccessibilityActionType::press);
}
@ -182,10 +187,8 @@ protected:
NSString* nsString = juceStringToNS (title);
#if ! JUCE_IOS
if (nsString != nil && [[self accessibilityValue] isEqual: nsString])
return @"";
#endif
return nsString;
}
@ -211,36 +214,58 @@ protected:
static NSInteger getAccessibilityRowCount (id self, SEL)
{
if (auto* tableInterface = getTableInterface (self))
return tableInterface->getNumRows();
if (auto* tableHandler = getEnclosingHandlerWithInterface (getHandler (self), &AccessibilityHandler::getTableInterface))
if (auto* tableInterface = tableHandler->getTableInterface())
return tableInterface->getNumRows();
return 0;
}
static NSInteger getAccessibilityColumnCount (id self, SEL)
{
if (auto* tableInterface = getTableInterface (self))
return tableInterface->getNumColumns();
if (auto* tableHandler = getEnclosingHandlerWithInterface (getHandler (self), &AccessibilityHandler::getTableInterface))
if (auto* tableInterface = tableHandler->getTableInterface())
return tableInterface->getNumColumns();
return 0;
}
template <typename Getter>
static NSRange getCellDimensions (id self, Getter getter)
{
const auto notFound = NSMakeRange (NSNotFound, 0);
auto* handler = getHandler (self);
if (handler == nullptr)
return notFound;
auto* tableHandler = getEnclosingHandlerWithInterface (getHandler (self), &AccessibilityHandler::getTableInterface);
if (tableHandler == nullptr)
return notFound;
auto* tableInterface = tableHandler->getTableInterface();
if (tableInterface == nullptr)
return notFound;
const auto result = (tableInterface->*getter) (*handler);
if (! result.hasValue())
return notFound;
return NSMakeRange ((NSUInteger) result->begin, (NSUInteger) result->num);
}
static NSRange getAccessibilityRowIndexRange (id self, SEL)
{
if (auto* cellInterface = getCellInterface (self))
return NSMakeRange ((NSUInteger) cellInterface->getRowIndex(),
(NSUInteger) cellInterface->getRowSpan());
return NSMakeRange (0, 0);
return getCellDimensions (self, &AccessibilityTableInterface::getRowSpan);
}
static NSRange getAccessibilityColumnIndexRange (id self, SEL)
{
if (auto* cellInterface = getCellInterface (self))
return NSMakeRange ((NSUInteger) cellInterface->getColumnIndex(),
(NSUInteger) cellInterface->getColumnSpan());
return NSMakeRange (0, 0);
return getCellDimensions (self, &AccessibilityTableInterface::getColumnSpan);
}
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibleObjCClass)

View File

@ -1,301 +1,327 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
#define JUCE_NATIVE_ACCESSIBILITY_INCLUDED 1
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
static bool isStartingUpOrShuttingDown()
{
if (auto* app = JUCEApplicationBase::getInstance())
if (app->isInitialising())
return true;
if (auto* mm = MessageManager::getInstanceWithoutCreating())
if (mm->hasStopMessageBeenSent())
return true;
return false;
}
static bool isHandlerValid (const AccessibilityHandler& handler)
{
if (auto* provider = handler.getNativeImplementation())
return provider->isElementValid();
return false;
}
//==============================================================================
class AccessibilityHandler::AccessibilityNativeImpl
{
public:
explicit AccessibilityNativeImpl (AccessibilityHandler& owner)
: accessibilityElement (new AccessibilityNativeHandle (owner))
{
++providerCount;
}
~AccessibilityNativeImpl()
{
accessibilityElement->invalidateElement();
--providerCount;
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
{
ComSmartPtr<IRawElementProviderSimple> provider;
accessibilityElement->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
uiaWrapper->disconnectProvider (provider);
if (providerCount == 0)
uiaWrapper->disconnectAllProviders();
}
}
//==============================================================================
ComSmartPtr<AccessibilityNativeHandle> accessibilityElement;
static int providerCount;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibilityNativeImpl)
};
int AccessibilityHandler::AccessibilityNativeImpl::providerCount = 0;
//==============================================================================
AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const
{
return nativeImpl->accessibilityElement;
}
static bool areAnyAccessibilityClientsActive()
{
const auto areClientsListening = []
{
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
return uiaWrapper->clientsAreListening() != 0;
return false;
};
const auto isScreenReaderRunning = []
{
BOOL isRunning = FALSE;
SystemParametersInfo (SPI_GETSCREENREADER, 0, (PVOID) &isRunning, 0);
return isRunning != 0;
};
return areClientsListening() || isScreenReaderRunning();
}
template <typename Callback>
void getProviderWithCheckedWrapper (const AccessibilityHandler& handler, Callback&& callback)
{
if (! areAnyAccessibilityClientsActive() || isStartingUpOrShuttingDown() || ! isHandlerValid (handler))
return;
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
{
ComSmartPtr<IRawElementProviderSimple> provider;
handler.getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
callback (uiaWrapper, provider);
}
}
void sendAccessibilityAutomationEvent (const AccessibilityHandler& handler, EVENTID event)
{
jassert (event != EVENTID{});
getProviderWithCheckedWrapper (handler, [event] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
{
uiaWrapper->raiseAutomationEvent (provider, event);
});
}
void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler& handler, PROPERTYID property, VARIANT newValue)
{
jassert (property != PROPERTYID{});
getProviderWithCheckedWrapper (handler, [property, newValue] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
{
VARIANT oldValue;
VariantHelpers::clear (&oldValue);
uiaWrapper->raiseAutomationPropertyChangedEvent (provider, property, oldValue, newValue);
});
}
void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, InternalAccessibilityEvent eventType)
{
if (eventType == InternalAccessibilityEvent::elementCreated
|| eventType == InternalAccessibilityEvent::elementDestroyed)
{
if (auto* parent = handler.getParent())
sendAccessibilityAutomationEvent (*parent, UIA_LayoutInvalidatedEventId);
return;
}
auto event = [eventType]() -> EVENTID
{
switch (eventType)
{
case InternalAccessibilityEvent::focusChanged: return UIA_AutomationFocusChangedEventId;
case InternalAccessibilityEvent::windowOpened: return UIA_Window_WindowOpenedEventId;
case InternalAccessibilityEvent::windowClosed: return UIA_Window_WindowClosedEventId;
case InternalAccessibilityEvent::elementCreated:
case InternalAccessibilityEvent::elementDestroyed:
case InternalAccessibilityEvent::elementMovedOrResized: break;
}
return {};
}();
if (event != EVENTID{})
sendAccessibilityAutomationEvent (handler, event);
}
void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventType) const
{
if (eventType == AccessibilityEvent::titleChanged)
{
VARIANT newValue;
VariantHelpers::setString (getTitle(), &newValue);
sendAccessibilityPropertyChangedEvent (*this, UIA_NamePropertyId, newValue);
}
auto event = [eventType]() -> EVENTID
{
switch (eventType)
{
case AccessibilityEvent::textSelectionChanged: return UIA_Text_TextSelectionChangedEventId;
case AccessibilityEvent::textChanged: return UIA_Text_TextChangedEventId;
case AccessibilityEvent::structureChanged: return UIA_StructureChangedEventId;
case AccessibilityEvent::rowSelectionChanged: return UIA_SelectionItem_ElementSelectedEventId;
case AccessibilityEvent::titleChanged:
case AccessibilityEvent::valueChanged: break;
}
return {};
}();
if (event != EVENTID{})
sendAccessibilityAutomationEvent (*this, event);
}
struct SpVoiceWrapper : public DeletedAtShutdown
{
SpVoiceWrapper()
{
auto hr = voice.CoCreateInstance (CLSID_SpVoice);
jassertquiet (SUCCEEDED (hr));
}
~SpVoiceWrapper() override
{
clearSingletonInstance();
}
ComSmartPtr<ISpVoice> voice;
JUCE_DECLARE_SINGLETON (SpVoiceWrapper, false)
};
JUCE_IMPLEMENT_SINGLETON (SpVoiceWrapper)
void AccessibilityHandler::postAnnouncement (const String& announcementString, AnnouncementPriority priority)
{
if (! areAnyAccessibilityClientsActive())
return;
if (auto* sharedVoice = SpVoiceWrapper::getInstance())
{
auto voicePriority = [priority]
{
switch (priority)
{
case AnnouncementPriority::low: return SPVPRI_OVER;
case AnnouncementPriority::medium: return SPVPRI_NORMAL;
case AnnouncementPriority::high: return SPVPRI_ALERT;
}
jassertfalse;
return SPVPRI_OVER;
}();
sharedVoice->voice->SetPriority (voicePriority);
sharedVoice->voice->Speak (announcementString.toWideCharPointer(), SPF_ASYNC, nullptr);
}
}
//==============================================================================
namespace WindowsAccessibility
{
long getUiaRootObjectId()
{
return static_cast<long> (UiaRootObjectId);
}
bool handleWmGetObject (AccessibilityHandler* handler, WPARAM wParam, LPARAM lParam, LRESULT* res)
{
if (isStartingUpOrShuttingDown() || (handler == nullptr || ! isHandlerValid (*handler)))
return false;
if (auto* uiaWrapper = WindowsUIAWrapper::getInstance())
{
ComSmartPtr<IRawElementProviderSimple> provider;
handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
if (! uiaWrapper->isProviderDisconnecting (provider))
*res = uiaWrapper->returnRawElementProvider ((HWND) handler->getComponent().getWindowHandle(), wParam, lParam, provider);
return true;
}
return false;
}
void revokeUIAMapEntriesForWindow (HWND hwnd)
{
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
uiaWrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
}
}
JUCE_IMPLEMENT_SINGLETON (WindowsUIAWrapper)
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
#define JUCE_NATIVE_ACCESSIBILITY_INCLUDED 1
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
static bool isStartingUpOrShuttingDown()
{
if (auto* app = JUCEApplicationBase::getInstance())
if (app->isInitialising())
return true;
if (auto* mm = MessageManager::getInstanceWithoutCreating())
if (mm->hasStopMessageBeenSent())
return true;
return false;
}
static bool isHandlerValid (const AccessibilityHandler& handler)
{
if (auto* provider = handler.getNativeImplementation())
return provider->isElementValid();
return false;
}
//==============================================================================
class AccessibilityHandler::AccessibilityNativeImpl
{
public:
explicit AccessibilityNativeImpl (AccessibilityHandler& owner)
: accessibilityElement (new AccessibilityNativeHandle (owner))
{
++providerCount;
}
~AccessibilityNativeImpl()
{
ComSmartPtr<IRawElementProviderSimple> provider;
accessibilityElement->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
accessibilityElement->invalidateElement();
--providerCount;
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
{
uiaWrapper->disconnectProvider (provider);
if (providerCount == 0 && JUCEApplicationBase::isStandaloneApp())
uiaWrapper->disconnectAllProviders();
}
}
//==============================================================================
ComSmartPtr<AccessibilityNativeHandle> accessibilityElement;
static int providerCount;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibilityNativeImpl)
};
int AccessibilityHandler::AccessibilityNativeImpl::providerCount = 0;
//==============================================================================
AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const
{
return nativeImpl->accessibilityElement;
}
static bool areAnyAccessibilityClientsActive()
{
const auto areClientsListening = []
{
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
return uiaWrapper->clientsAreListening() != 0;
return false;
};
const auto isScreenReaderRunning = []
{
BOOL isRunning = FALSE;
SystemParametersInfo (SPI_GETSCREENREADER, 0, (PVOID) &isRunning, 0);
return isRunning != 0;
};
return areClientsListening() || isScreenReaderRunning();
}
template <typename Callback>
void getProviderWithCheckedWrapper (const AccessibilityHandler& handler, Callback&& callback)
{
if (! areAnyAccessibilityClientsActive() || isStartingUpOrShuttingDown() || ! isHandlerValid (handler))
return;
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
{
ComSmartPtr<IRawElementProviderSimple> provider;
handler.getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
callback (uiaWrapper, provider);
}
}
void sendAccessibilityAutomationEvent (const AccessibilityHandler& handler, EVENTID event)
{
jassert (event != EVENTID{});
getProviderWithCheckedWrapper (handler, [event] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
{
uiaWrapper->raiseAutomationEvent (provider, event);
});
}
void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler& handler, PROPERTYID property, VARIANT newValue)
{
jassert (property != PROPERTYID{});
getProviderWithCheckedWrapper (handler, [property, newValue] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
{
VARIANT oldValue;
VariantHelpers::clear (&oldValue);
uiaWrapper->raiseAutomationPropertyChangedEvent (provider, property, oldValue, newValue);
});
}
void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, InternalAccessibilityEvent eventType)
{
if (eventType == InternalAccessibilityEvent::elementCreated
|| eventType == InternalAccessibilityEvent::elementDestroyed)
{
if (auto* parent = handler.getParent())
sendAccessibilityAutomationEvent (*parent, ComTypes::UIA_LayoutInvalidatedEventId);
return;
}
if (eventType == InternalAccessibilityEvent::windowOpened
|| eventType == InternalAccessibilityEvent::windowClosed)
{
if (auto* peer = handler.getComponent().getPeer())
if ((peer->getStyleFlags() & ComponentPeer::windowHasTitleBar) == 0)
return;
}
auto event = [eventType]() -> EVENTID
{
switch (eventType)
{
case InternalAccessibilityEvent::focusChanged: return ComTypes::UIA_AutomationFocusChangedEventId;
case InternalAccessibilityEvent::windowOpened: return ComTypes::UIA_Window_WindowOpenedEventId;
case InternalAccessibilityEvent::windowClosed: return ComTypes::UIA_Window_WindowClosedEventId;
case InternalAccessibilityEvent::elementCreated:
case InternalAccessibilityEvent::elementDestroyed:
case InternalAccessibilityEvent::elementMovedOrResized: break;
}
return {};
}();
if (event != EVENTID{})
sendAccessibilityAutomationEvent (handler, event);
}
void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventType) const
{
if (eventType == AccessibilityEvent::titleChanged)
{
VARIANT newValue;
VariantHelpers::setString (getTitle(), &newValue);
sendAccessibilityPropertyChangedEvent (*this, UIA_NamePropertyId, newValue);
return;
}
if (eventType == AccessibilityEvent::valueChanged)
{
if (auto* valueInterface = getValueInterface())
{
const auto propertyType = getRole() == AccessibilityRole::slider ? UIA_RangeValueValuePropertyId
: UIA_ValueValuePropertyId;
const auto value = getRole() == AccessibilityRole::slider
? VariantHelpers::getWithValue (valueInterface->getCurrentValue())
: VariantHelpers::getWithValue (valueInterface->getCurrentValueAsString());
sendAccessibilityPropertyChangedEvent (*this, propertyType, value);
}
return;
}
auto event = [eventType]() -> EVENTID
{
switch (eventType)
{
case AccessibilityEvent::textSelectionChanged: return ComTypes::UIA_Text_TextSelectionChangedEventId;
case AccessibilityEvent::textChanged: return ComTypes::UIA_Text_TextChangedEventId;
case AccessibilityEvent::structureChanged: return ComTypes::UIA_StructureChangedEventId;
case AccessibilityEvent::rowSelectionChanged: return ComTypes::UIA_SelectionItem_ElementSelectedEventId;
case AccessibilityEvent::titleChanged:
case AccessibilityEvent::valueChanged: break;
}
return {};
}();
if (event != EVENTID{})
sendAccessibilityAutomationEvent (*this, event);
}
struct SpVoiceWrapper : public DeletedAtShutdown
{
SpVoiceWrapper()
{
auto hr = voice.CoCreateInstance (ComTypes::CLSID_SpVoice);
jassertquiet (SUCCEEDED (hr));
}
~SpVoiceWrapper() override
{
clearSingletonInstance();
}
ComSmartPtr<ISpVoice> voice;
JUCE_DECLARE_SINGLETON (SpVoiceWrapper, false)
};
JUCE_IMPLEMENT_SINGLETON (SpVoiceWrapper)
void AccessibilityHandler::postAnnouncement (const String& announcementString, AnnouncementPriority priority)
{
if (! areAnyAccessibilityClientsActive())
return;
if (auto* sharedVoice = SpVoiceWrapper::getInstance())
{
auto voicePriority = [priority]
{
switch (priority)
{
case AnnouncementPriority::low: return SPVPRI_OVER;
case AnnouncementPriority::medium: return SPVPRI_NORMAL;
case AnnouncementPriority::high: return SPVPRI_ALERT;
}
jassertfalse;
return SPVPRI_OVER;
}();
sharedVoice->voice->SetPriority (voicePriority);
sharedVoice->voice->Speak (announcementString.toWideCharPointer(), SPF_ASYNC, nullptr);
}
}
//==============================================================================
namespace WindowsAccessibility
{
static long getUiaRootObjectId()
{
return static_cast<long> (UiaRootObjectId);
}
static bool handleWmGetObject (AccessibilityHandler* handler, WPARAM wParam, LPARAM lParam, LRESULT* res)
{
if (isStartingUpOrShuttingDown() || (handler == nullptr || ! isHandlerValid (*handler)))
return false;
if (auto* uiaWrapper = WindowsUIAWrapper::getInstance())
{
ComSmartPtr<IRawElementProviderSimple> provider;
handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
if (! uiaWrapper->isProviderDisconnecting (provider))
*res = uiaWrapper->returnRawElementProvider ((HWND) handler->getComponent().getWindowHandle(), wParam, lParam, provider);
return true;
}
return false;
}
static void revokeUIAMapEntriesForWindow (HWND hwnd)
{
if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
uiaWrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
}
}
JUCE_IMPLEMENT_SINGLETON (WindowsUIAWrapper)
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
} // namespace juce

View File

@ -1,80 +1,80 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
#define UIA_FullDescriptionPropertyId 30159
#define UIA_IsDialogPropertyId 30174
class AccessibilityNativeHandle : public ComBaseClassHelper<IRawElementProviderSimple,
IRawElementProviderFragment,
IRawElementProviderFragmentRoot>
{
public:
explicit AccessibilityNativeHandle (AccessibilityHandler& handler);
//==============================================================================
void invalidateElement() noexcept { valid = false; }
bool isElementValid() const noexcept { return valid; }
const AccessibilityHandler& getHandler() { return accessibilityHandler; }
//==============================================================================
JUCE_COMRESULT QueryInterface (REFIID refId, void** result) override;
//==============================================================================
JUCE_COMRESULT get_HostRawElementProvider (IRawElementProviderSimple** provider) override;
JUCE_COMRESULT get_ProviderOptions (ProviderOptions* options) override;
JUCE_COMRESULT GetPatternProvider (PATTERNID pId, IUnknown** provider) override;
JUCE_COMRESULT GetPropertyValue (PROPERTYID propertyId, VARIANT* pRetVal) override;
JUCE_COMRESULT Navigate (NavigateDirection direction, IRawElementProviderFragment** pRetVal) override;
JUCE_COMRESULT GetRuntimeId (SAFEARRAY** pRetVal) override;
JUCE_COMRESULT get_BoundingRectangle (UiaRect* pRetVal) override;
JUCE_COMRESULT GetEmbeddedFragmentRoots (SAFEARRAY** pRetVal) override;
JUCE_COMRESULT SetFocus() override;
JUCE_COMRESULT get_FragmentRoot (IRawElementProviderFragmentRoot** pRetVal) override;
JUCE_COMRESULT ElementProviderFromPoint (double x, double y, IRawElementProviderFragment** pRetVal) override;
JUCE_COMRESULT GetFocus (IRawElementProviderFragment** pRetVal) override;
private:
//==============================================================================
String getElementName() const;
bool isFragmentRoot() const { return accessibilityHandler.getComponent().isOnDesktop(); }
//==============================================================================
AccessibilityHandler& accessibilityHandler;
static int idCounter;
std::array<int, 2> rtid { UiaAppendRuntimeId, ++idCounter };
bool valid = true;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibilityNativeHandle)
};
}
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
#define UIA_FullDescriptionPropertyId 30159
#define UIA_IsDialogPropertyId 30174
class AccessibilityNativeHandle : public ComBaseClassHelper<IRawElementProviderSimple,
ComTypes::IRawElementProviderFragment,
ComTypes::IRawElementProviderFragmentRoot>
{
public:
explicit AccessibilityNativeHandle (AccessibilityHandler& handler);
//==============================================================================
void invalidateElement() noexcept { valid = false; }
bool isElementValid() const noexcept { return valid; }
const AccessibilityHandler& getHandler() { return accessibilityHandler; }
//==============================================================================
JUCE_COMRESULT QueryInterface (REFIID refId, void** result) override;
//==============================================================================
JUCE_COMRESULT get_HostRawElementProvider (IRawElementProviderSimple** provider) override;
JUCE_COMRESULT get_ProviderOptions (ProviderOptions* options) override;
JUCE_COMRESULT GetPatternProvider (PATTERNID pId, IUnknown** provider) override;
JUCE_COMRESULT GetPropertyValue (PROPERTYID propertyId, VARIANT* pRetVal) override;
JUCE_COMRESULT Navigate (ComTypes::NavigateDirection direction, ComTypes::IRawElementProviderFragment** pRetVal) override;
JUCE_COMRESULT GetRuntimeId (SAFEARRAY** pRetVal) override;
JUCE_COMRESULT get_BoundingRectangle (ComTypes::UiaRect* pRetVal) override;
JUCE_COMRESULT GetEmbeddedFragmentRoots (SAFEARRAY** pRetVal) override;
JUCE_COMRESULT SetFocus() override;
JUCE_COMRESULT get_FragmentRoot (ComTypes::IRawElementProviderFragmentRoot** pRetVal) override;
JUCE_COMRESULT ElementProviderFromPoint (double x, double y, ComTypes::IRawElementProviderFragment** pRetVal) override;
JUCE_COMRESULT GetFocus (ComTypes::IRawElementProviderFragment** pRetVal) override;
private:
//==============================================================================
String getElementName() const;
bool isFragmentRoot() const { return accessibilityHandler.getComponent().isOnDesktop(); }
//==============================================================================
AccessibilityHandler& accessibilityHandler;
static int idCounter;
std::array<int, 2> rtid { UiaAppendRuntimeId, ++idCounter };
bool valid = true;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibilityNativeHandle)
};
}

View File

@ -0,0 +1,429 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace ComTypes
{
/*
These interfaces would normally be included in the system platform headers.
However, those headers are likely to be incomplete when building with
MinGW. In order to allow building accessible applications under MinGW,
we reproduce all necessary definitions here.
*/
struct UiaPoint
{
double x;
double y;
};
struct UiaRect
{
double left;
double top;
double width;
double height;
};
enum NavigateDirection
{
NavigateDirection_Parent = 0,
NavigateDirection_NextSibling = 1,
NavigateDirection_PreviousSibling = 2,
NavigateDirection_FirstChild = 3,
NavigateDirection_LastChild = 4
};
enum ExpandCollapseState
{
ExpandCollapseState_Collapsed = 0,
ExpandCollapseState_Expanded = 1,
ExpandCollapseState_PartiallyExpanded = 2,
ExpandCollapseState_LeafNode = 3
};
enum TextPatternRangeEndpoint
{
TextPatternRangeEndpoint_Start = 0,
TextPatternRangeEndpoint_End = 1
};
enum TextUnit
{
TextUnit_Character = 0,
TextUnit_Format = 1,
TextUnit_Word = 2,
TextUnit_Line = 3,
TextUnit_Paragraph = 4,
TextUnit_Page = 5,
TextUnit_Document = 6
};
enum SupportedTextSelection
{
SupportedTextSelection_None = 0,
SupportedTextSelection_Single = 1,
SupportedTextSelection_Multiple = 2
};
enum CaretPosition
{
CaretPosition_Unknown = 0,
CaretPosition_EndOfLine = 1,
CaretPosition_BeginningOfLine = 2
};
enum ToggleState
{
ToggleState_Off = 0,
ToggleState_On = 1,
ToggleState_Indeterminate = 2
};
enum WindowVisualState
{
WindowVisualState_Normal = 0,
WindowVisualState_Maximized = 1,
WindowVisualState_Minimized = 2
};
enum WindowInteractionState
{
WindowInteractionState_Running = 0,
WindowInteractionState_Closing = 1,
WindowInteractionState_ReadyForUserInteraction = 2,
WindowInteractionState_BlockedByModalWindow = 3,
WindowInteractionState_NotResponding = 4
};
enum RowOrColumnMajor
{
RowOrColumnMajor_RowMajor = 0,
RowOrColumnMajor_ColumnMajor = 1,
RowOrColumnMajor_Indeterminate = 2
};
enum ScrollAmount
{
ScrollAmount_LargeDecrement = 0,
ScrollAmount_SmallDecrement = 1,
ScrollAmount_NoAmount = 2,
ScrollAmount_LargeIncrement = 3,
ScrollAmount_SmallIncrement = 4
};
const long UIA_InvokePatternId = 10000;
const long UIA_SelectionPatternId = 10001;
const long UIA_ValuePatternId = 10002;
const long UIA_RangeValuePatternId = 10003;
const long UIA_ScrollPatternId = 10004;
const long UIA_ExpandCollapsePatternId = 10005;
const long UIA_GridPatternId = 10006;
const long UIA_GridItemPatternId = 10007;
const long UIA_WindowPatternId = 10009;
const long UIA_SelectionItemPatternId = 10010;
const long UIA_TablePatternId = 10012;
const long UIA_TableItemPatternId = 10013;
const long UIA_TextPatternId = 10014;
const long UIA_TogglePatternId = 10015;
const long UIA_TransformPatternId = 10016;
const long UIA_ScrollItemPatternId = 10017;
const long UIA_TextPattern2Id = 10024;
const long UIA_StructureChangedEventId = 20002;
const long UIA_MenuOpenedEventId = 20003;
const long UIA_AutomationFocusChangedEventId = 20005;
const long UIA_MenuClosedEventId = 20007;
const long UIA_LayoutInvalidatedEventId = 20008;
const long UIA_Invoke_InvokedEventId = 20009;
const long UIA_SelectionItem_ElementSelectedEventId = 20012;
const long UIA_Text_TextSelectionChangedEventId = 20014;
const long UIA_Text_TextChangedEventId = 20015;
const long UIA_Window_WindowOpenedEventId = 20016;
const long UIA_Window_WindowClosedEventId = 20017;
const long UIA_IsPeripheralPropertyId = 30150;
const long UIA_IsReadOnlyAttributeId = 40015;
const long UIA_CaretPositionAttributeId = 40038;
const long UIA_ButtonControlTypeId = 50000;
const long UIA_CheckBoxControlTypeId = 50002;
const long UIA_ComboBoxControlTypeId = 50003;
const long UIA_EditControlTypeId = 50004;
const long UIA_HyperlinkControlTypeId = 50005;
const long UIA_ImageControlTypeId = 50006;
const long UIA_ListItemControlTypeId = 50007;
const long UIA_ListControlTypeId = 50008;
const long UIA_MenuBarControlTypeId = 50010;
const long UIA_MenuItemControlTypeId = 50011;
const long UIA_ProgressBarControlTypeId = 50012;
const long UIA_RadioButtonControlTypeId = 50013;
const long UIA_ScrollBarControlTypeId = 50014;
const long UIA_SliderControlTypeId = 50015;
const long UIA_TextControlTypeId = 50020;
const long UIA_ToolTipControlTypeId = 50022;
const long UIA_TreeControlTypeId = 50023;
const long UIA_TreeItemControlTypeId = 50024;
const long UIA_CustomControlTypeId = 50025;
const long UIA_GroupControlTypeId = 50026;
const long UIA_DataItemControlTypeId = 50029;
const long UIA_WindowControlTypeId = 50032;
const long UIA_HeaderControlTypeId = 50034;
const long UIA_HeaderItemControlTypeId = 50035;
const long UIA_TableControlTypeId = 50036;
interface IRawElementProviderFragmentRoot;
interface IRawElementProviderFragment;
JUCE_COMCLASS (IRawElementProviderFragmentRoot, "620ce2a5-ab8f-40a9-86cb-de3c75599b58") : public IUnknown
{
public:
JUCE_COMCALL ElementProviderFromPoint (double x, double y, __RPC__deref_out_opt IRawElementProviderFragment** pRetVal) = 0;
JUCE_COMCALL GetFocus (__RPC__deref_out_opt IRawElementProviderFragment * *pRetVal) = 0;
};
JUCE_COMCLASS (IRawElementProviderFragment, "f7063da8-8359-439c-9297-bbc5299a7d87") : public IUnknown
{
public:
JUCE_COMCALL Navigate (NavigateDirection direction, __RPC__deref_out_opt IRawElementProviderFragment** pRetVal) = 0;
JUCE_COMCALL GetRuntimeId (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
JUCE_COMCALL get_BoundingRectangle (__RPC__out UiaRect * pRetVal) = 0;
JUCE_COMCALL GetEmbeddedFragmentRoots (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
JUCE_COMCALL SetFocus() = 0;
JUCE_COMCALL get_FragmentRoot (__RPC__deref_out_opt IRawElementProviderFragmentRoot * *pRetVal) = 0;
};
JUCE_COMCLASS (IExpandCollapseProvider, "d847d3a5-cab0-4a98-8c32-ecb45c59ad24") : public IUnknown
{
public:
JUCE_COMCALL Expand() = 0;
JUCE_COMCALL Collapse() = 0;
JUCE_COMCALL get_ExpandCollapseState (__RPC__out ExpandCollapseState * pRetVal) = 0;
};
JUCE_COMCLASS (IGridItemProvider, "d02541f1-fb81-4d64-ae32-f520f8a6dbd1") : public IUnknown
{
public:
JUCE_COMCALL get_Row (__RPC__out int* pRetVal) = 0;
JUCE_COMCALL get_Column (__RPC__out int* pRetVal) = 0;
JUCE_COMCALL get_RowSpan (__RPC__out int* pRetVal) = 0;
JUCE_COMCALL get_ColumnSpan (__RPC__out int* pRetVal) = 0;
JUCE_COMCALL get_ContainingGrid (__RPC__deref_out_opt IRawElementProviderSimple * *pRetVal) = 0;
};
JUCE_COMCLASS (IGridProvider, "b17d6187-0907-464b-a168-0ef17a1572b1") : public IUnknown
{
public:
JUCE_COMCALL GetItem (int row, int column, __RPC__deref_out_opt IRawElementProviderSimple** pRetVal) = 0;
JUCE_COMCALL get_RowCount (__RPC__out int* pRetVal) = 0;
JUCE_COMCALL get_ColumnCount (__RPC__out int* pRetVal) = 0;
};
JUCE_COMCLASS (ITableItemProvider, "b9734fa6-771f-4d78-9c90-2517999349cd") : public IUnknown
{
public:
JUCE_COMCALL GetRowHeaderItems (SAFEARRAY** pRetVal) = 0;
JUCE_COMCALL GetColumnHeaderItems (SAFEARRAY** pRetVal) = 0;
};
JUCE_COMCLASS (ITableProvider, "9c860395-97b3-490a-b52a-858cc22af166") : public IUnknown
{
public:
JUCE_COMCALL GetRowHeaders (SAFEARRAY** pRetVal) = 0;
JUCE_COMCALL GetColumnHeaders (SAFEARRAY** pRetVal) = 0;
JUCE_COMCALL get_RowOrColumnMajor (RowOrColumnMajor* pRetVal) = 0;
};
JUCE_COMCLASS (IInvokeProvider, "54fcb24b-e18e-47a2-b4d3-eccbe77599a2") : public IUnknown
{
public:
JUCE_COMCALL Invoke() = 0;
};
JUCE_COMCLASS (IRangeValueProvider, "36dc7aef-33e6-4691-afe1-2be7274b3d33") : public IUnknown
{
public:
JUCE_COMCALL SetValue (double val) = 0;
JUCE_COMCALL get_Value (__RPC__out double* pRetVal) = 0;
JUCE_COMCALL get_IsReadOnly (__RPC__out BOOL * pRetVal) = 0;
JUCE_COMCALL get_Maximum (__RPC__out double* pRetVal) = 0;
JUCE_COMCALL get_Minimum (__RPC__out double* pRetVal) = 0;
JUCE_COMCALL get_LargeChange (__RPC__out double* pRetVal) = 0;
JUCE_COMCALL get_SmallChange (__RPC__out double* pRetVal) = 0;
};
JUCE_COMCLASS (ISelectionProvider, "fb8b03af-3bdf-48d4-bd36-1a65793be168") : public IUnknown
{
public:
JUCE_COMCALL GetSelection (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
JUCE_COMCALL get_CanSelectMultiple (__RPC__out BOOL * pRetVal) = 0;
JUCE_COMCALL get_IsSelectionRequired (__RPC__out BOOL * pRetVal) = 0;
};
JUCE_COMCLASS (ISelectionProvider2, "14f68475-ee1c-44f6-a869-d239381f0fe7") : public ISelectionProvider
{
JUCE_COMCALL get_FirstSelectedItem (IRawElementProviderSimple * *retVal) = 0;
JUCE_COMCALL get_LastSelectedItem (IRawElementProviderSimple * *retVal) = 0;
JUCE_COMCALL get_CurrentSelectedItem (IRawElementProviderSimple * *retVal) = 0;
JUCE_COMCALL get_ItemCount (int* retVal) = 0;
};
JUCE_COMCLASS (ISelectionItemProvider, "2acad808-b2d4-452d-a407-91ff1ad167b2") : public IUnknown
{
public:
JUCE_COMCALL Select() = 0;
JUCE_COMCALL AddToSelection() = 0;
JUCE_COMCALL RemoveFromSelection() = 0;
JUCE_COMCALL get_IsSelected (__RPC__out BOOL * pRetVal) = 0;
JUCE_COMCALL get_SelectionContainer (__RPC__deref_out_opt IRawElementProviderSimple * *pRetVal) = 0;
};
JUCE_COMCLASS (ITextRangeProvider, "5347ad7b-c355-46f8-aff5-909033582f63") : public IUnknown
{
public:
JUCE_COMCALL Clone (__RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
JUCE_COMCALL Compare (__RPC__in_opt ITextRangeProvider * range, __RPC__out BOOL * pRetVal) = 0;
JUCE_COMCALL CompareEndpoints (TextPatternRangeEndpoint endpoint, __RPC__in_opt ITextRangeProvider * targetRange, TextPatternRangeEndpoint targetEndpoint, __RPC__out int* pRetVal) = 0;
JUCE_COMCALL ExpandToEnclosingUnit (TextUnit unit) = 0;
JUCE_COMCALL FindAttribute (TEXTATTRIBUTEID attributeId, VARIANT val, BOOL backward, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
JUCE_COMCALL FindText (__RPC__in BSTR text, BOOL backward, BOOL ignoreCase, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
JUCE_COMCALL GetAttributeValue (TEXTATTRIBUTEID attributeId, __RPC__out VARIANT * pRetVal) = 0;
JUCE_COMCALL GetBoundingRectangles (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
JUCE_COMCALL GetEnclosingElement (__RPC__deref_out_opt IRawElementProviderSimple * *pRetVal) = 0;
JUCE_COMCALL GetText (int maxLength, __RPC__deref_out_opt BSTR* pRetVal) = 0;
JUCE_COMCALL Move (TextUnit unit, int count, __RPC__out int* pRetVal) = 0;
JUCE_COMCALL MoveEndpointByUnit (TextPatternRangeEndpoint endpoint, TextUnit unit, int count, __RPC__out int* pRetVal) = 0;
JUCE_COMCALL MoveEndpointByRange (TextPatternRangeEndpoint endpoint, __RPC__in_opt ITextRangeProvider * targetRange, TextPatternRangeEndpoint targetEndpoint) = 0;
JUCE_COMCALL Select() = 0;
JUCE_COMCALL AddToSelection() = 0;
JUCE_COMCALL RemoveFromSelection() = 0;
JUCE_COMCALL ScrollIntoView (BOOL alignToTop) = 0;
JUCE_COMCALL GetChildren (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
};
JUCE_COMCLASS (ITextProvider, "3589c92c-63f3-4367-99bb-ada653b77cf2") : public IUnknown
{
public:
JUCE_COMCALL GetSelection (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
JUCE_COMCALL GetVisibleRanges (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
JUCE_COMCALL RangeFromChild (__RPC__in_opt IRawElementProviderSimple * childElement, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
JUCE_COMCALL RangeFromPoint (UiaPoint point, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
JUCE_COMCALL get_DocumentRange (__RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
JUCE_COMCALL get_SupportedTextSelection (__RPC__out SupportedTextSelection * pRetVal) = 0;
};
JUCE_COMCLASS (ITextProvider2, "0dc5e6ed-3e16-4bf1-8f9a-a979878bc195") : public ITextProvider
{
public:
JUCE_COMCALL RangeFromAnnotation (__RPC__in_opt IRawElementProviderSimple * annotationElement, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
JUCE_COMCALL GetCaretRange (__RPC__out BOOL * isActive, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
};
JUCE_COMCLASS (IToggleProvider, "56d00bd0-c4f4-433c-a836-1a52a57e0892") : public IUnknown
{
public:
JUCE_COMCALL Toggle() = 0;
JUCE_COMCALL get_ToggleState (__RPC__out ToggleState * pRetVal) = 0;
};
JUCE_COMCLASS (ITransformProvider, "6829ddc4-4f91-4ffa-b86f-bd3e2987cb4c") : public IUnknown
{
public:
JUCE_COMCALL Move (double x, double y) = 0;
JUCE_COMCALL Resize (double width, double height) = 0;
JUCE_COMCALL Rotate (double degrees) = 0;
JUCE_COMCALL get_CanMove (__RPC__out BOOL * pRetVal) = 0;
JUCE_COMCALL get_CanResize (__RPC__out BOOL * pRetVal) = 0;
JUCE_COMCALL get_CanRotate (__RPC__out BOOL * pRetVal) = 0;
};
JUCE_COMCLASS (IValueProvider, "c7935180-6fb3-4201-b174-7df73adbf64a") : public IUnknown
{
public:
JUCE_COMCALL SetValue (__RPC__in LPCWSTR val) = 0;
JUCE_COMCALL get_Value (__RPC__deref_out_opt BSTR * pRetVal) = 0;
JUCE_COMCALL get_IsReadOnly (__RPC__out BOOL * pRetVal) = 0;
};
JUCE_COMCLASS (IWindowProvider, "987df77b-db06-4d77-8f8a-86a9c3bb90b9") : public IUnknown
{
public:
JUCE_COMCALL SetVisualState (WindowVisualState state) = 0;
JUCE_COMCALL Close() = 0;
JUCE_COMCALL WaitForInputIdle (int milliseconds, __RPC__out BOOL* pRetVal) = 0;
JUCE_COMCALL get_CanMaximize (__RPC__out BOOL * pRetVal) = 0;
JUCE_COMCALL get_CanMinimize (__RPC__out BOOL * pRetVal) = 0;
JUCE_COMCALL get_IsModal (__RPC__out BOOL * pRetVal) = 0;
JUCE_COMCALL get_WindowVisualState (__RPC__out WindowVisualState * pRetVal) = 0;
JUCE_COMCALL get_WindowInteractionState (__RPC__out WindowInteractionState * pRetVal) = 0;
JUCE_COMCALL get_IsTopmost (__RPC__out BOOL * pRetVal) = 0;
};
JUCE_COMCLASS (IScrollProvider, "b38b8077-1fc3-42a5-8cae-d40c2215055a") : public IUnknown
{
public:
JUCE_COMCALL Scroll (ScrollAmount horizontalAmount, ScrollAmount verticalAmount) = 0;
JUCE_COMCALL SetScrollPercent (double horizontalPercent,double verticalPercent) = 0;
JUCE_COMCALL get_HorizontalScrollPercent (double* pRetVal) = 0;
JUCE_COMCALL get_VerticalScrollPercent (double* pRetVal) = 0;
JUCE_COMCALL get_HorizontalViewSize (double* pRetVal) = 0;
JUCE_COMCALL get_VerticalViewSize (double* pRetVal) = 0;
JUCE_COMCALL get_HorizontallyScrollable (BOOL* pRetVal) = 0;
JUCE_COMCALL get_VerticallyScrollable (BOOL* pRetVal) = 0;
};
JUCE_COMCLASS (IScrollItemProvider, "2360c714-4bf1-4b26-ba65-9b21316127eb") : public IUnknown
{
public:
JUCE_COMCALL ScrollIntoView() = 0;
};
constexpr CLSID CLSID_SpVoice { 0x96749377, 0x3391, 0x11D2, { 0x9E, 0xE3, 0x00, 0xC0, 0x4F, 0x79, 0x73, 0x96 } };
} // namespace ComTypes
} // namespace juce
#ifdef __CRT_UUID_DECL
__CRT_UUID_DECL (juce::ComTypes::IRawElementProviderFragmentRoot, 0x620ce2a5, 0xab8f, 0x40a9, 0x86, 0xcb, 0xde, 0x3c, 0x75, 0x59, 0x9b, 0x58)
__CRT_UUID_DECL (juce::ComTypes::IRawElementProviderFragment, 0xf7063da8, 0x8359, 0x439c, 0x92, 0x97, 0xbb, 0xc5, 0x29, 0x9a, 0x7d, 0x87)
__CRT_UUID_DECL (juce::ComTypes::IExpandCollapseProvider, 0xd847d3a5, 0xcab0, 0x4a98, 0x8c, 0x32, 0xec, 0xb4, 0x5c, 0x59, 0xad, 0x24)
__CRT_UUID_DECL (juce::ComTypes::IGridItemProvider, 0xd02541f1, 0xfb81, 0x4d64, 0xae, 0x32, 0xf5, 0x20, 0xf8, 0xa6, 0xdb, 0xd1)
__CRT_UUID_DECL (juce::ComTypes::IGridProvider, 0xb17d6187, 0x0907, 0x464b, 0xa1, 0x68, 0x0e, 0xf1, 0x7a, 0x15, 0x72, 0xb1)
__CRT_UUID_DECL (juce::ComTypes::IInvokeProvider, 0x54fcb24b, 0xe18e, 0x47a2, 0xb4, 0xd3, 0xec, 0xcb, 0xe7, 0x75, 0x99, 0xa2)
__CRT_UUID_DECL (juce::ComTypes::IRangeValueProvider, 0x36dc7aef, 0x33e6, 0x4691, 0xaf, 0xe1, 0x2b, 0xe7, 0x27, 0x4b, 0x3d, 0x33)
__CRT_UUID_DECL (juce::ComTypes::ISelectionProvider, 0xfb8b03af, 0x3bdf, 0x48d4, 0xbd, 0x36, 0x1a, 0x65, 0x79, 0x3b, 0xe1, 0x68)
__CRT_UUID_DECL (juce::ComTypes::ISelectionProvider2, 0x14f68475, 0xee1c, 0x44f6, 0xa8, 0x69, 0xd2, 0x39, 0x38, 0x1f, 0x0f, 0xe7)
__CRT_UUID_DECL (juce::ComTypes::ISelectionItemProvider, 0x2acad808, 0xb2d4, 0x452d, 0xa4, 0x07, 0x91, 0xff, 0x1a, 0xd1, 0x67, 0xb2)
__CRT_UUID_DECL (juce::ComTypes::ITextRangeProvider, 0x5347ad7b, 0xc355, 0x46f8, 0xaf, 0xf5, 0x90, 0x90, 0x33, 0x58, 0x2f, 0x63)
__CRT_UUID_DECL (juce::ComTypes::ITextProvider, 0x3589c92c, 0x63f3, 0x4367, 0x99, 0xbb, 0xad, 0xa6, 0x53, 0xb7, 0x7c, 0xf2)
__CRT_UUID_DECL (juce::ComTypes::ITextProvider2, 0x0dc5e6ed, 0x3e16, 0x4bf1, 0x8f, 0x9a, 0xa9, 0x79, 0x87, 0x8b, 0xc1, 0x95)
__CRT_UUID_DECL (juce::ComTypes::IToggleProvider, 0x56d00bd0, 0xc4f4, 0x433c, 0xa8, 0x36, 0x1a, 0x52, 0xa5, 0x7e, 0x08, 0x92)
__CRT_UUID_DECL (juce::ComTypes::ITransformProvider, 0x6829ddc4, 0x4f91, 0x4ffa, 0xb8, 0x6f, 0xbd, 0x3e, 0x29, 0x87, 0xcb, 0x4c)
__CRT_UUID_DECL (juce::ComTypes::IValueProvider, 0xc7935180, 0x6fb3, 0x4201, 0xb1, 0x74, 0x7d, 0xf7, 0x3a, 0xdb, 0xf6, 0x4a)
__CRT_UUID_DECL (juce::ComTypes::IWindowProvider, 0x987df77b, 0xdb06, 0x4d77, 0x8f, 0x8a, 0x86, 0xa9, 0xc3, 0xbb, 0x90, 0xb9)
__CRT_UUID_DECL (juce::ComTypes::ITableItemProvider, 0xb9734fa6, 0x771f, 0x4d78, 0x9c, 0x90, 0x25, 0x17, 0x99, 0x93, 0x49, 0xcd)
__CRT_UUID_DECL (juce::ComTypes::ITableProvider, 0x9c860395, 0x97b3, 0x490a, 0xb5, 0x2a, 0x85, 0x8c, 0xc2, 0x2a, 0xf1, 0x66)
__CRT_UUID_DECL (juce::ComTypes::IScrollProvider, 0xb38b8077, 0x1fc3, 0x42a5, 0x8c, 0xae, 0xd4, 0x0c, 0x22, 0x15, 0x05, 0x5a)
__CRT_UUID_DECL (juce::ComTypes::IScrollItemProvider, 0x2360c714, 0x4bf1, 0x4b26, 0xba, 0x65, 0x9b, 0x21, 0x31, 0x61, 0x27, 0xeb)
#endif

View File

@ -1,86 +1,83 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAExpandCollapseProvider : public UIAProviderBase,
public ComBaseClassHelper<IExpandCollapseProvider>
{
public:
explicit UIAExpandCollapseProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle)
{
}
//==============================================================================
JUCE_COMRESULT Expand() override
{
return invokeShowMenu();
}
JUCE_COMRESULT Collapse() override
{
return invokeShowMenu();
}
JUCE_COMRESULT get_ExpandCollapseState (ExpandCollapseState* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = getHandler().getCurrentState().isExpanded()
? ExpandCollapseState_Expanded
: ExpandCollapseState_Collapsed;
return S_OK;
});
}
private:
JUCE_COMRESULT invokeShowMenu()
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
if (handler.getActions().invoke (AccessibilityActionType::showMenu))
{
sendAccessibilityAutomationEvent (handler, handler.getCurrentState().isExpanded()
? UIA_MenuOpenedEventId
: UIA_MenuClosedEventId);
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAExpandCollapseProvider)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAExpandCollapseProvider : public UIAProviderBase,
public ComBaseClassHelper<ComTypes::IExpandCollapseProvider>
{
public:
using UIAProviderBase::UIAProviderBase;
//==============================================================================
JUCE_COMRESULT Expand() override
{
return invokeShowMenu();
}
JUCE_COMRESULT Collapse() override
{
return invokeShowMenu();
}
JUCE_COMRESULT get_ExpandCollapseState (ComTypes::ExpandCollapseState* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = getHandler().getCurrentState().isExpanded()
? ComTypes::ExpandCollapseState_Expanded
: ComTypes::ExpandCollapseState_Collapsed;
return S_OK;
});
}
private:
JUCE_COMRESULT invokeShowMenu()
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
if (handler.getActions().invoke (AccessibilityActionType::showMenu))
{
sendAccessibilityAutomationEvent (handler, handler.getCurrentState().isExpanded()
? ComTypes::UIA_MenuOpenedEventId
: ComTypes::UIA_MenuClosedEventId);
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAExpandCollapseProvider)
};
} // namespace juce

View File

@ -1,105 +1,153 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAGridItemProvider : public UIAProviderBase,
public ComBaseClassHelper<IGridItemProvider>
{
public:
explicit UIAGridItemProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle)
{
}
//==============================================================================
JUCE_COMRESULT get_Row (int* pRetVal) override
{
return withCellInterface (pRetVal, [&] (const AccessibilityCellInterface& cellInterface)
{
*pRetVal = cellInterface.getRowIndex();
});
}
JUCE_COMRESULT get_Column (int* pRetVal) override
{
return withCellInterface (pRetVal, [&] (const AccessibilityCellInterface& cellInterface)
{
*pRetVal = cellInterface.getColumnIndex();
});
}
JUCE_COMRESULT get_RowSpan (int* pRetVal) override
{
return withCellInterface (pRetVal, [&] (const AccessibilityCellInterface& cellInterface)
{
*pRetVal = cellInterface.getRowSpan();
});
}
JUCE_COMRESULT get_ColumnSpan (int* pRetVal) override
{
return withCellInterface (pRetVal, [&] (const AccessibilityCellInterface& cellInterface)
{
*pRetVal = cellInterface.getColumnSpan();
});
}
JUCE_COMRESULT get_ContainingGrid (IRawElementProviderSimple** pRetVal) override
{
return withCellInterface (pRetVal, [&] (const AccessibilityCellInterface& cellInterface)
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
if (auto* handler = cellInterface.getTableHandler())
handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
});
}
private:
template <typename Value, typename Callback>
JUCE_COMRESULT withCellInterface (Value* pRetVal, Callback&& callback) const
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* cellInterface = getHandler().getCellInterface())
{
callback (*cellInterface);
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAGridItemProvider)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAGridItemProvider : public UIAProviderBase,
public ComBaseClassHelper<ComTypes::IGridItemProvider, ComTypes::ITableItemProvider>
{
public:
using UIAProviderBase::UIAProviderBase;
//==============================================================================
JUCE_COMRESULT get_Row (int* pRetVal) override
{
return withTableSpan (pRetVal,
&AccessibilityTableInterface::getRowSpan,
&AccessibilityTableInterface::Span::begin);
}
JUCE_COMRESULT get_Column (int* pRetVal) override
{
return withTableSpan (pRetVal,
&AccessibilityTableInterface::getColumnSpan,
&AccessibilityTableInterface::Span::begin);
}
JUCE_COMRESULT get_RowSpan (int* pRetVal) override
{
return withTableSpan (pRetVal,
&AccessibilityTableInterface::getRowSpan,
&AccessibilityTableInterface::Span::num);
}
JUCE_COMRESULT get_ColumnSpan (int* pRetVal) override
{
return withTableSpan (pRetVal,
&AccessibilityTableInterface::getColumnSpan,
&AccessibilityTableInterface::Span::num);
}
JUCE_COMRESULT get_ContainingGrid (IRawElementProviderSimple** pRetVal) override
{
return withTableInterface (pRetVal, [&] (const AccessibilityHandler& tableHandler)
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
tableHandler.getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
return true;
});
}
JUCE_COMRESULT GetRowHeaderItems (SAFEARRAY**) override
{
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT GetColumnHeaderItems (SAFEARRAY** pRetVal) override
{
return withTableInterface (pRetVal, [&] (const AccessibilityHandler& tableHandler)
{
if (auto* tableInterface = tableHandler.getTableInterface())
{
if (const auto column = tableInterface->getColumnSpan (getHandler()))
{
if (auto* header = tableInterface->getHeaderHandler())
{
const auto children = header->getChildren();
if (isPositiveAndBelow (column->begin, children.size()))
{
IRawElementProviderSimple* provider = nullptr;
if (auto* child = children[(size_t) column->begin])
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
if (child->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (&provider)) == S_OK && provider != nullptr)
{
*pRetVal = SafeArrayCreateVector (VT_UNKNOWN, 0, 1);
LONG index = 0;
const auto hr = SafeArrayPutElement (*pRetVal, &index, provider);
return ! FAILED (hr);
}
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
}
}
}
}
}
return false;
});
}
private:
template <typename Value, typename Callback>
JUCE_COMRESULT withTableInterface (Value* pRetVal, Callback&& callback) const
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* handler = getEnclosingHandlerWithInterface (&getHandler(), &AccessibilityHandler::getTableInterface))
if (handler->getTableInterface() != nullptr && callback (*handler))
return S_OK;
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT withTableSpan (int* pRetVal,
Optional<AccessibilityTableInterface::Span> (AccessibilityTableInterface::* getSpan) (const AccessibilityHandler&) const,
int AccessibilityTableInterface::Span::* spanMember) const
{
return withTableInterface (pRetVal, [&] (const AccessibilityHandler& handler)
{
if (const auto span = ((handler.getTableInterface())->*getSpan) (getHandler()))
{
*pRetVal = (*span).*spanMember;
return true;
}
return false;
});
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAGridItemProvider)
};
} // namespace juce

View File

@ -1,94 +1,151 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAGridProvider : public UIAProviderBase,
public ComBaseClassHelper<IGridProvider>
{
public:
explicit UIAGridProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle)
{
}
//==============================================================================
JUCE_COMRESULT GetItem (int row, int column, IRawElementProviderSimple** pRetVal) override
{
return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
{
if (! isPositiveAndBelow (row, tableInterface.getNumRows())
|| ! isPositiveAndBelow (column, tableInterface.getNumColumns()))
return E_INVALIDARG;
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
if (auto* handler = tableInterface.getCellHandler (row, column))
handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
return S_OK;
});
}
JUCE_COMRESULT get_RowCount (int* pRetVal) override
{
return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
{
*pRetVal = tableInterface.getNumRows();
return S_OK;
});
}
JUCE_COMRESULT get_ColumnCount (int* pRetVal) override
{
return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
{
*pRetVal = tableInterface.getNumColumns();
return S_OK;
});
}
private:
template <typename Value, typename Callback>
JUCE_COMRESULT withTableInterface (Value* pRetVal, Callback&& callback) const
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* tableInterface = getHandler().getTableInterface())
return callback (*tableInterface);
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAGridProvider)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAGridProvider : public UIAProviderBase,
public ComBaseClassHelper<ComTypes::IGridProvider, ComTypes::ITableProvider>
{
public:
using UIAProviderBase::UIAProviderBase;
//==============================================================================
JUCE_COMRESULT GetItem (int row, int column, IRawElementProviderSimple** pRetVal) override
{
return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
{
if (! isPositiveAndBelow (row, tableInterface.getNumRows())
|| ! isPositiveAndBelow (column, tableInterface.getNumColumns()))
return E_INVALIDARG;
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
if (auto* cellHandler = tableInterface.getCellHandler (row, column))
{
cellHandler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
return S_OK;
}
if (auto* rowHandler = tableInterface.getRowHandler (row))
{
rowHandler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
return S_OK;
}
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
return E_FAIL;
});
}
JUCE_COMRESULT get_RowCount (int* pRetVal) override
{
return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
{
*pRetVal = tableInterface.getNumRows();
return S_OK;
});
}
JUCE_COMRESULT get_ColumnCount (int* pRetVal) override
{
return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
{
*pRetVal = tableInterface.getNumColumns();
return S_OK;
});
}
JUCE_COMRESULT GetRowHeaders (SAFEARRAY**) override
{
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT GetColumnHeaders (SAFEARRAY** pRetVal) override
{
return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
{
if (auto* header = tableInterface.getHeaderHandler())
{
const auto children = header->getChildren();
*pRetVal = SafeArrayCreateVector (VT_UNKNOWN, 0, (ULONG) children.size());
LONG index = 0;
for (const auto& child : children)
{
IRawElementProviderSimple* provider = nullptr;
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
if (child != nullptr)
child->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (&provider));
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
if (provider == nullptr)
return E_FAIL;
const auto hr = SafeArrayPutElement (*pRetVal, &index, provider);
if (FAILED (hr))
return E_FAIL;
++index;
}
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_RowOrColumnMajor (ComTypes::RowOrColumnMajor* pRetVal) override
{
*pRetVal = ComTypes::RowOrColumnMajor_RowMajor;
return S_OK;
}
private:
template <typename Value, typename Callback>
JUCE_COMRESULT withTableInterface (Value* pRetVal, Callback&& callback) const
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* tableHandler = getEnclosingHandlerWithInterface (&getHandler(), &AccessibilityHandler::getTableInterface))
if (auto* tableInterface = tableHandler->getTableInterface())
return callback (*tableInterface);
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAGridProvider)
};
} // namespace juce

View File

@ -1,105 +1,119 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace VariantHelpers
{
inline void clear (VARIANT* variant)
{
variant->vt = VT_EMPTY;
}
inline void setInt (int value, VARIANT* variant)
{
variant->vt = VT_I4;
variant->lVal = value;
}
inline void setBool (bool value, VARIANT* variant)
{
variant->vt = VT_BOOL;
variant->boolVal = value ? -1 : 0;
}
inline void setString (const String& value, VARIANT* variant)
{
variant->vt = VT_BSTR;
variant->bstrVal = SysAllocString ((const OLECHAR*) value.toWideCharPointer());
}
inline void setDouble (double value, VARIANT* variant)
{
variant->vt = VT_R8;
variant->dblVal = value;
}
}
inline JUCE_COMRESULT addHandlersToArray (const std::vector<const AccessibilityHandler*>& handlers, SAFEARRAY** pRetVal)
{
auto numHandlers = handlers.size();
*pRetVal = SafeArrayCreateVector (VT_UNKNOWN, 0, (ULONG) numHandlers);
if (pRetVal != nullptr)
{
for (LONG i = 0; i < (LONG) numHandlers; ++i)
{
auto* handler = handlers[(size_t) i];
if (handler == nullptr)
continue;
ComSmartPtr<IRawElementProviderSimple> provider;
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
auto hr = SafeArrayPutElement (*pRetVal, &i, provider);
if (FAILED (hr))
return E_FAIL;
}
}
return S_OK;
}
template <typename Value, typename Object, typename Callback>
inline JUCE_COMRESULT withCheckedComArgs (Value* pRetVal, Object& handle, Callback&& callback)
{
if (pRetVal == nullptr)
return E_INVALIDARG;
*pRetVal = Value{};
if (! handle.isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
return callback();
}
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
namespace VariantHelpers
{
namespace Detail
{
template <typename Fn, typename ValueType>
inline VARIANT getWithValueGeneric (Fn&& setter, ValueType value)
{
VARIANT result{};
setter (value, &result);
return result;
}
}
inline void clear (VARIANT* variant)
{
variant->vt = VT_EMPTY;
}
inline void setInt (int value, VARIANT* variant)
{
variant->vt = VT_I4;
variant->lVal = value;
}
inline void setBool (bool value, VARIANT* variant)
{
variant->vt = VT_BOOL;
variant->boolVal = value ? -1 : 0;
}
inline void setString (const String& value, VARIANT* variant)
{
variant->vt = VT_BSTR;
variant->bstrVal = SysAllocString ((const OLECHAR*) value.toWideCharPointer());
}
inline void setDouble (double value, VARIANT* variant)
{
variant->vt = VT_R8;
variant->dblVal = value;
}
inline VARIANT getWithValue (double value) { return Detail::getWithValueGeneric (&setDouble, value); }
inline VARIANT getWithValue (const String& value) { return Detail::getWithValueGeneric (&setString, value); }
}
inline JUCE_COMRESULT addHandlersToArray (const std::vector<const AccessibilityHandler*>& handlers, SAFEARRAY** pRetVal)
{
auto numHandlers = handlers.size();
*pRetVal = SafeArrayCreateVector (VT_UNKNOWN, 0, (ULONG) numHandlers);
if (pRetVal != nullptr)
{
for (LONG i = 0; i < (LONG) numHandlers; ++i)
{
auto* handler = handlers[(size_t) i];
if (handler == nullptr)
continue;
ComSmartPtr<IRawElementProviderSimple> provider;
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
auto hr = SafeArrayPutElement (*pRetVal, &i, provider);
if (FAILED (hr))
return E_FAIL;
}
}
return S_OK;
}
template <typename Value, typename Object, typename Callback>
inline JUCE_COMRESULT withCheckedComArgs (Value* pRetVal, Object& handle, Callback&& callback)
{
if (pRetVal == nullptr)
return E_INVALIDARG;
*pRetVal = Value{};
if (! handle.isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
return callback();
}
} // namespace juce

View File

@ -1,62 +1,59 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAInvokeProvider : public UIAProviderBase,
public ComBaseClassHelper<IInvokeProvider>
{
public:
explicit UIAInvokeProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle)
{
}
//==============================================================================
JUCE_COMRESULT Invoke() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
if (handler.getActions().invoke (AccessibilityActionType::press))
{
if (isElementValid())
sendAccessibilityAutomationEvent (handler, UIA_Invoke_InvokedEventId);
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAInvokeProvider)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAInvokeProvider : public UIAProviderBase,
public ComBaseClassHelper<ComTypes::IInvokeProvider>
{
public:
using UIAProviderBase::UIAProviderBase;
//==============================================================================
JUCE_COMRESULT Invoke() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
if (handler.getActions().invoke (AccessibilityActionType::press))
{
if (isElementValid())
sendAccessibilityAutomationEvent (handler, ComTypes::UIA_Invoke_InvokedEventId);
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAInvokeProvider)
};
} // namespace juce

View File

@ -1,58 +1,58 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAProviderBase
{
public:
explicit UIAProviderBase (AccessibilityNativeHandle* nativeHandleIn)
: nativeHandle (nativeHandleIn)
{
}
bool isElementValid() const
{
if (nativeHandle != nullptr)
return nativeHandle->isElementValid();
return false;
}
const AccessibilityHandler& getHandler() const
{
return nativeHandle->getHandler();
}
private:
ComSmartPtr<AccessibilityNativeHandle> nativeHandle;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAProviderBase)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAProviderBase
{
public:
explicit UIAProviderBase (AccessibilityNativeHandle* nativeHandleIn)
: nativeHandle (nativeHandleIn)
{
}
bool isElementValid() const
{
if (nativeHandle != nullptr)
return nativeHandle->isElementValid();
return false;
}
const AccessibilityHandler& getHandler() const
{
return nativeHandle->getHandler();
}
private:
ComSmartPtr<AccessibilityNativeHandle> nativeHandle;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAProviderBase)
};
} // namespace juce

View File

@ -1,43 +1,43 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
void sendAccessibilityAutomationEvent (const AccessibilityHandler&, EVENTID);
void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler&, PROPERTYID, VARIANT);
}
#include "juce_win32_UIAProviderBase.h"
#include "juce_win32_UIAExpandCollapseProvider.h"
#include "juce_win32_UIAGridItemProvider.h"
#include "juce_win32_UIAGridProvider.h"
#include "juce_win32_UIAInvokeProvider.h"
#include "juce_win32_UIARangeValueProvider.h"
#include "juce_win32_UIASelectionProvider.h"
#include "juce_win32_UIATextProvider.h"
#include "juce_win32_UIAToggleProvider.h"
#include "juce_win32_UIATransformProvider.h"
#include "juce_win32_UIAValueProvider.h"
#include "juce_win32_UIAWindowProvider.h"
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
void sendAccessibilityAutomationEvent (const AccessibilityHandler&, EVENTID);
void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler&, PROPERTYID, VARIANT);
}
#include "juce_win32_UIAProviderBase.h"
#include "juce_win32_UIAExpandCollapseProvider.h"
#include "juce_win32_UIAGridItemProvider.h"
#include "juce_win32_UIAGridProvider.h"
#include "juce_win32_UIAInvokeProvider.h"
#include "juce_win32_UIARangeValueProvider.h"
#include "juce_win32_UIASelectionProvider.h"
#include "juce_win32_UIATextProvider.h"
#include "juce_win32_UIAToggleProvider.h"
#include "juce_win32_UIATransformProvider.h"
#include "juce_win32_UIAValueProvider.h"
#include "juce_win32_UIAWindowProvider.h"

View File

@ -1,140 +1,137 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIARangeValueProvider : public UIAProviderBase,
public ComBaseClassHelper<IRangeValueProvider>
{
public:
explicit UIARangeValueProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle)
{
}
//==============================================================================
JUCE_COMRESULT SetValue (double val) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
if (auto* valueInterface = handler.getValueInterface())
{
auto range = valueInterface->getRange();
if (range.isValid())
{
if (val < range.getMinimumValue() || val > range.getMaximumValue())
return E_INVALIDARG;
if (! valueInterface->isReadOnly())
{
valueInterface->setValue (val);
VARIANT newValue;
VariantHelpers::setDouble (valueInterface->getCurrentValue(), &newValue);
sendAccessibilityPropertyChangedEvent (handler, UIA_RangeValueValuePropertyId, newValue);
return S_OK;
}
}
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT get_Value (double* pRetVal) override
{
return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
{
return valueInterface.getCurrentValue();
});
}
JUCE_COMRESULT get_IsReadOnly (BOOL* pRetVal) override
{
return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
{
return valueInterface.isReadOnly();
});
}
JUCE_COMRESULT get_Maximum (double* pRetVal) override
{
return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
{
return valueInterface.getRange().getMaximumValue();
});
}
JUCE_COMRESULT get_Minimum (double* pRetVal) override
{
return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
{
return valueInterface.getRange().getMinimumValue();
});
}
JUCE_COMRESULT get_LargeChange (double* pRetVal) override
{
return get_SmallChange (pRetVal);
}
JUCE_COMRESULT get_SmallChange (double* pRetVal) override
{
return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
{
return valueInterface.getRange().getInterval();
});
}
private:
template <typename Value, typename Callback>
JUCE_COMRESULT withValueInterface (Value* pRetVal, Callback&& callback) const
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* valueInterface = getHandler().getValueInterface())
{
if (valueInterface->getRange().isValid())
{
*pRetVal = callback (*valueInterface);
return S_OK;
}
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIARangeValueProvider)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIARangeValueProvider : public UIAProviderBase,
public ComBaseClassHelper<ComTypes::IRangeValueProvider>
{
public:
using UIAProviderBase::UIAProviderBase;
//==============================================================================
JUCE_COMRESULT SetValue (double val) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
if (auto* valueInterface = handler.getValueInterface())
{
auto range = valueInterface->getRange();
if (range.isValid())
{
if (val < range.getMinimumValue() || val > range.getMaximumValue())
return E_INVALIDARG;
if (! valueInterface->isReadOnly())
{
valueInterface->setValue (val);
VARIANT newValue;
VariantHelpers::setDouble (valueInterface->getCurrentValue(), &newValue);
sendAccessibilityPropertyChangedEvent (handler, UIA_RangeValueValuePropertyId, newValue);
return S_OK;
}
}
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT get_Value (double* pRetVal) override
{
return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
{
return valueInterface.getCurrentValue();
});
}
JUCE_COMRESULT get_IsReadOnly (BOOL* pRetVal) override
{
return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
{
return valueInterface.isReadOnly();
});
}
JUCE_COMRESULT get_Maximum (double* pRetVal) override
{
return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
{
return valueInterface.getRange().getMaximumValue();
});
}
JUCE_COMRESULT get_Minimum (double* pRetVal) override
{
return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
{
return valueInterface.getRange().getMinimumValue();
});
}
JUCE_COMRESULT get_LargeChange (double* pRetVal) override
{
return get_SmallChange (pRetVal);
}
JUCE_COMRESULT get_SmallChange (double* pRetVal) override
{
return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
{
return valueInterface.getRange().getInterval();
});
}
private:
template <typename Value, typename Callback>
JUCE_COMRESULT withValueInterface (Value* pRetVal, Callback&& callback) const
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* valueInterface = getHandler().getValueInterface())
{
if (valueInterface->getRange().isValid())
{
*pRetVal = callback (*valueInterface);
return S_OK;
}
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIARangeValueProvider)
};
} // namespace juce

View File

@ -1,256 +1,245 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
JUCE_COMCLASS (ISelectionProvider2, "14f68475-ee1c-44f6-a869-d239381f0fe7") : public ISelectionProvider
{
JUCE_COMCALL get_FirstSelectedItem (IRawElementProviderSimple** retVal) = 0;
JUCE_COMCALL get_LastSelectedItem (IRawElementProviderSimple** retVal) = 0;
JUCE_COMCALL get_CurrentSelectedItem (IRawElementProviderSimple** retVal) = 0;
JUCE_COMCALL get_ItemCount (int* retVal) = 0;
};
//==============================================================================
class UIASelectionItemProvider : public UIAProviderBase,
public ComBaseClassHelper<ISelectionItemProvider>
{
public:
explicit UIASelectionItemProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle),
isRadioButton (getHandler().getRole() == AccessibilityRole::radioButton)
{
}
//==============================================================================
JUCE_COMRESULT AddToSelection() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
if (isRadioButton)
{
handler.getActions().invoke (AccessibilityActionType::press);
sendAccessibilityAutomationEvent (handler, UIA_SelectionItem_ElementSelectedEventId);
return S_OK;
}
handler.getActions().invoke (AccessibilityActionType::toggle);
handler.getActions().invoke (AccessibilityActionType::press);
return S_OK;
}
JUCE_COMRESULT get_IsSelected (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
const auto state = getHandler().getCurrentState();
*pRetVal = isRadioButton ? state.isChecked() : state.isSelected();
return S_OK;
});
}
JUCE_COMRESULT get_SelectionContainer (IRawElementProviderSimple** pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
if (! isRadioButton)
if (auto* parent = getHandler().getParent())
parent->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
return S_OK;
});
}
JUCE_COMRESULT RemoveFromSelection() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
if (! isRadioButton)
{
const auto& handler = getHandler();
if (handler.getCurrentState().isSelected())
getHandler().getActions().invoke (AccessibilityActionType::toggle);
}
return S_OK;
}
JUCE_COMRESULT Select() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
AddToSelection();
if (isElementValid() && ! isRadioButton)
{
const auto& handler = getHandler();
if (auto* parent = handler.getParent())
for (auto* child : parent->getChildren())
if (child != &handler && child->getCurrentState().isSelected())
child->getActions().invoke (AccessibilityActionType::toggle);
}
return S_OK;
}
private:
const bool isRadioButton;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIASelectionItemProvider)
};
//==============================================================================
class UIASelectionProvider : public UIAProviderBase,
public ComBaseClassHelper<ISelectionProvider2>
{
public:
explicit UIASelectionProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle)
{
}
//==============================================================================
JUCE_COMRESULT QueryInterface (REFIID iid, void** result) override
{
if (iid == _uuidof (IUnknown) || iid == _uuidof (ISelectionProvider))
return castToType<ISelectionProvider> (result);
if (iid == _uuidof (ISelectionProvider2))
return castToType<ISelectionProvider2> (result);
*result = nullptr;
return E_NOINTERFACE;
}
//==============================================================================
JUCE_COMRESULT get_CanSelectMultiple (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = isMultiSelectable();
return S_OK;
});
}
JUCE_COMRESULT get_IsSelectionRequired (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = getSelectedChildren().size() > 0 && ! isMultiSelectable();
return S_OK;
});
}
JUCE_COMRESULT GetSelection (SAFEARRAY** pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
return addHandlersToArray (getSelectedChildren(), pRetVal);
});
}
//==============================================================================
JUCE_COMRESULT get_FirstSelectedItem (IRawElementProviderSimple** pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
auto selectedChildren = getSelectedChildren();
if (! selectedChildren.empty())
selectedChildren.front()->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
return S_OK;
});
}
JUCE_COMRESULT get_LastSelectedItem (IRawElementProviderSimple** pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
auto selectedChildren = getSelectedChildren();
if (! selectedChildren.empty())
selectedChildren.back()->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
return S_OK;
});
}
JUCE_COMRESULT get_CurrentSelectedItem (IRawElementProviderSimple** pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
get_FirstSelectedItem (pRetVal);
return S_OK;
});
}
JUCE_COMRESULT get_ItemCount (int* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = (int) getSelectedChildren().size();
return S_OK;
});
}
private:
bool isMultiSelectable() const noexcept
{
return getHandler().getCurrentState().isMultiSelectable();
}
std::vector<const AccessibilityHandler*> getSelectedChildren() const
{
std::vector<const AccessibilityHandler*> selectedHandlers;
for (auto* child : getHandler().getComponent().getChildren())
if (auto* handler = child->getAccessibilityHandler())
if (handler->getCurrentState().isSelected())
selectedHandlers.push_back (handler);
return selectedHandlers;
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIASelectionProvider)
};
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
//==============================================================================
class UIASelectionItemProvider : public UIAProviderBase,
public ComBaseClassHelper<ComTypes::ISelectionItemProvider>
{
public:
explicit UIASelectionItemProvider (AccessibilityNativeHandle* handle)
: UIAProviderBase (handle),
isRadioButton (getHandler().getRole() == AccessibilityRole::radioButton)
{
}
//==============================================================================
JUCE_COMRESULT AddToSelection() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
if (isRadioButton)
{
handler.getActions().invoke (AccessibilityActionType::press);
sendAccessibilityAutomationEvent (handler, ComTypes::UIA_SelectionItem_ElementSelectedEventId);
return S_OK;
}
handler.getActions().invoke (AccessibilityActionType::toggle);
handler.getActions().invoke (AccessibilityActionType::press);
return S_OK;
}
JUCE_COMRESULT get_IsSelected (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
const auto state = getHandler().getCurrentState();
*pRetVal = isRadioButton ? state.isChecked() : state.isSelected();
return S_OK;
});
}
JUCE_COMRESULT get_SelectionContainer (IRawElementProviderSimple** pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
if (! isRadioButton)
if (auto* parent = getHandler().getParent())
parent->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
return S_OK;
});
}
JUCE_COMRESULT RemoveFromSelection() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
if (! isRadioButton)
{
const auto& handler = getHandler();
if (handler.getCurrentState().isSelected())
getHandler().getActions().invoke (AccessibilityActionType::toggle);
}
return S_OK;
}
JUCE_COMRESULT Select() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
AddToSelection();
if (isElementValid() && ! isRadioButton)
{
const auto& handler = getHandler();
if (auto* parent = handler.getParent())
for (auto* child : parent->getChildren())
if (child != &handler && child->getCurrentState().isSelected())
child->getActions().invoke (AccessibilityActionType::toggle);
}
return S_OK;
}
private:
const bool isRadioButton;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIASelectionItemProvider)
};
//==============================================================================
class UIASelectionProvider : public UIAProviderBase,
public ComBaseClassHelper<ComTypes::ISelectionProvider2>
{
public:
using UIAProviderBase::UIAProviderBase;
//==============================================================================
JUCE_COMRESULT QueryInterface (REFIID iid, void** result) override
{
if (iid == __uuidof (IUnknown) || iid == __uuidof (ComTypes::ISelectionProvider))
return castToType<ComTypes::ISelectionProvider> (result);
if (iid == __uuidof (ComTypes::ISelectionProvider2))
return castToType<ComTypes::ISelectionProvider2> (result);
*result = nullptr;
return E_NOINTERFACE;
}
//==============================================================================
JUCE_COMRESULT get_CanSelectMultiple (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = isMultiSelectable();
return S_OK;
});
}
JUCE_COMRESULT get_IsSelectionRequired (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = getSelectedChildren().size() > 0 && ! isMultiSelectable();
return S_OK;
});
}
JUCE_COMRESULT GetSelection (SAFEARRAY** pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
return addHandlersToArray (getSelectedChildren(), pRetVal);
});
}
//==============================================================================
JUCE_COMRESULT get_FirstSelectedItem (IRawElementProviderSimple** pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
auto selectedChildren = getSelectedChildren();
if (! selectedChildren.empty())
selectedChildren.front()->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
return S_OK;
});
}
JUCE_COMRESULT get_LastSelectedItem (IRawElementProviderSimple** pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
auto selectedChildren = getSelectedChildren();
if (! selectedChildren.empty())
selectedChildren.back()->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
return S_OK;
});
}
JUCE_COMRESULT get_CurrentSelectedItem (IRawElementProviderSimple** pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
get_FirstSelectedItem (pRetVal);
return S_OK;
});
}
JUCE_COMRESULT get_ItemCount (int* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = (int) getSelectedChildren().size();
return S_OK;
});
}
private:
bool isMultiSelectable() const noexcept
{
return getHandler().getCurrentState().isMultiSelectable();
}
std::vector<const AccessibilityHandler*> getSelectedChildren() const
{
std::vector<const AccessibilityHandler*> selectedHandlers;
for (auto* child : getHandler().getComponent().getChildren())
if (auto* handler = child->getAccessibilityHandler())
if (handler->getCurrentState().isSelected())
selectedHandlers.push_back (handler);
return selectedHandlers;
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIASelectionProvider)
};
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
} // namespace juce

View File

@ -1,80 +1,78 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAToggleProvider : public UIAProviderBase,
public ComBaseClassHelper<IToggleProvider>
{
public:
explicit UIAToggleProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle)
{
}
//==============================================================================
JUCE_COMRESULT Toggle() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
if (handler.getActions().invoke (AccessibilityActionType::toggle))
{
VARIANT newValue;
VariantHelpers::setInt (getCurrentToggleState(), &newValue);
sendAccessibilityPropertyChangedEvent (handler, UIA_ToggleToggleStatePropertyId, newValue);
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT get_ToggleState (ToggleState* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = getCurrentToggleState();
return S_OK;
});
}
private:
ToggleState getCurrentToggleState() const
{
return getHandler().getCurrentState().isChecked() ? ToggleState_On
: ToggleState_Off;
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAToggleProvider)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAToggleProvider : public UIAProviderBase,
public ComBaseClassHelper<ComTypes::IToggleProvider>
{
public:
using UIAProviderBase::UIAProviderBase;
//==============================================================================
JUCE_COMRESULT Toggle() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
if (handler.getActions().invoke (AccessibilityActionType::toggle)
|| handler.getActions().invoke (AccessibilityActionType::press))
{
VARIANT newValue;
VariantHelpers::setInt (getCurrentToggleState(), &newValue);
sendAccessibilityPropertyChangedEvent (handler, UIA_ToggleToggleStatePropertyId, newValue);
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT get_ToggleState (ComTypes::ToggleState* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = getCurrentToggleState();
return S_OK;
});
}
private:
ComTypes::ToggleState getCurrentToggleState() const
{
return getHandler().getCurrentState().isChecked() ? ComTypes::ToggleState_On
: ComTypes::ToggleState_Off;
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAToggleProvider)
};
} // namespace juce

View File

@ -1,125 +1,122 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIATransformProvider : public UIAProviderBase,
public ComBaseClassHelper<ITransformProvider>
{
public:
explicit UIATransformProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle)
{
}
//==============================================================================
JUCE_COMRESULT Move (double x, double y) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
if (auto* peer = getPeer())
{
RECT rect;
GetWindowRect ((HWND) peer->getNativeHandle(), &rect);
rect.left = roundToInt (x);
rect.top = roundToInt (y);
auto bounds = Rectangle<int>::leftTopRightBottom (rect.left, rect.top, rect.right, rect.bottom);
peer->setBounds (Desktop::getInstance().getDisplays().physicalToLogical (bounds),
peer->isFullScreen());
}
return S_OK;
}
JUCE_COMRESULT Resize (double width, double height) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
if (auto* peer = getPeer())
{
auto scale = peer->getPlatformScaleFactor();
peer->getComponent().setSize (roundToInt (width / scale),
roundToInt (height / scale));
}
return S_OK;
}
JUCE_COMRESULT Rotate (double) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT get_CanMove (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = true;
return S_OK;
});
}
JUCE_COMRESULT get_CanResize (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
if (auto* peer = getPeer())
*pRetVal = ((peer->getStyleFlags() & ComponentPeer::windowIsResizable) != 0);
return S_OK;
});
}
JUCE_COMRESULT get_CanRotate (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = false;
return S_OK;
});
}
private:
ComponentPeer* getPeer() const
{
return getHandler().getComponent().getPeer();
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIATransformProvider)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIATransformProvider : public UIAProviderBase,
public ComBaseClassHelper<ComTypes::ITransformProvider>
{
public:
using UIAProviderBase::UIAProviderBase;
//==============================================================================
JUCE_COMRESULT Move (double x, double y) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
if (auto* peer = getPeer())
{
RECT rect;
GetWindowRect ((HWND) peer->getNativeHandle(), &rect);
rect.left = roundToInt (x);
rect.top = roundToInt (y);
auto bounds = Rectangle<int>::leftTopRightBottom (rect.left, rect.top, rect.right, rect.bottom);
peer->setBounds (Desktop::getInstance().getDisplays().physicalToLogical (bounds),
peer->isFullScreen());
}
return S_OK;
}
JUCE_COMRESULT Resize (double width, double height) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
if (auto* peer = getPeer())
{
auto scale = peer->getPlatformScaleFactor();
peer->getComponent().setSize (roundToInt (width / scale),
roundToInt (height / scale));
}
return S_OK;
}
JUCE_COMRESULT Rotate (double) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT get_CanMove (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = true;
return S_OK;
});
}
JUCE_COMRESULT get_CanResize (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
if (auto* peer = getPeer())
*pRetVal = ((peer->getStyleFlags() & ComponentPeer::windowIsResizable) != 0);
return S_OK;
});
}
JUCE_COMRESULT get_CanRotate (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = false;
return S_OK;
});
}
private:
ComponentPeer* getPeer() const
{
return getHandler().getComponent().getPeer();
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIATransformProvider)
};
} // namespace juce

View File

@ -1,86 +1,83 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAValueProvider : public UIAProviderBase,
public ComBaseClassHelper<IValueProvider>
{
public:
UIAValueProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle)
{
}
//==============================================================================
JUCE_COMRESULT SetValue (LPCWSTR val) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
auto& valueInterface = *handler.getValueInterface();
if (valueInterface.isReadOnly())
return (HRESULT) UIA_E_NOTSUPPORTED;
valueInterface.setValueAsString (String (val));
VARIANT newValue;
VariantHelpers::setString (valueInterface.getCurrentValueAsString(), &newValue);
sendAccessibilityPropertyChangedEvent (handler, UIA_ValueValuePropertyId, newValue);
return S_OK;
}
JUCE_COMRESULT get_Value (BSTR* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
auto currentValueString = getHandler().getValueInterface()->getCurrentValueAsString();
*pRetVal = SysAllocString ((const OLECHAR*) currentValueString.toWideCharPointer());
return S_OK;
});
}
JUCE_COMRESULT get_IsReadOnly (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = getHandler().getValueInterface()->isReadOnly();
return S_OK;
});
}
private:
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAValueProvider)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAValueProvider : public UIAProviderBase,
public ComBaseClassHelper<ComTypes::IValueProvider>
{
public:
using UIAProviderBase::UIAProviderBase;
//==============================================================================
JUCE_COMRESULT SetValue (LPCWSTR val) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
const auto& handler = getHandler();
auto& valueInterface = *handler.getValueInterface();
if (valueInterface.isReadOnly())
return (HRESULT) UIA_E_NOTSUPPORTED;
valueInterface.setValueAsString (String (val));
VARIANT newValue;
VariantHelpers::setString (valueInterface.getCurrentValueAsString(), &newValue);
sendAccessibilityPropertyChangedEvent (handler, UIA_ValueValuePropertyId, newValue);
return S_OK;
}
JUCE_COMRESULT get_Value (BSTR* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
auto currentValueString = getHandler().getValueInterface()->getCurrentValueAsString();
*pRetVal = SysAllocString ((const OLECHAR*) currentValueString.toWideCharPointer());
return S_OK;
});
}
JUCE_COMRESULT get_IsReadOnly (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]
{
*pRetVal = getHandler().getValueInterface()->isReadOnly();
return S_OK;
});
}
private:
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAValueProvider)
};
} // namespace juce

View File

@ -1,197 +1,194 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAWindowProvider : public UIAProviderBase,
public ComBaseClassHelper<IWindowProvider>
{
public:
explicit UIAWindowProvider (AccessibilityNativeHandle* nativeHandle)
: UIAProviderBase (nativeHandle)
{
}
//==============================================================================
JUCE_COMRESULT SetVisualState (WindowVisualState state) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
if (auto* peer = getPeer())
{
switch (state)
{
case WindowVisualState_Maximized:
peer->setFullScreen (true);
break;
case WindowVisualState_Minimized:
peer->setMinimised (true);
break;
case WindowVisualState_Normal:
peer->setFullScreen (false);
peer->setMinimised (false);
break;
default:
break;
}
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT Close() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
if (auto* peer = getPeer())
{
peer->handleUserClosingWindow();
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT WaitForInputIdle (int, BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, []
{
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_CanMaximize (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
*pRetVal = (peer->getStyleFlags() & ComponentPeer::windowHasMaximiseButton) != 0;
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_CanMinimize (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
*pRetVal = (peer->getStyleFlags() & ComponentPeer::windowHasMinimiseButton) != 0;
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_IsModal (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
*pRetVal = peer->getComponent().isCurrentlyModal();
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_WindowVisualState (WindowVisualState* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
if (peer->isFullScreen())
*pRetVal = WindowVisualState_Maximized;
else if (peer->isMinimised())
*pRetVal = WindowVisualState_Minimized;
else
*pRetVal = WindowVisualState_Normal;
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_WindowInteractionState (WindowInteractionState* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
*pRetVal = peer->getComponent().isCurrentlyBlockedByAnotherModalComponent()
? WindowInteractionState::WindowInteractionState_BlockedByModalWindow
: WindowInteractionState::WindowInteractionState_Running;
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_IsTopmost (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
*pRetVal = peer->isFocused();
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
private:
ComponentPeer* getPeer() const
{
return getHandler().getComponent().getPeer();
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAWindowProvider)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
//==============================================================================
class UIAWindowProvider : public UIAProviderBase,
public ComBaseClassHelper<ComTypes::IWindowProvider>
{
public:
using UIAProviderBase::UIAProviderBase;
//==============================================================================
JUCE_COMRESULT SetVisualState (ComTypes::WindowVisualState state) override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
if (auto* peer = getPeer())
{
switch (state)
{
case ComTypes::WindowVisualState_Maximized:
peer->setFullScreen (true);
break;
case ComTypes::WindowVisualState_Minimized:
peer->setMinimised (true);
break;
case ComTypes::WindowVisualState_Normal:
peer->setFullScreen (false);
peer->setMinimised (false);
break;
default:
break;
}
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT Close() override
{
if (! isElementValid())
return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
if (auto* peer = getPeer())
{
peer->handleUserClosingWindow();
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT WaitForInputIdle (int, BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, []
{
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_CanMaximize (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
*pRetVal = (peer->getStyleFlags() & ComponentPeer::windowHasMaximiseButton) != 0;
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_CanMinimize (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
*pRetVal = (peer->getStyleFlags() & ComponentPeer::windowHasMinimiseButton) != 0;
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_IsModal (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
*pRetVal = peer->getComponent().isCurrentlyModal();
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_WindowVisualState (ComTypes::WindowVisualState* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
if (peer->isFullScreen())
*pRetVal = ComTypes::WindowVisualState_Maximized;
else if (peer->isMinimised())
*pRetVal = ComTypes::WindowVisualState_Minimized;
else
*pRetVal = ComTypes::WindowVisualState_Normal;
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_WindowInteractionState (ComTypes::WindowInteractionState* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
*pRetVal = peer->getComponent().isCurrentlyBlockedByAnotherModalComponent()
? ComTypes::WindowInteractionState::WindowInteractionState_BlockedByModalWindow
: ComTypes::WindowInteractionState::WindowInteractionState_Running;
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
JUCE_COMRESULT get_IsTopmost (BOOL* pRetVal) override
{
return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
{
if (auto* peer = getPeer())
{
*pRetVal = peer->isFocused();
return S_OK;
}
return (HRESULT) UIA_E_NOTSUPPORTED;
});
}
private:
ComponentPeer* getPeer() const
{
return getHandler().getComponent().getPeer();
}
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAWindowProvider)
};
} // namespace juce

View File

@ -1,158 +1,160 @@
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2020 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
End User License Agreement: www.juce.com/juce-6-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
class WindowsUIAWrapper : public DeletedAtShutdown
{
public:
bool isLoaded() const noexcept
{
return uiaReturnRawElementProvider != nullptr
&& uiaHostProviderFromHwnd != nullptr
&& uiaRaiseAutomationPropertyChangedEvent != nullptr
&& uiaRaiseAutomationEvent != nullptr
&& uiaClientsAreListening != nullptr
&& uiaDisconnectProvider != nullptr
&& uiaDisconnectAllProviders != nullptr;
}
//==============================================================================
LRESULT returnRawElementProvider (HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple* provider)
{
return uiaReturnRawElementProvider != nullptr ? uiaReturnRawElementProvider (hwnd, wParam, lParam, provider)
: (LRESULT) nullptr;
}
JUCE_COMRESULT hostProviderFromHwnd (HWND hwnd, IRawElementProviderSimple** provider)
{
return uiaHostProviderFromHwnd != nullptr ? uiaHostProviderFromHwnd (hwnd, provider)
: (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT raiseAutomationPropertyChangedEvent (IRawElementProviderSimple* provider, PROPERTYID propID, VARIANT oldValue, VARIANT newValue)
{
return uiaRaiseAutomationPropertyChangedEvent != nullptr ? uiaRaiseAutomationPropertyChangedEvent (provider, propID, oldValue, newValue)
: (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT raiseAutomationEvent (IRawElementProviderSimple* provider, EVENTID eventID)
{
return uiaRaiseAutomationEvent != nullptr ? uiaRaiseAutomationEvent (provider, eventID)
: (HRESULT) UIA_E_NOTSUPPORTED;
}
BOOL clientsAreListening()
{
return uiaClientsAreListening != nullptr ? uiaClientsAreListening()
: false;
}
JUCE_COMRESULT disconnectProvider (IRawElementProviderSimple* provider)
{
if (uiaDisconnectProvider != nullptr)
{
const ScopedValueSetter<IRawElementProviderSimple*> disconnectingProviderSetter (disconnectingProvider, provider);
return uiaDisconnectProvider (provider);
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT disconnectAllProviders()
{
if (uiaDisconnectAllProviders != nullptr)
{
const ScopedValueSetter<bool> disconnectingAllProvidersSetter (disconnectingAllProviders, true);
return uiaDisconnectAllProviders();
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
//==============================================================================
bool isProviderDisconnecting (IRawElementProviderSimple* provider)
{
return disconnectingProvider == provider || disconnectingAllProviders;
}
//==============================================================================
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (WindowsUIAWrapper)
private:
//==============================================================================
WindowsUIAWrapper()
{
// force UIA COM library initialisation here to prevent an exception when calling methods from SendMessage()
if (isLoaded())
returnRawElementProvider (nullptr, 0, 0, nullptr);
else
jassertfalse; // UIAutomationCore could not be loaded!
}
~WindowsUIAWrapper()
{
disconnectAllProviders();
if (uiaHandle != nullptr)
::FreeLibrary (uiaHandle);
clearSingletonInstance();
}
//==============================================================================
template<typename FuncType>
static FuncType getUiaFunction (HMODULE module, StringRef funcName)
{
return (FuncType) GetProcAddress (module, funcName);
}
//==============================================================================
using UiaReturnRawElementProviderFunc = LRESULT (WINAPI*) (HWND, WPARAM, LPARAM, IRawElementProviderSimple*);
using UiaHostProviderFromHwndFunc = HRESULT (WINAPI*) (HWND, IRawElementProviderSimple**);
using UiaRaiseAutomationPropertyChangedEventFunc = HRESULT (WINAPI*) (IRawElementProviderSimple*, PROPERTYID, VARIANT, VARIANT);
using UiaRaiseAutomationEventFunc = HRESULT (WINAPI*) (IRawElementProviderSimple*, EVENTID);
using UiaClientsAreListeningFunc = BOOL (WINAPI*) ();
using UiaDisconnectProviderFunc = HRESULT (WINAPI*) (IRawElementProviderSimple*);
using UiaDisconnectAllProvidersFunc = HRESULT (WINAPI*) ();
HMODULE uiaHandle = ::LoadLibraryA ("UIAutomationCore.dll");
UiaReturnRawElementProviderFunc uiaReturnRawElementProvider = getUiaFunction<UiaReturnRawElementProviderFunc> (uiaHandle, "UiaReturnRawElementProvider");
UiaHostProviderFromHwndFunc uiaHostProviderFromHwnd = getUiaFunction<UiaHostProviderFromHwndFunc> (uiaHandle, "UiaHostProviderFromHwnd");
UiaRaiseAutomationPropertyChangedEventFunc uiaRaiseAutomationPropertyChangedEvent = getUiaFunction<UiaRaiseAutomationPropertyChangedEventFunc> (uiaHandle, "UiaRaiseAutomationPropertyChangedEvent");
UiaRaiseAutomationEventFunc uiaRaiseAutomationEvent = getUiaFunction<UiaRaiseAutomationEventFunc> (uiaHandle, "UiaRaiseAutomationEvent");
UiaClientsAreListeningFunc uiaClientsAreListening = getUiaFunction<UiaClientsAreListeningFunc> (uiaHandle, "UiaClientsAreListening");
UiaDisconnectProviderFunc uiaDisconnectProvider = getUiaFunction<UiaDisconnectProviderFunc> (uiaHandle, "UiaDisconnectProvider");
UiaDisconnectAllProvidersFunc uiaDisconnectAllProviders = getUiaFunction<UiaDisconnectAllProvidersFunc> (uiaHandle, "UiaDisconnectAllProviders");
IRawElementProviderSimple* disconnectingProvider = nullptr;
bool disconnectingAllProviders = false;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsUIAWrapper)
};
} // namespace juce
/*
==============================================================================
This file is part of the JUCE library.
Copyright (c) 2022 - Raw Material Software Limited
JUCE is an open source library subject to commercial or open-source
licensing.
By using JUCE, you agree to the terms of both the JUCE 7 End-User License
Agreement and JUCE Privacy Policy.
End User License Agreement: www.juce.com/juce-7-licence
Privacy Policy: www.juce.com/juce-privacy-policy
Or: You may also use this code under the terms of the GPL v3 (see
www.gnu.org/licenses).
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
DISCLAIMED.
==============================================================================
*/
namespace juce
{
class WindowsUIAWrapper : public DeletedAtShutdown
{
public:
bool isLoaded() const noexcept
{
return uiaReturnRawElementProvider != nullptr
&& uiaHostProviderFromHwnd != nullptr
&& uiaRaiseAutomationPropertyChangedEvent != nullptr
&& uiaRaiseAutomationEvent != nullptr
&& uiaClientsAreListening != nullptr
&& uiaDisconnectProvider != nullptr
&& uiaDisconnectAllProviders != nullptr;
}
//==============================================================================
LRESULT returnRawElementProvider (HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple* provider)
{
return uiaReturnRawElementProvider != nullptr ? uiaReturnRawElementProvider (hwnd, wParam, lParam, provider)
: (LRESULT) nullptr;
}
JUCE_COMRESULT hostProviderFromHwnd (HWND hwnd, IRawElementProviderSimple** provider)
{
return uiaHostProviderFromHwnd != nullptr ? uiaHostProviderFromHwnd (hwnd, provider)
: (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT raiseAutomationPropertyChangedEvent (IRawElementProviderSimple* provider, PROPERTYID propID, VARIANT oldValue, VARIANT newValue)
{
return uiaRaiseAutomationPropertyChangedEvent != nullptr ? uiaRaiseAutomationPropertyChangedEvent (provider, propID, oldValue, newValue)
: (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT raiseAutomationEvent (IRawElementProviderSimple* provider, EVENTID eventID)
{
return uiaRaiseAutomationEvent != nullptr ? uiaRaiseAutomationEvent (provider, eventID)
: (HRESULT) UIA_E_NOTSUPPORTED;
}
BOOL clientsAreListening()
{
return uiaClientsAreListening != nullptr ? uiaClientsAreListening()
: false;
}
JUCE_COMRESULT disconnectProvider (IRawElementProviderSimple* provider)
{
if (uiaDisconnectProvider != nullptr)
{
const ScopedValueSetter<IRawElementProviderSimple*> disconnectingProviderSetter (disconnectingProvider, provider);
return uiaDisconnectProvider (provider);
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
JUCE_COMRESULT disconnectAllProviders()
{
if (uiaDisconnectAllProviders != nullptr)
{
const ScopedValueSetter<bool> disconnectingAllProvidersSetter (disconnectingAllProviders, true);
return uiaDisconnectAllProviders();
}
return (HRESULT) UIA_E_NOTSUPPORTED;
}
//==============================================================================
bool isProviderDisconnecting (IRawElementProviderSimple* provider)
{
return disconnectingProvider == provider || disconnectingAllProviders;
}
//==============================================================================
JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (WindowsUIAWrapper)
private:
//==============================================================================
WindowsUIAWrapper()
{
// force UIA COM library initialisation here to prevent an exception when calling methods from SendMessage()
if (isLoaded())
returnRawElementProvider (nullptr, 0, 0, nullptr);
else
jassertfalse; // UIAutomationCore could not be loaded!
}
~WindowsUIAWrapper()
{
disconnectAllProviders();
if (uiaHandle != nullptr)
::FreeLibrary (uiaHandle);
clearSingletonInstance();
}
//==============================================================================
template <typename FuncType>
static FuncType getUiaFunction (HMODULE module, LPCSTR funcName)
{
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-function-type")
return (FuncType) GetProcAddress (module, funcName);
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
}
//==============================================================================
using UiaReturnRawElementProviderFunc = LRESULT (WINAPI*) (HWND, WPARAM, LPARAM, IRawElementProviderSimple*);
using UiaHostProviderFromHwndFunc = HRESULT (WINAPI*) (HWND, IRawElementProviderSimple**);
using UiaRaiseAutomationPropertyChangedEventFunc = HRESULT (WINAPI*) (IRawElementProviderSimple*, PROPERTYID, VARIANT, VARIANT);
using UiaRaiseAutomationEventFunc = HRESULT (WINAPI*) (IRawElementProviderSimple*, EVENTID);
using UiaClientsAreListeningFunc = BOOL (WINAPI*) ();
using UiaDisconnectProviderFunc = HRESULT (WINAPI*) (IRawElementProviderSimple*);
using UiaDisconnectAllProvidersFunc = HRESULT (WINAPI*) ();
HMODULE uiaHandle = ::LoadLibraryA ("UIAutomationCore.dll");
UiaReturnRawElementProviderFunc uiaReturnRawElementProvider = getUiaFunction<UiaReturnRawElementProviderFunc> (uiaHandle, "UiaReturnRawElementProvider");
UiaHostProviderFromHwndFunc uiaHostProviderFromHwnd = getUiaFunction<UiaHostProviderFromHwndFunc> (uiaHandle, "UiaHostProviderFromHwnd");
UiaRaiseAutomationPropertyChangedEventFunc uiaRaiseAutomationPropertyChangedEvent = getUiaFunction<UiaRaiseAutomationPropertyChangedEventFunc> (uiaHandle, "UiaRaiseAutomationPropertyChangedEvent");
UiaRaiseAutomationEventFunc uiaRaiseAutomationEvent = getUiaFunction<UiaRaiseAutomationEventFunc> (uiaHandle, "UiaRaiseAutomationEvent");
UiaClientsAreListeningFunc uiaClientsAreListening = getUiaFunction<UiaClientsAreListeningFunc> (uiaHandle, "UiaClientsAreListening");
UiaDisconnectProviderFunc uiaDisconnectProvider = getUiaFunction<UiaDisconnectProviderFunc> (uiaHandle, "UiaDisconnectProvider");
UiaDisconnectAllProvidersFunc uiaDisconnectAllProviders = getUiaFunction<UiaDisconnectAllProvidersFunc> (uiaHandle, "UiaDisconnectAllProviders");
IRawElementProviderSimple* disconnectingProvider = nullptr;
bool disconnectingAllProviders = false;
//==============================================================================
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsUIAWrapper)
};
} // namespace juce