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

Retroarch Android swaps controller port to the next one if controller is disconnected and reconnected during runtime #3414

Closed
thedaryen opened this issue Aug 21, 2016 · 35 comments · Fixed by #13649

Comments

@thedaryen
Copy link

thedaryen commented Aug 21, 2016

Initially, when i launch Retroarch and press any button on the gamepad, it recognizes the controller and sets it to port #0. Ok. Everything works fine.

However, if at any given point I disconnect the controller and connect it again, Retroarch automatically sets it to the next port (port #1, then to port #2 if I disconnect and reconnect again, and so on until port #8, after which it loops back to port #0 and I regain my original maps and control over the menu).

I'm guessing it's not recognizing that the controller was disconnected, and treating the reconnect as a new controller, hence setting the "new" controller to the next available port and breaking the mappings etc.

Don't know if this is expected behavior, or if it's something to do with my controller or cfg. I'm using the latest build and a DualShock 4 controller on an unrooted Galaxy Tab E. I sometimes use it via Bluetooth and others via USB (through the OTG adapter), but both produce the same issue.

Edit: forgot to mention, another way of reverting it to port #0 is simply quitting Retroarch and opening it up again. When you first press a button with the controller it is always set to port #0.


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@Dinierto
Copy link

Is there a way to prevent it from happening though? I know that in most emulators it's not an issue, but I'm guessing RA handles things differently.

@sinni800
Copy link

The issue still persists, I am experiencing it with my devices, too.

@manojka
Copy link

manojka commented Aug 23, 2019

So, it turns out that with a Gamevice controller (in my case, on a Pixel 3), this is a bigger deal, because at least mine times out after a minute. I'm complaining to Gamevice about this, but in the mean time, sitting through a cut scene is enough to have the controller fall asleep, and thus being unusable even after it wakes up.

@LowFatBacon
Copy link

So, it turns out that with a Gamevice controller (in my case, on a Pixel 3), this is a bigger deal, because at least mine times out after a minute. I'm complaining to Gamevice about this, but in the mean time, sitting through a cut scene is enough to have the controller fall asleep, and thus being unusable even after it wakes up.

I'm having the same issue with retroarch on my phone. Just got my gamevice and it times out so easily. Really disappointing.

@manojka
Copy link

manojka commented Aug 29, 2019 via email

@Xjph
Copy link

Xjph commented Nov 24, 2019

Just discovered this problem myself after getting an Nvidia Shield TV and setting up RetroArch with an Xbox One controller via bluetooth. Was looking forward to using RetroArch on it, but this is annoying enough that I'll probably just not bother.

@adamf2001
Copy link

+1 after setting up retroarch on a firestick 4k with x2 Bluetooth controllers (8bitdo). If either of them disconnects it gets reconnected to the next port when switched back on and all control over the interface is lost (meaning we have to exit back to the fire interface and then go back into Retro Arch). Also only one controller is able to control the menu how do we configure both controllers to have RetroArch menu control?

P.S C'mon folks this issue has been here since 2016 we're now in 2020 surely a controller can be given a static port binding ...

@libretro libretro deleted a comment from andres-asm Apr 12, 2020
@manojka
Copy link

manojka commented May 7, 2020

The issue stopped being a problem for me for a while, but now I'm running RetroArch on a Shield TV with their branded controller, and I'm seeing the same behavior. Confirming that this also happens on my Nvidia Shield TV with its wifi controller if it goes unused for some number of minutes.

This issue is marked "minor" and I don't know if anyone who works on the project is paying attention to it, but yeah, I strongly suspect that detecting controller disconnection and reconnection shouldn't be too hard here for someone who has a developer environment up and running. I didn't have this problem using SNES9x EX+.

@mkopson
Copy link

mkopson commented Jul 19, 2020

I'm having the same problem with retroarch on the Nvidia Shield and 8bitdo sn30pro+ controllers. They work fine when reconnecting with every other app on the shield, including steam link. One workaround is to minimize retroarch and reopen it but doing so often crashes retroarch when running certain cores. Please fix this. Me and my kids get so frustrated when we lose progress in a game.

@RexBorova
Copy link

2020 and this issue is still going strong with no resolve lol. I sometimes forget about frustrations with RA until I dropped my xbox one controller on the carpet, and the batteries came flying out, only to put them in and set my controller to the next controller port, There's workaround like resetting RA, or going to android home screen and selecting RA to reset the port back to port 1, a many as stated, but this issue needs some resolving, or at least a better workaround.

An option to select which controller port to choose when a device is connected (kind of like how players choose to play on which side in fighting games in game lobbies, or choosing teams in Ffia/sports games by moving there controller left or right) could help. Just my 2 cents

@staggus
Copy link

staggus commented Aug 22, 2020

This bug is stopping anyone playing on a bluetooth controller. It is the only reason I have gone back to using separate emulators on my android phone. It must be a relatively simple fix, please sort it!!

@andy83-projects
Copy link

Such a pain. It's an issue for me as well

@srkelley
Copy link

srkelley commented Dec 2, 2020

Yes, this is still a present issue. I wish that a simple config option would be added to either allow/disallow all controllers to have the option to open the menu and reorder any connected controllers.

Maybe have a disconnected controller be automatically connected to whatever controller connects next.

How about being able to set a hotkey for controller remapping along with adding a toggle for allowing all connected controllers to either be able to use/not use the hotkey?

@leoo1995
Copy link

i have the same issue in retroarch when i play in my android smartphone with a wireless control and i have to close and reopen retroarch for the working of my gamepad

@whackawaldo
Copy link

whackawaldo commented Apr 4, 2021

Can we please remove the bug: minor tag? This is a complete showstopper preventing anyone from using Bluetooth controllers on Android, since anytime the connection stutters and the controller reconnects, it gets assigned to the next player.

I think it should be fixable in /input/drivers_hid/btstack_hid.c but I'm not comfortable enough with the codebase or the C programming language to open a PR myself.

@ds17f
Copy link

ds17f commented Jul 17, 2021

@whackawaldo is on to something. I looked at the code, built a binary, but couldn't get logging or debugging to work properly.

Is there any android specific documentation for working on this project? Is there a discord/forum/slack group or somewhere to get help getting started? I'm fairly sure I can fix this if I can just get some observability working.

@calebjely
Copy link

I have no idea how to run or compile this either. From looking at the code, btpad_increment_position(&insert_position) runs inside 5 different functions, including inside the bluetooth disconnect function, btpad_queue_hci_disconnect, line 856. There is a check of the insert_position pointer inside btpad_queue_process function on line 818, but insert_position will not match the read_position after disconnect because it will have been incremented. Removing all calls to the increment function should fix it, but then it would never increment, which would be a problem if you try to added multiple controllers. Also removing this function call just from btpad_queue_hci_disconnect may not fix it because insert_position may still increment during a different function called on connect. However, when initially connecting a controller there is no number pinned after the controller name, so simply removing line 856 may be all that is needed.

It may be that on disconnect you would actually need to decrement insert_position instead, reopening that position for when the same or another controller reconnects. In this case, a function that is a duplicate of btpad_increment_position(&insert_position)should be called but updated to decrement instead.

@ds17f
Copy link

ds17f commented Jul 18, 2021

@calebjely I'm exploring your suggestions. I tried just removing like 856 from btstack_hid.c and it appears that it did not work. But I'm going to keep poking around. I'll try other parts of what you suggest too and follow up.

I was unable to get building or debugging to work in Android Studio. I found these issues:

For the time being, the instructions which were likely updated by @thebunnyrules in the second issue above worked for me with some slight modifications as described below. I'd be happy to update the official docs to include this.

Building Retroarch Without Cores on a Macbook

I wanted to offer the following on getting the app to build. I'm using an Intel Macbook Pro running Big Sur. So I'm not sure if that maps to your environment at all. The build instructions here: https://docs.libretro.com/development/retroarch/compilation/android/ don't explicitly cover building on a Mac, but I followed the Linux instructions and things mostly worked as described.

For the SDK and NDK I installed the latest Android Studio and followed instructions online to get those packages installed using the built in tools installer. I had to make a new, empty, project, then look in the tools menu for the SDK Manager. I installed an older version of the NDK because the build scripts complained about the newer one. Version 22.0.7026061 seemed to be the one that the project is dependent on. Once I had that installed I was able to get a build going.

I skipped building the cores. It's a waste of time for what we're trying to do here. You can download them through retroarch once your dev build is installed on your device (just use the Online Updater to get the assets, lists of cores, controller profiles, etc...).

I jumped to the Build Retroarch section of the doc and then followed along. On a Mac, I had to use a slightly different path to the SDK and NDK that I installed. My local.properties looks something like:

ndk.dir=/Users/$USER/Library/Android/sdk/ndk/22.0.7026061
sdk.dir=/Users/$USER/Library/Android/sdk

you should put your username in place of $USER

Next I followed the instructions for the keystore.properties and just filled in pretty much any data and a file located in the local path. I'm not sure that this is necessary.

Again, I skipped the cores, the assets, and the rest and went down to the build. I ran the gradle commands and installed the APK on my tablet.

@ds17f
Copy link

ds17f commented Jul 18, 2021

Also as for a solution to the problem, I've been thinking about creating an in-memory map of the controller's bluetooth id and the port or address that it is supposed to be mapped to. Then, on reconnect, the ID could be looked up, and if found, could be restored to the correct port.

@ds17f
Copy link

ds17f commented Jul 25, 2021

Wonderful news! I'm able to run the debugger in Android Studio against a virtual device. It was super simple once I found this doc: https://github.com/libretro/RetroArch/tree/0ddfbd976c478f154100fababa3aea76270d12be/pkg/android/phoenix/sideload

All I had to do was:

  1. Open Android Studio
  2. Import a project
  3. Choose the actual path to the Android Frontend: libretro-super/retroarch/pkg/android/phoenix

Once that was loaded up I created a virtual device. If you look in the build.gradle file you'll see that the project will only build for:

        abiFilters 'arm64-v8a', 'x86_64'

So I had to make sure that I chose one of those OS images for the Virtual Device. I used x86_64.

Once that was in place I had normal build/debug options. I hit debug and it installed the APK onto the device, printed log out in the debugger console, and I was up and running.

I'll be trying this against my physical device shortly so that I can actually connect bluetooth controllers.

@oczr
Copy link

oczr commented Aug 3, 2021

I'm really struggeling with this issue currently.
Makes it almost impossible to step away for a couple of minutes, unless you were able to save.

I hope you're on the right path ds17f. Good luck.

@ds17f
Copy link

ds17f commented Aug 3, 2021

Unfortunately this wasn't it. I got confirmation on the forum that this file is only used in IOS. So there's more exploration to be done.

I really wish there was a way to get a response from the original author of some of this code. It's frustrating that it's not documented. :'(

@wardellbagby
Copy link

wardellbagby commented Nov 12, 2021

I went ahead and posted a $50 bounty on this one 'cause I'd really love to see it fixed. I know I'm not the only one afflicted by this so I encourage anyone else who wants to see this fixed to contribute, even a little bit, to help get this resolved.

https://www.bountysource.com/issues/37132974-retroarch-android-swaps-controller-port-to-the-next-one-if-controller-is-disconnected-and-reconnected-during-runtime

@Virusmater
Copy link

Added 15$ on it since it just happened to me

@theman8631
Copy link

+1 biggest issue I’ve had with retroarch. Makes using bluetooth unplayable after returning from idle state.

phcoder added a commit to phcoder/RetroArch that referenced this issue Feb 21, 2022
phcoder added a commit to phcoder/RetroArch that referenced this issue Feb 21, 2022
Closes libretro#3414

I have investigated the issue. The crux of the problem is that on Android there
is no way distinguishing 2 scenarios:
1) 2 identical bluetooth controllers A and B and first there are button presses
only on controller A and then on controller B
2) the same controller disconnects and reconnects.
Android doesn't give bluetooth mac address of where the touch came from, only
opaque ID and this opaque ID changes after reconnect. Hence without changes to
android this is infeasible without giving up the ability for 2 users to play on
identical controllers.

