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);
131 private static IntPtr AccessibilityGetDescriptionWrapper(IntPtr self)
133 string description = GetViewFromRefObject(self).AccessibilityGetDescription();
135 return DuplicateString(description);
138 private static uint AccessibilityGetInterfaces(IntPtr self)
140 View view = GetViewFromRefObject(self);
143 if (view is IAtspiEditableText)
145 flags |= (1U << (int)AccessibilityInterface.EditableText);
148 if (view is IAtspiSelection)
150 flags |= (1U << (int)AccessibilityInterface.Selection);
153 if (view is IAtspiText)
155 flags |= (1U << (int)AccessibilityInterface.Text);
158 if (view is IAtspiValue)
160 flags |= (1U << (int)AccessibilityInterface.Value);
166 private static IntPtr AccessibilityGetNameWrapper(IntPtr self)
168 string name = GetViewFromRefObject(self).AccessibilityGetName();
170 return DuplicateString(name);
177 private static void InitializeAccessibilityDelegateActionInterface()
179 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
181 ad.DoAction = AccessibilityDoActionWrapper;
182 ad.GetActionCount = AccessibilityGetActionCountWrapper;
183 ad.GetActionName = AccessibilityGetActionNameWrapper;
186 private static bool AccessibilityDoActionWrapper(IntPtr self, IntPtr name)
188 return GetViewFromRefObject(self).AccessibilityDoAction(Marshal.PtrToStringAnsi(name));
191 private static int AccessibilityGetActionCountWrapper(IntPtr self)
193 return GetViewFromRefObject(self).AccessibilityGetActionCount();
196 private static IntPtr AccessibilityGetActionNameWrapper(IntPtr self, int index)
198 string name = GetViewFromRefObject(self).AccessibilityGetActionName(index);
200 return DuplicateString(name);
204 // Component interface
207 private static void InitializeAccessibilityDelegateComponentInterface()
209 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
211 ad.IsScrollable = AccessibilityIsScrollableWrapper;
214 private static bool AccessibilityIsScrollableWrapper(IntPtr self)
216 return GetViewFromRefObject(self).AccessibilityIsScrollable();
220 // EditableText interface
223 private static void InitializeAccessibilityDelegateEditableTextInterface()
225 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
227 ad.CopyText = AccessibilityCopyTextWrapper;
228 ad.CutText = AccessibilityCutTextWrapper;
229 ad.DeleteText = AccessibilityDeleteTextWrapper;
230 ad.InsertText = AccessibilityInsertTextWrapper;
231 ad.SetTextContents = AccessibilitySetTextContentsWrapper;
234 private static bool AccessibilityCopyTextWrapper(IntPtr self, int startPosition, int endPosition)
236 return GetInterfaceFromRefObject<IAtspiEditableText>(self).AccessibilityCopyText(startPosition, endPosition);
239 private static bool AccessibilityCutTextWrapper(IntPtr self, int startPosition, int endPosition)
241 return GetInterfaceFromRefObject<IAtspiEditableText>(self).AccessibilityCutText(startPosition, endPosition);
244 private static bool AccessibilityDeleteTextWrapper(IntPtr self, int startPosition, int endPosition)
246 return GetInterfaceFromRefObject<IAtspiEditableText>(self).AccessibilityDeleteText(startPosition, endPosition);
249 private static bool AccessibilityInsertTextWrapper(IntPtr self, int startPosition, IntPtr text)
251 return GetInterfaceFromRefObject<IAtspiEditableText>(self).AccessibilityInsertText(startPosition, Marshal.PtrToStringAnsi(text));
254 private static bool AccessibilitySetTextContentsWrapper(IntPtr self, IntPtr newContents)
256 return GetInterfaceFromRefObject<IAtspiEditableText>(self).AccessibilitySetTextContents(Marshal.PtrToStringAnsi(newContents));
260 // Selection interface
263 private static void InitializeAccessibilityDelegateSelectionInterface()
265 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
267 ad.ClearSelection = AccessibilityClearSelectionWrapper;
268 ad.DeselectChild = AccessibilityDeselectChildWrapper;
269 ad.DeselectSelectedChild = AccessibilityDeselectSelectedChildWrapper;
270 ad.GetSelectedChild = AccessibilityGetSelectedChildWrapper;
271 ad.GetSelectedChildrenCount = AccessibilityGetSelectedChildrenCountWrapper;
272 ad.IsChildSelected = AccessibilityIsChildSelectedWrapper;
273 ad.SelectAll = AccessibilitySelectAllWrapper;
274 ad.SelectChild = AccessibilitySelectChildWrapper;
277 private static bool AccessibilityClearSelectionWrapper(IntPtr self)
279 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityClearSelection();
282 private static bool AccessibilityDeselectChildWrapper(IntPtr self, int childIndex)
284 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityDeselectChild(childIndex);
287 private static bool AccessibilityDeselectSelectedChildWrapper(IntPtr self, int selectedChildIndex)
289 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityDeselectSelectedChild(selectedChildIndex);
292 private static IntPtr AccessibilityGetSelectedChildWrapper(IntPtr self, int selectedChildIndex)
294 View child = GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityGetSelectedChild(selectedChildIndex);
296 return View.getCPtr(child).Handle;
299 private static int AccessibilityGetSelectedChildrenCountWrapper(IntPtr self)
301 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityGetSelectedChildrenCount();
304 private static bool AccessibilityIsChildSelectedWrapper(IntPtr self, int childIndex)
306 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilityIsChildSelected(childIndex);
309 private static bool AccessibilitySelectAllWrapper(IntPtr self)
311 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilitySelectAll();
314 private static bool AccessibilitySelectChildWrapper(IntPtr self, int childIndex)
316 return GetInterfaceFromRefObject<IAtspiSelection>(self).AccessibilitySelectChild(childIndex);
323 private static void InitializeAccessibilityDelegateTextInterface()
325 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
327 ad.GetCharacterCount = AccessibilityGetCharacterCountWrapper;
328 ad.GetCursorOffset = AccessibilityGetCursorOffsetWrapper;
329 ad.GetRangeExtents = AccessibilityGetRangeExtentsWrapper;
330 ad.GetSelection = AccessibilityGetSelectionWrapper;
331 ad.GetText = AccessibilityGetTextWrapper;
332 ad.GetTextAtOffset = AccessibilityGetTextAtOffsetWrapper;
333 ad.RemoveSelection = AccessibilityRemoveSelectionWrapper;
334 ad.SetCursorOffset = AccessibilitySetCursorOffsetWrapper;
335 ad.SetSelection = AccessibilitySetSelectionWrapper;
338 private static int AccessibilityGetCharacterCountWrapper(IntPtr self)
340 return GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetCharacterCount();
343 private static int AccessibilityGetCursorOffsetWrapper(IntPtr self)
345 return GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetCursorOffset();
348 private static IntPtr AccessibilityGetRangeExtentsWrapper(IntPtr self, int startOffset, int endOffset, int coordType)
350 using Rectangle rect = GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetRangeExtents(startOffset, endOffset, (AccessibilityCoordinateType)coordType);
352 return DuplicateAccessibilityRectangle(rect);
355 private static IntPtr AccessibilityGetSelectionWrapper(IntPtr self, int selectionNumber)
357 AccessibilityRange range = GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetSelection(selectionNumber);
359 return DuplicateAccessibilityRange(range);
362 private static IntPtr AccessibilityGetTextWrapper(IntPtr self, int startOffset, int endOffset)
364 string text = GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetText(startOffset, endOffset);
366 return DuplicateString(text);
369 private static IntPtr AccessibilityGetTextAtOffsetWrapper(IntPtr self, int offset, int boundary)
371 AccessibilityRange range = GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityGetTextAtOffset(offset, (AccessibilityTextBoundary)boundary);
373 return DuplicateAccessibilityRange(range);
376 private static bool AccessibilityRemoveSelectionWrapper(IntPtr self, int selectionNumber)
378 return GetInterfaceFromRefObject<IAtspiText>(self).AccessibilityRemoveSelection(selectionNumber);
381 private static bool AccessibilitySetCursorOffsetWrapper(IntPtr self, int offset)
383 return GetInterfaceFromRefObject<IAtspiText>(self).AccessibilitySetCursorOffset(offset);
386 private static bool AccessibilitySetSelectionWrapper(IntPtr self, int selectionNumber, int startOffset, int endOffset)
388 return GetInterfaceFromRefObject<IAtspiText>(self).AccessibilitySetSelection(selectionNumber, startOffset, endOffset);
395 private static void InitializeAccessibilityDelegateValueInterface()
397 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
399 ad.GetCurrent = AccessibilityGetCurrentWrapper;
400 ad.GetMaximum = AccessibilityGetMaximumWrapper;
401 ad.GetMinimum = AccessibilityGetMinimumWrapper;
402 ad.GetMinimumIncrement = AccessibilityGetMinimumIncrementWrapper;
403 ad.GetValueText = AccessibilityGetValueTextWrapper;
404 ad.SetCurrent = AccessibilitySetCurrentWrapper;
407 private static double AccessibilityGetCurrentWrapper(IntPtr self)
409 return GetInterfaceFromRefObject<IAtspiValue>(self).AccessibilityGetCurrent();
412 private static double AccessibilityGetMaximumWrapper(IntPtr self)
414 return GetInterfaceFromRefObject<IAtspiValue>(self).AccessibilityGetMaximum();
417 private static double AccessibilityGetMinimumWrapper(IntPtr self)
419 return GetInterfaceFromRefObject<IAtspiValue>(self).AccessibilityGetMinimum();
422 private static double AccessibilityGetMinimumIncrementWrapper(IntPtr self)
424 return GetInterfaceFromRefObject<IAtspiValue>(self).AccessibilityGetMinimumIncrement();
427 private static IntPtr AccessibilityGetValueTextWrapper(IntPtr self)
429 var view = GetViewFromRefObject(self);
430 var value = GetInterfaceFromRefObject<IAtspiValue>(self);
433 // Mimic the behaviour of the pairs AccessibilityNameRequested & AccessibilityGetName(),
434 // and AccessibilityDescriptionRequested & AccessibilityGetDescription(),
435 // i.e. a higher-priority Accessibility[…]Requested event for application developers,
436 // and a lower-priority AccessibilityGet[…]() virtual method for component developers.
437 // The difference is that event-or-virtual-method dispatching is done in C++ for
438 // Name and Description, and here in this wrapper method for ValueText (because there
439 // is no signal for ValueText in DALi.)
440 if (view.AccessibilityValueTextRequested?.GetInvocationList().Length > 0)
442 var args = new AccessibilityValueTextRequestedEventArgs();
443 view.AccessibilityValueTextRequested.Invoke(view, args);
448 text = value.AccessibilityGetValueText();
451 return DuplicateString(text);
454 private static bool AccessibilitySetCurrentWrapper(IntPtr self, double value)
456 return GetInterfaceFromRefObject<IAtspiValue>(self).AccessibilitySetCurrent(value);
463 private static void InitializeAccessibilityDelegateTizenExtensions()
465 var ad = Interop.ControlDevel.AccessibilityDelegate.Instance;
467 ad.ScrollToChild = AccessibilityScrollToChildWrapper;
470 private static bool AccessibilityScrollToChildWrapper(IntPtr self, IntPtr child)
472 View view = GetViewFromRefObject(self);
474 return view.AccessibilityScrollToChild(view.GetInstanceSafely<View>(child));