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
- InnerItemCollectionView.cs
- SoundPlayerAction.cs
- DataSourceNameHandler.cs
- SizeLimitedCache.cs
- WpfKnownType.cs
- UserControl.cs
- OracleRowUpdatedEventArgs.cs
- InternalConfigRoot.cs
- DisplayNameAttribute.cs
- PresentationAppDomainManager.cs
- ObjectDisposedException.cs
- QuaternionAnimationBase.cs
- Ref.cs
- Matrix.cs
- StoragePropertyMapping.cs
- OperatorExpressions.cs
- ListViewGroupItemCollection.cs
- ClientCultureInfo.cs
- webeventbuffer.cs
- ItemChangedEventArgs.cs
- HwndSourceParameters.cs
- XmlCharCheckingReader.cs
- FileStream.cs
- SHA512.cs
- X509Certificate.cs
- ToolBarButton.cs
- Token.cs
- LoginName.cs
- Geometry3D.cs
- RotateTransform3D.cs
- ConsumerConnectionPoint.cs
- ComponentEvent.cs
- XmlSchemaAttributeGroup.cs
- ResourcePart.cs
- PackWebRequestFactory.cs
- AdPostCacheSubstitution.cs
- ExpressionVisitorHelpers.cs
- TagNameToTypeMapper.cs
- HtmlInputImage.cs
- TextContainerChangeEventArgs.cs
- IsolatedStorageException.cs
- unsafeIndexingFilterStream.cs
- Visual.cs
- ITreeGenerator.cs
- WriteableBitmap.cs
- DBDataPermission.cs
- FreezableCollection.cs
- PropertyIDSet.cs
- dataobject.cs
- SyndicationLink.cs
- KeyValuePairs.cs
- EventArgs.cs
- GlobalItem.cs
- ItemContainerGenerator.cs
- MLangCodePageEncoding.cs
- ProcessHostConfigUtils.cs
- ArrangedElementCollection.cs
- DiscoveryEndpointValidator.cs
- StreamInfo.cs
- CustomUserNameSecurityTokenAuthenticator.cs
- ResolveDuplexCD1AsyncResult.cs
- DeclarativeCatalogPart.cs
- KnownBoxes.cs
- Exceptions.cs
- CellParagraph.cs
- BooleanSwitch.cs
- StaticExtension.cs
- WindowsAuthenticationModule.cs
- SqlConnectionPoolProviderInfo.cs
- PointAnimationUsingPath.cs
- ServerValidateEventArgs.cs
- XmlRootAttribute.cs
- IsolatedStorageFile.cs
- SchemaCollectionCompiler.cs
- ByeMessageApril2005.cs
- VirtualPathProvider.cs
- StdValidatorsAndConverters.cs
- WithStatement.cs
- MethodBuilder.cs
- nulltextcontainer.cs
- ToolBar.cs
- UshortList2.cs
- NodeFunctions.cs
- RadialGradientBrush.cs
- ValueType.cs
- PolicyException.cs
- StopStoryboard.cs
- CompilerGlobalScopeAttribute.cs
- FixedDocumentPaginator.cs
- DrawItemEvent.cs
- GeneralTransform.cs
- RequestCacheManager.cs
- QilReference.cs
- HttpCapabilitiesEvaluator.cs
- GridViewCancelEditEventArgs.cs
- XmlSerializer.cs
- Tuple.cs
- ReadOnlyHierarchicalDataSource.cs
- SourceFileBuildProvider.cs
- AtomServiceDocumentSerializer.cs