Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

TouchScreenKeyboard and losing focus

Discussion in 'Android' started by Rob4507, Aug 11, 2012.

  1. Rob4507

    Rob4507

    Joined:
    Aug 29, 2007
    Posts:
    53
    Hey guys,

    If anyone has a solution to this problem, I will be forever grateful.

    I need to use TouchScreenKeyboard to display the keyboard for different types of input: numbers, text, email, etc.

    The problem is that once you have "open"ed a keyboard, if the user touches the screen somewhere other than the keyboard, the keyboard disappears but Unity is not told anything. So, checking for done, active, or visible doesn't make any difference.

    This is really, really bad because my app has essentially froze because it is waiting for a keyboard that is now offscreen.

    Has anybody found a way around this? Please? I know I could possibly write a native extension or something but I'm limited for time and knowledge when it comes to native extensions.

    Thanks,

    -Rob.
     
    Last edited: Aug 13, 2012
  2. Rob4507

    Rob4507

    Joined:
    Aug 29, 2007
    Posts:
    53
    For anyone interested, I managed to get around the issue by checking for a button press and hiding the keyboard (.active=false) if it detects any button presses. The key is that the keyboard steals all input if you touch in the keyboard area but if you touch outside of that area, the app (your game) gets the input. So, on Android, if you touch outside of the keyboard and the keyboard disappears, it is ok because you have detected a button press and can exit out of your waiting loop and kill the old keyboard.

    It's not a perfect solution by any means but it does work!

    EDIT: On Android, it actually doesn't pick up the first button press but once the keyboard goes MIA by touching outside of the keyboard area, the next button press will be picked up and get you out of your loop.
     
    Last edited: Aug 13, 2012
  3. SolidSnake

    SolidSnake

    Joined:
    Dec 19, 2011
    Posts:
    63
    I am having similar issues with the implementation of keyboard on Android.. just posted all the details of issues i encountered..

    Seems that their implementation is really buggy
     
  4. ChrisYummi

    ChrisYummi

    Joined:
    Jul 5, 2012
    Posts:
    8
    And I'm afraid it still is. Never set the hideInput flag to anything other than false.
     
  5. ferraribeng

    ferraribeng

    Joined:
    Jul 14, 2011
    Posts:
    6
    This solution is not ideal. We can't expect the user of the app to know that they need to tap on the screen twice before everything works fine.

    Using the focus control, I manage to avoid using the Button command. Unfortunately, I end up with the same problem. Need to tap on the screen twice to disable the keyboard. It is a nuisance to the user. Unknowingly, they had to tap whatever they want to tap 3 times to do before they want do.
     
  6. ferraribeng

    ferraribeng

    Joined:
    Jul 14, 2011
    Posts:
    6
    Hi Rob,

    I managed to find the solution to the problem using the Touch commands.

    The basic problem is when the keyboard is shown, all focus control from your app is taken away completely and the focus is solely on the on-screen keyboard. When anywhere on the screen, except the keyboard is touched, your app will not register any activity. Even the GUI.Button and the GUI.Textfield will not register they are being touched and selected. The unfortunate thing is the keyboard slides off and disappeared and yet, the visible and active flags indicated TRUE, until you touch the screen again on area where there is no Button or Textfield or whatever. However, during the 2nd touch, the focus control is returned to your app. If you are using focus control for your Text input, it can really mess up your input, which many of us are encountering.

    The solution.
    The TouchPhase.Began phase is active for about 0.5 seconds. This is plenty of time to perform some checks and decide what task to do when the screen is being touched. I use 2 counters, touchVisbleCounter and touchNotVisibleCounter to count the number of loop that they visible flag is true and false from the moment the touch phase is began. I discovered that the condition want (keyboard disappeared after we touch outside the keyboard) is touchVisbleCounter will key increasing, but touchNotVisibleCounter = 0. Other than the wanted condition, I will get some increment in both counters. This is good because we have established a condition that is predictable.

    When I detect that the touch phase is ended, I reset both counters to 0.

    This is basically what I do to detect that my keyboard had already disappeared even though the visible flag indicate that it is active.

    private int touchVisbleCounter = 0;
    private int touchNotVisibleCounter = 0;

    void OnGui()
    {
    GUI.SetNextControlName("do-nothing"); //set the focus control to do nothig
    if(GUI.Button(new Rect(0,0,0,0), "")) //do nothing, just to get the focus control when needed
    {
    }

    //to check that keyboard entry is done
    if(keyboard is done)
    if(keyboardDoneProcessed = false)
    GUI.FocusControl("do-nothing"); //set focus to do nothng button
    keyboardDoneProcessed = true; //done
    set keyboard active to false;​
    endif keyboard done not processed​
    endif keyboard is done​

    else //keyboard not done
    keyboardDoneProcessed = false; //not done​
    endif //keyboard not done​

    //entry to field 1
    GUI.SetNextControlName("Text1"); //set the focus control to do nothing
    GUI.Textfield(position1, textstring1);
    if(ToOpenKeyboard()) /to open keyboard for text
    TouchScreenKeyboard.hideInput = false;​
    if (GUI.GetNameOfFocusedControl() == "Text1" and keyboard is not active)
    open keyboard using command TouchScreenKeyboard.Open
    endif focus control is Text1 and keyboard not active​
    endif to open keyboard for text 1​

    //entry to field 2
    GUI.SetNextControlName("Text2"); //set the focus control to do nothing
    GUI.Textfield(position2, textstring2);
    if(ToOpenKeyboard()) /to open keyboard for text 2
    TouchScreenKeyboard.hideInput = false;
    if (GUI.GetNameOfFocusedControl() == "Text2" and keyboard is not active)
    open keyboard using command TouchScreenKeyboard.Open​
    endif focus control is Text2 and keyboard not active​
    endif to open keyboard for text 2​
    }

    //this is the check for keyboard disappearted
    private bool ToOpenKeyboard()
    {
    bool toOpen = true; //default to open keyboard​

    if(TouchScreenKeyboard.visible) //keyboard visible
    if(Input.touchCount > 0) //if there is a touch
    if(Input.GetTouch(0).phase = TouchPhase.Began) //detected began phase
    increment touchNotVisibleCounter​

    //this is condition to discover the keyboard has disappeared
    if(touchVisbleCounter = 1 and touchNotVisibleCounter = 0)​

    Set keyboard active flag to false //force keyboard to be disabled
    toOpen = false; //don't open the keyboard yet.
    //Give at least 1 loop time for keyboard to be off​
    GUI.FocusControl("do-nothing"); //set focus to do nothng button​
    endif found keyboard disappeared​

    //this is condition to allow opening keyboard again.
    //give 2 loops for the keyboard to be inactive
    if(touchVisbleCounter = 2 and touchNotVisibleCounter = 0)
    toOpen = false; //to allow keyboard to be open again​
    endif to allow open keyboard again​

    //not keyboard disappear condition
    if(touchNotVisibleCounter > 0)
    toOpen = false; //to allow keyboard to be open again​
    endif not keyboard disappear condition​
    endif detected began phase

    if(Input.GetTouch(0).phase = TouchPhase.Ended) //detected touch ended
    reset touchNotVisibleCounter to 0
    reset touchVisbleCounter to 0​
    endif detected touch ended​
    endif there is touch​
    endif keyboard visible

    else //keyboard is not visible
    if(Input.touchCount > 0) //if there is a touch
    if(Input.GetTouch(0).phase = TouchPhase.Began) //detected began phase
    increment touchNotVisibleCounter​
    endif detected began phase

    if(Input.GetTouch(0).phase = TouchPhase.Ended) //detected touch ended
    reset touchNotVisibleCounter to 0
    reset touchVisbleCounter to 0​
    endif detected touch ended​
    endif there is touch​
    endif keyboard is not visible

    return toOpen;​
    }
     
    Last edited: Nov 10, 2014
  7. noamgat

    noamgat

    Joined:
    Nov 22, 2009
    Posts:
    125
  8. ABI16

    ABI16

    Joined:
    Mar 19, 2019
    Posts:
    16
  9. KaPow1

    KaPow1

    Joined:
    Jan 27, 2013
    Posts:
    9
    I'm on 2018.4.13 and still having this problem. When the keyboard is closed unity only gets one event, so I don't know where the user tapped to close the keyboard. Even the @ferraribeng solution doesn't solve the problem if the only thing it tells us is whether the touch is on the keyboard or not - I need to know where exactly the touch is. I tried casting a raycast from Input.GetTouch(0) in the keyboard closed event, but there are no active touches when the event is called.

    Has anyone else had any luck? I've seen a lot of talk around this subject between the forums and issue tracker but I still can't figure out how to tell where the user has tapped to close the keyboard.
     
    jiraphatK and giovi94 like this.
  10. JuliusM

    JuliusM

    Unity Technologies

    Joined:
    Apr 17, 2013
    Posts:
    824
    Have you tried to use https://docs.unity3d.com/2018.4/Documentation/ScriptReference/TouchScreenKeyboard-status.html ? The status differentiates between cancelled and lost focus.
     
  11. KaPow1

    KaPow1

    Joined:
    Jan 27, 2013
    Posts:
    9
    I tried that, but I'm still confused how I can use an enum to figure out where the user tapped outside the keyboard. If I have 2 UI buttons visible while the keyboard is up and the user presses one of them it seems that TouchScreenKeyboard.Status will only tell me that the keyboard lost focus. I'm not getting an event back that tells me where the user tapped to cause the keyboard to lose focus.
     
  12. Aardvarklord

    Aardvarklord

    Joined:
    Dec 28, 2017
    Posts:
    1
    I'm having more or less the same problem. Posted a question here before I found this thread. Everyone that have beta-tested my game clicks the UI button while Android keyboard is visible and expects the button to be clicked at the same time the keyboard is closed without having to click the button again after keyboard is closed.
     
    jiraphatK, giovi94 and KaPow1 like this.
  13. SevenPointRed

    SevenPointRed

    Joined:
    Feb 3, 2016
    Posts:
    207
    Im on 2018.4 (Android) and the keyboard status is ALWAYS visible after the first time the keyboard is opened, even if it clearly closed and is in no way visible, making it impossible to detect when a user inputs anything on the keyboard...
    Horrible bug..
     
  14. Ewan-K

    Ewan-K

    Joined:
    Sep 29, 2013
    Posts:
    4
    Hello, I've encountered the same issue today and managed to fix it with a small workaround. I still need to confirm it's working by testing on multiple devices, but for now I assume it's fine.

    The first thing I did was to simple override the InputField and add the following method:
    Code (CSharp):
    1.         protected virtual void OnApplicationFocus(bool focus)
    2.         {
    3.             if (focus)
    4.             {
    5.                 if (m_Keyboard != null)
    6.                 {
    7.                     if (m_Keyboard.active && m_Keyboard.status == TouchScreenKeyboard.Status.Visible)
    8.                     {
    9.                         m_Keyboard.active = false;
    10.                     }
    11.                 }
    12.             }
    13.         }
    This solves the initial problem - when the touchscreen keyboard is displayed and you tap somewhere other than the keyboard, the application regains the focus but the keyboard is not closed, it apparently just loses focus.
    So I try to detect that and close it myself by the above code.

    The problem is that there is a code within LateUpdate method of InputField, that only considers the keyboard 'cancelled' when the actual TouchScreenKeyboard.Status is set to Cancelled and consequently setting m_WasCanceled to true.
    Turning the keyboard off by setting ".active=false" is therefore incorrectly considered as 'submitted', which is obviously not what I wanted.

    Which brings me to the second part of my "fix".
    Code (CSharp):
    1.         protected virtual void OnApplicationFocus(bool focus)
    2.         {
    3.             if (focus)
    4.             {
    5.                 if (m_Keyboard != null)
    6.                 {
    7.                     if (m_Keyboard.active && m_Keyboard.status == TouchScreenKeyboard.Status.Visible)
    8.                     {
    9.                         m_WasCanceled = true;
    10.                         m_Keyboard.active = false;
    11.                     }
    12.                 }
    13.             }
    14.         }
    This would normally work, but "m_WasCanceled" is private within InputField class, so I needed to simply copy the whole sourcecode of InputField class into my own and adding the above method at the end.
    You probably need to do the same thing with the editor code for the input field, because it does add some specific inspector features.

    Other than that, the remaining issue is to replace all the instances of InputField you have with the new class and it should work. At least on Android it should.
     
    cLick1338 likes this.
  15. SevenPointRed

    SevenPointRed

    Joined:
    Feb 3, 2016
    Posts:
    207
    I tried this, and i got inconsistent timing between OnApplicationFocus and the keyboard status, it wasn't consistent enough to use. I wouldn't recommend this based on what I have been trying in 2018.4.

    I also found that using active = false or active = true sometimes bugged out when reopening the keyboard via the Open method. Not sure if that impacts the built in textfields, but something to be aware of as it might bug out for you at some point.
    I gave up in the end and rolled back versions.
     
  16. Ewan-K

    Ewan-K

    Joined:
    Sep 29, 2013
    Posts:
    4
    What do you mean by "inconsistent timing" ?
    As soon as OnApplicationFocus is called and the keyboard is still active and visible, you can assume that you caught the problem and you can just turn the keyboard off. Any other case should be handled by the keyboard itself already (ie submitting and explicitly cancelling by tapping on device's "back" button.

    Checking the m_WasCanceled is only important because the inputfield does not otherwise know if the keyboard was cancelled or not, which might not be important in many cases but it is in mine.
    The input field responds to any change of keyboard's visibility by clearing it properly anyway, so I don't see any issue with reopening it again. Seemed pretty consistent to me.

    I don't yet know if the experience might change with a different version of Unity or rather different version of device OS.
    I'll confirm as soon as I get it through the QA.
     
  17. SevenPointRed

    SevenPointRed

    Joined:
    Feb 3, 2016
    Posts:
    207
    Sometimes OnApplicationFocus would be called before Unity updated the touchscreenkeyboard state, sometimes after.
    It seemed to be an internal things as it was inconsistent, checking the keyboard state on the next frame sometimes showed it had delayed updating the keyboard state. With the exact same input and code.
     
  18. Ewan-K

    Ewan-K

    Joined:
    Sep 29, 2013
    Posts:
    4
    So you're saying that the fact the keyboard was submitted gets picked up after OnApplicationFocus? That hasn't happened to us yet.
    Even if it has, I'd rather have this working slightly inconsistently than not working at all.
     
  19. SevenPointRed

    SevenPointRed

    Joined:
    Feb 3, 2016
    Posts:
    207
    Yeah, exactly.
    After all the hacks I just rolled back to an earlier unity version. Will just have to wait on a fix.
    It happens in at least the newest 4 2018.4 LTS releases. So much for LTS being stable..
     
  20. Ewan-K

    Ewan-K

    Joined:
    Sep 29, 2013
    Posts:
    4
  21. Unity3dteacher

    Unity3dteacher

    Joined:
    Dec 14, 2012
    Posts:
    197
    still the issue is there.. with 2019.3
     
  22. superduperrobotguy

    superduperrobotguy

    Joined:
    Nov 12, 2018
    Posts:
    1
    This issue is still here with 2020.3.33f1. User never gets returned to the app. This is doubly annoying in Oculus Quest 2 because there's already a bug with the event system that doesn't display the keyboard in UI Events, even using the OVR Event Helper. So........

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.UI;
    4.  
    5. public class InputFieldController : MonoBehaviour {
    6.  
    7.   TouchScreenKeyboard _key;
    8.  
    9.   void Start() {
    10.  
    11.   }
    12.  
    13.   private void OnDestroy() {
    14.  
    15.     if (_key != null && _key.active)
    16.       _key.active = false;
    17.   }
    18.  
    19.   void Update() {
    20.  
    21.     var tb = GetComponent<InputField>();
    22.  
    23.     if (tb.isFocused && (_key == null || !_key.active))
    24.       _key = TouchScreenKeyboard.Open(DateTime.Now.ToString(), TouchScreenKeyboardType.DecimalPad);
    25.  
    26.     if (_key != null && _key.active)
    27.       tb.text = _key.text;
    28.   }
    29. }
    30.  
     
  23. DmitriySyomik

    DmitriySyomik

    Joined:
    Nov 28, 2018
    Posts:
    1
    Hi. Hope it can help someone.
    TouchScreenKeyboard.Android.consumesOutsideTouches = false;
     
  24. RahmatAli_Noob

    RahmatAli_Noob

    Joined:
    Sep 13, 2022
    Posts:
    73
    I Have Tried this but It Didn't Work The Functionality behind it according to my knowledge is that
    TouchScreenKeyboard.Android.consumesOutsideTouches = false;
    It only defines that we should Closed the Touchscreen keyboard on Outside Touches or not. If You Tried it By Yourself then Explain the Complete Procedure To do this.
    Thanks in Advance.