@@ -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