TouchPhase.Began doesn't always happen.

Hi all,

Just working with the new input system and I’ve found some issues with touch input. For some reason TouchPhase.Began doesn’t always happen, is there some reason why that would happen?
Maybe the update?

    private void Awake()
    {
        UnityEngine.InputSystem.EnhancedTouch.EnhancedTouchSupport.Enable();
    }

    public void Update()
    {
        foreach (var finger in UnityEngine.InputSystem.EnhancedTouch.Touch.activeFingers)
        {
            Debug.Log( finger.currentTouch.phase+" <<");
            if (finger.currentTouch.phase ==  UnityEngine.InputSystem.TouchPhase.Began)
            {
                Beep();
            }
        }
    }

Also for some weird reason, if I build to the iPad TouchPhase.Began fires constantly during a press.

Oh I should say this is on input system 1.0.0 and Unity 2019.4

Well it looks like the began phase is unreliable even though the touch count changes.
I moved my ‘Began’ code into touch phase - Began, Moved and Stationary with a bunch of checks to make sure it only runs once before any ‘moved’ stuff. Bit of a shame it feels pretty hacky.

Should be fixed as of 1.1-preview.1.

1 Like

Ahh that’s working great! Thanks :slight_smile:

Hi,

I try the same code from the first post.

i have the same issue the began work only about 8/10 time and i have installed the 1.1.preview 3

do you found a workaround?
or i need to setup differently? fixeupdate … ?

thank you for your help
Best Regards
Daniel

Unity 2020.2.3f1

hardware:
IIyama 27355msc (27") 10 touch
windows 10 V:2004
intel I7 9th gen 9750H / 32Gb
rtx 2080 Qmax

Hi Daniel, would you mind filing a ticket with the bug reporter (Help >> Report a Bug… in the Unity editor)? Sounds like there’s potentially a separate thing with Windows touch input that needs looking at.

Same. Some touches don’t trigger Began, but Input Debugger show Began phase.

Device: LG G2
Unity: 2020.2.1f1, 2020.3.12f1
Package: Input System 1.1.0-preview.3 (LTS doesn’t support newer package)

private void Update()
{
    var touch = Touchscreen.current?.primaryTouch;
    if (touch == null)
        return;

    var id = touch.touchId.ReadValue();
    var phase = touch.phase.ReadValue();

    // Missing (phase == TouchPhase.Began) for some swipes
    Debug.LogWarning($"Touch {id}, Phase {phase}");
}

How (I didn’t touching anything)?

I don’t know if this might help in your case, but I believe that is not recommended to use the Touchscreen API in an Update for pooling, Unity recommends using the EnanchedTouch for that use case: https://discussions.unity.com/t/785883

For what it’s worth, I stopped having the TouchBegan issue after updating to preview5!

For me the bug seems to still be happening for Version 1.1.1 (- September 09, 2021) and Unity 2021.1.21f1.3059 Personal. (Just trying to make a simple multitouch tester as a start)
Same code for touchphase detection like in the thread start. Touchphase.Began most times but not always run in the Update() loop, but touchcount correctly detected.
Running my test on redmi k20 miui 12.5.1 android 11.

Double checked with https://play.google.com/store/apps/details?id=com.the511plus.MultiTouchTester that it is not some device error. Also i ignore launcher gestures. (MIUI three finger [swipe] for screenshots as an example)

Most times Touchphase.Began seems to have not fired when finger quickly in succession are touching.
Maybe too fast for Update() polling? Could the touchphase of late finger at end of one Update() loop get overwritten by the start of the next Update() loop without firing?

Have looked at Touch support | Input System | 1.1.1 where the bug is even commented as a Note.

Would be nice to update the example Class EnhancedTouchSupport | Input System | 1.1.1 to
reflect the comment and show an event driven example that is decoupled from Update() polling.

I have adapted the example from

where functions are coupled to the events.

{
EnhancedTouchSupport.Enable();

Touch.onFingerDown += Touch_onFingerDown;
Touch.onFingerUp += Touch_onFingerUp;
Touch.onFingerMove += Touch_onFingerMove;
}

protected void OnDisable()
{
EnhancedTouchSupport.Disable();

Touch.onFingerDown -= Touch_onFingerDown;
Touch.onFingerUp -= Touch_onFingerUp;
Touch.onFingerMove -= Touch_onFingerMove;
}

private void Touch_onFingerDown(Finger latestFinger)
{
//use only the currently changed latestFinger
//or if you still need to process all fingers can still use the same function as in Update()
foreach (Finger finger in Touch.activeFingers)
{
}
}

//same for the other two functions Touch_onFingerUp(), Touch_onFingerMove()

Now finger seems to always be correctly detected

2 Likes

hi, i found a hackie way around this using a bool and a timer to reset, check out below.

in - else if (Input.touchCount <= 0 && hasShotSingle) i reset the touch object to default values, this resets the touch values manually, so far no issues.

touch = default;

if(canShoot)
        {
            if (justShotSingle)
            {
                singleShotCounter -= Time.deltaTime;
                if (singleShotCounter <= 0)
                {
                    ShootNow = true;
                    justShotSingle = false;
                    singleShotCounter = timeBetweenShots;
                }
            }
            if (Input.touchCount > 0)
            {
                touch = Input.GetTouch(0);
            }
            else if (Input.touchCount <= 0 && hasShotSingle)
            {
                touch = default;
                hasShotSingle = false;
                justShotSingle = true;
            }

            if (touch.phase > 0)
            {
                if (touch.phase == TouchPhase.Stationary || touch.phase == TouchPhase.Moved)
                {
                    shotCounter -= Time.deltaTime;
                    if (shotCounter <= 0)
                    {
                        shotOne = psPool.GetBullets();

                        shotOne.transform.position = shotPointL.position;
                        shotOne.transform.rotation = shotPointL.rotation;

                        shotOne.gameObject.SetActive(true);

                        shotTwo = psPool.GetBullets();

                        shotTwo.transform.position = shotPointR.position;
                        shotTwo.transform.rotation = shotPointR.rotation;

                        shotTwo.gameObject.SetActive(true);

                        shotOne = default;
                        shotTwo = default;

                        shotCounter = timeBetweenShots;
                        //hasShotSingle = true;
                    }
                }
                if (ShootNow)
                {
                    shotOne = psPool.GetBullets();

                    shotOne.transform.position = shotPointL.position;
                    shotOne.transform.rotation = shotPointL.rotation;

                    shotOne.gameObject.SetActive(true);

                    shotTwo = psPool.GetBullets();

                    shotTwo.transform.position = shotPointR.position;
                    shotTwo.transform.rotation = shotPointR.rotation;

                    shotTwo.gameObject.SetActive(true);

                    shotOne = default;
                    shotTwo = default;

                    shotCounter = timeBetweenShots;
                    singleShotCounter = timeBetweenShots;
                    ShootNow = false;
                    hasShotSingle = true;
                    //justShotSingle = true;
                    //hasShotSingle = true;
                }
            }
        }