In the old Input System, using GetMouseButton(0) is checking the operating system’s Primary button.
However in the new System you can only bind actions to either Left or Right buttons - not Primary or Secondary.
This means that if I use the mouse in my left hand, changing my Windows settings so my primary button is right one - the UI (and any other actions using the mouse) stops working.
And testing Input.GetMouseButton(0) is called correctly according to whichever button I set as the primary one.
Am I missing an obvious solution for this?
In the Input System UI Input Module the Left Click is assigned the UI/Click action.
The UI/Click action is bound to the Left Button [Mouse].
Heh, I seriously had to go check the source code for that as the docs don’t mention it. And even in the code, I’m wondering whether it’s just a side effect or was expressly done this way. But you’re right, in the old system mouse input is picked up via two different code paths. Some from RawInput but most from WM_ messages which indeed flip the meaning of “left button” according to the system setting (as reflected by the test you’ve done).
Unfortunately, no. It’s missing on our side. I’ve made a note in the backlog (ISX-322).
button values are 0 for the primary button (often the left button), 1 for secondary button, and 2 for the middle button.
I also thought the docs might be wrong so had to actually write the code and change my Primary button on the fly to make sure it actually works
Thanks for the reply! Is there a workaround you can think of? I thought about:
Creating a Custom Device and setting its state with the old Input.GetMouseDown. This works, BUT apparently the InputSystemUIInputModule does not actually use the bound actions it seems.
Changing InputSystemUIInputModule so when it sends the UI events it uses the old Input System behind the scenes. Looking specifically at InputSystemUIInputModule.ProcessMouse.
I think the “right” approach (and by right I mean something I can do myself without digging too deep into the low-level code), is replace the Process Mouse functionality with something that reads the old Input data and constructs a pointer event data from that.
Since I assume the old Input Module created the Pointer Event Data like that - is there a reference anywhere where I can see that code and copy just the relevant bit over?
Any chance of any follow-up on this?
Not sure how long it would take the fix now it’s in the backlog, but it would be great if you could point me in the right direction to fixing this locally, hacky or otherwise.
My suggested workaround would be to PInvoke into the Win32 API to find the setting and then alter the binding in the UI input module accordingly. The module does pick up input entirely through actions so depending on what you read out from the system setting, you could swap the left and right click action on the fly.
Thanks for the reply!
Out of interest - is that how the old input system does that when doing GetMouseButton(0)?
If so, any chance you could share the relevant code here?
Right, so if I wanted to use that it would essentially be creating a “new” mouse input with new controls and invoking them myself I suppose?
A bit more than I had hoped!
Is there any info you can share about priority on your end? Is the issue small and will likely be fixed in any upcoming versions? Or is it too much of a pain and will likely not get fixed, in which case I should solve it on my own anyway?
Luckily, it’s simpler than that. Basically like this (typing this out on the fly in a chat box so no guarantees this even compiles :)).
public class MyWin32ButtonSwapFixer : MonoBehaviour
{
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
[DllImport("User32.dll")]
private static int GetSystemMetrics(int);
public void OnEnable()
{
// Determine if button is swapped.
if (GetSystemMetrics(23) == 0) // 23 is SM_SWAPBUTTON
return; // No.
// Override left button bindings to refer to right button and vice versa.
var playerInput = GetComponent<PlayerInput>();
var actions = playerInput.actions;
foreach (var map in actions.actionMaps)
{
var bindings = map.bindings;
for (var i = 0; i < bindingsCount; ++i)
if (bindings[i].effectivePath == "<Mouse>/leftButton";
map.ApplyBindingOverride(i, new InputBinding { overridePath = "<Mouse>/rightButton" });
else if (bindings[i].effectivePath == "<Mouse>/rightButton";
map.ApplyBindingOverride(i, new InputBinding { overridePath = "<Mouse>/leftButton" });
}
}
#endif
}
The effect could be applied may different ways (different control schemes, switch statement if polling devices directly, swapping path strings from Mouse.current[“leftButton”] to Mouse.current[“rightButton”], etc).
It’s a small change. Unfortunately it’s one in the native backend so makes this a bit more painful. It’ll get fixed but not for 1.0.
To apply some extra pressure, feel free to file a bug report in case you haven’t already
@Rene-Damm
Was it changed somehow since that time?
I’m on Input System 1.3.0 and the issue still occurs - Input System seems to ignore system settings.
Is there any way to change/alter this behavior or do I still need to read system settings manually (and swap buttons by myself somewhere during input processing)?