File: MS\Internal\AutomationProxies\WindowsAltTab.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\UIAutomation\UIAutomationClientSideProviders\UIAutomationClientSideProviders.csproj (UIAutomationClientSideProviders)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
// Description: HWND-based Alt-Tab (Task Switch) Window Proxy
 
// PRESHARP: In order to avoid generating warnings about unknown message numbers and unknown pragmas.
#pragma warning disable 1634, 1691
 
using System;
using System.Collections;
using System.Globalization;
using System.Text;
using System.ComponentModel;
using Accessibility;
using System.Windows.Automation.Provider;
using System.Windows.Automation;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using MS.Win32;
 
namespace MS.Internal.AutomationProxies
{
    // This class represents the Alt-Tab (task switch) window.
    class WindowsAltTab : ProxyHwnd
    {
        // ------------------------------------------------------
        //
        // Constructors
        //
        // ------------------------------------------------------
 
        #region Constructors
 
        internal WindowsAltTab(IntPtr hwnd, ProxyFragment parent, int item)
            : base(hwnd, parent, item)
        {
            _fIsKeyboardFocusable = true;
            _cControlType = ControlType.List;
 
            // support for events
            _createOnEvent = new WinEventTracker.ProxyRaiseEvents(RaiseEvents);
 
            GetAltTabInfo(_hwnd, 0, ref _altTabInfo, null);
        }
 
        #endregion
 
        #region Proxy Create
 
        // Static Create method called by UIAutomation to create this proxy.
        // returns null if unsuccessful
        internal static IRawElementProviderSimple Create(IntPtr hwnd, int idChild, int idObject)
        {
            return Create(hwnd, idChild);
        }
 
        internal static IRawElementProviderSimple Create(IntPtr hwnd, int idChild)
        {
            IRawElementProviderSimple rawElementProviderSimple = null;
            try
            {
                ProxyFragment parent = null;
 
                WindowsAltTab altTab = new WindowsAltTab(hwnd, parent, 0);
                if (idChild == 0)
                {
                    rawElementProviderSimple = altTab;
                }
                else
                {
                    rawElementProviderSimple = altTab.CreateAltTabItem(idChild - 1);
                }
            }
            catch (ElementNotAvailableException)
            {
                rawElementProviderSimple = null;
            }
 
            return rawElementProviderSimple;
        }
 
        // Static Create method called by the event tracker system
        internal static void RaiseEvents (IntPtr hwnd, int eventId, object idProp, int idObject, int idChild)
        {
            if (idObject != NativeMethods.OBJID_VSCROLL && idObject != NativeMethods.OBJID_HSCROLL)
            {
                ProxySimple el = (ProxyHwnd) WindowsAltTab.Create(hwnd, 0);
                if (el != null)
                {
                    el.DispatchEvents(eventId, idProp, idObject, idChild);
                }
            }
        }
 
        #endregion
 
        //------------------------------------------------------
        //
        //  ProxyFragment Overrides
        //
        //------------------------------------------------------
 
        #region ProxyFragment Overrides
 
        // Returns the next sibling element in the raw hierarchy.
        internal override ProxySimple GetNextSibling(ProxySimple child)
        {
            return CreateAltTabItem(child._item + 1);
        }
 
        // Returns the previous sibling element in the raw hierarchy.
        internal override ProxySimple GetPreviousSibling(ProxySimple child)
        {
            return CreateAltTabItem(child._item - 1);
        }
 
        // Returns the first child element in the raw hierarchy.
        internal override ProxySimple GetFirstChild()
        {
            return CreateAltTabItem(0);
        }
 
        // Returns the last child element in the raw hierarchy.
        internal override ProxySimple GetLastChild()
        {
            return CreateAltTabItem(Count - 1);
        }
 
        // Returns a Proxy element corresponding to the specified screen coordinates.
        internal override ProxySimple ElementProviderFromPoint(int x, int y)
        {
            ProxySimple proxyElement = null;
 
            // Convert screen to client coords.
            NativeMethods.Win32Point pt = new NativeMethods.Win32Point(x, y);
            if (Misc.MapWindowPoints(System.IntPtr.Zero, _hwnd, ref pt, 1))
            {
                // GetClientRect
                NativeMethods.Win32Rect clientRect = new NativeMethods.Win32Rect();
                if(Misc.GetClientRect(_hwnd, ref clientRect))
                {
                    if (Misc.PtInRect(ref clientRect, pt.x, pt.y))
                    {
                        int column = (pt.x - _altTabInfo.ptStart.x) / _altTabInfo.cxItem;
                        int row = (pt.y - _altTabInfo.ptStart.y) / _altTabInfo.cyItem;
                        if (column >= 0 && column < Columns && row >= 0 && row < Rows)
                        {
                            proxyElement = CreateAltTabItem(ItemIndex(row, column));
                        }
                    }
                }
            }
            if (proxyElement == null)
            {
                proxyElement = base.ElementProviderFromPoint(x, y);
            }
 
 
            return proxyElement;
        }
 
        // Returns an item corresponding to the focused element (if there is one), 
        // or null otherwise.
        internal override ProxySimple GetFocus()
        {
            ProxySimple focus = this;
            int focusIndex = FocusIndex;
            if (focusIndex >= 0)
            {
                focus = CreateAltTabItem(focusIndex);
            }
            return focus;
        }
 
        #endregion
 
 
        // ------------------------------------------------------
        //
        // Protected Methods
        //
        // ------------------------------------------------------
 
