Get the ElementFromPoint (IUIAutomation) from the 2nd scaled monitor

youki 996 Reputation points
2021-11-27T12:04:38.343+00:00

Hello,
I'm getting the wrong IUIAutomation element from the 2nd monitor, if use it in a browser window like edge (which is not the main monitor and has a dpi for i.e. 125% in the windows settings.)
I tried a few things and can't find a working solution.

The following is not working (they are all far above the element under the mouse cursor):

  • GetCursorPos
  • GetPhysicalCursorPos
  • Mousehook (hookStruct.pt.X + " "+ hookStruct.pt.Y)
  • PhysicalToLogicalPointForPerMonitorDPI (don't understand how i could get the cursor position since i'm getting the window's data?!)

I've read:
https://learn.microsoft.com/en-us/dotnet/framework/ui-automation/ui-automation-and-screen-scaling
https://support.microsoft.com/en-us/topic/windows-scaling-issues-for-high-dpi-devices-508483cd-7c59-0d08-12b0-960b99aa347d

It's not supported by a method, so i have to calculate it by myself after getting GetCursorPos?! (Getting the dpi, the monitor bounds to offset it against the GetCursorPos.)

[...and while i'm asking, i'm reading that it could be working by SetThreadDpiAwarenessContext function? (because it looks really weird, if my form's dpiAwareness is true). ------ FAILED]

EDIT: I also tried to get the dpi and monitor bounds for calculating it by the following example (gives me really weird data) :

https://stackoverflow.com/questions/29438430/how-to-get-dpi-scale-for-all-screens

Isn't there a solution for just getting the set dpi from the windows settings for the specific monitor and simply calculating the right cursor position for finding the element?!

Regards

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,265 questions
0 comments No comments
{count} votes

7 answers

Sort by: Most helpful
  1. youki 996 Reputation points
    2021-11-28T00:33:41.07+00:00

    Ok,
    tested (also with inspect.exe) and read the whole day/night and it doesn't work. Could it be that this is not supported by UIA (the different DPIs on multiple monitors for interacting with windows of other applications)?!
    In my case:
    I have 1 monitor and a notebook. The monitor is 100% and the notebook on 125%. It properly works, if i set my notebook to 100% but it hurts my eyes :).
    I tried it by setting the dpiAwareness in a manifest file and all the methods but it makes no difference.
    If i set the cursor tagPoint (x & y) for the ElementFromPoint by code, it also behaves totally unpredictable.
    That's really unsatisfactory.

    0 comments No comments

  2. Xiaopo Yang - MSFT 11,496 Reputation points Microsoft Vendor
    2021-11-30T02:52:34.94+00:00

    According to the attached documents, It‘s needed to make the client application dpi-aware firstly(Try SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE)). And then GetPhysicalCursorPos because the UI Automation API does not use logical coordinates.
    Perhaps you should have a try on Highlighter which is mentioned in the previous document.
    I have found the Positioning Objects on a Multiple Display Setup sample.
    Finally, we can convert between logical and physical coordinates by using the Win32 functions PhysicalToLogicalPoint and LogicalToPhysicalPoint in regard of non-DPIAwake process.

    0 comments No comments

  3. youki 996 Reputation points
    2021-12-02T10:39:46.51+00:00

    Hi XiaopoYang,
    will try it again today evening after work. Are you sure that it must work with my settings (1 monitor & 1 laptop/ both 1920 * 1080/ the first on 100% and the laptop on 125% )?!
    I've tried SetProcessDpiAwareness and all cominations and parameters (i also tried the manifest file because it's recommended in the documentation).

    All methods i've tried as i can remember:

    • GetPhysicalCursorPos (it's not different from GetCursorPos [logical position])
    • LogicalToPhysicalPoint (not supported anymore)
    • PhysicalToLogicalPointForPerMonitorDPI
    • LogicalToPhysicalPointForPerMonitorDPI
    • SetThreadDpiAwarenessContext

    As i mentioned i tried it by setting the x and y by code which didn't change the behaviour (if i change it one by one, I can't even get to the cursor, it's so weird). I always get an other element far above the cursor on the 125% monitor and it's exactly the same behaviour like in inspect.exe that i don't want (it marks an an element far above and left).

    public static void ShowUIAData(IUIAutomationElement element)
            {
                Console.WriteLine("------------------------------------------------");
                Console.WriteLine("ShowUIAData");
                Console.WriteLine("- NAME: " + element.CurrentName);
                Console.WriteLine("- ARIAROLE: " + element.CurrentAriaRole);
                Console.WriteLine("- CONTROLTYPE: " + (ControlType)element.CurrentControlType);
                Console.WriteLine("- ITEMTYPE: " + element.CurrentItemType);
                Console.WriteLine("- FOCUSABLE: " + element.CurrentIsKeyboardFocusable);
                Console.WriteLine("- CurrentName: " + element.CurrentName);
                Console.WriteLine("- CurrentClassName: " + element.CurrentClassName);
                Console.WriteLine("- CurrentControlType: " + element.CurrentControlType);
            }
    
     public static IUIAutomationElement ElementFromCursor()
        {
            var automation = new CUIAutomation();
            var point = new Point(Cursor.Position.X, Cursor.Position.Y);
            var tp = new tagPOINT
            {
                x = (int)point.X,
                y = (int)point.Y
            };
    
            return automation.ElementFromPoint(tp);
        }
    

    Regards


  4. youki 996 Reputation points
    2021-12-20T02:26:10.87+00:00

    Hi,
    sorry for the late reply, was ill 1 week.
    I think you don't understand the task for me here.
    I need the element under the cursor independent of the monitor dpi.
    My 2 monitors have 2 different dpi settings for that i can work properly on them.
    UiAutomation doesn't give me the element under the cursor on the second monitor.
    It doesn't work properly, if the second monitor has a different dpi than the main monitor.

    Looked at your examples:

    • OnFocusChanged (won't help me?! top level window/ focused element)
    • Multiple Accessibility (can't find it under the link?!)
    • I have also tried the managed Api and DPI Awareness again. I really don't understand how could that work because it doesn't.

    I need the element under cursor because i have a function that depends on it.
    The function checks the element under the cursor in for i.e. browsers (apps without handles).
    Since websites also have for i.e. menus like for i.e. (i posted it month ago):

    https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.runtimehelpers.preparemethod?redirectedfrom=MSDN&view=net-6.0#System_Runtime_CompilerServices_RuntimeHelpers_PrepareMethod_System_RuntimeMethodHandle_System_RuntimeTypeHandle___
    I have to consider this and really have to get the element under the cursor because of further calculations.

    Background:
    I have to consider different ariaroles and controltypes which are not uniformly because of the webdesign conditions in general.
    Then i have to get "the element under the cursor" to get the needed element closest to it (not in the for i.e. side menu) as fast as possible (takes to long for usability which i have to treat next).

    Best regards

    0 comments No comments

  5. youki 996 Reputation points
    2021-12-23T08:55:38.63+00:00

    Ah, it works without enabling the dpi awareness with the controls of an other application (this is what you mean?!) but not on the content of a website in a browser...

    0 comments No comments