I guess that this sacrifice makes sense for affected users
@phcoder
Copy link
Contributor

phcoder commented Feb 21, 2022

I have investigated the issue. The crux of the problem is that on Android there is no way distinguishing 2 scenarios:

  1. 2 identical bluetooth controllers A and B and first there are button presses only on controller A and then on controller B
  2. the same controller disconnects and reconnects.
    Android doesn't give bluetooth mac address of where the touch came from, only opaque ID and this opaque ID changes after reconnect. Hence without changes to android this is infeasible without giving up the ability for 2 users to play on identical controllers.

For use of this sacrifice use: #13649 and enable the workaround

@manojka
Copy link

manojka commented Mar 8, 2022

I'm not well-versed in Android dev specifically or Retroarch, but would https://developer.android.com/reference/android/view/InputDevice#getDescriptor() do the job here?

"An input device descriptor uniquely identifies an input device. Its value is intended to be persistent across system restarts, and should not change even if the input device is disconnected, reconnected or reconfigured at any time."

@phcoder
Copy link
Contributor

phcoder commented Mar 8, 2022

I'm not well-versed in Android dev specifically or Retroarch, but would https://developer.android.com/reference/android/view/InputDevice#getDescriptor() do the job here?

"An input device descriptor uniquely identifies an input device. Its value is intended to be persistent across system restarts, and should not change even if the input device is disconnected, reconnected or reconfigured at any time."

