Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refuses to load the last used profiles (Windows 11 only) #632

Closed
1 task done
davek00997744 opened this issue Nov 23, 2022 · 27 comments · Fixed by #665
Closed
1 task done

Refuses to load the last used profiles (Windows 11 only) #632

davek00997744 opened this issue Nov 23, 2022 · 27 comments · Fixed by #665
Labels
bug Something isn't working help from outside needed Issues, which cannot be entirely solved by our team, help from outside is needed. Windows Windows-only issues

Comments

@davek00997744
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

Upon restarting the app, it loads with profile shown and not the previous used ones for each joystick device

Expected Behavior

I would expect "Load last used profile" to actually load the last used profiles upon restart

Steps To Reproduce

Load app, set profiles up & save, close app, re-load app - profiles are not loaded

Environment

- OS:Windows 11 22H2
- AntiMicroX version:3.3.2

Anything else?

No response

@davek00997744 davek00997744 added the bug Something isn't working label Nov 23, 2022
@pktiuk
Copy link
Member

pktiuk commented Nov 23, 2022

Could you again collect some logs? https://github.com/AntiMicroX/antimicrox/wiki/Collecting-Logs
Just open and close an app. (They will show me whether app tried to load these configs)

Can you load config manually? It seems to be a duplicate or at least something similar to: #618

@davek00997744
Copy link
Author

Log attached, yes i can manually load profiles fine.

antimicrox_log.log

@pktiuk
Copy link
Member

pktiuk commented Nov 23, 2022

Do you have this setting enabled? (Auto load last profile)
image

@davek00997744
Copy link
Author

Yes that setting is certainly ticked

@pktiuk
Copy link
Member

pktiuk commented Nov 23, 2022

Could you upload your AntiMicroX settings file?

C://Users/YOURNAME/AppData/Local/antimicrox/antimicrox_settings.ini It should in this kind of location

@davek00997744
Copy link
Author

Of course, here we go...

antimicrox_settings.ini.zip

@pktiuk pktiuk added the Windows Windows-only issues label Dec 2, 2022
@pktiuk
Copy link
Member

pktiuk commented Dec 2, 2022

Any updates on this?

Asking about updated doesn't generate any updates.

@davek00997744
Could you delete your settings file?

@davek00997744
Copy link
Author

Of course, will try it tomorrow.

@pktiuk pktiuk added the waiting for feedback Waiting for feedback from users label Dec 3, 2022
@davek00997744
Copy link
Author

Settings file deleted, makes no difference - the new file is created but refuses to re-load when started up again.

@pktiuk pktiuk removed the waiting for feedback Waiting for feedback from users label Dec 3, 2022
@pktiuk
Copy link
Member

pktiuk commented Dec 3, 2022

I could not reproduce this problem on Windows 10. Maybe this is specific windows 11 thing... 🤔
Does it happen also with other devices? (like regular PlayStation gamepads)

@davek00997744
Copy link
Author

I will try my xbox game controller tomorrow

@JoeggiCH
Copy link

JoeggiCH commented Dec 4, 2022

I observe the same issue.

Current Behavior
Upon restarting the app, it loads no profiles (and not the previous used ones for each joystick device)
"Auto Load Last Opened Profile" is ticked

Expected Behavior
I would expect "Load last used profile" to actually load the last used profiles upon restart

Steps To Reproduce
Load app, set profiles up & save, close app, re-load app - profiles are not loaded

Environment

OS:Windows 11 22H2
AntiMicroX version:3.3.2
Joysticks: Sidewinder Force Feedback 2 Joystick, Saitek X52 Pro Flight Control System, Saitek Pro Flight Rudder Pedals

@nitz
Copy link
Contributor

nitz commented Dec 5, 2022

Same issue for me as well, also on Windows 11, will give it a shot on Windows 10 tomorrow to see if I can reproduce there. or not.

@pktiuk
Copy link
Member

pktiuk commented Dec 12, 2022

@nitz

@pktiuk pktiuk added the waiting for feedback Waiting for feedback from users label Dec 12, 2022
@nitz
Copy link
Contributor

nitz commented Dec 13, 2022

Ah yes, the famous "8 days later" tomorrow. I swear as soon as I can get my brain upgraded to not this fallible squishy one. Sorry @pktiuk!

Anyways!

My test device is a third party controller that presents as an Xbox One S controller.

I am glad to report that I'm unable to reproduce the issue on my Windows 10 machine (22H2; 19045.2251). I've tested using both the installer and portable versions of 3.3.2, and both properly load the previous profile as expected.

I'm using a similar setup for where I've stored my profiles (in a OneDrive folder with the contents locally hydrated,) and have check to ensure that the settings I have are uniform across where I've tested.

The differences between my Windows 11 machine and this one, is that there's only a single controller being enumerated. My windows 11 machine typically has a few more:

