Creating a Custom Bullet Masked Password Field in LiveCode

Creating a Custom Bullet Masked Password Field in LiveCode

This blog post is a step by step how to tutorial for creating a custom bullet masked password field in LiveCode that may be used in your own projects. All the necessary password field script handlers and functions are included. LiveCode already has a quick and easy built-in method to get an asterisk masked password with this simple command.

ask password “Please enter your password:”

Which creates the following password entry modal dialog with the password field’s text entry masked by asterisks. When the dialog is dismissed with the (OK) button the password is returned in the default variable “it.”

LiveCode's Standard Ask Password Dialog - Creating a Custom Bullet Masked Password Field in LiveCode

The ask password command works fine for a simple password dialog but sometimes it’s useful to have a password field that may be used for more custom or more complicated applications. For example, I’m currently in the process of building a brand new version of our DreamLight network rendering utility, DLI_SNUB-Launcher™ from scratch in LiveCode. This will allow us to bring Drag-and-drop-dead-easy™ network rendering setup to Windows users in addition to our current Macintosh users. I had programmed the previous versions of DLI_SNUB-Launcher in Apple’s Xcode, which limits it to Mac users. DLI_SNUB-Launcher has a custom user registration panel that includes a clear text user name field paired with a bullet masked password field. LiveCode doesn’t have a standalone password text field as Xcode does, so I created a custom password field that’s masked with bullets and that is robust enough to handle selection, editing, deleting and pasting into the password field. I thought this custom bullet masked password field would make a good blog post that I could share with other LiveCode developers.

UPDATE (5/31/15): I’ve revised this post with additional information for a simple hack fix to allow pasting from the clipboard despite a bug in LiveCode where implementing a standard Edit menu with a Paste menu item using command-V or (control-V on Windows) blocks the pasteKey message from reaching the password field. This is done by creating a global list of any objects that need to receive pasteKey messages and then manually dispatching the message to those objects when needed.


Scripts for Creating a Custom Bullet Masked Password Field in LiveCode

I started by creating a basic LiveCode text field, in this case I named it UserPass. Then on the Property Inspector for the field I created a Custom Property named cpClearText. This property field will hold the clear text password while the field contents will be filled with bullet characters to mask the content. I then used the following handlers in the password field’s script, starting with declaring local variables.

-- Password Field with bullet masked text by DreamLight.com
-- The cpClearText custom property contains the clear text password
-- Bullets are placed in the field contents for viewing
-- full editing including selection, deletion and pasting is supported

global gPasteKeyList -- list of object names with PasteKey handlers

local pBulletCodeMac = 165
local pBulletCodeWin = 149
local pBulletChar
local pSelectStart, pSelectEnd

The first handler, initializeField, is manually sent to the password field by the stack’s preOpenStack handler. It sets the field script’s local variables to choose the appropriate bullet character based on the current platform the stack is running on.

on initializeField initialPassword
   --manually sent to the field from the preOpenStack
   -- choose the platform specific bullet character
   if the platform = "MacOS" then 
      put numToChar( pBulletCodeMac ) into pBulletChar
   else -- win
      put numToChar( pBulletCodeWin ) into pBulletChar
   end if
   set the cpClearText of me to initialPassword
   bulletIt
   
   -- check object name in to receive pasteKey messages
   put the short name of me after the last line of gPasteKeyList
end initializeField

The next few handlers take care of basic typing into the password field, handling cases where there may be selected characters before a key is pressed.

-- Handle basic typing into the field

on keydown tKey
   put the cpClearText of me into tEditText
   
   updateSelection
   if pSelectEnd >= pSelectStart then 
      -- some text is selected, delete to replace
      delete char pSelectStart to pSelectEnd of me
      delete char pSelectStart to pSelectEnd of tEditText
   end if
   
   updateSelection
   put pBulletChar after char pSelectEnd of me
   put tKey after char pSelectEnd of tEditText
   updateClearText tEditText
end keyDown

on updateSelection
   put word 2 of the selectedChunk of me into pSelectStart
   put word 4 of the selectedChunk of me into pSelectEnd
end updateSelection

on updateClearText tPassword
   set the cpClearText of me to tPassword
   textChanged
end updateClearText

The next few handlers take care of deleting and pasting into the password field.

-- Handle deleting and pasting

on backspaceKey
   put the cpClearText of me into tEditText
   
   updateSelection
   if pSelectEnd >= pSelectStart then 
      -- some text is selected to delete
      delete char pSelectStart to pSelectEnd of me
      delete char pSelectStart to pSelectEnd of tEditText
   else
      delete char pSelectEnd of me
      delete char pSelectEnd of tEditText
   end if
   
   updateClearText tEditText
end backspaceKey

on deleteKey
   -- forward delete key
   put the cpClearText of me into tEditText
   
   updateSelection
   if pSelectEnd >= pSelectStart then 
      -- some text is selected to delete
      delete char pSelectStart to pSelectEnd of me
      delete char pSelectStart to pSelectEnd of tEditText
   else
      delete char pSelectStart of me
      delete char pSelectStart of tEditText
   end if
   
   updateClearText tEditText
end deleteKey