Except that if you have 2 bluetooth devices of the same model they will get the same descriptor. Hence if we rely on it we lose the ability to have 2 players on such controllers. Hence I made it an option

@manojka
Copy link

manojka commented Mar 8, 2022 via email

@DOSO-draws
Copy link

Hey ppl, I'm also struggling with this issue. I don't know enough about coding to fix it myself, but after reading through all the comments here, I think I can see a simple workaround:

We just need a new option to change between 1-player mode and multiplayer.

1-player mode will fix the issue but remove the possibility to connect multiple gamepads.

Multiplayer will retain this issue, but in that case it won't be as much of a problem - since when several people are playing together, it's more likely they'll be 100% focused on gaming rather than playing intermittently while doing something else.

What do you think, could that work?

phcoder added a commit to phcoder/RetroArch that referenced this issue Apr 5, 2022
Closes libretro#3414

I have investigated the issue. The crux of the problem is that on Android there
is no way distinguishing 2 scenarios:
1) 2 identical bluetooth controllers A and B and first there are button presses
only on controller A and then on controller B
2) the same controller disconnects and reconnects.
Android doesn't give bluetooth mac address of where the touch came from, only
opaque ID and this opaque ID changes after reconnect. Hence without changes to
android this is infeasible without giving up the ability for 2 users to play on
identical controllers.