        #region Protected Methods
        #endregion
 
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        // Creates an alt-tab item.
        private ProxySimple CreateAltTabItem(int item)
        {
            ProxySimple altTabItem = null;
            if (item >= 0 && item < this.Count)
            {
                altTabItem = new WindowsAltTabItem(_hwnd, this, item);
            }
            return altTabItem;
        }
 
        // Get the 0-based index of an item from its row and column.
        private int ItemIndex(int row, int column)
        {
            return row * Columns + column;
        }
 
        // Get the index of the currently focused item (-1 if none).
        private int FocusIndex
        {
            get
            {
                int focusItem = -1;
                UnsafeNativeMethods.ALTTABINFO altTabInfo =
                    new UnsafeNativeMethods.ALTTABINFO();
                if (GetAltTabInfo(_hwnd, -1, ref altTabInfo, null))
                {
                    focusItem =
                        altTabInfo.iRowFocus * altTabInfo.cColumns + altTabInfo.iColFocus;
                }
                return focusItem;
            }
        }
 
        #endregion
 
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        // To get itemText, set item to the item index (or -1 otherwise).
        // Returns true for success.
        internal static bool
            GetAltTabInfo(IntPtr hwnd, int item,
                            ref UnsafeNativeMethods.ALTTABINFO altTabInfo,
                            StringBuilder itemText)
        {
            altTabInfo.cbSize = (uint)Marshal.SizeOf(typeof(UnsafeNativeMethods.ALTTABINFO));
            uint cchItemText = 0;
            if (itemText != null)
            {
                cchItemText = (uint)itemText.Capacity;
            }
            bool result =
                UnsafeNativeMethods.GetAltTabInfo(
                    hwnd, item, ref altTabInfo, itemText, (uint)cchItemText);
 
            int lastWin32Error = Marshal.GetLastWin32Error();
            if (!result)
            {
                Misc.ThrowWin32ExceptionsIfError(lastWin32Error);
            }
            return result;
        }
 
        #endregion
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
        #region Private Fields
 
        private const int MaxItemNameLength = 1000;
 
        // Note this is only used for "stable" state;
        // iRow/ColFocus should always be fetched "fresh".
        private UnsafeNativeMethods.ALTTABINFO _altTabInfo =
            new UnsafeNativeMethods.ALTTABINFO();
 
        private int Rows
        {
            get
            {
                return _altTabInfo.cRows;
            }
        }
 
        private int Columns
        {
            get
            {
                return _altTabInfo.cColumns;
            }
        }
 
        private int Count
        {
            get
            {
                return _altTabInfo.cItems;
            }
        }
 
        #endregion
 
        // ------------------------------------------------------
        //
        //  WindowsAltTabItem Private Class
        //
        //------------------------------------------------------
 
        #region WindowsAltTabItem
 
        // Proxy class for an entry in the Alt-Tab window, representing
        // a single running program.
        class WindowsAltTabItem : ProxySimple
        {
            // ------------------------------------------------------
            //
            // Constructors
            //
            // ------------------------------------------------------
 
            #region Constructors
 
            // Constructor.
            internal WindowsAltTabItem(IntPtr hwnd, WindowsAltTab parent, int item)
                : base(hwnd, parent, item)
            {
                _cControlType = ControlType.ListItem;
                _fIsKeyboardFocusable = true;
                _altTab = parent;
            }
 
            #endregion
 
            //------------------------------------------------------
            //
            //  Patterns Implementation
            //
            //------------------------------------------------------
 
            #region ProxySimple Interface
 
            // Gets the bounding rectangle for this element.
            internal override Rect BoundingRectangle
            {
                get
                {
                    return GetBoundingRect().ToRect(Misc.IsControlRTL(_hwnd));
                }
            }
 
            // Returns the text of the alt-tab item.
            internal override string LocalizedName
            {
                get
                {
                    UnsafeNativeMethods.ALTTABINFO altTabInfo =
                        new UnsafeNativeMethods.ALTTABINFO();
                    String localizedName = String.Empty;
                    StringBuilder itemText = new StringBuilder(WindowsAltTab.MaxItemNameLength);
                    if (WindowsAltTab.GetAltTabInfo(_hwnd, _item, ref altTabInfo, itemText))
                    {
                        localizedName = itemText.ToString();
                    }
                    return localizedName;
                }
            }
 
            #endregion
 
            //------------------------------------------------------
            //
            //  Private Methods
            //
            //------------------------------------------------------
 
            #region Private Methods
 
            private NativeMethods.Win32Rect GetBoundingRect()
            {
                int columns = this._altTab._altTabInfo.cColumns;
                int cxItem = this._altTab._altTabInfo.cxItem;
                int cyItem = this._altTab._altTabInfo.cyItem;
                int row = _item / columns;
                int column = _item % columns;
                NativeMethods.Win32Point ptStart = this._altTab._altTabInfo.ptStart;
 
                int left = ptStart.x + column * cxItem;
                int top = ptStart.y + row * cyItem;
                NativeMethods.Win32Rect itemRect =
                    new NativeMethods.Win32Rect(left, top, left + cxItem, top + cyItem);
 
                if(!Misc.MapWindowPoints(_hwnd, IntPtr.Zero, ref itemRect, 2))
                {
                    // MapWindowPoints() failed.
                    itemRect = NativeMethods.Win32Rect.Empty;
                }
                return itemRect;
            }
 
            #endregion
 
            //------------------------------------------------------
            //
            //  Private Fields
            //
            //------------------------------------------------------
            #region Private Fields
 
            private WindowsAltTab _altTab;
 
            #endregion
        }
 
        #endregion
    }
}