Morph21/MercuryTrade-Community-Fork

[BUG] - Wrong window focused with multiple clients

Opened this issue · 5 comments

rpav commented

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:

  • The client corresponding to the message ought to be focused
  • At a minimum, a single configurable client ought to be focused

Desktop (please complete the following information):

  • Windows 10, DX11/DX12, latest release as of filing

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.

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

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

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

rpav commented

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

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.