I guess that this sacrifice makes sense for affected users
@phcoder
Copy link
Contributor

phcoder commented Apr 5, 2022

I rebased my PR

@jamtempisto
Copy link

Hi there, any news about this?

I followed a guide to make an USB adapter for the original Sega Genesis/Mega Drive controller, but because of this bug it is unusable on Android. The adapter works fine on RetroArch for Windows.

I've downloaded the code from @phcoder's repo, and after some time I eventually found out how to build the phoenix apk for my phone's architecture with Android Studio.

(Unfortunately, installing the debug build deleted my Android/data/com.retroarch settings... but my saves were stored elsewhere)

I can confirm that his code does solve the problem, though I had to activate it in Settings->Input->Android disconnect workaround.

In my opinion, it should be active by default, maybe with a fancier name like "Android joypad persistent mode" or something.

Any chances of his solution making it into the final build?

Thank you all for your hard work!

@kold666number
Copy link

I found a version in The internet with this problema fixed, looks like Windows version of Retroarch 1.15 ported to Android, It have a option on input: fix disconects, i made tests: when you bluetooth controller lose The sinal and back, The Control still in Port 1, you can press home to reset connection and your controller still use Port 1, is awesome! Download: https://apkmody.io/pt/games/retro-arch

@hizzlekizzle
Copy link
Contributor

@kold666number you're probably better off downloading the apk from retroarch.com instead of from an untrusted site.

@StarFilledDonut
Copy link

StarFilledDonut commented May 27, 2023

Hii im new here, is there a way i fan solve this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.