Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions Assets/Scripts/Screen Reader/AccessibilityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -359,11 +359,7 @@ static void RemoveSubHierarchyForService(AccessibilityService service)

static void CreateSubHierarchyForService(AccessibilityService service)
{
var rootNode = hierarchy.AddNode(service.serviceName);
rootNode.role = AccessibilityRole.Container;
rootNode.isActive = Application.platform == RuntimePlatform.OSXPlayer; // false;

service.hierarchy = new AccessibilitySubHierarchy(hierarchy, rootNode);
service.hierarchy = new AccessibilitySubHierarchy(hierarchy);
}

static void GenerateSubHierarchyForService(Scene scene, AccessibilityService service)
Expand Down
64 changes: 30 additions & 34 deletions Assets/Scripts/Screen Reader/AccessibilitySubHierarchy.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Accessibility;

Expand All @@ -17,7 +18,7 @@ public struct AccessibilitySubHierarchy
/// <summary>
/// Returns the node used as root for this sub-hierarchy.
/// </summary>
public AccessibilityNode rootNode { get; private set; }
public List<AccessibilityNode> rootNodes { get; private set; }

/// <summary>
/// Returns true if this sub-hierarchy is valid.
Expand All @@ -27,39 +28,31 @@ public struct AccessibilitySubHierarchy
/// <summary>
/// Constructs a sub-hierarchy from the specified hierarchy and root node.
/// </summary>
/// <param name="mainHierarchy"></param>
/// <param name="rootNode"></param>
public AccessibilitySubHierarchy(AccessibilityHierarchy mainHierarchy, AccessibilityNode rootNode)
/// <param name="hierarchy"></param>
public AccessibilitySubHierarchy(AccessibilityHierarchy hierarchy)
{
// Assert that the main hierarchy exists.
if (mainHierarchy == null)
{
throw new System.ArgumentNullException(nameof(mainHierarchy), "The main hierarchy cannot be null.");
}

// Assert that the root node belongs to the main hierarchy.
if (rootNode != null && !mainHierarchy.ContainsNode(rootNode))
{
throw new System.ArgumentException("The root node must belong to the main hierarchy.", nameof(rootNode));
}

// Note: if the root element is null then the sub-hierarchy represents the whole hierarchy.
this.mainHierarchy = mainHierarchy;
this.rootNode = rootNode;
mainHierarchy = hierarchy ?? throw new System.ArgumentNullException(nameof(hierarchy), "The main hierarchy cannot be null.");
rootNodes = new List<AccessibilityNode>();
}

/// <summary>
/// Disposes the sub-hierarchy removing the root node from the main hierarchy.
/// </summary>
public void Dispose()
{
if (mainHierarchy != null && rootNode != null && mainHierarchy.ContainsNode(rootNode))
if (mainHierarchy != null)
{
mainHierarchy.RemoveNode(rootNode);
foreach (var rootNode in rootNodes)
{
if (mainHierarchy.ContainsNode(rootNode))
{
mainHierarchy.RemoveNode(rootNode);
}
}
}

mainHierarchy = null;
rootNode = null;
rootNodes?.Clear();
}

/// <summary>
Expand All @@ -80,16 +73,16 @@ public bool ContainsNode(AccessibilityNode node)
}

// We know the node is in the main hierarchy, now we need to check if it's part of this sub-hierarchy.
var parentNode = node.parent;
var currentNode = node;

while (parentNode != null)
while (currentNode != null)
{
if (parentNode == rootNode)
if (rootNodes.Contains(currentNode))
{
return true;
}

parentNode = parentNode.parent;
currentNode = currentNode.parent;
}

return false;
Expand Down Expand Up @@ -159,9 +152,14 @@ public AccessibilityNode InsertNode(int childIndex, string label = null, Accessi
return null;
}

var actualParent = parent ?? rootNode;
var node = mainHierarchy.InsertNode(childIndex, label, parent);

if (parent == null)
{
rootNodes.Add(node);
}

return mainHierarchy.AddNode(label, actualParent);
return node;
}

/// <summary>
Expand All @@ -178,9 +176,7 @@ public bool MoveNode(AccessibilityNode node, AccessibilityNode newParent, int ne
return false;
}

var actualParent = newParent ?? rootNode;

