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
- PropertyCollection.cs
- MouseEventArgs.cs
- ModuleBuilderData.cs
- DataGridSortingEventArgs.cs
- Privilege.cs
- DocumentXmlWriter.cs
- SchemaSetCompiler.cs
- CallbackHandler.cs
- TextServicesContext.cs
- Transform3D.cs
- CompositeScriptReferenceEventArgs.cs
- SecurityDocument.cs
- KeyManager.cs
- CompositeFontParser.cs
- Preprocessor.cs
- Freezable.cs
- SafeLocalAllocation.cs
- SmiRecordBuffer.cs
- DispatcherProcessingDisabled.cs
- IndexedGlyphRun.cs
- COM2AboutBoxPropertyDescriptor.cs
- Tablet.cs
- sapiproxy.cs
- PreviewPrintController.cs
- HashCodeCombiner.cs
- RadioButtonStandardAdapter.cs
- DirectionalLight.cs
- ListViewAutomationPeer.cs
- DatatypeImplementation.cs
- RestClientProxyHandler.cs
- ValidatorCollection.cs
- CellLabel.cs
- CheckBoxField.cs
- KeyNotFoundException.cs
- IDReferencePropertyAttribute.cs
- ScriptHandlerFactory.cs
- BufferedStream.cs
- FeatureManager.cs
- SendMailErrorEventArgs.cs
- DataGridViewCellConverter.cs
- ListSortDescriptionCollection.cs
- ReferenceConverter.cs
- EmitterCache.cs
- PriorityQueue.cs
- HMACMD5.cs
- UpdateProgress.cs
- PolicyDesigner.cs
- DetailsViewDeletedEventArgs.cs
- RulePatternOps.cs
- XomlCompilerParameters.cs
- SqlNotificationRequest.cs
- ImageClickEventArgs.cs
- Metadata.cs
- DataIdProcessor.cs
- DoubleLinkList.cs
- CaseStatementSlot.cs
- DebugView.cs
- FontWeightConverter.cs
- ObjectStateFormatter.cs
- SystemEvents.cs
- BooleanExpr.cs
- Attribute.cs
- SessionStateSection.cs
- CallInfo.cs
- ContextToken.cs
- SuppressMergeCheckAttribute.cs
- NameObjectCollectionBase.cs
- TraceRecord.cs
- XmlValidatingReaderImpl.cs
- Receive.cs
- ReflectEventDescriptor.cs
- HttpResponseHeader.cs
- BufferedStream.cs
- Durable.cs
- bidPrivateBase.cs
- Package.cs
- ETagAttribute.cs
- DeflateInput.cs
- ObjectQueryProvider.cs
- NativeMethods.cs
- ConfigurationElement.cs
- JsonMessageEncoderFactory.cs
- OdbcConnectionStringbuilder.cs
- TemplateBindingExtensionConverter.cs
- CompilerGlobalScopeAttribute.cs
- Duration.cs
- RoleGroup.cs
- SchemaElementLookUpTable.cs
- OraclePermissionAttribute.cs
- IOException.cs
- SerializationEventsCache.cs
- WrapPanel.cs
- NumericUpDownAccelerationCollection.cs
- TemplateManager.cs
- _UriSyntax.cs
- BasicHttpBindingElement.cs
- PropertyKey.cs
- __ConsoleStream.cs
- FormViewInsertEventArgs.cs
- WebPartDescriptionCollection.cs