Skip to content

Commit 14a1e0e

Browse files
SamBentlindexi
authored andcommitted
use unscaled mouse coordintes for convex hull test (#6332)
dotnet/wpf#6332
1 parent 88ea4c0 commit 14a1e0e

File tree

1 file changed

+48
-31
lines changed

1 file changed

+48
-31
lines changed

src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/PopupControlService.cs

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,39 +1558,56 @@ private void AddPoints(PointList points, in NativeMethods.RECT rect, bool rectIs
15581558
// Test whether the current mouse point lies within the convex hull
15591559
internal bool ContainsMousePoint()
15601560
{
1561-
IInputElement rootElement = _source.RootVisual as IInputElement;
1562-
if (rootElement != null)
1561+
// get the coordinates of the current mouse point, relative to the Active source
1562+
PresentationSource mouseSource = Mouse.PrimaryDevice.CriticalActiveSource;
1563+
System.Windows.Point pt = Mouse.PrimaryDevice.NonRelativePosition;
1564+
1565+
// translate the point to our source's coordinates, if necessary
1566+
// (e.g. if the tooltip's owner comes from a window with capture,
1567+
// such as the popup of a ComboBox)
1568+
if (mouseSource != _source)
15631569
{
1564-
// get the coordinates of the current mouse point, relative to our PresentationSource
1565-
System.Windows.Point pt = Mouse.PrimaryDevice.GetPosition(rootElement);
1566-
1567-
// check whether the point lies within the hull
1568-
return ContainsPoint(_source, (int)pt.X, (int)pt.Y);
1569-
1570-
// NOTE: GetPosition doesn't actually return the position of the current mouse point,
1571-
// but rather the last recorded position. (See MouseDevice.GetScreenPositionFromSystem,
1572-
// which says that "Win32 has issues reliably returning where the mouse is".)
1573-
// This causes a small problem when (a) the PresentationSource has capture, e.g.
1574-
// the popup of a ComboBox, and (b) the mouse moves to a position that lies outside both the
1575-
// capturing PresentationSource (popup window) and the input-providing PresentationSource
1576-
// (main window). The MouseDevice only records positions within the input-providing
1577-
// PresentationSource, so we'll test the position where the mouse left the main window,
1578-
// rather than the current position.
1579-
// This means we may leave a tooltip open even when the mouse leaves its SafeArea,
1580-
// but only when the tooltip belongs to a capturing source, and the "leaving the SafeArea"
1581-
// action occurs outside the surrounding main window. For our example, it can happen
1582-
// when the ComboBox is close to the edge of the main window so that a tooltip from its
1583-
// popup content extends beyond the main window.
1584-
// This can only be fixed by changing MouseDevice.GetScreenPositionFromSystem to
1585-
// use a "better way" to find the current mouse position, which allegedly needs work from the OS.
1586-
// But we can live with this behavior, because
1587-
// * this is a corner case - tooltips from popup content that extend beyond the main window
1588-
// * the effect is transient - the tooltip will close when the user dismisses the popup
1589-
// * there's no accessibility issue - WCAG 2.1 only requires that the tooltip stays open under
1590-
// proscribed conditions, not that it has to close when the conditions cease to apply
1570+
System.Windows.Point ptScreen = PointUtil.ClientToScreen(pt, mouseSource);
1571+
pt = PointUtil.ScreenToClient(ptScreen, _source);
15911572
}
1592-
else
1593-
return false;
1573+
1574+
#if DEBUG
1575+
// NonRelativePosition returns the mouse point in unscaled screen coords, relative
1576+
// to the active window's client area (despite the name).
1577+
// Compute the point a different way, and check that it agrees. The second
1578+
// way uses public API, but in our case ends up doing a lot of transforms
1579+
// and multiplications that should simply cancel each other out.
1580+
System.Windows.Interop.HwndSource hwndSource = _source as System.Windows.Interop.HwndSource;
1581+
IInputElement rootElement = hwndSource?.RootVisual as IInputElement;
1582+
Debug.Assert(hwndSource != null && rootElement != null, "expect non-null hwndSource and rootElement");
1583+
System.Windows.Point pt2 = hwndSource.TransformToDevice(Mouse.PrimaryDevice.GetPosition(rootElement));
1584+
Debug.Assert(((int)pt.X == (int)Math.Round(pt2.X)) && ((int)pt.Y == (int)Math.Round(pt2.Y)), "got incorrect mouse point");
1585+
#endif
1586+
1587+
// check whether the point lies within the hull
1588+
return ContainsPoint(_source, (int)pt.X, (int)pt.Y);
1589+
1590+
// NOTE: NonRelativePosition doesn't actually return the position of the current mouse point,
1591+
// but rather the last recorded position. (See MouseDevice.GetScreenPositionFromSystem,
1592+
// which says that "Win32 has issues reliably returning where the mouse is".)
1593+
// This causes a small problem when (a) the PresentationSource has capture, e.g.
1594+
// the popup of a ComboBox, and (b) the mouse moves to a position that lies outside both the
1595+
// capturing PresentationSource (popup window) and the input-providing PresentationSource
1596+
// (main window). The MouseDevice only records positions within the input-providing
1597+
// PresentationSource, so we'll test the position where the mouse left the main window,
1598+
// rather than the current position.
1599+
// This means we may leave a tooltip open even when the mouse leaves its SafeArea,
1600+
// but only when the tooltip belongs to a capturing source, and the "leaving the SafeArea"
1601+
// action occurs outside the surrounding main window. For our example, it can happen
1602+
// when the ComboBox is close to the edge of the main window so that a tooltip from its
1603+
// popup content extends beyond the main window.
1604+
// This can only be fixed by changing MouseDevice.GetScreenPositionFromSystem to
1605+
// use a "better way" to find the current mouse position, which allegedly needs work from the OS.
1606+
// But we can live with this behavior, because
1607+
// * this is a corner case - tooltips from popup content that extend beyond the main window
1608+
// * the effect is transient - the tooltip will close when the user dismisses the popup
1609+
// * there's no accessibility issue - WCAG 2.1 only requires that the tooltip stays open under
1610+
// proscribed conditions, not that it has to close when the conditions cease to apply
15941611
}
15951612

15961613
// Test whether a given mouse point (x,y) lies within the convex hull

0 commit comments

Comments
 (0)