Home 0 SoundRaider 0 Director 0 Faust 0 Nectarine 9 0 Personal 0
 
 XObjects
 Shockwave Gallery
 Technical Guide for Director Developers
 Director Tips and Tricks
 
 Director Users Group
 DUG Members List
 

© Andy Wilson, 1998

Tips and Tricks: Password Input

A few weeks ago someone asked me about inputting a password into a Director Text field, so that the field hides the password from the user and any onlookers. This is the kind of field you see when you enter a password into a form on the internet. It allows you to input text into a field whilst keeping the text private.

To achieve this we're going to use a regular Director text field and write a behaviour for it. Let's start, then, by creating a new input field. To do this, select the toolbar, click on the field icon and then click on the stage where you'd like to position the field. To finish things off, select the new field cast member in the cast library and view it's properties. Assuming that you'd like to limit the size of the field, you'll want to set the properties dialogue box to look something like the following:

Now we'll need to add a new behaviour to the password field sprite. To do this you can click on the sprite, either on the stage or in the score, then right click on it, and select behaviours from the dropdown menu that appears. In the behaviours window that opens you should click on the + button and then on 'New Behaviour'. This opens the script window to allow you to enter the code we're going to write to control the new behaviour.

If you've never used behaviours before you may be a little nervous of starting to code them now. Don't be. Behaviours provide a simple way for you to describe complex modules of object orientated code which you can reuse in one project after another. Just like regular lingo objects, behaviours allow you assign properties to each instance of the behaviour and manipulate these properties easily. That's how we'll start coding our password behaviour - by deciding what properties the behaviour will require. I'm going to use the following properties: pPasswordEntry, to hold the users current input string; pPassword to hold the actual password which the user must enter correctly, pHandler to hold the name of the handler we want to call if and when the user enters the correct password (which may, for instance, take the user to a new part of the projector, open a new movie, open a URL, or similar); pCursor to hold the current position of the fields' input cursor; and pField to hold the field into which the password is being typed.

We can start coding the object by typing in all of these new properties at the top of the script window, so our script now looks as follows;

property pPasswordEntry, pPassword,
property pHandler, pCursor, pField

These properties work in the same way that properties work with a regular parent-child object authored in lingo - they allow each specific instance of the object, or behaviour, to have unique values associated with it. To create a regular child object, you have to write a line of lingo as follows;

set myObject = new (script "Object Parent Script")

With behaviours, on the other hand, a new instance of the behaviour is created whenever a sprite that the behaviour is attached to appears on stage. Behaviours also allow you to implement a simple interface that allows users to set the properties of an object without touching any of the script that controls the behaviour. This is done by writing a handler, getPropertyDescriptionList, which Director calls as appropriate. We also need to write a handler, called getBehaviourDescription, which Director uses to describe the behaviour to other developers who use it. If you want to find out more about these special handlers, see your Director documentation. In the meantime I'll simply show you the code that will allow Director both to describe the behaviour to users and let them set it's two most important properties - the password itself and the handler to be called when the user has typed in the correct password. The code for these two handlers is as follows;

on getBehaviorDescription
  return "Allows the user to input a password
  into a field. The Password property sets the
  password that the user must type in, and the
  Handler property should be set to the name
  of the handler that you wish to be called
  if the user types in the right password."
end

on getPropertyDescriptionList 
  set p_list = [
    #pPassword: [#comment:"Password:",
		#format:#string, #default:"" ],
    #pHandler: [#comment:"Handler:",
		#format:#string, #default:"beep" ]]
  return p_list  
end

Now, when the behaviour is dragged onto a sprite on the stage, the user sees a dialogue box which allows him to enter the two key properties of the behaviour.

Our next step will be to write the code that initialises some of the other properties we'd like to use. Now, with a regular lingo object you would initialise the properties in the on new( ) handler that is called whenever you create a new instance of the object. With behaviours, however, things are a little different. A behaviour instance is only created when a sprite with the behaviour attached to it appears on the stage. The event that is fired when this happens is the beginSprite event, so you need to write an on beginSprite handler to trap the event and do the required initialisation. All we want to do when the sprite is initialised is set the pPasswordEntry to EMPTY, clear the input field, set the pCursor property to zero and set the pField property to point to the appropriate input field. The code to do this is as follows;

on beginSprite me
  set pField = the member of sprite
    the spriteNum of me
  set pPasswordEntry = EMPTY
  put EMPTY into field pField
  set pCursor = 0
end

As an aside, note the me property which is passed to all of our remaining behaviour handlers. This works in the same way as with other lingo objects - it is necessary so that whenever one of these handlers is called it knows the context in which it is being called. In other words, it represents the specific instance of the behaviour that is being invoked. It is necessary for Director to understand this context so that it knows which properties are being referred to in the code. Remember that there may be many instances of the behaviour in existence at the same time, all with their properties set to different values. To know which instance of the behaviour is being invoked, and therefore which properties to work with, it must be told this context - that is the sole function of the mysterious-looking me argument.

So far all our work has been to do with setting up the behaviour and initialising its properties. Before we go on to write the heart of the behaviour we will prepare a few utility handlers. The first two are very simple - all they do is increment and decrement the pCursor property that we use to see where we are in the input string;

on incrementCursor me
  set pCursor = pCursor + 1
end

on decrementCursor me
  set pCursor = pCursor - 1
end

We'll also need a handler that positions the input cursor within the input field according to the value of the pCursor property. This is necessary because, later in the project, we'll have to reposition the input cursor when the user uses, for example, the left and right arrow keys. The code looks like this;

on positionCursor me
  set the selStart = pCursor
  set the selEnd = pCursor
end

This handler uses the selStart and selEnd properties, which refer to the points where the selection inside the currently active input field starts and ends. This property can be written as well as read, which means that we can tell Director where to put the text input cursor within a field.

The final utility handler will be used to actually paint into the input field. This is necessary because, of course, we don't want to put the users actual input into the field, instead we'll replace every character in the input string with an asterisk. The code to do this is really very simple. All we do is examine the length of the user's current guess at the password and put an asterisk into the field for every character in the user's input. There is one initial check that the user has already entered some characters and, if not, simply put an EMPTY string into the field.

on paintField me
  set cnt = length (pPasswordEntry)
  if not cnt then
    put EMPTY into field pField
  else
   set str = EMPTY
   repeat with x = 1 to cnt
      put "*" after str
   end repeat
   put str into field pField
  end if
end

Now, at last, we are going to approach the heart of our problem. What we will do is to trap any keydown event fired by the user typing text into the input field. This in itself is easy enough to do - we write a keyDown handler to trap the event. The point of this part of the operation is to see what character the user has entered, add it on to the pPasswordEntry string, and paint the results into the input field;

on keyDown me
  set pCursor = the selStart
  put the key after char pCursor ¬
    of pPasswordEntry
  if (pCursor < length (pPasswordEntry)) then
    incrementCursor (me)
  end if
  paintField (me)
  positionCursor (me)
  if pPasswordEntry = pPassword then
    do (pHandler)
  end if
end

What happens is that the key that the user types is added to the pPasswordEntry string immediately after the position indicated by the pCursor property (put the key after char pCursor of pPasswordEntry), the field is painted and the cursor position is updated. The next line of code is vital. First, a test is done to see whether what the user has typed in matches the target password (if pPasswordEntry = pPassword…) and, if so, the handler that you set to be invoked when this happens is duly called (… then do (pHandler)). This is the key to the whole behaviour - characters are typed in by the user, trapped by our keyDown handler, added to the pPasswordEntry string, an extra asterisk is put in the field and our target handler is called if the password has been guessed.

Despite having written the core of the behaviour there is still a little work for us to do. This is because the user may type non-character keys, such as the delete keys, the arrow keys, and so on. Unfortunately it is not possible to use these keys directly. Instead, what we have to do is examine, not the key itself, but the keyCode. The keyCode of is a numeric value unique to the key that has been pressed. You can discover the keyCode for any key by writing a generic keyDown handler that simply puts the keyCode into the message box, type a few keys and note the numbers that appear. Watch out, though, for the differences between Mac and PC keyboards, which have different keycodes for the same keys. In either case, make sure you test your projector thoroughly on different systems to make sure you have covered the obvious possibilities. In what follows I have used the keycodes that worked on my (PC) machine.

What we'll do next is examine the keyCode to see whether the user has pressed the Delete, Delete back, left arrow or right arrow keys. Is so we'll respond appropriately, moving the cursor and deleting characters as necessary. Our rewritten keyDown handler should look as follows;

on keyDown me
  set pCursor = the selStart
  case the keyCode of
    51 : 
      -- Back Delete key
      if length(pPasswordEntry) ¬
	      and pCursor then
        delete char pCursor of pPasswordEntry
        decrementCursor (me)
      end if
      paintField (me)
    117 : 
      -- Back Delete key
      if length(pPasswordEntry) and ¬
	    (pCursor < length(pPasswordEntry)) then
        delete char pCursor + 1 of ¬
		  pPasswordEntry
      end if
      paintField (me)
    123 : 
      -- Arrow Back
      if pCursor then decrementCursor (me)
    124 : 
      -- Arrow Forward
      if (pCursor < length (pPasswordEntry)) ¬
	      then
	    incrementCursor (me)
	  end if
    otherwise :
      -- Other keys
      put the key after char ¬
	    pCursor of pPasswordEntry
      if (pCursor < ¬
	      length (pPasswordEntry)) then
	    incrementCursor (me)
	  end if
      paintField (me)
  end case
  positionCursor (me)
  put pPasswordEntry
  if pPasswordEntry = pPassword then
    do (pHandler)
  end if
end

As you can see, the rewritten code examines the keyCode and uses it in a long case statement to deal with all the possibilities we wish to respond to. Of course I have not covered every possibility - there may be other keys that you wish to trap - but you should now know enough to work out how to find new keycodes and code the behaviour to respond appropriately.

As in previous months, included a version of the code I've described here as a zipped file for you to download and modify for your own use. Download it here.

 
There are currently users connected. You have viewed 1 pages. Unless otherwise stated, all content is ©1996-2003 Andy Wilson. If you have any questions or suggestions you can mail me: andyw at dircon dot co dot uk. This site is hosted by LShift Ltd.