on pasteKey
   put the clipboardData["text"] into tPasteText
   if tPasteText is not empty then
      put the cpClearText of me into tEditText
      
      -- replace returns with spaces on the tPasteText
      put replaceText(tPasteText,return,space) into tPasteText
      put makeBullets( the length of tPasteText ) into tBullets
      
      updateSelection
      if pSelectEnd >= pSelectStart then 
         -- some text is selected, delete to replace
         delete char pSelectStart to pSelectEnd of me
         delete char pSelectStart to pSelectEnd of tEditText
      end if
      
      updateSelection
      put tBullets after char pSelectEnd of me
      put tPasteText after char pSelectEnd of tEditText
      updateClearText tEditText
   end if
end pasteKey

function makeBullets howMany
   put empty into tBullets
   repeat howMany times
      put pBulletChar after tBullets
   end repeat
   return tBullets
end makeBullets

The next few handlers deal with dragging and dropping text onto the password field.

-- Handle dragging and dropping text onto the field

on dragEnter
   set the dragAction to "copy"
end dragEnter

on dragDrop
   put the dragData["text"] into tPasteText
   if tPasteText is not empty then
      
      -- replace returns with spaces on the tPasteText
      put replaceText(tPasteText,return,space) into tPasteText
      
      setPassword tPasteText
   end if
end dragDrop

The final few handlers take care of internal and external communications to set and get the password. Other scripts can send the setPassword command to set the password and can call the getPassword function, using value( “getPassword()”, field “UserPass”), to get the current password.

-- Handlers and functions to set and get the password

on setPassword tPassword
   -- set the password such as when loading a pre-saved password
   updateClearText tPassword
   bulletIt
end setPassword

function getPassword
   -- return the password saved in the cpClearText custom property
   return the cpClearText of me
end getPassword

on bulletIt
   -- process the custom property cpClearText
   -- and put the bulleted version in the field for show
   put empty into tBullets -- empty visible field
   repeat for each character tChar in the cpClearText of me
      put pBulletChar after tBullets
   end repeat
   put tBullets into me
end bulletIt

UPDATE NOTE: There’s an issue in LiveCode where if you are implementing a standard Edit menu with a Paste item it will block the pasteKey messages from reaching the password field. In order for the paste functionality to work you’ll need to add the following code to your Edit menu button to manually dispatch a pasteKey message to the password field object.

global gPasteKeyList -- list of object names with PasteKey handlers

--The following menuPick handler was generated by the Menu Builder.
on menuPick pWhich
   switch pWhich
      case "Cut"
         cut
         break
      case "Copy"
         copy
         break
      case "Paste"
         -- Paste menu blocks pasteKey messages so manually dispatch 
         -- pasteKey if focused object has a pasteKey handler
         put the focusedObject into tObject
         if gPasteKeyList contains the short name of tObject then
            dispatch "pasteKey" to tObject
         else
            paste
         end if
         break
      case "Clear"
         clear
         break
      case "Preferences"
         -- do preferences handling here
         break
   end switch
end menuPick

In the above pasteKey hack fix I’m using a manual global list of object names that need to receive pasteKey messages. This method works in the IDE, with Suspend LiveCode UI, as well as in standalone apps, even if the scripts are encrypted in password protected stacks. Other more automatic methods such as searching “the script” property for “on pasteKey” or querying the revAvailableHandlers or get revAvailableHandlers() for “pasteKey” fail in standalone apps in password protected stacks because the handlers are encrypted.

If any other LiveCode developers find this custom bullet masked password field useful, feel free to use it in your own projects. -ENJOY!

At this point I’ve ported the entire DLI_SNUB-Launcher from Apple’s XCode to LiveCode. It’s up and running, including a pretty robust custom built implementation of a drawer window because that’s another feature of XCode that LiveCode lacks. Stay tuned, I may make a future blog post sharing my custom drawer window implementation. I’m currently in the process of adding a few new features to DLI_SNUB-Launcher as well as adding cross-platform functionality to allow it to run on Windows as well. Once the new features are ready I’ll release the new version DLI_SNUB-Launcher 2.0 on our DLI_SNUB-Launcher WebShop page.

Here’s the current 2.0 GUI in LiveCode under development as it looks on Mac OS X Snow Leopard with the custom-built drop down drawer open at the bottom. It’ll look different on different versions of the OS and different platforms. Stay tuned!

DLI_SNUB-Launcher_2.0 with drop down drawer

DLI_SNUB-Launcher 2 – First Test Launch on Windows with LiveCode

DLI_SNUB-Launcher 1st Run on Windows in LiveCode[Update 5/13/15] Wow. I’m impressed with LiveCode so far. While still beta testing DLI_SNUB-Launcher 2 on Mac OS X I figured I’d have LiveCode generate a build for Windows. That way I could give it a quick spin to see how much work it will take to release the Windows version. I expected to be greeted with a bunch of error messages but it was up and running within minutes, without any errors. Everything worked right off the bat from the exact same code base, from the user panel dialog with my custom bullet masked password field to my custom built slide out drawer on the bottom. Looks like all I’ll have to adjust is to flip the path delimiter from the Mac OS X / Unix / LiveCode forward slash to the Windows backslash, change some defaults and clean up some of the text placement on some of the buttons. Cool!

Here are a few more links with other ways to deal with password fields in LiveCode

How do I mask a users input (e.g. password) within a LiveCode field?

LiveCode Share – Password Field

LiveCode Forum – Field type Password



If you enjoyed this tutorial please consider making a donation to fund more!


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.