Get current song title from Windows Media Player UI in the bottom left

45 Views Asked by At

enter image description here

I want to get the text from the UI element in the bottom left of Windows Media Player. I want to store it in a python variable. How can I programmatically navigate the UI hierarchy to achieve this?

1

There are 1 best solutions below

0
TeamDman On

First we need to get the element. The Accessibility Insights program helps here: enter image description here

We know we are looking for an edit control with Name="metadata" I'm using a jupyter notebook for this.

UIAutomationCore = comtypes.client.GetModule("UIAutomationCore.dll")
IUIAutomation = comtypes.client.CreateObject("{ff48dba4-60ef-4201-aa87-54103eef594e}", 
                                            interface=UIAutomationCore.IUIAutomation)
ViewWalker = IUIAutomation.RawViewWalker

desktop = IUIAutomation.GetRootElement()
ViewWalker.getFirstChildElement(desktop)

# https://github.com/microsoft/accessibility-insights-windows/issues/1122#issuecomment-834145895
# Thanks yinkaisheng!
def WalkTree(top, max_depth: int = 0xFFFFFFFF):
    if max_depth <= 0:
        return
    child = ViewWalker.GetFirstChildElement(top)
    childList = [child]
    depth = 0
    while depth >= 0:
        lastItem = childList[-1]
        if lastItem:
            yield lastItem, depth + 1
            child = ViewWalker.GetNextSiblingElement(lastItem)
            childList[depth] = child
            if depth + 1 < max_depth:
                child = ViewWalker.GetFirstChildElement(lastItem)
                if child:
                    depth += 1
                    childList.append(child)
        else:
            del childList[depth]
            depth -= 1

for x, depth in WalkTree(desktop, max_depth=1):
    if x.CurrentClassName == "WMPlayerApp":
        wmp = x

assert wmp

for ele, depth in WalkTree(wmp, max_depth=4):
    if ele.CurrentName == "metadata":
        print(ele.CurrentName)
        break

metadata

Now we have our ele variable containing <POINTER(IUIAutomationElement) ptr=0x24c5ee4baf0 at 24c61e1e140>

https://learn.microsoft.com/en-us/windows/win32/api/uiautomationclient/nn-uiautomationclient-iuiautomationelement

https://learn.microsoft.com/en-us/windows/win32/api/uiautomationclient/nn-uiautomationclient-iuiautomationtreewalker

Next, we need to get the ValuePattern Value out of it.

value_pattern = ele.GetCurrentPattern(UIAutomationCore.UIA_ValuePatternId)
value_pattern

<POINTER(IUnknown) ptr=0x24c5ee452b0 at 24c6246bc40>

Nice, lets finish it off by casting the pointer and getting the value.

# Import the IValuePattern interface definition from UIAutomationCore
from comtypes.gen.UIAutomationClient import IUIAutomationValuePattern

# Cast the IUnknown pointer to IValuePattern
value_pattern_interface = value_pattern.QueryInterface(IUIAutomationValuePattern)
print(value_pattern_interface)

# Now you can use value_pattern_interface to get the value
current_value = value_pattern_interface.CurrentValue
print(f"Value: {current_value}")

<POINTER(IUIAutomationValuePattern) ptr=0x24c5ee452b0 at 24c62536ec0>

Value: For you sounds

(The song title has been changing as I write this)

A simple test program:

from time import sleep
while True:
    print(value_pattern_interface.CurrentValue)
    sleep(1)

enter image description here