Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / UIAutomation / UIAutomationClient / MS / Internal / Automation / ClickablePoint.cs / 1 / ClickablePoint.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: Class to get a point that some can click on // // History: // 06/03/2003 : preid Created // //--------------------------------------------------------------------------- using System.Windows.Automation; using MS.Internal.Automation; using MS.Win32; using System; namespace System.Windows.Automation { static internal class ClickablePoint { //----------------------------------------------------- // // Public Methods // //----------------------------------------------------- #region Public Methods // We will not always find the clickable point. There are times when it would take so long // to locate the point that it is just not worth it, so make a reason effort than quit. public static bool HitTestForClickablePoint(AutomationElement el, out Point pt) { Rect rect = el.Current.BoundingRectangle; pt = new Point(0, 0); if (rect.Left >= rect.Right || rect.Top >= rect.Bottom) return false; // if this is not on any monitor than there is no point in going on. If the element is // off the screen hit testing actually works and would end up returning a point offscreen. NativeMethods.RECT winRect = new NativeMethods.RECT((int)rect.Left, (int)rect.Top, (int)rect.Height, (int)rect.Bottom); if (SafeNativeMethods.MonitorFromRect( ref winRect, SafeNativeMethods.MONITOR_DEFAULTTONULL ) == IntPtr.Zero) return false; // try the center point first pt = new Point((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2); AutomationElement hitElement; if ( TryPoint( ref pt, el, out hitElement ) ) return true; if ( IsTopLevelWindowObscuring( el, rect, hitElement ) ) return false; // before we start hit testing more there are some control types that we know where the // clickable point is or we know does not have a clickable point so take care of those here. if ( el.Current.ControlType == ControlType.ScrollBar ) return false; // Try the mid point of all four sides pt = new Point(rect.Left + (rect.Width /2), rect.Top + 1); if ( TryPoint( ref pt, el ) ) return true; pt = new Point(rect.Left + (rect.Width /2), rect.Bottom - 1); if ( TryPoint( ref pt, el ) ) return true; pt = new Point( rect.Left + 1, rect.Top + (rect.Height /2) ); if ( TryPoint( ref pt, el) ) return true; pt = new Point( rect.Right - 1, rect.Top + (rect.Height /2) ); if ( TryPoint( ref pt, el ) ) return true; if ( TrySparsePattern( out pt, ref rect, el ) ) return true; if ( TryLinePattern( out pt, ref rect, el ) ) return true; return false; } #endregion Public Methods //------------------------------------------------------ // // Private Methods // //----------------------------------------------------- #region Private Methods // Go from the top left on a diagonal the lower right but don't do more than 25 hits private static bool TryLinePattern( out Point pt, ref Rect rect, AutomationElement el) { double x = rect.Left + 1; double y = rect.Top + 1; int hits; // Adjust the number of hits we do based on how big something is Double size = rect.Width * rect.Height; if ( size < 2500 ) hits = 10; else if ( size < 20000 ) hits = 18; else hits = 25; double xIncr = rect.Width / hits; double yIncr = rect.Height / hits; for ( int i = 0; i < hits; i++) { pt = new Point(x, y); if ( TryPoint( ref pt, el ) ) return true; x += xIncr; y += yIncr; } pt = new Point(0, 0); return false; } // Hit test in a fairly uniform pattern like a grid adjusting the spacing based on the // size of element. Don't more than about 25 hits. private static bool TrySparsePattern( out Point pt, ref Rect rect, AutomationElement el) { int hits; // Adjust the number of hits we do based on how big somting is Double size = rect.Width * rect.Height; if ( size < 2500 ) hits = 3; else if ( size < 20000 ) hits = 4; else hits = 5; // make the scatter pattern fit the proportions of the rect double xHits = hits * (rect.Width / rect.Height); double yHits = hits * (rect.Height / rect.Width); double xMovePixels = rect.Width / xHits; double yMovePixels = rect.Height / yHits; return TryPattern( xMovePixels, yMovePixels, out pt, ref rect, el ); } // this goes across the rect in icrements of x pixels and the down y pixels and across again... private static bool TryPattern(double x, double y, out Point pt, ref Rect rect, AutomationElement el ) { for ( double down = rect.Top + y; down < rect.Bottom; down += y ) { for ( double across = rect.Left + x; across < rect.Right; across += x ) { pt = new Point(across, down); if ( TryPoint(ref pt, el) ) return true; } } pt = new Point(0, 0); return false; } private static bool TryPoint( ref Point pt, AutomationElement el ) { AutomationElement hitEl; return TryPoint( ref pt, el, out hitEl ); } private static bool TryPoint( ref Point pt, AutomationElement el, out AutomationElement hitEl ) { // If the element is obscured by another window or hidden somehow when we try to hit test we don't get back // the same element. We want to make sure if someone clicks they click on what they expected to click on. hitEl = AutomationElement.FromPoint(pt); return hitEl == el; } // figure out if there is a top level window totally obscuring the element. If that is the case // there is not point in going on. This code assumes that toplevel windows are rects and that // everything in that rect covers up what is underneath. private static bool IsTopLevelWindowObscuring( AutomationElement target, Rect targetRect, AutomationElement hitTarget) { // get the toplevel window for the element that we hit on our first try and the element the we are // trying to find a clickable point for. If they are part of the same top level hwnd than there is // no toplevel window obscuring this element. // There is a rather strange case that can occur with apps like media player where the // hitTarget could be something underneth the element. In this case zorder might be something to // check but this is hwnd specific it may be better for the provider to provide a clickable point. AutomationElement hitTargetAncestor = GetTopLevelAncestor(hitTarget); if ( GetTopLevelAncestor(target) == hitTargetAncestor || hitTargetAncestor == null ) return false; // If this toplevel widow completely covers the element than we are obscured. Rect hitTargetAncestorRect = hitTargetAncestor.Current.BoundingRectangle; if (hitTargetAncestorRect.Contains( targetRect ) ) return true; return false; } private static AutomationElement GetTopLevelAncestor( AutomationElement target ) { AutomationElement root = AutomationElement.RootElement; AutomationElement targetAncestor = null; while (target != root) { targetAncestor = target; target = TreeWalker.ControlViewWalker.GetParent( target ); } return targetAncestor; } } #endregion Private Methods } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: Class to get a point that some can click on // // History: // 06/03/2003 : preid Created // //--------------------------------------------------------------------------- using System.Windows.Automation; using MS.Internal.Automation; using MS.Win32; using System; namespace System.Windows.Automation { static internal class ClickablePoint { //----------------------------------------------------- // // Public Methods // //----------------------------------------------------- #region Public Methods // We will not always find the clickable point. There are times when it would take so long // to locate the point that it is just not worth it, so make a reason effort than quit. public static bool HitTestForClickablePoint(AutomationElement el, out Point pt) { Rect rect = el.Current.BoundingRectangle; pt = new Point(0, 0); if (rect.Left >= rect.Right || rect.Top >= rect.Bottom) return false; // if this is not on any monitor than there is no point in going on. If the element is // off the screen hit testing actually works and would end up returning a point offscreen. NativeMethods.RECT winRect = new NativeMethods.RECT((int)rect.Left, (int)rect.Top, (int)rect.Height, (int)rect.Bottom); if (SafeNativeMethods.MonitorFromRect( ref winRect, SafeNativeMethods.MONITOR_DEFAULTTONULL ) == IntPtr.Zero) return false; // try the center point first pt = new Point((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2); AutomationElement hitElement; if ( TryPoint( ref pt, el, out hitElement ) ) return true; if ( IsTopLevelWindowObscuring( el, rect, hitElement ) ) return false; // before we start hit testing more there are some control types that we know where the // clickable point is or we know does not have a clickable point so take care of those here. if ( el.Current.ControlType == ControlType.ScrollBar ) return false; // Try the mid point of all four sides pt = new Point(rect.Left + (rect.Width /2), rect.Top + 1); if ( TryPoint( ref pt, el ) ) return true; pt = new Point(rect.Left + (rect.Width /2), rect.Bottom - 1); if ( TryPoint( ref pt, el ) ) return true; pt = new Point( rect.Left + 1, rect.Top + (rect.Height /2) ); if ( TryPoint( ref pt, el) ) return true; pt = new Point( rect.Right - 1, rect.Top + (rect.Height /2) ); if ( TryPoint( ref pt, el ) ) return true; if ( TrySparsePattern( out pt, ref rect, el ) ) return true; if ( TryLinePattern( out pt, ref rect, el ) ) return true; return false; } #endregion Public Methods //------------------------------------------------------ // // Private Methods // //----------------------------------------------------- #region Private Methods // Go from the top left on a diagonal the lower right but don't do more than 25 hits private static bool TryLinePattern( out Point pt, ref Rect rect, AutomationElement el) { double x = rect.Left + 1; double y = rect.Top + 1; int hits; // Adjust the number of hits we do based on how big something is Double size = rect.Width * rect.Height; if ( size < 2500 ) hits = 10; else if ( size < 20000 ) hits = 18; else hits = 25; double xIncr = rect.Width / hits; double yIncr = rect.Height / hits; for ( int i = 0; i < hits; i++) { pt = new Point(x, y); if ( TryPoint( ref pt, el ) ) return true; x += xIncr; y += yIncr; } pt = new Point(0, 0); return false; } // Hit test in a fairly uniform pattern like a grid adjusting the spacing based on the // size of element. Don't more than about 25 hits. private static bool TrySparsePattern( out Point pt, ref Rect rect, AutomationElement el) { int hits; // Adjust the number of hits we do based on how big somting is Double size = rect.Width * rect.Height; if ( size < 2500 ) hits = 3; else if ( size < 20000 ) hits = 4; else hits = 5; // make the scatter pattern fit the proportions of the rect double xHits = hits * (rect.Width / rect.Height); double yHits = hits * (rect.Height / rect.Width); double xMovePixels = rect.Width / xHits; double yMovePixels = rect.Height / yHits; return TryPattern( xMovePixels, yMovePixels, out pt, ref rect, el ); } // this goes across the rect in icrements of x pixels and the down y pixels and across again... private static bool TryPattern(double x, double y, out Point pt, ref Rect rect, AutomationElement el ) { for ( double down = rect.Top + y; down < rect.Bottom; down += y ) { for ( double across = rect.Left + x; across < rect.Right; across += x ) { pt = new Point(across, down); if ( TryPoint(ref pt, el) ) return true; } } pt = new Point(0, 0); return false; } private static bool TryPoint( ref Point pt, AutomationElement el ) { AutomationElement hitEl; return TryPoint( ref pt, el, out hitEl ); } private static bool TryPoint( ref Point pt, AutomationElement el, out AutomationElement hitEl ) { // If the element is obscured by another window or hidden somehow when we try to hit test we don't get back // the same element. We want to make sure if someone clicks they click on what they expected to click on. hitEl = AutomationElement.FromPoint(pt); return hitEl == el; } // figure out if there is a top level window totally obscuring the element. If that is the case // there is not point in going on. This code assumes that toplevel windows are rects and that // everything in that rect covers up what is underneath. private static bool IsTopLevelWindowObscuring( AutomationElement target, Rect targetRect, AutomationElement hitTarget) { // get the toplevel window for the element that we hit on our first try and the element the we are // trying to find a clickable point for. If they are part of the same top level hwnd than there is // no toplevel window obscuring this element. // There is a rather strange case that can occur with apps like media player where the // hitTarget could be something underneth the element. In this case zorder might be something to // check but this is hwnd specific it may be better for the provider to provide a clickable point. AutomationElement hitTargetAncestor = GetTopLevelAncestor(hitTarget); if ( GetTopLevelAncestor(target) == hitTargetAncestor || hitTargetAncestor == null ) return false; // If this toplevel widow completely covers the element than we are obscured. Rect hitTargetAncestorRect = hitTargetAncestor.Current.BoundingRectangle; if (hitTargetAncestorRect.Contains( targetRect ) ) return true; return false; } private static AutomationElement GetTopLevelAncestor( AutomationElement target ) { AutomationElement root = AutomationElement.RootElement; AutomationElement targetAncestor = null; while (target != root) { targetAncestor = target; target = TreeWalker.ControlViewWalker.GetParent( target ); } return targetAncestor; } } #endregion Private Methods } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SafeHandles.cs
- ParamArrayAttribute.cs
- Point3DAnimationBase.cs
- XsltSettings.cs
- Baml2006ReaderSettings.cs
- TextWriter.cs
- InsufficientMemoryException.cs
- SqlPersonalizationProvider.cs
- CurrencyManager.cs
- UpdateInfo.cs
- CustomBindingCollectionElement.cs
- TextParaClient.cs
- AppDomainFactory.cs
- TypeForwardedToAttribute.cs
- PersonalizationProviderCollection.cs
- HttpHandlerAction.cs
- Models.cs
- EntityConnectionStringBuilder.cs
- CompilerWrapper.cs
- DataSourceHelper.cs
- AssemblyName.cs
- DynamicDocumentPaginator.cs
- NamedObject.cs
- DeleteMemberBinder.cs
- DecoderBestFitFallback.cs
- ArrayConverter.cs
- DiagnosticTrace.cs
- OleDbCommand.cs
- Matrix3DValueSerializer.cs
- UserMapPath.cs
- FrameworkRichTextComposition.cs
- Transform.cs
- ToolboxItemCollection.cs
- StorageAssociationSetMapping.cs
- iisPickupDirectory.cs
- PagedDataSource.cs
- SHA256Managed.cs
- Stroke2.cs
- AnnotationService.cs
- SingleConverter.cs
- FileCodeGroup.cs
- RayMeshGeometry3DHitTestResult.cs
- TextContainerChangeEventArgs.cs
- TableCellAutomationPeer.cs
- EntityTypeEmitter.cs
- MarginsConverter.cs
- X509RecipientCertificateClientElement.cs
- TransportSecurityBindingElement.cs
- ProtocolsConfigurationHandler.cs
- XsltException.cs
- EDesignUtil.cs
- HtmlEncodedRawTextWriter.cs
- StateDesignerConnector.cs
- PeerApplicationLaunchInfo.cs
- QilXmlWriter.cs
- WindowsButton.cs
- InvalidWMPVersionException.cs
- EdmMember.cs
- TextTreeTextBlock.cs
- ToolStripGripRenderEventArgs.cs
- OleDbException.cs
- _CookieModule.cs
- RemotingClientProxy.cs
- RtType.cs
- BitmapFrame.cs
- DLinqAssociationProvider.cs
- _SpnDictionary.cs
- AccessibleObject.cs
- Base64Decoder.cs
- AudioDeviceOut.cs
- XmlSchemaImport.cs
- EntitySqlQueryCacheEntry.cs
- XslAstAnalyzer.cs
- AttributeCollection.cs
- XmlNamespaceDeclarationsAttribute.cs
- Property.cs
- MatchingStyle.cs
- UICuesEvent.cs
- XmlCountingReader.cs
- FixedElement.cs
- PlatformCulture.cs
- ValidationError.cs
- SoapInteropTypes.cs
- BindingGraph.cs
- XmlSchemaComplexContentExtension.cs
- CodeTypeConstructor.cs
- PhysicalFontFamily.cs
- QueryExpr.cs
- PropertyIDSet.cs
- RefreshEventArgs.cs
- SupportsEventValidationAttribute.cs
- DebugView.cs
- FlowDocumentScrollViewer.cs
- ControlOperationInvoker.cs
- BulletedList.cs
- KeyBinding.cs
- _NTAuthentication.cs
- WindowsListView.cs
- PreviewPrintController.cs
- SortQuery.cs