Example Keyboard

The main goal of this example is to show how Internal RAM string variables can be used to create an onscreen keyboard. The main page is comprised of six buttons which receive their label from an Internal RAM string variable. Clicking on any of the buttons takes you to a new screen containing a keyboard comprised of many function buttons and a string field widget which displays an Internal RAM string variable, which is the label for the button just pressed. The keyboard allows you to modify the string being displayed in the string field widget. The keyboard starts out with all uppercase letters. Hitting the "shift" key in the lower left hand corner switches to a lowercase keyboard. Once the label is finished, hit the "ENTER" key to return to the main screen with the six buttons. The button you previously hit should now have a new label that you created while in the keyboard. The label has also been saved to the serial data flash, so if you turn the power off and turn it back on, the button will retain the new label you just created. 

The button labels are stored in InternalRAM string variables 0-5. The count of characters used in each button label is stored in InternalRAM byte variables 0-5. These InternalRAM variables are initialized in the file called keyboardInternalRAM.ini.

Here is a snapshot of what the main html page with the six buttons looks like in a "WYSIWYG" tool:


Figure 1.

Here is what the source for one of the above FunctionButtons looks like:

Notice the label attribute is set to FromInitHref. This signifies the button label will be set based upon the value returned from the initHref function. The initHref function is Amulet:internalRAM.label(0).value(), which returns the string located in Amulet Internal RAM string variable #0. Read the note regarding using Internal RAM string variables for button labels using initHref. In CompileMe.htm in this directory, there is a META tag that looks like this:

The above META tag is used to initialize the Internal RAM string variables used in this project. For more information, see Internal RAM documentation. Open keyboardInternalRAM.ini in a text editor to see how the Internal RAM string variables were initialized. You will also see that the InternalRAM byte variables used to hold the count of bytes in the strings are also initialized in this file as well.

The href attribute of the button has two unique functions which are both launched upon a button "hit". The first function sets Internal RAM byte variable #100 to 0. Internal RAM byte variable #100 is used by the keyboard pages to determine which button was pressed. All six of the buttons use a unique number to save in Internal RAM byte variable #100. That unique number coorelates to the index into the InternalRAM string variables used for the labels and the InternalRAM byte variables used for the count of characters in each label. The second function launches the META Refresh tag called metaChangeLabel.

Here's the source code for the META Refresh tag called metaChangeLabel:

<meta http-equiv="Refresh" content="0;
       URL=Amulet:InternalRAM.string(InternalRAM.byte(100)).copyToRAMString(190),
       Amulet:InternalRAM.byte(InternalRAM.byte(100)).copyToRAMByte(191),

       background.html;

   NAME=metaChangeLabel">
</head>

Notice that the updateRate of metaChangeLabel is 0, meaning that it will only launch if a forceHit() is executed. When metaChangeLabel is forceHit(), it will launch three functions. The first function copies the InternalRAM string variable pointed to by InternalRAM byte variable #100 into InternalRAM string variable #190. InternalRAM string variable #190 was arbitrarily chosen to hold the label of the button that was just pressed. The keyboard pages make changes to InternalRAM string variable #190, not the actual string variable used by the button. The second function copies the InternalRAM byte variable pointed to by InternalRAM byte variable #100 into InternalRAM byte variable #191. InternalRAM byte variable #191 was arbitrarily chosen to hold the count of bytes in the label of the button that was just pressed. The keyboard pages use the value in InternalRAM byte variable #191 to limit check the string. The final function jumps to the page called background.html.

Here is a snapshot of what background.html looks like in a "WYSIWYG" tool:

The background page provides the rectangular outline around the keyboard, to give it a more finished look. There is a META Refresh tag that immediately launches to the uppercase keyboard page, alphaKey.html. The reason for using a separate page for the background image is for aesthetic purposes only. The keyboard pages can switch back and forth between upper and lower case keys, but the pages look identical except for the case of the buttons. Both keyboard pages use the NoClearLCD META attribute, so the LCD is not cleared when loading either one of the keyboard pages. That is why the background image does not get written over, since none of the objects on the keyboard pages overlap the rectangular frame loaded by the background page. If the background image was included on the keyboard pages, the functionality would be the same, but there would be a slight flicker, since the background image actually overwrites all the buttons and the stringField widget, which defeats the purpose of the NoClearLCD META attribute. Hit the shift key on the keyboard pages and the buttons should change case, but there should not be a noticeable flicker.

Here is a snapshot of what the uppercase keyboard page, alphaKey.html, looks like in a "WYSIWYG" tool:

Figure 3.

 At the top of the upper case keyboard page, there is a META which looks like:

This signifies that this page does not clear the LCD prior to displaying this page. The reason for this is that the "shift" key hyperlinks to the lower case keyboard page, which looks exactly like the upper case keyboard page, except for the lowercase keys. By not clearing the page first, you will not see the screen flicker while the new page is loaded. This only works because the two keyboard pages are layed out exactly the same. If any of the objects were in different locations on the LCD, you would have remnants of the previous page appearing on the new page.

 There is also another META at the top of alphaKey.html which looks like:

This attaches a cursor at the end of the "scratch pad" string variable. Notice the update rate of 0,0.01 which means it has an update of 0, which is never, and an initial delay of .01, which means it will happen 10ms after loading the page. The next function forces StringField1, which is used to display InternalRAM.String(190), to update itself.

The html for the stringField widget which is used to display InternalRAM.String(190) looks like:

Notice that the updateRate is set to 0, meaning that it will never update itself on its own. It will only update when given a forceUpdate() command. Everytime a new character is added, a forceUpdate() command is sent, which makes StringField1 read the string located in InternalRAM string variable #190, the "scratch pad". One thing to note is the waitForInit parameter. By making it true, StringField1 will not display anything until it receives a valid string. This is important because if this parameter was left off, StringField1 would first clear the string field text area and then not display anything until it got the string from Internal RAM string #190. It all happens very quickly, but there is a noticeable flicker if waitForInit is either set to false or not present. You can easily test this for yourself by changing the true to a false and recompiling the project. Note that there are two keyboard pages and if you only change one of the pages, you can see the difference between using waitForInit and not by hitting the "shift" key over and over.

Hitting any of the keyboard keys causes a number of functions to occur. Here's the html code for the 'A' key:

Notice the href has two separate functions separated by commas, meaning that both functions will be launched upon this button being hit. The first function, Amulet:InternalRAM.byte(190).setValue('A'), which will set InternalRAM byte variable #190 to ASCII 'A'. The reason for this will become more obvious when we look at the second function and the META Refresh tag it performs a forceUpdate() on. The second function, Amulet:document.metaAddChar.forceUpdate(), launches the ONVAR function of the META Refresh Tag called metaAddChar.

Here is the source code for the META Refresh Tag called metaAddChar. This META is called when almost any of the keyboard buttons are pressed.

<meta http-equiv="Refresh" content="0;
   ONVAR=Amulet:InternalRAM.byte(191).value();

   TRIGGER.LT=17;

   URL=Amulet:InternalRAM.String(190).backspace(),

       Amulet:InternalRAM.String(190).appendChar(InternalRAM.byte(190)),

       Amulet:InternalRAM.String(190).appendChar('_'),

       Amulet:InternalRAM.byte(191).increment(),

       Amulet:document.StringField1.forceUpdate();

   NAME=metaAddChar">

Notice that the updateRate of metaAddChar is 0, which means it will only launch when another object performs a forceUpdate() on it. In this case, almost anytime a keyboard button is pressed, it will load InternalRAM byte variable #190 with the ASCII character equivalent of the button and then launch the forceUpdate() on metaAddChar. When launched via forceUpdate(), the first thing that occurs is the ONVAR function gets called and returns a value. In this case, it will be returning the value of InternalRAM byte variable #191, which holds the current count of bytes in the currently loaded string. If the current count is 17 or greater, nothing further will occur, which means that all strings are limited to 17 bytes in length. If the current count of bytes is less than 17, then the URL functions will be launched. First, the last character in IR.string(190) is removed, which is the underscore located at the end of the string. Then the new ASCII character that was just loaded into IR.byte(190) is appended to IR.string(190). Then a new underscore is appended to IR.string(190). The current count of bytes within the string is then incremented to account for the addition of the new character. Finally, StringField1 is made to update itself since we just modified IR.string(190).

When the "ENTER" key is hit, there's another group of functions that occur. Here is the html code for the "Enter" key:

Once again, the first thing that happens upon the "ENTER" key being pressed is the removal of the underbar cursor, by using the Amulet:InternalRAM.String(190).backSpace() function. The second function, Amulet:InternalRAM.String(InternalRAM.byte(100)).setValue(InternalRAM.string(190)) is the key to the keyboard example. Remember, in CompileMe.html, when one of the buttons was pushed, the first thing it did was set Internal RAM byte variable #100 with a unique number. The string in Internal RAM string variable #190 is copied to the Internal RAM string whose variable number is the number found in Internal RAM byte variable #100. If you are not used to indirection, you might want to reread this paragraph until it makes sense, because it can be confusing. The next function performs a similar indirect operation, but this time the count of bytes in the current string (InternalRAM.byte(191)) is copied to the Internal RAM byte variable whose variable number is the number found in Internal RAM byte variable #100. The next function clears the LCD and is there for aesthetics and to provide a bit of feedback to the user, letting him know something happened after pressing the button. The reason for having the clearing of the LCD is because the next function, Amulet:InternalRAM.saveToFlash(), saves all the InternalRAM variables to the serial data flash and there is an inherent delay in saving to the serial data flash. If the clearing of the LCD did not take place, there would be a noticeable delay before launching the final function, which is a hyperlink back to the CompileMe.html page. Because the Internal RAM variables have been saved to flash, if you turn the Amulet off and then turn it back on, the changes you made in the keyboard example will be retained.

If the "Cancel" button is pressed, it launches directly to CompileMe.html. Since only the "scratch pad", Internal RAM string #190, has been modified, when CompileMe.html loads, there's been no change to any of the buttons, which all use Internal RAM strings 0 through 5..

Just to give an example of how this all works, if "Button 1" is selected from CompileMe.html, Internal RAM byte variable #100 will be loaded with the value of 1, Internal RAM string variable #1 will be copied into Internal RAM string variable #190, and Internal RAM byte variable #1 will be copied into Internal RAM byte variable #191. At the keyboard pages, if the "ENTER" button is pressed, then Internal RAM string variable #190 has its cursor removed and is then copied back into Internal RAM string variable #1 and the value of Internal RAM byte variable #191 is copied back into InternalRAM byte variable #1. The initial page now shows the updated change to InternalRAM string #1.

NOTES:



Amulet HTMLCompiler,
Copyright © 2000-2004 by
Amulet Technologies, LLC

Back to Welcome - Contact Amulet - Amulet Home