Two presented by Razer keyboards as part of their IO suite: "(Razer Xbox 360 Controller)", "Joystick (Razer Huntsman V2 Analog)", two presented by 3Dconnexion's IO suite: "Spacemouse Compact", "3Dconnexion KMJ Emulator", and one presented by this adapter, "GC KB+JS to USB v3.6".

Let me know how else I can help!

@pktiuk pktiuk removed the waiting for feedback Waiting for feedback from users label Dec 13, 2022
@pktiuk pktiuk changed the title Refuses to load the last used profiles Refuses to load the last used profiles (Windows 11 only) Dec 13, 2022
@pktiuk
Copy link
Member

pktiuk commented Dec 13, 2022

Thanks for your feedback.
I am a typical Linux user and it may be difficult for me to find the exact difference between Windows 11 and Windows 10, which causes this problem.
Moreover, I don't have a Windows 11 machine available.

@pktiuk pktiuk added the help from outside needed Issues, which cannot be entirely solved by our team, help from outside is needed. label Dec 13, 2022
@davek00997744
Copy link
Author

Is there anything more I can do??

@pktiuk
Copy link
Member

pktiuk commented Dec 13, 2022

For now not. (Unless you are a C++ developer ;) )

@bodote
Copy link

bodote commented Dec 16, 2022

same here (same Bug on Windows 11, not a C++ dev)

@JoeggiCH
Copy link

JoeggiCH commented Dec 16, 2022 via email

@nitz
Copy link
Contributor

nitz commented Dec 16, 2022

I'm a C++ dev, I'll see if I can find some time this weekend to step through and see if I can find where it falls apart under w11.

@pktiuk — Any chance you could point me to around where the last used profile tries to load? (If not no big deal I'm sure I'll find it!)

@pktiuk
Copy link
Member

pktiuk commented Dec 16, 2022

@nitz
I would recommend looking for LastSelected" in code.

There are some entries in mainwindow.cpp and joytabwidget.cpp

This region seems promising

void JoyTabWidget::loadSettings(bool forceRefresh)
{
////
QString controlEntryLastSelected = QString("Controller%1LastSelected").arg(m_joystick->getStringIdentifier());
    QString controlEntryProfileName = QString("Controller%1ProfileName%2").arg(m_joystick->getStringIdentifier());


///
    if (!m_joystick->getStringIdentifier().isEmpty() && autoOpenLastProfile)
    {
        lastfile = m_settings->value(controlEntryLastSelected, "").toString();
    }

@nitz
Copy link
Contributor

nitz commented Dec 17, 2022

Alright, I've got it building and am reproducing the issue, which has allowed me to narrow it down a bit further:

  • If built with PORTABLE_WIN and used from a R/W directory or ran elevated (so it can correctly read/write antimicrox_settings.ini), it behaves as expected.
  • When built without PORTABLE_WIN, the issue occurs regardless of where it's executed from, and regardless of elevation. However, all other settings seem to persist correctly in %localappdata%\antimicrox\antimicrox_settings.ini as you'd expect. Interestingly enough it does write the preference correctly, only blanking it on load.

I'm going to step through loadSettings() now and see if I can see what's going differently between the portable and non-portable builds.

An aside, when building with mingw64, gcc liked to spew over and over again that findWinConfigPath was defined but not used. MSVC had no such qualms 😂

The investigation continues!

nitz added a commit to nitz/antimicrox that referenced this issue Dec 17, 2022
This is enough of a fix to resolve the issue in AntiMicroX#632, but there are a few other edge cases that investigation brought up that may cause a similar issue in the future.
@nitz
Copy link
Contributor

nitz commented Dec 17, 2022

Alright, so here's what I've found.

I've managed to reproduce the issue with one controller, and have it not reproduce with another.

The symptom of the issue seems to be coming from JoyTabWidget::convToUniqueIDControllerGroupSett(...).

It reads:

void JoyTabWidget::convToUniqueIDControllerGroupSett(QSettings *sett, QString guidControllerSett,
                                                     QString uniqueControllerSett)
{
    if (sett->contains(guidControllerSett))
    {
        sett->setValue(uniqueControllerSett, sett->value(guidControllerSett));
        sett->remove(guidControllerSett);
    }
}

When this gets called with the controller that doesn't produce the behavior, the values of the strings are:

  guidControllerSett: Controller030070db2852617a6572205862007200ConfigFile1
uniqueControllerSett: Controller030070db2852617a657220586200720000ConfigFile1

Notice the extra 00 in the guid vs the unique. Because it seems that the QSettings instance doesn't contain an entry for the guid string (which, it doesn't, it only has one matching the unique,) the setValue/remove never runs. I pulled the sett->value(guidControllerSett) call outside of the condition just to check, and sure enough it does have the proper value.

