Skip to content

Commit

Permalink
Merge pull request #225 from raisingthefloor/christopher/v1.6
Browse files Browse the repository at this point in the history
Enhanced a11y bug reporting; initial update for macOS 14 support
  • Loading branch information
christopher-rtf authored Oct 2, 2023
2 parents b723ce2 + 1802073 commit bd024cf
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
9D6916182911B718002F3A21 /* MorphicProcess.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9D6916172911B718002F3A21 /* MorphicProcess.swift */; };
9D69161B2911B752002F3A21 /* MorphicCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9D69161A2911B752002F3A21 /* MorphicCore.framework */; };
9D69161C2911B752002F3A21 /* MorphicCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9D69161A2911B752002F3A21 /* MorphicCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
CE2313D42ABE1D3800075B18 /* MorphicA11yUIElementError.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE2313D32ABE1D3800075B18 /* MorphicA11yUIElementError.swift */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand All @@ -38,6 +39,7 @@
9D6916152911B6DB002F3A21 /* MorphicA11yUIElement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MorphicA11yUIElement.swift; sourceTree = "<group>"; };
9D6916172911B718002F3A21 /* MorphicProcess.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MorphicProcess.swift; sourceTree = "<group>"; };
9D69161A2911B752002F3A21 /* MorphicCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MorphicCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
CE2313D32ABE1D3800075B18 /* MorphicA11yUIElementError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MorphicA11yUIElementError.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -85,6 +87,7 @@
9D6916112911B6D2002F3A21 /* MorphicA11yAuthorization.swift */,
9D6916132911B6D6002F3A21 /* MorphicA11yUIAttributeValueCompatible.swift */,
9D6916152911B6DB002F3A21 /* MorphicA11yUIElement.swift */,
CE2313D32ABE1D3800075B18 /* MorphicA11yUIElementError.swift */,
);
path = AccessibilityUI;
sourceTree = "<group>";
Expand Down Expand Up @@ -185,6 +188,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CE2313D42ABE1D3800075B18 /* MorphicA11yUIElementError.swift in Sources */,
9D6916182911B718002F3A21 /* MorphicProcess.swift in Sources */,
9D6916162911B6DB002F3A21 /* MorphicA11yUIElement.swift in Sources */,
9D6916122911B6D2002F3A21 /* MorphicA11yAuthorization.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ public struct MorphicA11yUIElement {
return result
} catch let error as InitError {
throw error
} catch let error {
assertionFailure("undocumented error path")
throw error
}
}

Expand All @@ -94,8 +97,14 @@ public struct MorphicA11yUIElement {
guard self.supportedAttributes.contains(.children) == true else {
return []
}
guard let children: [MorphicA11yUIElement] = try? self.values(forAttribute: .children) else {
throw MorphicError.unspecified
let children: [MorphicA11yUIElement]
do {
children = try self.values(forAttribute: .children)
} catch let error as MorphicA11yUIElementError {
throw error
} catch let error {
assertionFailure("undocumented error path")
throw error
}
//
return children
Expand Down Expand Up @@ -129,41 +138,66 @@ public struct MorphicA11yUIElement {
case .noValue:
return nil
default:
throw MorphicError.unspecified
throw MorphicA11yUIElementError.axError(error)
}
}
//
guard let result = try? MorphicA11yAttributeValueCompatibleSampleImpl.fromCFTypeRef(valueAsCFTypeRef!) else {
throw MorphicError.unspecified
let result: FoundationA11yUIAttributeValueCompatible
do {
result = try MorphicA11yAttributeValueCompatibleSampleImpl.fromCFTypeRef(valueAsCFTypeRef!)
} catch let error as MorphicA11yUIAttributeValueCompatibleError {
throw MorphicA11yUIElementError.uiAttributeValueCompatibleError(error)
} catch let error {
assertionFailure("undocumented error path")
throw error
}
return (result as! T)
}

//

public func values<T>(forAttribute attribute: NSAccessibility.Attribute) throws -> [T] where T: MorphicA11yUIAttributeValueCompatible {
guard let result: [T] = try? MorphicA11yUIElement.values(forAttribute: attribute, forAXUIElement: self.axUiElement) else {
throw MorphicError.unspecified
let result: [T]
do {
result = try MorphicA11yUIElement.values(forAttribute: attribute, forAXUIElement: self.axUiElement)
} catch let error as MorphicA11yUIElementError {
throw error
} catch let error {
assertionFailure("undocumented error path")
throw error
}

return result
}

public static func values<T>(forAttribute attribute: NSAccessibility.Attribute, forAXUIElement axUiElement: AXUIElement) throws -> [T] where T: MorphicA11yUIAttributeValueCompatible {
var valuesAsCFArray: CFArray? = nil

guard let numberOfValues = try? MorphicA11yUIElement.valueCount(forAttribute: attribute, forAXUIElement: axUiElement) else {
throw MorphicError.unspecified
let numberOfValues: Int
do {
numberOfValues = try MorphicA11yUIElement.valueCount(forAttribute: attribute, forAXUIElement: axUiElement)
} catch MorphicA11yUIElementError.axError(let error) {
throw MorphicA11yUIElementError.axError(error)
} catch let error {
assertionFailure("undocumented error path")
throw error
}

let error = AXUIElementCopyAttributeValues(axUiElement, attribute.rawValue as CFString, 0, numberOfValues, &valuesAsCFArray)
guard error == .success && valuesAsCFArray != nil else {
throw MorphicError.unspecified
throw MorphicA11yUIElementError.axError(error)
}
//
var values: [T] = []
for valueAsCFTypeRef in valuesAsCFArray! as [CFTypeRef] {
guard let value = try? MorphicA11yAttributeValueCompatibleSampleImpl.fromCFTypeRef(valueAsCFTypeRef) else {
throw MorphicError.unspecified
let value: FoundationA11yUIAttributeValueCompatible
do {
value = try MorphicA11yAttributeValueCompatibleSampleImpl.fromCFTypeRef(valueAsCFTypeRef)
} catch let error as MorphicA11yUIAttributeValueCompatibleError {
throw MorphicA11yUIElementError.uiAttributeValueCompatibleError(error)
} catch let error {
assertionFailure("undocumented error path")
throw error
}
values.append(value as! T)
}
Expand All @@ -177,7 +211,7 @@ public struct MorphicA11yUIElement {
var count: CFIndex = 0
let error = AXUIElementGetAttributeValueCount(axUiElement, attribute.rawValue as CFString, &count)
guard error == .success else {
throw MorphicError.unspecified
throw MorphicA11yUIElementError.axError(error)
}
return count as Int
}
Expand All @@ -192,7 +226,7 @@ public struct MorphicA11yUIElement {
let valueAsCFTypeRef = value.toCFTypeRef()
let error = AXUIElementSetAttributeValue(axUiElement, attribute.rawValue as CFString, valueAsCFTypeRef)
guard error == .success else {
throw MorphicError.unspecified
throw MorphicA11yUIElementError.axError(error)
}
}

Expand All @@ -202,7 +236,7 @@ public struct MorphicA11yUIElement {
var supportedActionNamesAsCFArray: CFArray?
let error = AXUIElementCopyActionNames(axUiElement, &supportedActionNamesAsCFArray)
guard error == .success && supportedActionNamesAsCFArray != nil else {
throw MorphicError.unspecified
throw MorphicA11yUIElementError.axError(error)
}
//
var supportedActions: [NSAccessibility.Action] = []
Expand All @@ -219,7 +253,7 @@ public struct MorphicA11yUIElement {
public func perform(action: NSAccessibility.Action) throws {
let error = AXUIElementPerformAction(self.axUiElement, action.rawValue as CFString)
guard error == .success else {
throw MorphicError.unspecified
throw MorphicA11yUIElementError.axError(error)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2021-2023 Raising the Floor - US, Inc.
//
// Licensed under the New BSD license. You may not use this file except in
// compliance with this License.
//
// You may obtain a copy of the License at
// https://github.com/raisingthefloor/morphic-macos/blob/master/LICENSE.txt
//
// The R&D leading to these results received funding from the:
// * Rehabilitation Services Administration, US Dept. of Education under
// grant H421A150006 (APCP)
// * National Institute on Disability, Independent Living, and
// Rehabilitation Research (NIDILRR)
// * Administration for Independent Living & Dept. of Education under grants
// H133E080022 (RERC-IT) and H133E130028/90RE5003-01-00 (UIITA-RERC)
// * European Union's Seventh Framework Programme (FP7/2007-2013) grant
// agreement nos. 289016 (Cloud4all) and 610510 (Prosperity4All)
// * William and Flora Hewlett Foundation
// * Ontario Ministry of Research and Innovation
// * Canadian Foundation for Innovation
// * Adobe Foundation
// * Consumer Electronics Association Foundation

import Cocoa

public enum MorphicA11yUIElementError: Error {
case axError(_ error: AXError)
case uiAttributeValueCompatibleError(_ error: MorphicA11yUIAttributeValueCompatibleError)
}
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,23 @@ internal class SystemSettingsMainWindow_macOS13 {
// STEP 2: find the Back button (which is a child of the toolbar)
let backButtonA11yUIElement: MorphicA11yUIElement?
do {
backButtonA11yUIElement = try toolbarUIElement.accessibilityUiElement.descendant(identifier: "go back", maxDepth: 1)
if #available(macOS 14.0, *) {
// macOS 14.0 and newer
backButtonA11yUIElement = try toolbarUIElement.accessibilityUiElement.dangerousFirstDescendant(where: {
guard $0.role == .button else {
return false
}

guard let buttonLabel: String = try? $0.value(forAttribute: .description) else {
return false
}

return buttonLabel == "Back"
})
} else {
// macOS 13.x
backButtonA11yUIElement = try toolbarUIElement.accessibilityUiElement.descendant(identifier: "go back", maxDepth: 1)
}
} catch let error {
throw error
}
Expand Down

0 comments on commit bd024cf

Please sign in to comment.