Is GUI.PasswordField buggered ? ... iPad / iPhone

I just noticed that - perhaps on the latest iOS -

GUI.PasswordField really doesn’t work. In the (infuriating) small text display attached to the iOS keyboard, it shows •••••••.

BUT in the GUI.PasswordField in your Unity scene, it seems to swap to clear text (as if a GUI.TextField).

Anyone noticed ??


Note it is totally broken as of mid-2013

Google many questions on this eg

http://forum.unity3d.com/threads/65337-GUI-PasswordField-issue

Using the following code works fine for me (running in unity 4.0.1 for pc/mac standalone):

var passwordToEdit : String = "My Password";

function OnGUI () {
    // Make a password field that modifies passwordToEdit.
    passwordToEdit = GUI.PasswordField (Rect (10, 10, 200, 20), passwordToEdit, "*"[0], 25);
}

It’s true that surprisingly, as of mid-2013,

the function GUI.PasswordField is completely broken and not-usable - just seems to be how it is!

Note too that GUI.TextField is essentially unusable, it has various minor problems.


Here’s some workaround code which who knows may help future readers…

have two normal “buttons” in your scene that work exactly like your other buttons (ie, using 2DToolkit or whatever - i don’t mean “GUI buttons” - never use those for any reason)

make them simply flat squares of color - that is exactly as if it looks like a text input field (gray or whatever you want0 – so literally just a long stretched cube or maybe a simple plain color 2DToolkit sprite stretch to the size you want.

#Easy fake input fields!
10083-fakebuttons.png

private var positionEmail:GameObject;		// it's a quasi button
private var positionPassword:GameObject;	// it's a quasi button

// do this in awake or whatever....
fieldPositionA = FindUnderHereNamed("positionEmail").gameObject;
fieldPositionB = FindUnderHereNamed("positionPassword").gameObject;

so, however you treat the other notmal buttons in your scene (say “OK” etc etc) … treat the two “fake” buttons like this:

if ( nn == "positionEmail" ) // that's a normal button n a collider, just a square of color
// i just call them "position" because they're clever position markers
	{
	Debug.Log(" POS EMAIL");
	
	keyboard = TouchScreenKeyboard.Open(
		"", TouchScreenKeyboardType.EmailAddress, false, false, true);
	// the three fields are autocorr, multiline, secure-style
	
	// funnily enough it's best to use "secure style" (third arguments there)
	// for the username as well as the passwd field - since - that avoids
	// the ridiculous "defaults to caps lock" problem that Apple helpfully offers
	// for clarity recall that we are not seeing the small line of text
	// just above the keyboard that Apple offers (see next line of code)
	// which would be dots with "secure style" on so that's irrelevant
	// Also remember we're totally drawing the actual text display all on our
	// own so again it's irrelevant for that issue.  so that's why you use
	// secure-style true even for a plain text field like username
	
	keyboard.hideInput = true;
	
	textInputIsNow = 1;
	// our code is 1 for username, 2 for passie, 0 for, well, nuthin being entered
	
	transform.localPosition.y = 0.7;
	isElevated = true;
	
	return;
	}
if ( nn == "positionPassword" )
	{
	Debug.Log(" POS PASSWORD");
	
	keyboard = TouchScreenKeyboard.Open(
		"", TouchScreenKeyboardType.EmailAddress, false, false, true);
	
	// EmailAddress is about the best, for both
	
	keyboard.hideInput = true;
	
	textInputIsNow = 2;
	
	transform.localPosition.y = 0.7;
	isElevated = true;
	
	return;
	}

next note that in your OTHER CONVENTION BUTTONS (say “ok” or whatever) add this

if ( nn == "bbOK" )
	{
	if ( isElevated ) return; // turn off conventional buttons when typing
	.. blah
	}

Next, here is basically the code to make it work tidily. Note that in this example (see above and below) I move the whole input area to “0.7” (of course you move it up typically when the user is using the keyboard to more clearly show the user/pass fields on the screen above the keyboard) (Obviously you could use a marker object or something to move it to no big deal.)

//////////////////////////////////////////////////////////////////////////////

private var TFAA:String;
private var TFBB:String;

private var rectAA:Rect;
private var rectBB:Rect;

var bigType:GUIStyle;

private var keyboard:TouchScreenKeyboard = null;

private var textInputIsNow:int = 0;		// 1 for username, 2 for pass

private var fieldPositionA:GameObject;
private var fieldPositionB:GameObject;

function OnGUI ()
	{
	if ( ! UIAvailableHere )
		return;
	
	_setTextFieldRects();

	if ( textInputIsNow == 1 ) TFAA = keyboard.text;
	if ( textInputIsNow == 2 ) TFBB = keyboard.text;
	// be careful not to change them if it is zero
	
	GUI.Label( rectAA, TFAA, bigType );
	GUI.Label( rectBB, _dots(TFBB), bigType );
	
	if (	keyboard != null &&
			( keyboard.done || keyboard.wasCanceled || ( ! keyboard.active) )
			)
		{
		textInputIsNow = 0;
		// and thus don't change them anymore
		
		keyboard = null;
		
		isElevated = false;
		transform.localPosition.y = 0;
		
		_setOKAVailable();
		}
	}

function _dots(ss:String)
	{
	var nn:int = ss.Length;
	var rr:String = "";
	for ( var k:int=0; k<nn; ++k ) rr += "•";
	return rr;
	}

//////////////////////////////////////////////////////////////////////////////

finally this code will basically set it up

note that I use this critical silly trick http://answers.unity3d.com/questions/438098/changing-font-size-per-screen-height-do-you-do-thi.html to set the !$!#ing point size of the @#@#$ guilabel type correctly. So where it says “50” – simply in Editor (which is 768 height of course) I found a size i want which happened to be “50” nominal, this trick will make it look fairly-close to that on all devices. (well all apple touch devices at least :open_mouth: )

function beginForm()
	{
	bbCancel.collider.enabled = true;
	bbOK.collider.enabled = true;
	
	TFAA = "username enter it";
	TFBB = "password";
	
	_setOKAVailable();
	
	UIAvailableHere = true;
	
	Debug.Log("start fresh");
	
	var calcSize:float;
	calcSize = (Screen.height * 1.0f) / 768.0f;
	calcSize = calcSize * 50.0f;
	
	bigType.fontSize = Mathf.RoundToInt( calcSize );
	
	Debug.Log("font size settings ... " + bigType.fontSize + " " + Screen.height);
	
	transform.localPosition.y = 0;
	isElevated = false;
	}

var isOKAvailable:boolean;

function _setOKAVailable()
	{
	// note never use proper stateful programming when you
	// can have cheap spaghetti code...
	if ( TFAA == "username enter it" || TFBB == "password"
			|| TFAA == "" || TFBB == "" )
		isOKAvailable = false;
	else
		isOKAvailable = true;
	
	if ( isOKAvailable )
		bbOK.GetComponent(tk2dSprite).color.a = 1.0;
	else
		bbOK.GetComponent(tk2dSprite).color.a = 0.4;
	}
/////////////////////////////////////////////////////////////////////////////

function _setTextFieldRects()
// magically make label fields (you could also use it for TextField - if that worked)
// the same size as your fake fields, see image up above
// you can simply change the fake-fields in your editor (even while running)
// and it will all work
	{
	var bAA:Bounds = fieldPositionA.renderer.bounds;
	var bBB:Bounds = fieldPositionB.renderer.bounds;
	
	var TL:Vector2;
	var TLgui:Vector2;
	var BIG:Vector2;
	
	///
	
	TL.y = Camera.main.WorldToScreenPoint( bAA.center + bAA.extents ).y;
	TL.x = Camera.main.WorldToScreenPoint( bAA.center - bAA.extents ).x;
	
	BIG.x =
		Camera.main.WorldToScreenPoint(bAA.max).x -
		Camera.main.WorldToScreenPoint(bAA.min).x;
	BIG.y =
		Camera.main.WorldToScreenPoint(bAA.max).y -
		Camera.main.WorldToScreenPoint(bAA.min).y;
	
	TLgui = TL;
	TLgui.y = Screen.height - TLgui.y;
	
	rectAA = new Rect( TLgui.x, TLgui.y, BIG.x, BIG.y );
	
	///
	
	TL.y = Camera.main.WorldToScreenPoint( bBB.center + bBB.extents ).y;
	TL.x = Camera.main.WorldToScreenPoint( bBB.center - bBB.extents ).x;
	
	BIG.x =
		Camera.main.WorldToScreenPoint(bBB.max).x -
		Camera.main.WorldToScreenPoint(bBB.min).x;
	BIG.y =
		Camera.main.WorldToScreenPoint(bBB.max).y -
		Camera.main.WorldToScreenPoint(bBB.min).y;
	
	TLgui = TL;
	TLgui.y = Screen.height - TLgui.y;
	
	rectBB = new Rect( TLgui.x, TLgui.y, BIG.x, BIG.y );
	
	///
	
	// Destroy(fieldPositionA);
	// Destroy(fieldPositionB);
	}

/////////////////////////////////////////////////////////////////////////////

Ultimately when the person clicks your “OK” button it is yourBoss.theyClickedOK( TFAA, TFBB );

What a pain !!!