Morph21 / MercuryTrade-Community-Fork

An overlay application for Path of Exile(Tracking, Trading, Chat, etc)
MIT License
139 stars 24 forks source link

[BUG] - Wrong window focused with multiple clients #123

Open rpav opened 2 years ago

rpav commented 2 years ago

Describe the bug When running multiple clients, e.g. one "trading character" and one "main character," the client focused for sending messages / invites / etc is incorrect.

To Reproduce Steps to reproduce the behavior:

  1. Run 2 clients.
  2. Use Mercury to do anything causing the client to be focused
  3. A random client will be focused

Expected behavior Either:

Desktop (please complete the following information):

Additional context

This appears to be a problem with gameToFront() in ChatHelper.java:204. This iterates all the windows and finds one with the expected class ("POEWindowClass"), which ends up semi-randomly picking a window.

However, this should be pretty easy to fix... the proper PID for every message is in Client.txt! One should be able to either check for the window's PID, or only iterate the proper client's windows, etc. I personally would be happy enough with setting a single global pid at this point.

I'm filing this in case it's something that can be fixed relatively quickly. I may try hacking out a solution this weekend, but I'm not really set up for java dev at the moment. I'll file a PR if I get to it and have something not entirely a hack.

And thanks for maintaining this, it's incredibly useful.

Morph21 commented 2 years ago

You probably could change this (gameToFront function)

if (SystemUtils.IS_OS_WINDOWS) {
            WindowUtils.getAllWindows(false).forEach(window -> {
                char[] className = new char[512];
                User32.INSTANCE.GetClassName(window.getHWND(), className, 512);
                if (Native.toString(className).equals("POEWindowClass")) {
                    User32.INSTANCE.ShowWindow(window.getHWND(), 5);

                    boolean isAtFront = User32.INSTANCE.SetForegroundWindow(window.getHWND());
                    int counter = 0;
                    while (!isAtFront && counter < 10) {
                        isAtFront = User32.INSTANCE.SetForegroundWindow(window.getHWND());
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        counter++;
                    }

                    User32.INSTANCE.SetFocus(window.getHWND());
                }
            });

into this:

if (SystemUtils.IS_OS_WINDOWS) {
            WindowUtils.getAllWindows(false).forEach(window -> {
                char[] className = new char[512];
                IntByReference pid = new IntByReference();
                User32.INSTANCE.GetWindowThreadProcessId(window.getHWND(), pid);
                if (pid == 12345) {
                    User32.INSTANCE.ShowWindow(window.getHWND(), 5);

                    boolean isAtFront = User32.INSTANCE.SetForegroundWindow(window.getHWND());
                    int counter = 0;
                    while (!isAtFront && counter < 10) {
                        isAtFront = User32.INSTANCE.SetForegroundWindow(window.getHWND());
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        counter++;
                    }

                    User32.INSTANCE.SetFocus(window.getHWND());
                }
            });

replace 12345 with pid of your path of exile. It should work if you build it like that

Morph21 commented 2 years ago

But overall it's an hack, I have no idea right now how to make it work for multiple instances in a good way

HiPoEGH commented 2 years ago

Make a dropdown list? Populate the list with all processes matching the "POEWindowClass", and let the user select one.

rpav commented 2 years ago

@HiPoEGH This was my thought.

I have all the mechanics in place but the dropdown... right now I have a text box where you can enter a PID, and it only uses that PID. If the PID is 0, it uses the current behavior. As a side effect, if you enter an invalid nonzero PID, it simply won't switch (which is nice too).

My next step is making a dropdown with "Don't Switch" / "Old behavior" / "<Window 1>" / "<Window 2>". This seems straightforward.

However, even better, will be to actually parse the PID out of messages and use that where it can be. That's down the road, but I will try to get a PR in soon with the dropdown.

LordBlick commented 8 months ago

I can't give any code here because I'm rather Python developer, but I can put some kind of assumption – at the first „Do not switch any window, I'll do it manually” option in UI might be a good fix – usually active window is properly selected plus both characters frequently could go to hideout, view betrayal cheat sheet etc.