return mainHierarchy.MoveNode(node, actualParent, newChildIndex);
return mainHierarchy.MoveNode(node, newParent, newChildIndex);
}

/// <summary>
Expand All @@ -203,12 +199,12 @@ public void RemoveNode(AccessibilityNode node, bool removeChildren = true)
/// </summary>
public void Clear()
{
if (rootNode != null)
if (rootNodes is { Count: > 0 })
{
// Removes from the last to the first to avoid messing up the indices.
for (var i = rootNode.children.Count - 1; i >= 0; i--)
for (var i = rootNodes.Count - 1; i >= 0; i--)
{
mainHierarchy.RemoveNode(rootNode.children[i]);
mainHierarchy.RemoveNode(rootNodes[i]);
}
}
else
Expand Down
48 changes: 0 additions & 48 deletions Assets/Scripts/Screen Reader/UITk/UITkAccessibilityService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,51 +27,8 @@ public UITkAccessibilityService() : base("UITk", 100)
AssistiveSupport.nodeFocusChanged += OnNodeFocusChanged;
}

bool m_NeedsToRecomputeRootFrames;

public void DirtyRootFrames()
{
m_NeedsToRecomputeRootFrames = true;
}

public void UpdateRootAndPanelFrames()
{
m_NeedsToRecomputeRootFrames = true;

foreach (var accessibilityUpdater in m_AccessibilityUpdaters)
{
accessibilityUpdater.UpdateRootFrame();
}

var serviceRootFrame = Rect.zero;

foreach (var panelNode in hierarchy.rootNode.children)
{
// Calculate the union of all root nodes frames.
if (panelNode.frame.size != Vector2.zero)
{
Encompass(ref serviceRootFrame, panelNode.frame);
}
}

hierarchy.rootNode.frame = serviceRootFrame;
void Encompass(ref Rect a, Rect b)
{
a.xMin = Math.Min(a.xMin, b.xMin);
a.yMin = Math.Min(a.yMin, b.yMin);
a.xMax = Math.Max(a.xMax, b.xMax);
a.yMax = Math.Max(a.yMax, b.yMax);
}
}

