2 * Copyright(c) 2022 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 using System.Runtime.InteropServices;
20 using Tizen.NUI.Accessibility;
22 namespace Tizen.NUI.BaseComponents
24 public partial class View
26 private static AccessibilityStates AccessibilityInitialStates = new AccessibilityStates();
28 private static void RegisterAccessibilityDelegate()
30 InitializeAccessibilityDelegateAccessibleInterface();
31 InitializeAccessibilityDelegateActionInterface();
32 InitializeAccessibilityDelegateComponentInterface();
33 InitializeAccessibilityDelegateEditableTextInterface();
34 InitializeAccessibilityDelegateSelectionInterface();
35 InitializeAccessibilityDelegateTextInterface();
36 InitializeAccessibilityDelegateValueInterface();
37 InitializeAccessibilityDelegateTizenExtensions();
39 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
40 var size = Marshal.SizeOf<Interop.ControlDevel.AccessibilityDelegate>();
41 var ptr = Marshal.AllocHGlobal(size);
43 Marshal.StructureToPtr(ad, ptr, false);
44 Interop.ControlDevel.DaliAccessibilitySetAccessibilityDelegate(ptr, Convert.ToUInt32(size));
47 private static View GetViewFromRefObject(IntPtr refObjectPtr)
49 return Registry.GetManagedBaseHandleFromRefObject(refObjectPtr) as View;
52 private static T GetInterfaceFromRefObject<T>(IntPtr refObjectPtr)
54 var view = GetViewFromRefObject(refObjectPtr);
56 // NUIViewAccessible::CallMethod<T> checks whether a given interface is implemented
57 // before jumping to managed code, so this condition should always be true.
58 if (view is T atspiInterface)
60 return atspiInterface;
66 private static IntPtr DuplicateString(string value)
68 return Interop.ControlDevel.DaliAccessibilityDuplicateString(value ?? "");
71 private static IntPtr DuplicateAccessibilityRange(AccessibilityRange range)
73 return Interop.ControlDevel.DaliAccessibilityNewRange(range.StartOffset, range.EndOffset, range.Content);
76 private static IntPtr DuplicateAccessibilityRectangle(Rectangle rect)
78 return Interop.Rectangle.NewRectangle(rect.X, rect.Y, rect.Width, rect.Height);
82 // Accessible interface
85 private static void InitializeAccessibilityDelegateAccessibleInterface()
87 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
89 ad.CalculateStates = AccessibilityCalculateStatesWrapper;
90 ad.GetAttributes = AccessibilityGetAttributes; // Not a wrapper, entirely private implementation
91 ad.GetDescription = AccessibilityGetDescriptionWrapper;
92 ad.GetInterfaces = AccessibilityGetInterfaces; // Not a wrapper, entirely private implementation
93 ad.GetName = AccessibilityGetNameWrapper;
96 private static ulong AccessibilityCalculateStatesWrapper(IntPtr self, ulong initialStates)
98 View view = GetViewFromRefObject(self);
104 lock (AccessibilityInitialStates)
106 AccessibilityInitialStates.BitMask = initialStates;
107 bitMask = view.AccessibilityCalculateStates().BitMask;
108 AccessibilityInitialStates.BitMask = 0UL;
114 private static void AccessibilityGetAttributes(IntPtr self, Interop.ControlDevel.AccessibilityDelegate.AccessibilityGetAttributesCallback callback, IntPtr userData)
116 var view = GetViewFromRefObject(self);
117 var attributes = view.AccessibilityAttributes;
118 var classKey = "class";
120 if (!attributes.ContainsKey(classKey))
122 attributes[classKey] = view.GetType().Name;
125 foreach (var attribute in attributes)
127 callback(attribute.Key, attribute.Value, userData);
130 foreach (var attribute in view.AccessibilityDynamicAttributes)
132 callback(attribute.Key, attribute.Value.Invoke(), userData);
136 private static IntPtr AccessibilityGetDescriptionWrapper(IntPtr self)
138 string description = GetViewFromRefObject(self).AccessibilityGetDescription();
140 return DuplicateString(description);
143 private static uint AccessibilityGetInterfaces(IntPtr self)
145 View view = GetViewFromRefObject(self);
148 if (view is IAtspiEditableText)
150 flags |= (1U << (int)AccessibilityInterface.EditableText);
153 if (view is IAtspiSelection)
155 flags |= (1U << (int)AccessibilityInterface.Selection);
158 if (view is IAtspiText)
160 flags |= (1U << (int)AccessibilityInterface.Text);
163 if (view is IAtspiValue)
165 flags |= (1U << (int)AccessibilityInterface.Value);
171 private static IntPtr AccessibilityGetNameWrapper(IntPtr self)
173 string name = GetViewFromRefObject(self).AccessibilityGetName();
175 return DuplicateString(name);
182 private static void InitializeAccessibilityDelegateActionInterface()
184 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
186 ad.DoAction = AccessibilityDoActionWrapper;
187 ad.GetActionCount = AccessibilityGetActionCountWrapper;
188 ad.GetActionName = AccessibilityGetActionNameWrapper;
191 private static bool AccessibilityDoActionWrapper(IntPtr self, IntPtr name)
193 return GetViewFromRefObject(self).AccessibilityDoAction(Marshal.PtrToStringAnsi(name));
196 private static int AccessibilityGetActionCountWrapper(IntPtr self)
198 return GetViewFromRefObject(self).AccessibilityGetActionCount();
201 private static IntPtr AccessibilityGetActionNameWrapper(IntPtr self, int index)
203 string name = GetViewFromRefObject(self).AccessibilityGetActionName(index);
205 return DuplicateString(name);
209 // Component interface
212 private static void InitializeAccessibilityDelegateComponentInterface()
214 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
216 ad.IsScrollable = AccessibilityIsScrollableWrapper;
219 private static bool AccessibilityIsScrollableWrapper(IntPtr self)
221 return GetViewFromRefObject(self).AccessibilityIsScrollable();
225 // EditableText interface
228 private static void InitializeAccessibilityDelegateEditableTextInterface()
230 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
232 ad.CopyText = AccessibilityCopyTextWrapper;
233 ad.CutText = AccessibilityCutTextWrapper;
234 ad.DeleteText = AccessibilityDeleteTextWrapper;
235 ad.InsertText = AccessibilityInsertTextWrapper;
236 ad.SetTextContents = AccessibilitySetTextContentsWrapper;
239 private static bool AccessibilityCopyTextWrapper(IntPtr self, int startPosition, int endPosition)
241 return GetInterfaceFromRefObject<IAtspiEditableText>(self).AccessibilityCopyText(startPosition, endPosition);
244 private static bool AccessibilityCutTextWrapper(IntPtr self, int startPosition, int endPosition)
246 return GetInterfaceFromRefObject<IAtspiEditableText>(self).AccessibilityCutText(startPosition, endPosition);
249 private static bool AccessibilityDeleteTextWrapper(IntPtr self, int startPosition, int endPosition)
251 return GetInterfaceFromRefObject<IAtspiEditableText>(self).AccessibilityDeleteText(startPosition, endPosition);
254 private static bool AccessibilityInsertTextWrapper(IntPtr self, int startPosition, IntPtr text)
256 return GetInterfaceFromRefObject<IAtspiEditableText>(self).AccessibilityInsertText(startPosition, Marshal.PtrToStringAnsi(text));
259 private static bool AccessibilitySetTextContentsWrapper(IntPtr self, IntPtr newContents)
261 return GetInterfaceFromRefObject<IAtspiEditableText>(self).AccessibilitySetTextContents(Marshal.PtrToStringAnsi(newContents));
265 // Selection interface
268 private static void InitializeAccessibilityDelegateSelectionInterface()
270 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
272 ad.ClearSelection = AccessibilityClearSelectionWrapper;
273 ad.DeselectChild = AccessibilityDeselectChildWrapper;
274 ad.DeselectSelectedChild = AccessibilityDeselectSelectedChildWrapper;
275 ad.GetSelectedChild = AccessibilityGetSelectedChildWrapper;
276 ad.GetSelectedChildrenCount = AccessibilityGetSelectedChildrenCountWrapper;
277 ad.IsChildSelected = AccessibilityIsChildSelectedWrapper;
278 ad.SelectAll = AccessibilitySelectAllWrapper;
279 ad.SelectChild = AccessibilitySelectChildWrapper;
282 private static bool AccessibilityClearSelectionWrapper(IntPtr self)
284 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityClearSelection();
287 private static bool AccessibilityDeselectChildWrapper(IntPtr self, int childIndex)
289 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityDeselectChild(childIndex);
292 private static bool AccessibilityDeselectSelectedChildWrapper(IntPtr self, int selectedChildIndex)
294 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityDeselectSelectedChild(selectedChildIndex);
297 private static IntPtr AccessibilityGetSelectedChildWrapper(IntPtr self, int selectedChildIndex)
299 View child = GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityGetSelectedChild(selectedChildIndex);
301 return View.getCPtr(child).Handle;
304 private static int AccessibilityGetSelectedChildrenCountWrapper(IntPtr self)
306 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityGetSelectedChildrenCount();
309 private static bool AccessibilityIsChildSelectedWrapper(IntPtr self, int childIndex)
311 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityIsChildSelected(childIndex);
314 private static bool AccessibilitySelectAllWrapper(IntPtr self)
316 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilitySelectAll();
319 private static bool AccessibilitySelectChildWrapper(IntPtr self, int childIndex)
321 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilitySelectChild(childIndex);
328 private static void InitializeAccessibilityDelegateTextInterface()
330 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
332 ad.GetCharacterCount = AccessibilityGetCharacterCountWrapper;
333 ad.GetCursorOffset = AccessibilityGetCursorOffsetWrapper;
334 ad.GetRangeExtents = AccessibilityGetRangeExtentsWrapper;
335 ad.GetSelection = AccessibilityGetSelectionWrapper;
336 ad.GetText = AccessibilityGetTextWrapper;
337 ad.GetTextAtOffset = AccessibilityGetTextAtOffsetWrapper;
338 ad.RemoveSelection = AccessibilityRemoveSelectionWrapper;
339 ad.SetCursorOffset = AccessibilitySetCursorOffsetWrapper;
340 ad.SetSelection = AccessibilitySetSelectionWrapper;
343 private static int AccessibilityGetCharacterCountWrapper(IntPtr self)
345 return GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetCharacterCount();
348 private static int AccessibilityGetCursorOffsetWrapper(IntPtr self)
350 return GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetCursorOffset();
353 private static IntPtr AccessibilityGetRangeExtentsWrapper(IntPtr self, int startOffset, int endOffset, int coordType)
355 using Rectangle rect = GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetRangeExtents(startOffset, endOffset, (AccessibilityCoordinateType)coordType);
357 return DuplicateAccessibilityRectangle(rect);
360 private static IntPtr AccessibilityGetSelectionWrapper(IntPtr self, int selectionNumber)
362 AccessibilityRange range = GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetSelection(selectionNumber);
364 return DuplicateAccessibilityRange(range);
367 private static IntPtr AccessibilityGetTextWrapper(IntPtr self, int startOffset, int endOffset)
369 string text = GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetText(startOffset, endOffset);
371 return DuplicateString(text);
374 private static IntPtr AccessibilityGetTextAtOffsetWrapper(IntPtr self, int offset, int boundary)
376 AccessibilityRange range = GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetTextAtOffset(offset, (AccessibilityTextBoundary)boundary);
378 return DuplicateAccessibilityRange(range);
381 private static bool AccessibilityRemoveSelectionWrapper(IntPtr self, int selectionNumber)
383 return GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityRemoveSelection(selectionNumber);
386 private static bool AccessibilitySetCursorOffsetWrapper(IntPtr self, int offset)
388 return GetInterfaceFromRefObject<IAtspiText>(self).AccessibilitySetCursorOffset(offset);
391 private static bool AccessibilitySetSelectionWrapper(IntPtr self, int selectionNumber, int startOffset, int endOffset)
393 return GetInterfaceFromRefObject<IAtspiText>(self).AccessibilitySetSelection(selectionNumber, startOffset, endOffset);
400 private static void InitializeAccessibilityDelegateValueInterface()
402 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
404 ad.GetCurrent = AccessibilityGetCurrentWrapper;
405 ad.GetMaximum = AccessibilityGetMaximumWrapper;
406 ad.GetMinimum = AccessibilityGetMinimumWrapper;
407 ad.GetMinimumIncrement = AccessibilityGetMinimumIncrementWrapper;
408 ad.GetValueText = AccessibilityGetValueTextWrapper;
409 ad.SetCurrent = AccessibilitySetCurrentWrapper;
412 private static double AccessibilityGetCurrentWrapper(IntPtr self)
414 return GetInterfaceFromRefObject<IAtspiValue>(self).AccessibilityGetCurrent();
417 private static double AccessibilityGetMaximumWrapper(IntPtr self)
419 return GetInterfaceFromRefObject<IAtspiValue>(self).AccessibilityGetMaximum();
422 private static double AccessibilityGetMinimumWrapper(IntPtr self)
424 return GetInterfaceFromRefObject<IAtspiValue>(self).AccessibilityGetMinimum();
427 private static double AccessibilityGetMinimumIncrementWrapper(IntPtr self)
429 return GetInterfaceFromRefObject<IAtspiValue>(self).AccessibilityGetMinimumIncrement();
432 private static IntPtr AccessibilityGetValueTextWrapper(IntPtr self)
434 var view = GetViewFromRefObject(self);
435 var value = GetInterfaceFromRefObject<IAtspiValue>(self);
438 // Mimic the behaviour of the pairs AccessibilityNameRequested & AccessibilityGetName(),
439 // and AccessibilityDescriptionRequested & AccessibilityGetDescription(),
440 // i.e. a higher-priority Accessibility[…]Requested event for application developers,
441 // and a lower-priority AccessibilityGet[…]() virtual method for component developers.
442 // The difference is that event-or-virtual-method dispatching is done in C++ for
443 // Name and Description, and here in this wrapper method for ValueText (because there
444 // is no signal for ValueText in DALi.)
445 if (view.AccessibilityValueTextRequested?.GetInvocationList().Length > 0)
447 var args = new AccessibilityValueTextRequestedEventArgs();
448 view.AccessibilityValueTextRequested.Invoke(view, args);
453 text = value.AccessibilityGetValueText();
456 return DuplicateString(text);
459 private static bool AccessibilitySetCurrentWrapper(IntPtr self, double value)
461 return GetInterfaceFromRefObject<IAtspiValue>(self).AccessibilitySetCurrent(value);
468 private static void InitializeAccessibilityDelegateTizenExtensions()
470 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
472 ad.ScrollToChild = AccessibilityScrollToChildWrapper;
475 private static bool AccessibilityScrollToChildWrapper(IntPtr self, IntPtr child)
477 View view = GetViewFromRefObject(self);
479 return view.AccessibilityScrollToChild(view.GetInstanceSafely<View>(child));