Because the last commit made us use separate folders for GCPad and
GCKey profiles, we should also use separate game INI keys for them.
Otherwise setting e.g. PadProfile1 in a game INI will make both GCPad
and GCKey try to load it, typically with one of them succeeding and the
other one showing a panic alert due to the profile not existing in its
folder.
Better do this breaking change for GCKeys in the same PR as the other
breaking change rather than later.
After reading the previous commit, you might think "hold on, what's the
difference between GetProfileName and GetProfileDirectoryName"? These
two are being used for the exact same thing - figuring out where
profiles are stored - yet they return different values for certain
controllers like GC keyboards! As far as I can tell, the existing code
has been broken for GC keyboards since they were introduced a decade
ago. The GUI (and more recently, also InputCycler) would write and read
profiles in one location, and our code for loading profiles specified in
a game INI file would read profiles in another location.
This commit gets rid of the set of values used by the game INI code in
favor of the other set. This does breaking existing setups where a
GCKey profile has been configured in a game INI, but I think the number
of working such setups is vanishingly small. The alternative would make
existing GCKey profiles go missing from the profile dropdown in the GUI,
which I think would be more disruptive. The alternative would also force
new GCKey profiles into the same directory as GCPad profiles.
This commit also fixes a regression from d6c0f8e749. The Android GUI was
using GetProfileName to figure out what key to use in the game INI,
which made it use incorrect game INI entries for GameCube controller
profiles but not Wii Remote profiles. Now the Android GUI uses
GetProfileKey for this, fixing the problem.
By having getters for this information, other code that needs access to
the same information can call the getters instead of duplicating the
information.
This specific issue was already addressed by https://github.com/dolphin-emu/dolphin/pull/11635
though I felt like there was something more we could do, and wasn't too happy with the
likelihood of devices update calls being skipped (due to `m_devices_population_mutex` being locked).
These aren't necessarily cheap to copy, since a control qualifier will
have around 3 std::strings inside of it, so passing by value can churn
allocations a little bit.
Fix -WSwitch warning about unhandled enum value SDL_NUM_LOG_PRIORITIES.
log_level is initialized to LNOTICE right before the switch statement so
this doesn't cause any behavior changes.
I've received a report from an Android user with a gamepad (a "BSP-D3")
where one physical trigger is controlling two analog axes at the same
time. This was causing RemoveSpuriousTriggerCombinations to delete both
axes, which is clearly not a desireable outcome.
With this change, now the axis with the greatest smoothness is kept,
or both in case they have the same smoothness.
A comment removed by this commit gives two reasons for listening to
slave devices, both of which no longer apply:
- "Only slaves emit raw motion events": perhaps this was true when the
comment was written, but now master devices provide raw motion events
along with the other raw events.
- "Selecting slave keyboards avoids dealing with key focus": we get raw
key events regardless of the focus.
Listening to both master and slave devices results in duplicate raw
events. For button and key events, that's a tiny waste of time setting
the update flag a second time, but for raw mouse events the raw motion
will be processed twice. That makes this commit a user-facing change.
In X, the ButtonPress events generated when a mouse button is pressed
have a special property: if they don't activate an existing passive
grab, the X server automatically activates the "implicit passive grab"
on behalf of the client the event is delivered to. This ensures the
ButtonRelease event is delivered to the same client even if the pointer
moves between windows, but it also causes all events from that pointer
to be delivered exclusively to that client. As a consequence of the
implicit passive grab, for each window, only one client can listen for
ButtonPress events; any further listeners would never receive the event.
XInput 1 made the implicit grab optional and explicit by allowing
clients to listen for DeviceButtonPress events without
DeviceButtonPressGrab events. XInput 2 does not have a separate grab
event class, but multiple clients can listen for XI_ButtonPress on the
same window. When a button is pressed, the X server first tries to
deliver an XI_ButtonPress event; if no clients want it, then the server
tries to deliver a DeviceButtonPress event; if no clients want it, then
the server tries to deliver a ButtonPress event. Once an event has been
delivered, event processing stops and earlier protocol levels are not
considered. The reason for this rule is not obviously documented, but
it is probably because of the implicit passive grab; a client receiving
a ButtonPress event assumes it is the only client receiving that event,
and later protocols maintain that property for backward compatibility.
Before this commit, Dolphin listened for XI_ButtonPress events on the
root window. This interferes with window managers that expect to
receive ButtonPress events on the root window, such as awesome and
Openbox. In Openbox, applications are often launched from a menu
activated by clicking on the root window, and desktops are switched by
scroll wheel input on the root window. This makes normal use of other
applications difficult when Dolphin is open (though Openbox keyboard
shortcuts still work). Conversely, Dolphin only receives XI_ButtonPress
events for clicks on the root window or window decorations (title bars),
not on Dolphin's windows' content or the render window. In window
managers that use a "virtual root window" covering the actual root
window, such as Mutter running in X, Dolphin and the window manager do
not conflict, but clicks delivered to other applications using XInput2
(for testing, try xinput --test-xi2) are not seen by Dolphin, which is
relevant when background input is enabled.
This commit changes Dolphin to listen for XI_RawButtonPress (and the raw
versions of other events); Dolphin was already listening to XI_RawMotion
for raw mouse movement. Raw events are always and exclusively delivered
to the root window and are delivered to every client listening for them,
so Dolphin will not interfere with (or be interfered with by) other
applications listening for events.
As part of being raw, button numbers and keycodes in raw events have not
had mapping applied. If a left-handed user swapped the left and right
buttons on their mouse, raw events do not reflect that. It is possible
to query the mappings for each device and apply them manually, but that
would require a fair amount of code, including listening for mapping
changes.
Instead, Dolphin now uses the events only to set a "changed" flag, then
queries the current button and key state after processing all events.
Dolphin was already querying the pointer to get its absolute position
and querying the keyboard to filter the key bitmap it created from
events; now Dolphin also uses the button state from the pointer query
and uses the keyboard query directly.
Queries have a performance cost because they are synchronous requests to
the X server (Dolphin waits for the result). Commit 2b640a4f made the
pointer query conditional on receiving a motion event to "cut down on
round trips", but commit bbb12a75 added an unconditional keyboard query,
and there have apparently been no performance complaints. This commit
queries the pointer slightly more often (on button events in addition to
motion), but only queries the keyboard after key events, so the total
rate of queries should be substantially reduced.
Fixes: https://bugs.dolphin-emu.org/issues/10668
We need XInput 2.1 to get raw events on the root window even while
another client has a grab. We currently use raw events for relative
mouse input, and upcoming commits will use raw events for buttons and
keys.
This reads Steam Deck controls bypassing Steam Input. This allows for access to
motion controls as well as independent access to thumb sticks, trackpads, and
back grip buttons.
XInput2 was created to support multiple pointer/keyboard pairs (often
called MPX for multi-pointer X). Dolphin's XInput2 implementation has
always supported MPX by creating a KeyboardMouse object per master
pointer. Since commit bbb12a7, Dolphin's keyboard state is filtered by
the output of XQueryKeymap. As a core X function, XQueryKeymap queries
"the" keyboard, which by default is the first master keyboard. As a
result, Dolphin will ignore keys pressed on other master keyboards
unless the first master is simultaneously pressing the same keys.
XInput2 doesn't provide a function to query the keyboard state. There
is no XIQueryKeymap and the current state is not a member of the
XIKeyClassInfo returned by XIQueryDevice. Instead, XInput2 allows a
master pointer to be nominated as "the" pointer on a per-client basis,
with "the" keyboard automatically becoming the associated master
keyboard. The "documentation" [1] says passing None for the window is
only for debugging purposes, but it is documented in the
XISetClientPointer man page and seems to be the only way to query
keyboards beyond the first.
With this commit, Dolphin correctly reads keys from keyboards other than
the first master keyboard. To test, use the xinput command-line utility
to create a master pointer and reattach a keyboard to the associated
master keyboard.
[1]: https://who-t.blogspot.com/2009/07/xi2-recipes-part-6.html
(the XInput2 developer's blog)
In UpdateInput, lock m_devices_population_mutex before m_devices_mutex
to be consistent with other ControllerInterface functions. Normally the
former lock isn't needed in UpdateInput, but when a Wii Remote
disconnects it calls RemoveDevice which results in the mutexes being
locked in the wrong order.
Up until now, there have been two settings on Android that stored the
selected Wii Remote extension: the normal one that's also used on PC,
and a SharedPreferences one that's used by the overlay controls to
determine what controls to show. It is possible for these two to end up
out of sync, and my input changes have made that more likely to happen.
To fix this, let's rework how the overlay controller setting works.
We don't want it to encode the currently selected Wii Remote extension.
However, we can't simply get rid of the setting, because for some Wii
games we need the ability to switch between a GameCube controller and a
Wii Remote. What this commit does is give the user the option to select
any of the 4 GameCube controllers and any of the 4 Wii Remotes. (Before,
controllers 2-4 weren't available in the overlay.) Could be useful for
things like the Psycho Mantis fight in Metal Gear Solid. I'm also
switching from SharedPreferences to Dolphin.ini while I'm at it.
It's missing a lot of features from the PC version for now, like
buttons for inserting functions and the ability to see what the
expression evaluates to. I mostly just wanted to get something in
place so you can set up rumble.
Co-authored-by: Charles Lombardo <clombardo169@gmail.com>
This is a battery-saving measure. Whether a sensor should be suspended
is determined in the same way as whether key events and motion events
should be handled by the OS rather than consumed by Dolphin.
When Android presents an input event to an app, it wants the app to
return true or false depending on whether the app handled the event or
not. If the event wasn't handled by the app, it will be passed on to
the system, which may decide to take an action depending on what kind
of input event it is. For instance, if a B button press is passed on to
the system, it will be turned into a Back press. But if an R1 press is
passed on to the system, nothing in particular happens.
It's important that we get this return value right in Dolphin. For
instance, the user generally wouldn't want a B button press to open
the EmulationActivity menu, so B button presses usually shouldn't be
passed on to the system - but volume button presses usually should be
passed on to the system, since it would be hard to adjust the volume
otherwise. What ButtonManager did was to pass on input events that are
for a button which the user has not mapped, which I think makes sense.
But exactly how to implement that is more complicated in the new input
backend than in ButtonManager, because now we have a separation between
the input backend and the code that keeps track of the user's mappings.
What I'm going with in this commit is to treat an input as mapped if
it has been polled recently. In part I chose this because it seemed
like a simple way of implementing it that wouldn't cause too many
layering violations, but it also has two useful side effects:
1. If a controller is not being polled (e.g. GameCube controllers in
Wii games that don't use them), its mappings will not be considered.
2. Once sensor input is implemented in the Android input backend,
we will be able to use this "polled recently" tracking to power down
the sensors at times when the game is using a Wii Remote reporting
mode that doesn't include motion data. (Assuming that the sensor
inputs only are mapped to Wii Remote motion controls, that is.)
Android doesn't let us poll inputs whenever we want. Instead, we
listen to input events (activities will have to forward them to the
input backend), and store the received values in atomic variables
in the Input classes. This is similar in concept to how ButtonManager
worked, but without its homegrown second input mapping system.
ButtonManager is very different from how a normal input backend works,
and is making it hard for us to improve controller support on Android.
The following commits will add a new input backend in its place.
I also changed LoadConfig, but that change doesn't affect correctness,
it's only so it looks neat by matching SaveConfig.
This bug was added in 18a4afb053, the
commit that introduced DefaultValue::Disabled. The bug can't actually be
triggered in master, but it can be triggered in the Android input
overhaul PR.