// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Drawing; using Windows.Win32.System.Variant; using Windows.Win32.UI.Accessibility; namespace System.Windows.Forms; public partial class ComboBox { /// <summary> /// Represents the ComboBox child (inner) DropDown button accessible object with UI Automation functionality. /// </summary> internal sealed class ComboBoxChildDropDownButtonUiaProvider : AccessibleObject { private const int COMBOBOX_DROPDOWN_BUTTON_ACC_ITEM_INDEX = 2; // Made up constant from MSAA proxy. When MSAA proxy is used as an accessibility provider, the similar Runtime ID // is returned (for consistency purpose). private const int GeneratedRuntimeId = 61453; private readonly ComboBox _owner; /// <summary> /// Initializes new instance of ComboBoxChildDropDownButtonUiaProvider. /// </summary> /// <param name="owner">The owning ComboBox control.</param> public ComboBoxChildDropDownButtonUiaProvider(ComboBox owner) { _owner = owner; UseStdAccessibleObjects(owner.InternalHandle); } /// <inheritdoc/> /// <remarks> /// <para> /// "Open" or "Close" depending on the state of the DropDown. /// </para> /// </remarks> public override string Name => _owner.DroppedDown ? SR.ComboboxDropDownButtonCloseName : SR.ComboboxDropDownButtonOpenName; internal override bool CanGetNameInternal => false; public override unsafe Rectangle Bounds => SystemIAccessible.TryGetLocation(GetChildId()); public override string? DefaultAction => GetDefaultActionInternal().ToNullableStringAndFree(); private protected override bool IsInternal => true; internal override BSTR GetDefaultActionInternal() => SystemIAccessible.TryGetDefaultAction(GetChildId()); internal override IRawElementProviderFragment.Interface? FragmentNavigate(NavigateDirection direction) { if (!_owner.IsHandleCreated) { return null; } return direction switch { NavigateDirection.NavigateDirection_Parent => _owner.AccessibilityObject, NavigateDirection.NavigateDirection_PreviousSibling => _owner.DropDownStyle == ComboBoxStyle.DropDownList ? _owner.ChildTextAccessibleObject : _owner.ChildEditAccessibleObject, // We should return null for NextSibling because it is always the last item in the tree NavigateDirection.NavigateDirection_NextSibling => null, _ => base.FragmentNavigate(direction) }; } internal override IRawElementProviderFragmentRoot.Interface FragmentRoot => _owner.AccessibilityObject; internal override int GetChildId() => COMBOBOX_DROPDOWN_BUTTON_ACC_ITEM_INDEX; internal override VARIANT GetPropertyValue(UIA_PROPERTY_ID propertyID) => propertyID switch { UIA_PROPERTY_ID.UIA_ControlTypePropertyId => (VARIANT)(int)UIA_CONTROLTYPE_ID.UIA_ButtonControlTypeId, UIA_PROPERTY_ID.UIA_HasKeyboardFocusPropertyId => (VARIANT)_owner.Focused, UIA_PROPERTY_ID.UIA_IsEnabledPropertyId => (VARIANT)_owner.Enabled, UIA_PROPERTY_ID.UIA_IsKeyboardFocusablePropertyId => (VARIANT)State.HasFlag(AccessibleStates.Focusable), _ => base.GetPropertyValue(propertyID) }; public override string? Help => GetHelpInternal().ToNullableStringAndFree(); internal override BSTR GetHelpInternal() => SystemIAccessible.TryGetHelp(GetChildId()); public override string? KeyboardShortcut => GetKeyboardShortcutInternal((VARIANT)GetChildId()).ToNullableStringAndFree(); internal override BSTR GetKeyboardShortcutInternal(VARIANT childID) => SystemIAccessible.TryGetKeyboardShortcut(childID); internal override bool IsPatternSupported(UIA_PATTERN_ID patternId) => patternId switch { UIA_PATTERN_ID.UIA_LegacyIAccessiblePatternId or UIA_PATTERN_ID.UIA_InvokePatternId => true, _ => base.IsPatternSupported(patternId) }; public override AccessibleRole Role => SystemIAccessible.TryGetRole(GetChildId()); internal override int[] RuntimeId => [ RuntimeIDFirstItem, (int)_owner.InternalHandle, _owner.GetHashCode(), GeneratedRuntimeId, COMBOBOX_DROPDOWN_BUTTON_ACC_ITEM_INDEX ]; public override AccessibleStates State => SystemIAccessible.TryGetState(GetChildId()); } }