Now, when I proceed to my next controller, the one that does produce the issue, the values of the strings are:

  guidControllerSett: Controller0300395b9b2800006800000000000000ConfigFile1
uniqueControllerSett: Controller0300395b9b2800006800000000000000ConfigFile1

The hoisted sett->value() does show that the setting loaded correctly in the QSettings instance, but with the guid and unique setting keys being the same, the condition passes, an effective noop happens with the setValue, and then the very next line deletes the setting!

When loadSettings() goes to retrieve it on it's very next line, it doesn't exist, and value() gives back the empty string. Everything past that is moot because it never gets a chance to try and load the profile.


Now, to look at the cause rather than just the symptom.

The generation of the unique ID vs the guid seem to be different enough: The unique ID includes the guid, so one would assume that the unique ID is more specific than just SDL's guid on it's own.

//// snip

QString GameController::getRawGUIDString() const
{
    QString temp = QString();

    if (controller != nullptr)
    {
        SDL_Joystick *joyhandle = SDL_GameControllerGetJoystick(controller);

        if (joyhandle != nullptr)
        {
            SDL_JoystickGUID tempGUID = SDL_JoystickGetGUID(joyhandle);
            char guidString[65] = {'0'};
            SDL_JoystickGetGUIDString(tempGUID, guidString, sizeof(guidString));
            temp = QString(guidString);
        }
    }

    return temp;
}

//// snip

QString GameController::getRawUniqueIDString() const
{
    return (getRawGUIDString() + getRawVendorString() + getRawProductIDString() + getSerialString());
}

//// snip

But this is where the real rub seems to come from.

I broke out the calls in getRawUniqueIDString() to take a closer look.

So here's my first controller (Happens to be an emulated Xbox 360 controller presented by a razer keyboard driver):
image

And sure enough, between the VID and PID showing up as zeroes, we've discovered where the delta between our unique ID and guid has come from.

Now, on to my second controller. Uh oh, it doesn't hit GameController::getRawUniqueIDString()! Took me more than a few minutes to realize that's because it's presenting as a Joystick, which has a very nearly identical method.

Giving it the same treatment as the GameController flavor:

image

And we have a bingo. No strings of "0" coming back from Joystick::getVendorString(), and Joystick::getProductIDString(), just actually empty strings. This makes the guid and unique ID match, which is what causes the above behavior in JoyTabWidget::convToUniqueIDControllerGroupSett!

On my machine at least, controller is nullptr, so there's no attempt to even get vid/pid/serials via SDL. I'm not familiar at all with SDL but I'm thinking perhaps the distinction between a joystick and a game controller is something that doesn't matter on windows 10, but somehow does on windows 11?

Either way, we've got a SDL_Joystick*, might as well use it with the SDL_Joystick(*) flavor of those functions! (Assuming minimum versions of SDL.


I've submitted a small PR (#665) that does that, which does resolve the issue on my end, but I'm unsure of the implications surrounding the required SDL version. Though it does seem v2.0.6 came out in 2017, so it's probably a safe thing to bet on.

I also don't know if you wanted to make changes to the profile loading logic, with the bit I caught about how it can potentially delete a setting if the unique ID and guid happen to match. I figured I'd leave that one out of the PR in case you had more thoughts on how you might like to approach it.

I hope you enjoyed my sleuthing and rambling, was a fun thing to track down!

P.S.: If you'd like, I can also send a PR for the small cmake (and some msvs specific warnings-as-errors) changes I had to make to build and debug through visual studio, just let me know!

Cheers

@pktiuk
Copy link
Member

pktiuk commented Dec 17, 2022

@nitz
WOW, great analysis.

I'm unsure of the implications surrounding the required SDL version. Though it does seem v2.0.6

Don't worry, we require at least 2.0.6 to compile (according to cmake).

P.S.: If you'd like, I can also send a PR for the small cmake (and some msvs specific warnings-as-errors) changes I had to make to build and debug through visual studio, just let me know!

Feel free to contribute in any way you wish :)
If you are not sure you can always create a draft pull request showing the general idea before spending more time implementing it.
If you like you can also check other issues on this repo, maybe something will catch your eye.

nitz added a commit to nitz/antimicrox that referenced this issue Dec 17, 2022
This is enough of a fix to resolve the issue in AntiMicroX#632, but there are a few other edge cases that investigation brought up that may cause a similar issue in the future.
pktiuk pushed a commit that referenced this issue Dec 17, 2022
This is enough of a fix to resolve the issue in #632, but there are a few other edge cases that investigation brought up that may cause a similar issue in the future.
@davek00997744
Copy link
Author

Does this mean it is fixed? Its all a bit confusing to me :)

@pktiuk
Copy link
Member

pktiuk commented Dec 18, 2022

Yes, it will be included in the next release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working help from outside needed Issues, which cannot be entirely solved by our team, help from outside is needed. Windows Windows-only issues
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants