Set Caret Height / Y Position in InputField

Hi there.

I have searched and searched but can’t find anything that works for me on this… I’m basically trying to manipulate the look of the caret that is displayed when using an InputField UI element that I have created through code. I want it to be less tall and to move down slightly.

I’m creating everything from scratch using code for various reasons, so prefab not an option (although I suspect accessing the caret in a prefab InputField would still require code and I assume suffer from the same issue).

Here is what I’m doing when actually trying to reposition the caret (go, w and h are passed in as parameters)

GameObject theCaret = GameObject.Find(go.name+" Input Caret");
Transform inputCaretTrans = theCaret.GetComponent<RectTransform>();
Vector2 currentPosition = inputCaretTrans.position;
inputCaretTrans.position = new Vector2(currentPosition.x,(currentPosition.y-10.0f));
theCaret.GetComponent<RectTransform>().sizeDelta = new Vector2 (w, h);

Here is the structure that displays in the hierarchy:

Canvas
– Game Object
– – Input Caret
– – Text

The game object has a custom script attached to it that constructs the rest of the object, adds children, assigns components etc.

All elements are in the Unity UI layer.

The code finds the input caret, recognises its current position and knows it has been moved - if I log the new position, it is displayed correctly. But it’s not actually moved on-screen when running the app in Unity. It is where it always was.

The only thing that seems to affect the height or position of the caret is if I change the font size or position of the text component, but then the text is off.

I’ve tried various methods I found on these forums, none of which worked and all seemed to work sporadically for some people and not others based on comments on those threads. I’ve tried running the above in the update method repeatedly in case something was resetting it when I did it just once when initialising the input field.

Completely stuck. I’m new to Unity, so could easily be missing something obvious, but I have 15 years experience with developing games so I’m comfortable with the concepts involved and have applied the same logic to other objects no problems… the caret seems different for some reason.

It seems like it should be incredibly simple to do this. But I’ve been banging my head against a wall for ages now with no progress.

Thanks in advance for any help.

Ian

Textmeshpro’s inputfield may be a little easier to work with. You can copy the package into your projects package folder to get rid of the read only and make it project specific. Otherwise, your other option is you can download the UI code for the standard inputfield as it’s available from Unity and look at modifying that code instead.

Honestly, while it’s cool you’re trying to do your own inputfield, it may be easier to work with the UI code that already exist. If nothing else, maybe it can give you an idea of how they do it if you’d rather just use it for reference.

Good luck, sorry I can’t be of much more help.

Thanks for the reply. Appreciate it. Will definitely have a look at TextMeshPro.

Sorry - I don’t think I was clear - I am working with the InputField code that exists from Unity, just not using prefabs or creating the field in the editor or anything. I’m constructing a custom input field using c# in a few steps (ie create a game object, add an image component with a 9 slice sprite for the background, add an InputField component, add a text component and then tie them all together). It’s not much code and it works perfectly except this issue with the input caret, which is exactly the same issue I have if I create the whole thing in the editor.

The caret basically seems to be tied to the font size and whilst there are settings for width, blink rate and color, there is nothing for height or y position.

It’s created automatically when an InputField component is added and appears in the editor hierarchy when I test the project as a game object, but it doesn’t seem that I can manipulate the look / positioning of it and it’s ridiculously tall for the font I’m using - it fills pretty much twice the height of the font.

If anyone has any general idea on whether it’s even possible to do what I’m trying to do via any method that would be great.

Thanks again for getting back to me. It’s certainly an enjoyable learning curve.

Oh sorry, I guess I didn’t explain myself well. Unity has inputfield code available to download and edit.

https://bitbucket.org/Unity-Technologies/ui/src/2019.1/UnityEngine.UI/UI/Core/InputField.cs

Now, the downside is it only goes up to 2019.1, an issue with their code is it isn’t kept up to date on there for editing. Now, it may not have changed much between 2019.1 and 2019.3, so it may work the same, but it’s hard to know for certain. What I was suggesting is you can take their code, make your own version and have access to the height value. In this case, if you look at the GenerateCaret method you see they are getting the height and startPosition.y as you suspected from the characterLine.

The reason I suggested textmeshpro is it is already open to editing no matter what version you grab on the package manager, so you could edit the most current version of the inputfield script, which I’m guessing has a method that handles generating the caret as well, and be all set to go.

You just need to grab the textmeshpro package from it’s central source and put it into the project specific package folder and if I remember, the folder should have an @<version #> on it, that you just need to remove from the folder name and that project will now have it’s own version of the textmeshpro code.

Thanks for the reply - really appreciate that and all understood now. Will investigate & if I figure anything out worth sharing will post here.

For anyone interested, I found (with Brathnann’s help) how to change the height of the input caret… caveat is that I have only tested this so far in Unity, not on a device.

  1. Copy TextMesh Pro into your project’s “packages” folder. It should be located within your project at Library/PackageCache/com.unity.textmeshpro@2.0.1/Scripts/Runtime/(2.0.1 is the current version I’m using - this may be different for you). After copying it over, remove the @2.0.1 or whatever your version is from the folder name in the new location.

  2. Find the TMP_InputField.cs file

  3. Look for the GenerateCaret function (around line 3285).

  4. Within that, find the place where the height is set. This is done in two places (from what I can tell, once when there is no content in the input field and once when there is at least one character present).

  5. Change the height to suit you. I multiplied the current height by a factor of 0.75 to achieve the height I wanted

height = (currentCharacter.ascender - currentCharacter.descender) * 0.75f;

You can also change the y position of the caret by adding a y offset to the y value of the vector2 (add to currentCharacter.descender) via the lines:

float yOffset = 5.0f;
// OLD:
// startPosition = new Vector2(currentCharacter.origin, currentCharacter.descender);
// NEW:
startPosition = new Vector2(currentCharacter.origin, currentCharacter.descender + yOffset);

and

float yOffset = 5.0f;
// OLD:
// startPosition = new Vector2(currentCharacter.xAdvance, currentCharacter.descender);
// NEW:
startPosition = new Vector2(currentCharacter.xAdvance, currentCharacter.descender + yOffset);

I also ended up editing the script so the mobile keyboard doesn’t appear so I can use my own custom keyboard.

Once I’ve finished I’ll post the full code to create a TextMeshPro input field from scratch using c#

Thanks.

1 Like

Glad you were able to get it figured out! I had modified other TextMeshPro scripts, so I figured it wouldn’t be difficult to do the same with the inputfield script. Good info provided for others.

Thanks for the help - saved me a lot of time.