Search Unity

TextMesh Pro Reset On Deactivation leaves blinking caret

Discussion in 'Unity UI & TextMesh Pro' started by hgrayvivox, Jun 12, 2018.

  1. hgrayvivox

    hgrayvivox

    Joined:
    Mar 3, 2017
    Posts:
    15
    Unity 2017.1.3.f1, TMP 2017.1

    When I disable the "Reset On Deactivation" checkbox on a TMP input field, the caret continues blinking even when the field loses focus. I'd expect the insert position to be retained but the caret to disable while the field is out of focus.

    Thanks,
    Hardin
     
  2. hgrayvivox

    hgrayvivox

    Joined:
    Mar 3, 2017
    Posts:
    15
  3. Ninjatime

    Ninjatime

    Joined:
    Aug 11, 2017
    Posts:
    1
    Having the same issue here...
     
  4. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    2,278
    Still trying to get to looking at this. I'll try looking at it over the weekend and provide feedback thereafter.
     
  5. NotEvenTrying

    NotEvenTrying

    Joined:
    May 17, 2017
    Posts:
    4
    still having this issue in 2018.2.4f1 with the latest version of TMPro to date
     
  6. Gladyon

    Gladyon

    Joined:
    Sep 10, 2015
    Posts:
    155
    I confirm that it's still an issue with Unity 2018.3.0f2.
     
  7. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    2,278
    Currently working on the Input Field and will address this.

    UPDATE
    Tweaks to handling...
    When pressing Enter or Done or OK on a soft keyboard, the selection / caret position will be released even if Reset On Deactivation is false. I believe this makes sense since the intent of the user is clear in this case. Ie. Done with changing the text.

    When Escape or Cancel (available on some soft keyboards) is pressed / used, the selection will be released again because the intent of the user is clear.

    When focus is lost on the Input Field, this might be because the user is clicking some slider to control scrolling or pressing some on screen buttons / keys on some custom keyboard they have implemented. So in this case the selection / caret blinking would be maintained.

    Double clicking in some empty space will release the selection.

    Thoughts?
     
    Last edited: Jan 18, 2019
  8. Gladyon

    Gladyon

    Joined:
    Sep 10, 2015
    Posts:
    155
    I am not sure about double-clicking in empty space, in fact I don't see why it should have any impact on the input field (except for losing the focus of course).

    As for Escape, I suppose that if the focus is on another UI component then it will not release the input field, is that it?

    When the input is validated (Enter, Done or OK), then I first agreed that the caret can be reset, but after giving it some more thoughts, I am not all that sure.
    I mean, it will not clear the input field right? So that must be manually done in code, which will automatically reset the caret to its initial position as there's no characters anymore.
    I can't really think about a user-case, but what if the code do not clear the input field? In that case, the caret shouldn't be impacted

    In fact, I do not see why events other modifications of the content of the input and a few keys (such as left-right arrow, Home and End keys) should move the caret.
    The more things are done automatically, the more difficult it will be for someone to go against these behaviours.

    For example, I am creating a debug console, for some reasons I want the input field to always have the focus when the console is open.
    When I use the 'Up' arrow key I do not want to move the caret because I use that key to open the history and to navigate the history/suggestions.
    Currently I have to 'fight' the behaviour of the input field.

    I understand that some behaviours must be implemented by default, which is why Left/Right arrows, Home and End keys must be implemented in the input field.
    In fact, I think that only the navigation keys/events should move the caret (along with adding a new character of course).
    I cannot see any reason to reset the caret position as long as the input field is not empty.
    Or we should have a way to intercept these events in order to manually reset the caret to its old position, but I suspect it wouldn't be easy as it would mean tracking constantly its position.


    Also, it is a slightly different thing and may not belong in this thread, but I'm not sure.
    I have some difficulties moving the caret position manually.
    For example, when I auto-complete the input field with a suggestion in my console, I overwrite the content of the input field, but the caret stays at the previous index position.
    If I move it just after having modified the content then it will not move, I have to do it one or 2 (I think it's 2) frames later, which is not very easy as it means having a frame counter to delay the action, and it also means spending some time on the internet looking for a 'clean' solution.
    For the record, I use that code to move the caret position:
    Code (CSharp):
    1. InputField.caretPosition = Int32.MaxValue;
    2. InputField.MoveToEndOfLine(false, false);
    If there's another way which works better I'd be happy to know about it, if there's not and if you're working on the input field, maybe you could 'fix' that problem.
     
  9. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    2,278
    It is to force losing focus when the flag Reset On DeActivation is set to false.

    When pressing the Escape key or Cancel (if available on the device), this would turn off the caret or selection of the text in the currently selected Input Field. If the Restore on Esc Key is set to true then it would restore whatever the text was prior to the initial edit.

    This simply ends the editing of the text and triggers the relevant events like OnSubmit and OnEndEdit and de-activates the input field. In this process, the caret position or potential text selection / highlight are released. The text remains.

    Assuming you just pressed Enter and then moved the mouse back over the Input Field, if you ended up clicking on some of the text, I would expect the caret to get inserted there. If I ended up clicking in some empty space near the end of the text, I would expect the caret to end up at the end of the text. Whatever previous caret position (when I selected done) is effectively negated by this new action.

    When I use pressed Enter or Done, would you expect to then check what was the caret position or potential selection in the text field after that?

    Besides navigation keys (which are not available on soft keyboard on most devices), touches / mouse clicks are used to modify the caret position and selection / highlight of text. I am not changing this behavior.

    Let me test this part and get back to you when I have more info.
     
    Last edited: Jan 18, 2019
  10. Gladyon

    Gladyon

    Joined:
    Sep 10, 2015
    Posts:
    155
    You're right, I haven't even though about touch devices.
    Anyway, until now you did a very good job with TMP, so I trust you for choosing what's best.

    Thanks, having a clean way to move the caret manually would be nice.
     
  11. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    2,278
    I had a chance to verify the handling of caret position changes in the updated version of the Input Field that I am working on.

    Based on my testing, the change of the caret position takes affect right away. However, although the position has changed internally, it is important to note that given the caret blinks, its position might not (visually) appear to change until several frame later depending on the blinking rate.

    As far as I can tell this should behave correctly now but if you could provide me with some sample code that reproduces the behavior you reported, I'll be more than happy to double check this again.
     
  12. Gladyon

    Gladyon

    Joined:
    Sep 10, 2015
    Posts:
    155
    Here is a script which can reproduce the problem:
    Code (CSharp):
    1.  
    2. using System;
    3. using UnityEngine;
    4. using TMPro;
    5.  
    6. public class Test2 : MonoBehaviour
    7. {
    8.     private TMP_InputField TheInputField = null;
    9.  
    10.     virtual protected void Awake()
    11.     {
    12.         TheInputField = GetComponent<TMP_InputField>();
    13.         TheInputField.onValidateInput = OnDirectValidateInput;
    14.     }
    15.  
    16.     private Char OnDirectValidateInput(String InputText, Int32 CharPos, Char InputChar)
    17.     {
    18.         if (' ' == InputChar)
    19.         {
    20.             TheInputField.text += "Appended";
    21.  
    22.             TheInputField.caretPosition = Int32.MaxValue;
    23.             TheInputField.MoveToEndOfLine(false, false);
    24.         }
    25.  
    26.         return InputChar;
    27.     }
    28. }
    29.  
    30.  
    Steps to reproduce:
    - place a TMP input field in an empty project
    - place the above script on the input field
    - start the project
    - type '1234'
    - observe that the characters are written normally in the input field and that the caret is always blinking at the end of the input field
    - press 'space'
    - observe that the input field contain '1234 Appended' (it should have been '1234Appended ', with the space at the end)
    - observe that the caret is blinking just after the space and before the 'A', for as long as no other key is pressed
    - type '5678'
    - observe that the field now contains '1234 5678Appended'
    - observe that the caret is now blinking between the '8' and the 'A'


    Note that maybe it's not the caret which is not moving, maybe it's the append which is not immediate.
    Anyway, it means that it's a bit difficult to append some text with code to the input field as it's necessary to wait 2 frames in order to have the caret moved correctly and to return '\0' and to remember the typed character in order to append it manually after the caret has been moved.

    On the same subject, I tried to use custom character validation, with the ScriptableObject.
    Unfortunately it seems that it doesn't go through the same path-code than 'onValidateInput', and the returned character is not automatically appended.
    In addition, the selection behaved differently (from memory, if you select some text and press 'e' for example, the selected text will not be replaced by 'e', in fact the selected text will not be deleted, but it may be more subtle, I'm just remembering the problem I had a few days ago).
     
  13. hgrayvivox

    hgrayvivox

    Joined:
    Mar 3, 2017
    Posts:
    15
    Thanks for the updates on this Stephan!
     
  14. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    2,278
    I had a chance to test this out last night and thank you for the time you took to provide the sample code and steps to reproduce the behavior.

    Although perhaps confusing, the behavior is actually correct.

    The onValidateInput delegate is designed to allow validation of a single character. If the character or any other character is returned, then the input is deemed validated. If the return char is ZERO then the input is not valid and rejected / not inserted.

    Now in this validation function, you are modifying the string to add "Appended" but when this occurs, the Input Field is iterating over individual characters to validate them so it already has validated "1", "2", "3", "4" and then it also ends up validating the space which is inserted exactly where it was in terms of position / iteration or after the 4.

    Note this validation function inserts the space at the CharPos which is why even though you are modifying the string in the validation function, the space ends up before the "Appended".

    The same is true for the change in Caret position as these do take effect but are subsequently overwritten by the validation / insertion of the character which re-positions the caret right after the inserted / validated character.

    I don't think using the character validation callback is suited for injecting new characters. Can you provide more insight on the use case.
     
  15. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    2,278
    I just made a change where the following code will now behave more as expected.

    Code (csharp):
    1.  
    2. private Char OnDirectValidateInput(String InputText, Int32 CharPos, Char InputChar)
    3. {
    4.      if (' ' == InputChar)
    5.      {
    6.           TheInputField.text += "ABC";
    7.  
    8.           TheInputField.MoveToEndOfLine(false, false);
    9.          
    10.           // Replace Space by *
    11.           return '*';
    12.      }
    13.      
    14.      // Accept all other input characters
    15.      return InputChar;
    16. }
    17.  
    The above will produce "123ABC*" with the caret at the end of the line.

    Commenting out "TheInputField.MoveToEndOfLine(false, false);" will result in "123*ABC" with the caret after the "*".

    The validated / injected character is inserted at the location of the caret.

    I am still playing / experimenting with this but I believe this is closer to what you were expecting.
     
  16. Gladyon

    Gladyon

    Joined:
    Sep 10, 2015
    Posts:
    155
    Thanks for the explanation and the time you spend on it.

    My use-case is a debug console.
    When the user use the space or dot character, I want to auto-complete the input-field with the first matching suggestion, and then add the ' ' or '.' character.

    With the modification you made, if the user has entered "123" and then he add a '.', then it will take the first matching suggestion and then add '.', resulting in "123ABC.", which is exactly what I need.


    Note that I think that a good way to do what I want may also be by using Custom Character Validation (with the ScriptableObject) because it allow to change the character position as it is a 'ref'.
    Unfortunately I haven't been able to use it easily because it behave completely differently from the 'OnDirectValidateInput' delegate.
    It doesn't auto-insert the returned character, and also because it behaves differently when there are several characters selected in the input field (it's probably related to the fact that it doesn't auto-insert the returned character).

    But this behaviour may be totally normal, as I'm not sure exactly what is the intended use of the Custom Character Validation.
     
  17. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    2,278
    I created that TMP_InputValidator a while back to allow users to create more complex / custom validation but I haven't looked at that in a long while so it might be in a confused state. I'll try taking a look over the next few days / after I release the first preview of version 1.4.0.
     
  18. Gladyon

    Gladyon

    Joined:
    Sep 10, 2015
    Posts:
    155
    It may also me who is in a confused state, it happens from time to time ;)


    Anyway, thanks again for changing the behaviour of the caret position changing in the 'OnDirectValidateInput' delegate, it will make my code a lot cleaner.
     
    Stephan_B likes this.