Forum rules - please read before posting.

Tap to click on MacOS and Input System

Hi!

If this is too Unity-specific, please forgive me and tell me to go elsewhere, but here goes:

We wanted to customize the mouse and touchscreen input a bit for our game and being somewhat new to Unity, Input Manager got us nowhere while Input System did. What we want to achieve is RMB/SlowTap opening the interaction menu, basically, and outside hotspots showing the hotspot labels of all visible hotspots.

Unity version is 2021.3.16f1 though it behaves the same on 2022.whatever, which makes sense, as the Input System Package is the same 1.4.4.

I used the Wiki delegates as a baseline, made mouse always return false; to rely on InteractionA and InteractionB, all of which is fine.

Until I dug up my old MacBook Pro and enabled tap-to-click.

This is a problem practically impossible to screenshot, but through the input debugger, I see tapping the touchpad counts toward clickCount and only seldom does a double-click act as leftButton. Same in the game, unreliable movement and such by double-tapping.

I'm also a bit at a loss of what to "leak" about our code, because none of it's broken if you use a mouse or real clicks on the Mac. OTOH the project did completely break down on Android, but I haven't gotten around to debugging it yet, and that's a subject for another thread if needed, unless it's all the some shared underlying issue.

Just in case, here's InputSystemIntegration https://pastebin.com/2EXUvSY9 with a one-week expiry.

The MenuManager EventSystem prefab should be quite simple as well, pasted at https://www.imgpaste.net/image/K6cb1x

I suppose my question to get us started is this: Do I need to reimplement basically all of the PlayerInput.UpdateInput() code just to manually account for what adds up to a click or doubleclick? There must be a simpler way.

Thanks to anyone who has ideas for this!