public override void Update()
{
if (m_NeedsToRecomputeRootFrames)
{
UpdateRootAndPanelFrames();
m_NeedsToRecomputeRootFrames = false;
}

foreach (var accessibilityUpdater in m_AccessibilityUpdaters)
{
accessibilityUpdater.Update();
Expand Down Expand Up @@ -172,11 +129,6 @@ public override void SetUp(Scene scene)
}

var panel = uiDocument.runtimePanel;
var rootAcc = uiDocument.rootVisualElement.GetOrCreateAccessibleProperties();

rootAcc.label = uiDocument.rootVisualElement.name;
rootAcc.active = Application.platform == RuntimePlatform.OSXPlayer; // false;
rootAcc.role = AccessibilityRole.Container;

if (!panels.Contains(panel))
{
Expand Down
85 changes: 14 additions & 71 deletions Assets/Scripts/Screen Reader/UITk/VisualTreeAccessibilityUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,11 @@ enum NotificationType
VisualElement m_VisualTree;
IVisualElementScheduledItem m_UpdateJob;
UITkAccessibilityService m_AccessibilityService;
AccessibilitySubHierarchy m_SubHierarchy;

/// <summary>
/// The sub-hierarchy this updater is managing.
/// </summary>
public AccessibilitySubHierarchy hierarchy
{
get => m_SubHierarchy;
set
{
m_SubHierarchy = value;

if (m_SubHierarchy.isValid && visualTree != null)
{
DirtyRootFrame();
}
}
}
public AccessibilitySubHierarchy hierarchy { get; set; }

/// <summary>
/// The panel of the visual tree being managed.
Expand Down Expand Up @@ -111,14 +98,10 @@ public VisualTreeAccessibilityUpdater(IPanel panel, VisualElement visualTree, UI
m_AccessibilityService = service;
visualTree.RegisterCallback<AttachToPanelEvent>(OnAttachmentToPanel);
visualTree.RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);

DirtyRootFrame();
}

void OnGeometryChanged(GeometryChangedEvent evt)
{
DirtyRootFrame();

// OnScreenDebug.Log("OnGeometryChanged " + evt.target);

OnVersionChanged(evt.target as VisualElement, VersionChangeType.Size | VersionChangeType.Transform);
Expand Down Expand Up @@ -202,9 +185,9 @@ void InsertNode(VisualElementAccessibilityHandler parentHandler, VisualElementAc

m_HandlersForNodes[node] = accHandler;

if (p != null)
if (parentHandler != null)
{
p.nextInsertionIndex++;
parentHandler.nextInsertionIndex++;
}
else
{
Expand All @@ -216,14 +199,13 @@ void InsertNode(VisualElementAccessibilityHandler parentHandler, VisualElementAc

bool MoveNode(VisualElementAccessibilityHandler parentElement, VisualElementAccessibilityHandler accHandler)
{
var p = parentElement;
var parentNode = p?.node;
var index = p?.nextInsertionIndex ?? m_RootNextInsertionIndex;
var parentNode = parentElement?.node;
var index = parentElement?.nextInsertionIndex ?? m_RootNextInsertionIndex;
var moved = hierarchy.MoveNode(accHandler.node, parentNode, index);

if (p != null)
if (parentElement != null)
{
p.nextInsertionIndex++;
parentElement.nextInsertionIndex++;
}
else
{
Expand Down Expand Up @@ -431,19 +413,6 @@ void GetMinMaxY(Vector3[] vector, out float min, out float max)
}
}

void DirtyRootFrame()
{
m_AccessibilityService.DirtyRootFrames();
}

public void UpdateRootFrame()
{
if (hierarchy.isValid)
{
hierarchy.rootNode.frame = GetScreenPosition(visualTree);
}
}

void UpdateNode(VisualElementAccessibilityHandler accElement)
{
if (!IsNodeValid(accElement.node))
Expand Down Expand Up @@ -528,30 +497,9 @@ public void Update()
Update(visualTree);
}

string GetPanelName(VisualElement ve)
{
// Try to get the name of the panel using reflection.
var panel = ve.panel;

if (panel == null)
{
return null;
}

var panelType = panel.GetType();
var nameProperty = panelType.GetProperty("name");

if (nameProperty != null)
{
return nameProperty.GetValue(panel, null) as string;
}

return null;
}

NotificationType m_Notification = NotificationType.None;

void Update(VisualElement visualTree)
void Update(VisualElement ve)
{
var shouldSendNotification = false;

Expand All @@ -563,13 +511,8 @@ void Update(VisualElement visualTree)
{
if (!hierarchy.isValid)
{
var panelName = GetPanelName(visualTree);
var rootNode = m_AccessibilityService.hierarchy.AddNode(string.IsNullOrEmpty(panelName) ?
visualTree.name : panelName);
rootNode.role = AccessibilityRole.Container;
rootNode.isActive = Application.platform == RuntimePlatform.OSXPlayer;
hierarchy = new AccessibilitySubHierarchy(m_AccessibilityService.hierarchy.mainHierarchy, rootNode);
DirtyRootFrame();
hierarchy = new AccessibilitySubHierarchy(m_AccessibilityService.hierarchy.mainHierarchy);

shouldSendNotification = true;
}

Expand All @@ -578,24 +521,24 @@ void Update(VisualElement visualTree)

var modalElement = currentModalElement;

UpdateAccessibilityHierarchyRecursively(visualTree, null, false, true);
UpdateAccessibilityHierarchyRecursively(ve, null, false, true);

// If there is a current modal element or if the current model element has changed then update the
// active state of all nodes.
if (currentModalElement != null || currentModalElement != modalElement)
{
OnScreenDebug.Log("Updating active state from modality " + currentModalElement?.name);
UpdateActiveStateFromModalityRecursively(visualTree);
UpdateActiveStateFromModalityRecursively(ve);
}
}

if (shouldSendNotification || m_Notification.HasFlag(NotificationType.ScreenChanged))
{
visualTree.schedule.Execute(() => AssistiveSupport.notificationDispatcher.SendScreenChanged());
ve.schedule.Execute(() => AssistiveSupport.notificationDispatcher.SendScreenChanged());
}
else if (m_Notification.HasFlag(NotificationType.LayoutChanged))
{
visualTree.schedule.Execute(() => AssistiveSupport.notificationDispatcher.SendLayoutChanged());
ve.schedule.Execute(() => AssistiveSupport.notificationDispatcher.SendLayoutChanged());
}
}

Expand Down