Search Unity

TextMesh Pro TextMesh Pro UGUI hidden characters?

Discussion in 'UGUI & TextMesh Pro' started by kabumere, Nov 20, 2017.

  1. kabumere

    kabumere

    Joined:
    Oct 2, 2016
    Posts:
    31
    I noticed the content pulled from a seemingly empty TMP UGUI Text object was not hitting my string.IsNullOrEmpty conditional. When I printed it to Debug it was empty, but when I got the length of it, it was 1. Is there a hidden character (new line, tab, space) that is automatically given to all TMP Text objects?

    Unity doesn't use the version of .NET that includes string.IsNullOrWhitespace, so a text object not being equal to empty when you think it should creates unnecessary calls to Trim().
     
  2. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    Can you provide a simple script example the reproduces the behavior you are running into?
     
  3. kabumere

    kabumere

    Joined:
    Oct 2, 2016
    Posts:
    31
    Stephan,

    Simply creating a script with a TMP_InputField class variable, then assigning a reference to that variable from the editor will do it. Now in the script when you reference the text of that input field (like: emailInputField.text), the length will be 1 even though it's empty (it's populated with some whitespace character that can't be seen). Calling trim on it (emailInputField.text.Trim()) solves the issue, so it must be like a newline, space, etc.

    It seems like this was brought up back in April by someone else as well (https://issuetracker.unity3d.com/is...extmesh-pro-input-field-the-length-of-it-is-1). They tested on older versions of Unity but I can confirm the issue still arises on Unity 2017.2.0f3.

    EDIT: Note that if you reference the underlying TextMeshProUGUI object of the InputField directly, the same issue occurs.
     
  4. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    When working with the TMP_InputField, you should be accessing the TMP_InputField.text property and not the text property of the underlying text component which is only there to display text. The length of the text property of the input field itself should be correct.

    You should be using the following.
    Code (csharp):
    1. string text = tmp_inputField.text;
    Why not rely / use the .text property of the underlying text component?

    Let's say the TMP_InputField is set to Content Type = Password. The underlying text component would contain a bunch of "******" whereas the TMP_InputField.text property would contain the actual password.

    Here is a previous post about this topic.
     
  5. kabumere

    kabumere

    Joined:
    Oct 2, 2016
    Posts:
    31
    Stephan, my original response WAS using the text property of the InputField, I stated that multiple times ("like: emailInputField.text", exact quote from above). The edit I added at the bottom was just letting you know this also occurs if you use the underlying Text object. But using the TMP InputField definitely does still set the string length to 1 and not 0 for an empty input field.
     
  6. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    I ran several tests and the string length is returning zero on my end when I delete the text.

    Can you provide a simple repro project or script that would enable me to reproduce this behavior?
     
  7. inakiktp

    inakiktp

    Joined:
    Nov 6, 2014
    Posts:
    35
    Hi @Stephan-B ,

    I have run into something similar to what @kabumere describes. However, when I was in the process of doing a small repro for you. When testing the repro, everything worked as expected and as you described. Which now made me wonder if I am doing something wrong or I am not able to reproduce the problem I am experiencing.

    In my case, I have a Base Scene which loads a UI Scene. In this UI Scene there are several Canvases, which contain Child Canvases and CanvasGroups. I enable the Canvases and CanvasGroups as I required them. However, on my main project whenever I enable the Canvas that contains the Input Fields, they are empty but do not show the Placeholder Text. On the other hand, when I did the same thing on the repro, the Input Fields are not empty and display the Placeholder Text. As I said, if you try this, it will work as I just checked on my test repro. However, still does not work on my main project. :(

    After some trial and error, I found a workaround for my specific case (still unsure why happens in the first place). Just after enabling the Canvas and CanvasGroup of my InputFields TMP, I quickly assign some dummy string and then remove it. I tried doing this before enabling the Canvas and CanvasGroup, but it did not work.

    _inputField.text = "a";
    _inputField.text = "";

    This is not ideal by all means, but it does the trick for me.
     
  8. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    So the issue you are running into is the placeholder text not showing up when you enable these canvases?
     
  9. inakiktp

    inakiktp

    Joined:
    Nov 6, 2014
    Posts:
    35
    Yes. The Input Fields appear "empty" and do not display the Placeholder Text they are supposed to do when their text property contains nothing.

    However, when I tried this on a repro project, it worked as expected and I was not able to reproduce the same situation I get on my main project.
     
  10. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    By their text property, you mean the TMP_InputField.text and not the child text object's text property?

    In terms of reproduction, are you using the same version of Unity in both cases? Same number of Canvases?
     
  11. inakiktp

    inakiktp

    Joined:
    Nov 6, 2014
    Posts:
    35
    Yes, I am using TMP_InputField.text property, not the textComponent.text.

    Yes, I am using the same version of Unity, 2017.1.1f1 (64 bit) OSX.

    Yes, I tried (to the best of my knowledge) to reproduce it using the same number of Canvases and Elements, loading the InputField Scene from a script from another Scene, etc. without success.

    Is there any extra information I can provide? I will give it another try tomorrow and see if I can repro it. If I am successful (I hope I am) I will send you a repro.
     
    Last edited: Dec 10, 2017
  12. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    If it only happens in your project, you could provide me with a Repro of the project either via some link in a Private Message or via the Unity bug reporter and then providing me the case #.
     
  13. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,260
    I am experiencing this issue myself. Right now a work around is to trim out the zero space character from the string as the OP's work around didn't work for me. Would normally be fine only it broke byte parsing when checking for a valid IP address.

    Code (CSharp):
    1. string text = inputField.text.Trim((char)8203);
    There should not be any extra character in the TMP_InputField.text property. On the child text object there would be but not on the parent.

    Can you check to make sure we are talking about the same object and property?
     
    Last edited by a moderator: Jan 18, 2018
  14. tperezstolfa

    tperezstolfa

    Joined:
    Oct 22, 2016
    Posts:
    3
    I ran into the same issue, thanks Chris, your workaround worked for me... Still, I agree, there shouldn't be any extra character in the TMP_InputField.text property... Running on Unity 2018.1.0f2
     
  15. Kesh

    Kesh

    Joined:
    Jan 13, 2014
    Posts:
    21
    Same problem for me running Unity 2018.1.7f1
    Thanks for the workaround Chris.
     
  16. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    I just tested this again and the TMP_InputField.text does not contain any additional characters. The child / underlying text object .text property would but this child should not be accessed.

    The parent TMP_InputField.text should.

    If anyone can provide an example / script that would enable me to reproduce this, that would be most useful.
     
  17. Chris-Trueman

    Chris-Trueman

    Joined:
    Oct 10, 2014
    Posts:
    1,260
    I would say this is the cause of the problem, accessing the child is the wrong way to do it. Accessing the input field itself works fine and no work around's needed.
     
    BaraShiro likes this.
  18. GuyKurt

    GuyKurt

    Joined:
    Sep 22, 2018
    Posts:
    1
    I'm assuming that this is why the child text of the input field will not equal a string of the same value? Just ran into this and was trying to see if someone else had the same problem. The fix is to just access the Input Field instead of the child text. If this is unrelated, then potentially a new bug?
     
  19. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    The child text object should never be accessed directly as it contains formatting characters in addition to the characters that will be displayed which will never matches the content of the parent TMP_InputField.text.

    For example, in the case of a password, the child text object .text property would contain something like "****" whereas the parent TMP_InputField.text would contain "1234".
     
    ShokWayve likes this.
  20. centaurianmudpig

    centaurianmudpig

    Joined:
    Dec 16, 2011
    Posts:
    92
    I was having the same problem, Stephen_B your explanation has been very helpful and was exactly what I wasn't doing.
     
  21. BernEugen

    BernEugen

    Joined:
    Mar 13, 2015
    Posts:
    4
    Hello.
    I'm facing another issue:
    Unity 2018.4.8f1

    - Create an empty project
    - Switch platform to UWP
    - Create a TMP_InputField
    - Build the project
    - Run the project
    - Highlight the empty input field and press Ctrl+A (select all) or paste any letter/word from you buffer

    Result:
    - The case when Ctrl+A pressed. It creates an extra symbol (rectangle)
    https://ibb.co/KbYwM9h

    - The case when a letter/word pasted. Or adds an extra symbol to the end of a letter/word
    https://ibb.co/y5xsdfz
     
  22. boolean01

    boolean01

    Joined:
    Nov 16, 2013
    Posts:
    92
    Good lord I just wasted 2 days on this same issue. The problem is Trim() wont solve anything since the extra value being added to the end of the string isn't a blank space, it's a hidden character. The workaround from Chris fixes the issue.

    Does anyone know if there's a ticket somewhere for this? I'd be happy to make a new one if it's not a duplicate. It's trivial to replicate - just do "bool isSame = "1234" == inputField.text".
     
  23. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    I just double checked and the .text property of the TMP_InputField is as expected and does not have any hidden or extra character. So for instance, the text is "1234" and you check TMP_InputField.text, it will be "1234". However, if you check the .text property of the child text object, it will have this extra formatting character.

    Again, it is important to use the .text property of the input field and not the .text property of the child text component.
     
  24. boolean01

    boolean01

    Joined:
    Nov 16, 2013
    Posts:
    92
    So I think I got to the bottom of this. The way I was accessing the value was actually through the Input fields "OnTextChanged" event, which wasn't referencing either of the text fields (so I figured I couldn't mix them up). But I had my form validation running on the .text property of the child text component.

    :oops:

    On the plus side I guess we know the advice in this thread is correct....
     
    Stephan_B likes this.
  25. ShervinM

    ShervinM

    Joined:
    Sep 16, 2017
    Posts:
    67
    Good lord I just spent 3 solid hours trying to figure out why my string comparisons werent working because of this... oof
     
    genaray likes this.
  26. genaray

    genaray

    Joined:
    Feb 8, 2017
    Posts:
    191
    Same... why the heck is there a cursor inside ? Whats even the purpose of that ? Please fire the one thats responsible for this xD
     
  27. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    What do you mean by the cursor inside?
     
  28. DebugDotLog

    DebugDotLog

    Joined:
    Feb 1, 2019
    Posts:
    23
    Hi @Stephane_B it seems I have a problem with inputfield too.
    I'm using an inputfield to edit string from a server. So at first the I get the string from the server to display it with an inputfield and then that string can be edited and save to the server with any changes.
    Everything works fine as long as my inputfield linetype is set up to "Single line" but as soon as I change it to "Multi line new line" the initial setting of the string is cropped by the input field.
    I'm setting the input field text like so :

    - myInputField.text = textReceiveFromServer

    And so for example I'm receiving this from the server : "fwefefewefwf\nefwefwfwefwe\nfwefwefwefwef\nweffewfwefwefewfewf\n3rr3r3rr"

    but my input field truncate to : "fwefe"

    Do you have any idea on why ? and how can I solve this ?

    EDIT : after some debugs it seems that this behavior is due to the Line Limit of my inputfield.(which is set to 5)
    This value seems to impact the truncation. For example if I set the Line Limit to 5 the inputfield will truncate every char after index > 5 in my string.
    Is this an intended behavior ?
     
    Last edited: Apr 15, 2021
    Flavelius likes this.
  29. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    Are you using the TMP Input Field or the UI Input Field?

    If the TMP Input Field, are you getting the text from the input field or the child text object? Make sure it is from the Input Field itself and not the child text component.

    Can you post an image of the settings of your input field so that I can try to reproduce the behavior?
     
    byrnedermot likes this.
  30. DebugDotLog

    DebugDotLog

    Joined:
    Feb 1, 2019
    Posts:
    23
    Hello @Stephane_B I'm using TMP Input Field.
    To assign the text in the Input Field I'm using the .text of the input field but for visual purpose I assign some values to the .textComponent also (color, fontsize etc)

    I've tried removing the .textComponent assignation completely but the truncation still happened.

    Here are some samples as requested :
     

    Attached Files:

  31. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    I am pretty confident assigning text directly to the child text component is likely to result in some potential unexpected behaviors.

    Since you are using layout components and making these changes via scripting, I would ask that you please submit a bug report with the project and steps for me to reproduce it. This will make it easier and quicker for me to figure out what is going on.

    If you are able to submit a bug report, please provide me with the Case # once you have it from Unity via email.

    EDIT: Just changing properties like color on the child text object should be fine. I missed that part.
     
  32. DebugDotLog

    DebugDotLog

    Joined:
    Feb 1, 2019
    Posts:
    23
    I'll try to submit a bug report as soon as I can but for the record I am pretty positive that the problem is somewhat linked to the InputField.LineLimit behavior as everything works fine when set to 0 but as soon as I change it to less than the number of char in my string it truncates every chars in my string beside the first [LineLimit.value] one.

    So for example :

    Code (CSharp):
    1. string dataFromServer = "Hi I'm Stephan";
    2.  
    3. myInputField.lineLimit = 6;
    4. myInputField.text = dataFromServer;
    5.  
    6. //This will print "Hi I'm" => it seems the number set in lineLimit is repercuting on the number of chars set
    7. Debug.Log(myInputField.text);
    8.  
    9. ____________________________________________________
    10.  
    11. string dataFromServer = "Hi I'm Stephan";
    12.  
    13. myInputField.lineLimit = 0;
    14. myInputField.text = dataFromServer;
    15.  
    16. //This will print "Hi I'm Stephan"
    17. Debug.Log(myInputField.text);
    18.  
     
  33. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    I appreciate the personal attention in the example ;)

    Let me see if I can reproduce it on my end.
     
    DebugDotLog likes this.
  34. lixi_x

    lixi_x

    Unity Technologies

    Joined:
    May 5, 2021
    Posts:
    9
    Hi I've been trying to reproduce the issue, could you provide the rect transform width of the input field ?

    The rect transform width affects word wrapping which in turn affects the number of lines which will then affects where the text gets truncated. For instance if the width is 0, then 1 character per line will be displayed and the rest will be trancated and you get 6 characters in total from the field.
     
  35. DebugDotLog

    DebugDotLog

    Joined:
    Feb 1, 2019
    Posts:
    23
    Hello @lixiunity,

    Sorry for the late reply, well my input field's rect transform has a layout with a min Width of 334.18. I should have added previously that this inputfield has a content size fitter which scale its rect depending on the text inside. I'll provide you some screens below.
    It looks to me that the trouble maker might be one of the content size fitter.

    Regards
     

    Attached Files:

  36. bollywoodmantis

    bollywoodmantis

    Joined:
    Feb 15, 2021
    Posts:
    1

    This worked mate.
     
  37. Mlackey

    Mlackey

    Joined:
    Dec 5, 2014
    Posts:
    41
    This seriously should not still be a thing. Why is this even a problem?

    Unity version 2020.3.14f1

    Without trimming, the byte size of the string being fetched is 2 with a length of 1 if you check string length. When trimmed, this returns a value of 0 bytes with a length of 0. It should be null at this point.

    When attempting to check if it is null, empty, or even whitespace... none of those return a value of "true".

    Why is there a zero width space hidden?

    Even when I set input to " " <- that includes a space, I still don't get the proper boolean response with null/empty/whitespace checking.

    upload_2021-8-1_3-5-0.png

    (_inputfield.text size = 4 bytes with a space, 2 without a space)
    (s = 2 bytes with a space, 0 without)

    string comparison with (s) does not result in proper boolean response. string....(s) always results in false.

    upload_2021-8-1_3-14-33.png

    I should add, I went ahead and tested this with the child component text script of InputField just to see what'd happen, same results.
     

    Attached Files:

  38. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    As stated previously, the text should never be set or checked on the child text component. This component is used for formatting. For instance, when the input field is set to password, the child component's text property would contain "****" which is essentially gibberish.|

    The Zero Width Space <zwsp> (char)8203 character is used for formatting.

    The text should only be get / set via the TMP_InputField.text property.

    Is there a reason you need to access the child text?
     
  39. brandonholt95

    brandonholt95

    Joined:
    Feb 12, 2020
    Posts:
    14
    @Stephan_B How do we properly access the wordInfo array when using TMP_InputField? The only place I can find one is on the child text component, but I'm running into these same issues where there are hidden characters, getting null reference exceptions, etc.

    For example, I'm trying to access the last word in the input field with this code, and getting a NRE on the last line:

    Code (CSharp):
    1. private TMP_InputField input;
    2.  
    3. TMP_WordInfo[] wordInfo = input.textComponent.textInfo.wordInfo;
    4.  
    5. string newWord = wordInfo[wordInfo.Length - 1].GetWord();
    Edit: A workaround I plan on using for the time being is splitting the input.text string with a space char and grabbing the last element of the array. My only concern here is performance. Should this be any slower, given that I'm calling this every frame update?

    Code (CSharp):
    1. string[] words = input.text.Split(' ');
    2.      
    3. newWord = words[words.Length - 1];
     
    Last edited: Sep 15, 2021
  40. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    The reason you are getting those index out of range issues is because you are using the array lengths to iterate over the potential words.

    Since the internal buffers for the textInfo are allocated in blocks (power of two), the array length will almost always exceed the count. As such, you cannot rely on array lengths. Instead you should be using the textInfo.characterCount, textInfo.wordCount, textInfo.lineCount, etc.
     
    brandonholt95 likes this.
  41. brandonholt95

    brandonholt95

    Joined:
    Feb 12, 2020
    Posts:
    14
    @Stephan_B This makes sense, worked for me, thanks!

    One last question I have is regarding large chunks of text in TMP_InputField. Once I get above about 5,000 words, I start to notice some input delay. Are there ways to avoid this, or perhaps a better object type to use if the user should be inputting large amounts of text? (e.g., a notes app).

    Edit: Here's a snapshot of the profiler running while typing in an input field with about 7,000 words. The frame rate is high when not typing.
     
    Last edited: Sep 15, 2021
  42. Stephan_B

    Stephan_B

    Joined:
    Feb 26, 2017
    Posts:
    6,595
    As the text grows in size so does the performance overhead in terms the parsing and layout of this text. As such it is best to look for ways to split these large text objects (perhaps per line, paragraph, etc.) and use multiple text objects.

    Unfortunately, I don't have a solution ready for this but here are some thoughts on how this could be implemented using the current version of TMP.

    I think for a notes like app, I would split this by paragraph as from a layout point of view, paragraph don't affect each other with the exception of some rich text spanning more than one paragraph which is something I will ignore in this post.

    The idea would be to use an input field for each paragraph as this would limit the parsing and layout refresh to the paragraph being edited.

    Each paragraph would be tracked in a list as to enable you each time there is a change to re-position each of the visible input field sequentially to make it appear as this is a single large input field.

    You would need to handle navigation between each of these input fields as well.

    In theory, you could use a single text input field with many text objects but would add more complexities so we can skip this part.

    I would use a pool of input fields as we only need to deal with what is visible.

    As a user clicks on an input field to edit its content, you would need to adjust the positioning of subsequent input fields but this would not require a re-layout of those other input fields thus remaining very efficient as we are just moving objects around and only moving those visible.

    I realize this would be a pretty big undertaking to implement this type of system but it is certainly something that can be implemented. I made the following post a while ago which is along these lines. I suggest you look at it as well as it might contain addition tidbits of information.

    P.S. This is a quick reply in the sense that I would need to spend more time to provide even more details but I didn't want to let your reply sit here for days while I think about all of this... so consider this a rough draft.
     
    brandonholt95 likes this.
  43. brandonholt95

    brandonholt95

    Joined:
    Feb 12, 2020
    Posts:
    14

    @Stephan_B I appreciate the reply, I will think more about the implementation of this idea.
     
  44. brandonholt95

    brandonholt95

    Joined:
    Feb 12, 2020
    Posts:
    14
    @Stephan_B
    At the moment this is my biggest bottleneck. Any update on the massive text editor, or even an example package for this idea you’ve described?

    would be a massive help!
     
  45. brandonholt95

    brandonholt95

    Joined:
    Feb 12, 2020
    Posts:
    14
    @Stephan_B Any update?
     
  46. vrezzoug

    vrezzoug

    Joined:
    Feb 25, 2021
    Posts:
    3
    Unity 2021.3.2f1 this issue is still here
     
    Stormer2020 and CodeFluegel2 like this.
  47. Stormer2020

    Stormer2020

    Joined:
    Sep 14, 2020
    Posts:
    92
    Wow! inputField.text.Trim((char)8203) is working for me! Thanks, I love u!
     
  48. Flavelius

    Flavelius

    Joined:
    Jul 8, 2012
    Posts:
    945
    I have that same issue (still) in unity 2021.3f25 with TMP 3.0.6, has this been addressed in the meantime?
    It's exactly as the earlier poster said, the line limit seems to be used as character limit, as in my case i have 25, and it keeps 25 characters while cutting off the rest. And removing the line limit does make it work as expected, apart from not having a line limit anymore.
     
  49. Pheck

    Pheck

    Joined:
    Jul 9, 2009
    Posts:
    225
    Hmmm... I still have issues related to this and still need to create hand work arounds... bumber.

    -IME for multilanguage seems to have issues with using inputfield.text, but inputfield.textcomponent.text is correct.

    -Also on consoles where the virtual keyboard is used and inputfield.text is only modified by Unity, the string gets longer and longer each time you enter and exit the keyboard window.
    -Plus on one specific console if you are editing using the number pad window, you cant type new numbers if the hidden characters exist until you backspace to erase the hidden character.
     
    Last edited: Aug 8, 2023
  50. wenqian157

    wenqian157

    Joined:
    Aug 10, 2021
    Posts:
    3
    it's 2024 the issue remains