yasb icon indicating copy to clipboard operation
yasb copied to clipboard

[FEATURE] Tray/Task Support?

Open M1ch431 opened this issue 3 years ago • 3 comments

What is the request?

Tray and taskbar button support for Windows

Why is it useful?

In order to ditch the default taskbar, which received a very (IMO) terrible rewrite in Windows 11. Calling the tray popup with AHK is rather inconsistent/buggy.

How could it be implemented?

https://github.com/cairoshell/ManagedShell - This repo might be useful in implementing this.

I understand that this is a gargantuan request - just implementing a tray widget would make a world of difference.

M1ch431 avatar Jul 19 '22 23:07 M1ch431

Leaving this as a comment for future reference regarding implementation:

https://social.msdn.microsoft.com/Forums/vstudio/en-US/dd2b6360-0077-4b69-8126-fb6d52b7eb20/get-all-tray-icons-in-taskbar-and-display-them-in-wpf?forum=wpf

da-rth avatar Aug 03 '22 02:08 da-rth

I've been looking into this. The linked reference from the last message is busted, win11 replaced the system tray with a XAML app. This means that it'll most likely need multiple implementations for different OS versions.

BalintCsala avatar Dec 20 '23 13:12 BalintCsala

Got somewhere but got stuck. I'll post my findings here in case anybody else has ideas.

So, the new tray app is XAML based, so navigating it with FindWindowEx is not possible after a while. The path to the important window is TopLevelWindowForOverflowXamlIsland/Windows.UI.Composition.DesktopWindowContentBridge/Windows.UI.Input.InputSite.WindowClass

after this point I had to upgrade windows-rs to 0.52.0 for convenience, then I tried using UI Automation. This let me take the InputSite window and convert it to an automation element, from there it's just a tree walk down, code for this so far is:

    let hwnd_tray_overflow = FindWindowW(w!("TopLevelWindowForOverflowXamlIsland"), PCWSTR(std::ptr::null()));
    if hwnd_tray_overflow.0 == 0 {
        return None;
    }
    let hwnd_content_bridge = FindWindowExW(
        hwnd_tray_overflow,
        HWND(0),
        w!("Windows.UI.Composition.DesktopWindowContentBridge"),
        PCWSTR(std::ptr::null()),
    );
    if hwnd_content_bridge.0 == 0 {
        return None;
    }
    let hwnd_ms_inputsite = FindWindowExW(
        hwnd_content_bridge,
        HWND(0),
        w!("Windows.UI.Input.InputSite.WindowClass"),
        PCWSTR(std::ptr::null()),
    );
    if hwnd_ms_inputsite.0 == 0 {
        return None;
    }
    let automation: IUIAutomation = CoCreateInstance(&CUIAutomation, None, CLSCTX_ALL).unwrap();
    let element = automation.ElementFromHandle(hwnd_ms_inputsite).unwrap();
    let children = element.FindAll(TreeScope_Children, &automation.CreateTrueCondition().unwrap());
    if children.is_err() {
        println!("Error finding children");
        return None;
    }

    let children = children.unwrap();
    // Discord is index 2 for me
    let discord = children.GetElement(2).unwrap();
    let image = discord
        .FindFirst(TreeScope_Children, &automation.CreateTrueCondition().unwrap())
        .unwrap();

This is where I got stuck. There's no apparent way to either

  • Get the Source property from the image
  • Convert the automation element to a uwp Image object.

If I had more time, I'd check out the source code of UWPSpy: https://github.com/m417z/UWPSpy

This managed to at least tell what the source is set to.

BalintCsala avatar Dec 20 '23 22:12 BalintCsala