Comments

  • Welcome the community, @mjtorn.

    AC's UpdateInput function will auto-detect double-clicks when it registers two clicks in succession made within its doubleClickDelay float variable.

    The clicks themselves are detected using the delegates you've been overriding - which one is used will be based on your settings. You can uncheck Mouse clicks have default functionality?, for example, to have AC only rely on the "InputGetButton" variants, rather than "InputGetMouseButton".

    It sounds like you've delved some way into the issue beforehand, but I think it's best if we take things back a little and start with the original issue. Input System has its advantages (and a proper integration package can be found on the Downloads page), but it shouldn't be strictly necessary just to get things working. It's also the case that the integration relies on overriding the delegates, so if you end up rewriting these it may be best to go back to Input Manager and tweak things from there.

    To get a more general sense of what you're trying to achieve: you're looking to have the game work both on desktop, and mobiles? These would need separate builds, with each having the Settings Manager's Input method set differently. If you can share a screenshot of your full Settings Manager, that will help me understand how your game is played.

    With Mouse And Keyboard, and rechecking the "default functionality" box mentioned above, you can switch to a right-click for opening Interaction menus with the following:

    using UnityEngine;
    using AC;
    
    public class RightClickInteractions : MonoBehaviour
    {
    
        void Start ()
        {
            KickStarter.playerInput.InputGetMouseButtonDownDelegate = My_GetMouseButtonDown;
        }
    
    
        bool My_GetMouseButtonDown (int button)
        {
            if (button == 0 && KickStarter.playerInteraction.GetActiveHotspot ())
            {
                return Input.GetMouseButtonDown (1);
            }
            return Input.GetMouseButtonDown (0);
        }
    
    }
    

    An additional override can be added to have this work with touch-screen, but I'm not sure I'm clear on what you mean by "slow tap". When using Touch Screen input, are you looking to open Interaction menus by double-tapping within a set timeframe?

  • Welcome the community, @mjtorn.

    Thank you!

    AC's UpdateInput function will auto-detect double-clicks when it registers two clicks in succession made within its doubleClickDelay float variable.

    Though we're drifting into Android territory here, note that the big issue here is pretty much what you just said, but with MacOS giving tap-to-click touchpad events in some bizarre manner, where they don't count as mouse buttons but only clickCounts.

    Which is why I'm worried I'll end up re-implementing a lot of your excellent work, probably poorly.

    Thus I'd like to know if there's an Input System configuration for AC-on-MacOS that I've missed or something else :/

    The clicks themselves are detected using the delegates you've been overriding - which one is used will be based on your settings. You can uncheck Mouse clicks have default functionality?, for example, to have AC only rely on the "InputGetButton" variants, rather than "InputGetMouseButton".

    That's what I've done, sure, because I figured using Input System will give me the correct abstractions for dealing with InteractionA and InteractionB without separately worrying about mice and touches. Let's see how wrong I end up being.

    It sounds like you've delved some way into the issue beforehand, but I think it's best if we take things back a little and start with the original issue. Input System has its advantages (and a proper integration package can be found on the Downloads page), but it shouldn't be strictly necessary just to get things working.

    I did install it before and kinda forgot about it, which is probably a good thing. Probably means that it's in effect ;)

    It's also the case that the integration relies on overriding the delegates, so if you end up rewriting these it may be best to go back to Input Manager and tweak things from there.

    I might have learned enough from this ordeal that Input Manager is less daunting now, but the worst situation of all - on Android - is as follows: Using two fingers (doubletap?) for RMB/InteractionB is essentially unusable in our game, on phones, because the inventory is always visible at the center botton. You gotta cram those fingers incredibly tight and be superhumanly precise to trigger the Examine action.

    That's the impetus for looking into Input System instead, to remap that to keeping one finger on the inventory item a bit longer instead.

    Tap to pick up, slowtap to examine, deselect item, any RMB thing.

    To get a more general sense of what you're trying to achieve: you're looking to have the game work both on desktop, and mobiles? These would need separate builds, with each having the Settings Manager's Input method set differently.

    Yes. I do not know what the best practices are, but we have a sanctified Android branch that gets rebased onto our integration branch. It contains separate PNGs for gameplay instructions, some slightly larger menus, we like the "legacy" 186:100 aspect ratio, and of course that input method.

    If you can share a screenshot of your full Settings Manager, that will help me understand how your game is played.

    Sure, though it doesn't fit all at once so I'm pasting in parts.

    Here's the interaction and inventory settings https://www.imgpaste.net/image/K6CMuI

    Required inputes, movement, and camera https://www.imgpaste.net/image/K6CF7T

    Hotspot, audio, raycast, loading, and default options and you don't probably need a screenshot for the debug settings that didn't quite fit https://www.imgpaste.net/image/K6Ct3z

    The less likely to be interesting save, cutscene, and characters https://www.imgpaste.net/image/K6C3Ru

    I didn't debug this fully yet, but I suppose my code changes things because double-tapping does not open the action menu.

    There's a separate handler I wrote for Input Manager, if (AC.KickStarter.playerInput.GetMouseState() == AC.MouseState.DoubleClick), which runs a use interaction if available, as default behavior.

    With Mouse And Keyboard, and rechecking the "default functionality" box mentioned above, you can switch to a right-click for opening Interaction menus with the following:

    [snip]

    That looks like a really simple solution, but I'm quite tempted to get this Input System code going. There's so little left in the way of issues!

    An additional override can be added to have this work with touch-screen, but I'm not sure I'm clear on what you mean by "slow tap". When using Touch Screen input, are you looking to open Interaction menus by double-tapping within a set timeframe?

    The way touchscreen would have to work is, and as said, I haven't debugged this at all yet:

    1) Two fingers on the screen would preferably do nothing, but won't consider it a release blocker if it does
    2) Tapping for longer than a regular tap, ie slowtap, would deselect the current inventory item
    3) Slowtap over an item in the inventory would do the examine action
    4) Slowtap over a hotspot would open the interaction menu

    The following are broken:

    2) It does not deselect, but I'm sure the delegate would listen for InteractionB and check if runtimeInventory.selectedItem or somesuch is not null and SetNull where required
    3) Something similar to 2)

    The interesting bug is maybe a misplaced GetLastOrActiveHotspot() which causes 4) to misbehave. If you tap a hotspot, then tap outside the hotspot, the menu opens where you clicked outside it. Click again elsewhere off-hotspot, it closes, but again off-hotspot it opens again.

    So this is how far we strayed from Apple's tap-to-touch not working properly, but I do speak for more than myself when I say we appreciate the help with Android as well! :)

  • Thanks for the details.

    As you're using a custom Interaction system, a lot of the input delegate overriding may not be needed. If you're in control over the effect of a right-click/double-tap, then having AC still register those as normal may not necessarily be an issue.

    We can see about an Input System equivalent later, but as it's another layer of complexity I'd like to see if we can get the intended behaviour working with Input Manager first. Best to start simple and build up from there.

    This code snippet allows for a "slow tap/click" over Hotspots to bring up the Interaction menu. It does work for me on a MacOS touchpad, but differing OS versions may account for a difference in behaviour on your end:

    bool isTapped;
    float tapDuration;
    public float slowTapDuration = 0.5f;
    
    void Update ()
    {
        if (TapIsHeld ())
        {
            isTapped = true;
            tapDuration += Time.deltaTime;
        }
        else
        {
            if (isTapped && tapDuration > slowTapDuration)
            {
                OnSlowTap ();
            }
    
            isTapped = false;
            tapDuration = 0f;
        }
    }
    
    void OnSlowTap ()
    {
        Hotspot hotspot = KickStarter.playerInteraction.GetActiveHotspot ();
        if (hotspot)
        {
            KickStarter.playerMenus.EnableInteractionMenus (hotspot);
        }
    }
    
    bool TapIsHeld ()
    {
        return Input.GetMouseButton (0) || Input.touchCount == 1;
    }
    

    If you have this replace your own interaction script, does this give you the correct interaction menu behaviour on your intended platforms?

  • A quick status update, as it took me a jolly while to get rid of the Input System integration with the weekend and all: With a few further tweaks to the RightClickInteraction script, that seems to fulfill our needs, so thank you :)

    There's a catch, though, because we also have this script attached to our hotspots, checking omitted for brevity:

    public class HotspotDoubleClick : MonoBehaviour {
        void Update() {
            if (AC.KickStarter.playerInput.GetMouseState() == AC.MouseState.DoubleClick) {
                AC.KickStarter.playerInteraction.GetActiveHotspot().RunUseInteraction();
            }
        }
    }
    

    The idea being that the first interaction is run by default. The state appears to always be RightClick and I haven't yet found a way to make LMB do the double-clicking correctly despite your script; is there an obvious solution I'm missing?

    The offending part must be return Input.GetMouseButtonDown(1); because when we're looking for LMB for a potential double-click, we always return the RMB state, which gets set as mouseState when asking for PlayerInput.InputGetMouseButtonDown(1).

    I also checked out the OnDoubleClickHotspot delegate but that appeared to be only for inventory items, or at least I didn't see it work.

    Android will be checked out soon, don't worry, and thank you again!

  • If you're looking to have double-clicks come from LMB, then bypass the RightClickInteractions script, which works by replacing LMB calls with RMB input.

    Overriding delegates is more suited to more isolated input tweaks, and I'd recommend the reading of input directly as above over trying to change behaviour using overrides.

    Since you're triggering interactions manually through script, you're not limited to using AC's input checks - the double-clicks can be checked for within your HotspotDoubleClick script:

    private float clickTimer;
    public float doubleClickDuration = 0.3f;
    
    private void Update ()
    {
        if (clickTimer > 0f)
        {
            clickTimer += Time.unscaledDeltaTime;
            if (clickTimer > doubleClickDuration) clickTimer = 0f;
        }
    
        if (Input.GetMouseButtonDown (0))
        {
            if (clickTimer > 0f && clickTimer <= doubleClickDuration)
            {
                AC.KickStarter.playerInteraction.GetActiveHotspot ().RunUseInteraction ();
            }
            else
            {
                clickTimer = Time.unscaledDeltaTime;
            }
        }
    }
    
  • Still nothing on Android on our end (yay weekend) but I adapted your script and it works great.

    I actually had some issues with something we had in Active Inputs, which I'd done completely differently on Input System, and eventually had to drop the Active Inputs entirely and deal with it separately.

    From that experience I realized that the best implementation (for us, at least) is a loving parody of what Input System would do, put in menuManager.eventSystem. And tie things tightly together because synchronizing things across Update()s feels quite difficult.

    Moved our HotspotDoubleClick there as well to save the hassle of adding to every hotspot; much rather have a HotspotDoubleClickDisabler if we ever needed one.

    Good stuff, thank you very much! I'll let you know how mobile works out :)

  • I didn't try it on Android myself yet, but the guy who integrated it says it works great for him. I did try out what happens on a PC and the effect is interesting with a real mouse ;) Maybe not something to document as a primary choice but someone may find it as an easter egg and want to play that way.

    I doubt the extra checking for hotspots costs that many cpu cycles and now we don't need to do build-time checking for Android.

    Thank you once again!

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.