Search Unity

Bug shouldHideSoftKeyboard bug on iOS?

Discussion in 'UGUI & TextMesh Pro' started by bigbrainz, Mar 31, 2023.

  1. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    177
    Hello, we're encountering an issue in our project where it's having a hard time correctly working with an iPad's Smart Keyboard.

    If we never set `shouldHideSoftKeyboard` to anything, the TMPRO inputs can detect and use the keyboard input correctly. Or, if we only set it to `false`, it works correctly.

    But if we start detecting whether the keyboard is attached, or not, and switch it back and forth from `true` to `false`, it stops detecting keyboard input.

    After updating to the 3.2.0 preview version, it now accepts one character input, and then stops. So it seems like they fixed it, but only for 1 frame or 1 input.

    Maybe it has something to do with this "fix" we saw in this new version:

    Or maybe we're just not using it quite right. We can't find any documentation for shouldHideSoftKeyboard.
    Very strange. If you have any tips about how we might be able to fix this, that would be superb.

    Thanks!

    Code (CSharp):
    1.     private void UpdateControlType()
    2.     {
    3.         if (MobileCheck())
    4.         {
    5.             if (GameManagers.currentControl == GameManagers.CurrentControlType.Physical_Keyboard)
    6.             {
    7.                 shouldHideSoftKeyboard = false;
    8.             }
    9.             else
    10.             {
    11.                 shouldHideSoftKeyboard = true;
    12.             }
    13.         }
    14.     }
     
  2. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    177
    Well, the "solution" was curious. It turns out that calling this function from `Update` broke it for Smart Keyboards. Not exactly sure why.

    Also, simply referencing the status of `shouldHideSoftKeyboard` n a debug statement, from within a LateUpdate function, broke it. Fragile.
     
  3. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    177
  4. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    177
    Ah, and it seems like the Pre-Release 3.2 TMPro release is definitely helping. That's why it's working as well as it is now. But it's still pretty fragile. I'll see if we can put together a clean file we can use to submit for a bug report.
     
  5. Tricnic

    Tricnic

    Joined:
    Apr 6, 2014
    Posts:
    6
    I am facing a very similar bug on the Quest 2. Digging into the TMP_InputField code, it really feels like this line of code in LateUpdate on line 1537 is the culprit.

    Code (CSharp):
    1.  
    2.             if (InPlaceEditing() && isKeyboardUsingEvents() || !isFocused)
    3.             {
    4.                 return;
    5.             }
    6.  
    On Android platforms:
    InPlaceEditing() will return true if TouchScreenKeyboard.isSupported (always true on Android) and either shouldHideSoftKeyboard or shouldHideMobileInput is set to true.

    Code (CSharp):
    1.  
    2.         private bool InPlaceEditing()
    3.         {
    4.             if (Application.platform == RuntimePlatform.WSAPlayerX86 || Application.platform == RuntimePlatform.WSAPlayerX64 || Application.platform == RuntimePlatform.WSAPlayerARM)
    5.                 return !TouchScreenKeyboard.isSupported || m_TouchKeyboardAllowsInPlaceEditing;
    6.  
    7.             if (TouchScreenKeyboard.isSupported && shouldHideSoftKeyboard)
    8.                 return true;
    9.  
    10.             if (TouchScreenKeyboard.isSupported && shouldHideSoftKeyboard == false && shouldHideMobileInput == false)
    11.                 return false;
    12.  
    13.             return true;
    14.         }
    15.  
    That's all good. If you want to handle the input yourself, set one of those two properties to true, but...

    isKeyboardUsingEvents() will never return true on Android due to this:

    Code (CSharp):
    1.  
    2.         private bool isKeyboardUsingEvents()
    3.         {
    4.             switch (Application.platform)
    5.             {
    6.                 case RuntimePlatform.Android:
    7.                 case RuntimePlatform.IPhonePlayer:
    8.                 case RuntimePlatform.tvOS:
    9.                 #if UNITY_2020_2_OR_NEWER
    10.                 case RuntimePlatform.PS4:
    11.                     #if !(UNITY_2020_2_1 || UNITY_2020_2_2)
    12.                     case RuntimePlatform.PS5:
    13.                     #endif
    14.                 #endif
    15.                 case RuntimePlatform.Switch:
    16.                     return false;
    17.                 default:
    18.                     return true;
    19.             }
    20.         }
    21.  
    What this means is that "InPlaceEditing() && isKeyboardUsingEvents()" will never be true on Android, meaning that the above if statement will only ever be true if the input field is not focused.

    I think the if statement should be changed to:
    Code (CSharp):
    1.  
    2.             if (InPlaceEditing() || isKeyboardUsingEvents() || !isFocused)
    3.             {
    4.                 return;
    5.             }
    6.  
    If someone has more info on this and has a good reason why it should be &&, I'd love to be enlightened, but my understanding of this bit of code is telling me it should be ||.

    As a bonus observation, wouldn't the isKeyboardUsingEvents() method mean that you couldn't attach a USB/Bluetooth keyboard to an Android device and use that? I've never tried using a physical keyboard on an Android device before, so I'm not sure.
     
  6. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    177
    @Tricnic, we haven't dug into the Android part yet, so I don't have anything helpful to say about your insight yet, although I suspect you're right.

    However, I need to add that it seems this issue has been "fixed." Part of the problem may have been our very large project code. Part of it may be that now we're on the Pre-Release 3.2 AND we updated from 2021.3.21f1 to 2021.3.22f1.

    But in a nutshell, we finally got the functionality to basically work like we wanted it to with Smart Keyboards on iPads. Keyboard input was being recognized. But we were still seeing some weird stuff and errors. And then in the endless pursuit of tracking down all these weird bugs, we tested out just totally disabling this effort to manually switch back and forth between triggering shouldHideSoftKeyboard and shouldHideMobileInput . . . and that fixed it.

    I'm not sure if TMPro updated something or 2021.3.22f1 fixed something. But the "fixes" we were using previously were working, but also causing other problems and breaking it. So now it SEEMS to work just fine, automatically, switching smoothly back and forth between iPads with or without a Smart Keyboard. Without any "help" from us.

    We're really not sure what happened, but if you're having issues try just not messing with these settings at all and see if it might just work perfectly for you now.
     
  7. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    177
  8. bigbrainz

    bigbrainz

    Joined:
    Jul 21, 2015
    Posts:
    177
    Update: Solved it (again) by updating (again). Apparently they broke this around 2021.3.25f1, but fixed it again by 2021.3.31f1.
     
  9. Steopushkin

    Steopushkin

    Joined:
    May 13, 2016
    Posts:
    4
    You can fix this bug by making the TMP package local and changing the code of the TMP_InputField class on line 1553 from this one:

    Code (CSharp):
    1.  
    2.             if (m_SoftKeyboard == null || m_SoftKeyboard.status != TouchScreenKeyboard.Status.Visible)
    3.             {
    4.                 if (m_SoftKeyboard != null)
    5.                 {
    6.                     if (!m_ReadOnly)
    7.                         text = m_SoftKeyboard.text;
    8.  
    9.                     if (m_SoftKeyboard.status == TouchScreenKeyboard.Status.LostFocus)
    10.                         SendTouchScreenKeyboardStatusChanged();
    11.  
    12.                     if (m_SoftKeyboard.status == TouchScreenKeyboard.Status.Canceled)
    13.                     {
    14.                         m_ReleaseSelection = true;
    15.                         m_WasCanceled = true;
    16.                         SendTouchScreenKeyboardStatusChanged();
    17.                     }
    18.  
    19.                     if (m_SoftKeyboard.status == TouchScreenKeyboard.Status.Done)
    20.                     {
    21.                         m_ReleaseSelection = true;
    22.                         OnSubmit(null);
    23.                         SendTouchScreenKeyboardStatusChanged();
    24.                     }
    25.                 }
    26.  
    27.                 OnDeselect(null);
    28.                 return;
    29.             }
    30.  

    To this:
    Code (CSharp):
    1.  
    2.             if (m_SoftKeyboard == null)
    3.             {
    4.                 return;
    5.             }
    6.          
    7.             if (m_SoftKeyboard.status != TouchScreenKeyboard.Status.Visible)
    8.             {
    9.                 if (!m_ReadOnly)
    10.                     text = m_SoftKeyboard.text;
    11.  
    12.                 if (m_SoftKeyboard.status == TouchScreenKeyboard.Status.LostFocus)
    13.                     SendTouchScreenKeyboardStatusChanged();
    14.  
    15.                 if (m_SoftKeyboard.status == TouchScreenKeyboard.Status.Canceled)
    16.                 {
    17.                     m_ReleaseSelection = true;
    18.                     m_WasCanceled = true;
    19.                     SendTouchScreenKeyboardStatusChanged();
    20.                 }
    21.  
    22.                 if (m_SoftKeyboard.status == TouchScreenKeyboard.Status.Done)
    23.                 {
    24.                     m_ReleaseSelection = true;
    25.                     OnSubmit(null);
    26.                     SendTouchScreenKeyboardStatusChanged();
    27.                 }
    28.  
    29.                 OnDeselect(null);
    30.                 return;
    31.             }
    32.  

    Unity version 2021.3.0f1
    TMP version: 3.0.7

    This worked for me. I hope it will help you!