Skip to content

ViSi: Keyboard Demo

Details

Number 4D-AN-00073
Difficulty Medium
Supported Processors PICASO, DIABLO-16, PIXXI-28, PIXXI-44
Supported Environments ViSi

Description

This application note is intended to demonstrate to the user the usage of the keyboard widget from the Workshop4 IDE ViSi Environment.

Downloadable Resources

You can find the project file used in this application note:

Project File

The target module can be changed to your touchscreen display module powered by any of the supported processors: PICASO, DIABLO-16, PIXXI-28 or PIXXI-44.

Prerequisites

Application Overview

The main focus of this application note is to demonstrate the use of a Keyboard widget in the Workshop4 ViSi environment. Alphanumeric inputs are one of the most valuable mediums of input. In this application documentation, a ViSi-based keyboard is used to type and edit characters on-screen. We will customise a qwerty type keyboard to change key colours, edit a key and remove some keys.

Setup Procedure

This application note comes with a zip file which contains a ViSi project.

project-file

For instructions on how to launch Workshop4, how to open a ViSi project, and how to change the target display, kindly refer to the section Setup Procedure of the application note:

Create a New Project

For instructions on how to create a new ViSi project, please refer to the section Create a New Project of the application note

Designing the Project

Let us now add widgets to our project. We will start by adding the Keyboard widget.

Adding the Keyboard Widget

The keyboard is a customizable widget from the Workshop4 IDE ViSi environment. You can customise a ready-to-use keyboard type, a previously used keyboard or start from an empty board.

To add the keyboard widget follow the steps below.

  1. Go to Widgets menu.
  2. Select the Inputs pane.
  3. Choose the Keyboard widget. add-kb-object

Click on the screen to place the keyboard widget.

add-kb-to-wysiwyg

Keyboard Editor

After adding the Keyboard widget into the project, several object properties are displayed on the Object Inspector. The Keyboard widget can be configured according to the user's need. To set the desired configuration, open the Keyboard editor.

  1. On Object Inspector select the Form as Form1 and Object as Keyboard1.
  2. Go to KeyboardType property.
  3. Click on the button with the three dots.

open-kb-editor

The Keyboard editor window will open.

kb-editor

The Keyboard editor is a visual assistant that simplifies the editing of the Keyboard widget.

There are four(4) available keyboard types.

  1. Qwerty - A complete 106-key keyboard
  2. Numeric - A 17-key numeric keypad
  3. Cellphone - A 12-Key cellphone keypad
  4. Custom - A user customized keyboard

Keys Column Headers

Let's now discuss the column headers for the key properties.

column-headers

The Key and Shift Key columns are the text that displayed on each key of the keyboard.

The Key Value and Sh Key Value columns use a default value of -1 for most of the keys which defaults to the ASCII code of the Key and Shift Key. For keys with long name (Key or Shift Key), -1 defaults to the ASCII code of the first character. The values of Key Value and Sh Key Value can be customized as required. However, it is highly recommended to only do this for buttons with special functionalities.

The Special Key column is use to set key for SHIFT, SHIFTLOCK, CAPS, and CRTL keys. This setting should be set to NONE for the key to output the Key Value / Sh Key Value.

Color column is the key's color if the keys are not press and Color Down column is the key's color when the keys are pressed.

Text Color is the text color if the key is not press and Text Color Down is the text color when the key is pressed.

Height of the key is distance between the top to the bottom edge of the key and Width of the key is the distance between left to the right edge of the key.

X is the horizontal position of the Key which start at the left while Y is the vertical position of the Key which start from the top.

Load button is use to Load a previously saved keyboard.

Other keyboard editor properties and option will be discuss on separate application notes.

For this application note, we will customised a qwerty type keyboard that we need.

select-qwerty

We will first remove Ctrl, Arrow Up(˄) and Arrow Down(˅) keys.

To remove a key from the keyboard:

  1. Select the key that you want to remove from Key column.
  2. Click on the Delete Key button.

    remove-ctrl

    remove-up

    remove-down

After removing the right Ctrl key, Up Arrow key and Down Arrow key, we will now edit the left Ctrl key. First, we need to change the text of the key from Ctrl to Clear. Then, set the Key Value to 24 (0x18) and Special Key value to None.

The settings should look as shown.

edit-ctrl

We also need to change the size and position of left and right arrow keys for better keyboard design.

Change the Width of both keys from 40 to 60. And change the X position of right arrow key to 541.

width-and-x

Now, let us change the key color of Alphanumeric keys to LIME and other keys to RED.

To change the Alphanumeric keys color,

  1. Make sure that the Change Matching column colors is checked.
  2. Go to Color column and choose one alphanumeric key.

set-alphanumeric

A Color Picker window will appear, then from the Windows Color option select dLime and click OK button.

set-color-to-lime

To change the others key color, select a non-alphanumeric key from the Color column.

set-others-key

Color Picker window will appear again, select dRed from the Windows Color option and press OK button.

set-color-to-red

Then, lets also change the keys Color Down from GRAY to dBlue.

color-down

Color Picker window will appear again, select dBlue from the Windows Color option and press OK button.

color-down-blue

The custom qwerty keyboard will now shown below.

updated-kb

Click OK button to exit from the Keyboard editor window.

Size, Key Distance and Position

To set the keyboard size, go to Object Inspector's Height and Width properties and adjust the values to fit on the screen that you have. The distance between keys can be alter by adjusting the Key Distance property. The position of the keyboard can be set using the Top and Left properties.

Below are the property settings for this application note.

property-settings

The final appearance of the Keyboard as shown.

final-gui

Adding the Border Widget

Border widget will be use as a textbox and to add this widget follow the steps below.

  1. Go to Widgets menu.
  2. Select Backgrounds pane.
  3. Choose the Border widget border

Click on the WYSIWYG area to place the Border.

border-wysiwyg

Set the Border widget properties as shown below.

border-properties

The updated graphical user interface as shown.

kb-and-border

Adding Rectangle Widgets

We need to add two (2) Rectangle widgets, one is inside the textbox for clearing the textbox and the other one is background for the Entered Text.

To add a Rectangle widget follow the steps below.

  1. Go to Widgets menu.
  2. Select Primitives pane.
  3. Choose the Rectangle widget. rectangle-object

Click on the WYSIWYG area to place the first Rectangle widget. Repeat step 3 to add the other Rectangle.

rectangles

Set the properties for the two(2) Rectangles as shown.

rect1-properties

rect2-properties

The final GUI design as shown below.

final-gui

Writing the Code

After all the widgets have been laid out, let’s continue with the other half, which involves the project's code. This will be presented in a sectional manner to avoid confusion with the project.

Note

It is highly recommended that the graphics design / user interface is finalized before writing code. This is because some widgets require additional information to be in the generated code which can change when the user interface is altered.

Default code

Workshop 4 IDE automatically provides a default code, a program skeleton to which developers can simply add their codes. The progran skeleton contains the basic parts needed to start designing an application.

For more information on the default code for ViSi environment, please refer to the section Default Code of the application note

The Target Device and Include Section

On top of the code is the is the target device that will be use on the project that is declared by #platform function. For the program to function properly files are included herein using the #inherit pre-processor directive.

#platform "Gen4-uLCD-24PT"

// Program Skeleton 1.4 
#inherit "4DGL_16bitColours.fnc"
#inherit "KBRoutines.inc"

#inherit "VisualConst.inc"

Constants and Global Variables declarations

This section of the declares the constant and global variables which we will be using.

#constant MAX_STRING 36 // maximum character that can be printed inside the textbox(border)
#constant LINE 1        // line to start the text in using the function txt_MoveCursor()
#constant COLUMN 2      // column to start the text in using the function txt_MoveCursor()

var stringCtr;
var pointer;
var buffer[MAX_STRING/2];

The Main Program

The main program contains several sections:

  • Local variable declarations
  • Mounting of micro-SD card
  • Initialization
  • Continous loop repeat forever

Mounting of micro-SD card

Let's start with the initialization of the micro-SD card. The micro-SD card contains all the image information about the widgets used in the project. The object information and data are saved under a .dat and .gci filename extension which is copied to the micro-SD card during project compilation.

The following line of code statement for mounting the micro-SD card.

putstr("Mounting...\n");
if (!(file_Mount()))
    while(!(file_Mount()))
        putstr("Drive not mounted...");
        pause(200);
        gfx_Cls();
        pause(200);
    wend
endif

hndl := file_LoadImageControl("4D-AN-00.dat", "4D-AN-00.gci", 1);

The last part of this statements uses a function file_LoadImageControl() to call on the object data/information files on the micro-SD card. This initializes the data to be called in using the variable hndl.

Having been able to load and initialize the uSD drive, the processor is now able to access the information stored therein. As mentioned from the previous section, the filenames with an extension of dat and gci has the image data and information. Therefore, the next part of the main program is to display all the objects that were placed on the Workshop IDE form viewer.

Initialization

This section initializes the display orientation, clearing the screen, enabling the touch detection, set text properties, raise string pointer, show border and rectangle filled.

gfx_Set(SCREEN_MODE,LANDSCAPE) ;
touch_Set(TOUCH_ENABLE);
gfx_Cls();

txt_Height(1);                  // set text height multiplier to 1
txt_FGcolour(WHITE);            // set text foreground color to WHITE
txt_BGcolour(BLACK);            // set text backfround color to BLACK

pointer := str_Ptr(buffer);     // Raise the string pointer so we can use the 
                                // string functions

Paste Code to Code Editor

A button from the Object Inspector can help reduce development time by providing code for each widget.

paste-code-btn

On the code editor, put the blinking cursor to the place where to insert/paste the code.

Paste the Border and Rectangle1 at the bottom of the initialization section.

// Border1 1.1 
// Borders are 'embedded' in the background of each form, 
// this means even a form without a background image will have one created if it has 
// a border.
// Borders, Gradients and Scales are all done this way, 
// so you only need to Paste the main form, or one of them, 
// if several are included on a form.
img_Show(hndl,iForm1) ;

img_SetAttributes(hndl, iForm1, I_TOUCH_DISABLE);   // disable the touch functionality of 
                                                    // the form1 object

// Rectangle1 1.0 
gfx_RectangleFilled(5, 40, 314, 64, GRAY) ;

// Rectangle2 1.0 
gfx_RectangleFilled(8, 7, 310, 26, BLACK) ;

The keyboard widget generated code has three sections that needs to place on the right locations in the program.

  • Show initial keyboard
  • Keydown event
  • keyup event

The show initial keyboard section of the pasted code should be copied to the initialization section.

// Keyboard1 1.0 
img_Show(hndl,iKeyboard1) ; // show initial keyboard
for (i := iKeyboard1+1; i <= iKeyboard1+oKeyboard1[KbButtons]; i++)
    img_ClearAttributes(hndl, i, I_TOUCH_DISABLE);  // set to enable touch, only need to 
                                                    //do this once
next

The img_Show() function draws the active frame of the target GCI object from the loaded GCI file. The for() loop will display all key images.

The touch feature is enabled for the keyboard object by using the img_ClearAttributes() function for each of the keyboard buttons.

Also, the file named KBRoutines.inc is pasted on the include section that defines the functions used for the keyboard widget.

#inherit "KBRoutines.inc"

The repeat-forever Loop

This section of the main program contains statements that are continually run by the processor. The statements inside the repeat-forever loop starts with the touch status being checked and saved into a variable status. A variable n, on the other hand is used to store the returned image being touched.

Furthermore, the repeat forever contains three conditions that are related to the touch status. A condition during a press, moving and a release of the touch panel.

repeat
    status := touch_Get(TOUCH_STATUS);
    n := img_Touched(hndl, -1);

    //-------------- If there is a Key pressed --------------------------
    if(status == TOUCH_PRESSED)
        x := touch_Get(TOUCH_GETX);
        y := touch_Get(TOUCH_GETY);

        // keydown event
        if ((n >= iKeyboard1) && (n <= iKeyboard1+oKeyboard1[KbButtons]))
            kbDown(iKeyboard1, oKeyboard1, iKeyboard1keystrokes, n-iKeyboard1, KbHandler) ;
        endif
    //-------------- If touch is moving ---------------------------------
    else if (status == TOUCH_MOVING)
        x := touch_Get(TOUCH_GETX);
        y := touch_Get(TOUCH_GETY);
    //--------------- If touch is released
    else if (status == TOUCH_RELEASED)
        // keyup event
        if (oKeyboard1[KbDown] != -1) kbUp(iKeyboard1, oKeyboard1) ;
    endif
forever

Referring to the statements above, after a press is detected on the screen is a set of if-conditions. These if-conditions are checks-out which image is touched. If one of the images related conditions is satisfied the statements contained in the conditional loop is executed.

As a start, let us consider the touch related if-condition. For a touch that is moving, the processor is directed to simply read and save the value of the touch x and y position to variables x and y, respectively.

Another one of the if-condition is the touch_pressed condition. Whenever there is a press detected on the screen, the statements within this condition is executed. For the statements shown above, a sub condition dedicated for the keyboard widget is included. The condition for the touch needs to satisfy two things – that a touch must be inside the keyboard widget and that is a key inside the keyboard widget. The keydown event section of the keyboard paste code will be located.

// keydown event
if ((n >= iKeyboard1) && (n <= iKeyboard1+oKeyboard1[KbButtons]))
    kbDown(iKeyboard1, oKeyboard1, iKeyboard1keystrokes, n-iKeyboard1, KbHandler) ;
endif

With the conditions satisfied, the button state is changed. This means that the colour of the button changed according to the setting on the Keyboard Editor. The resulting value of the depressed key is directed to the function ‘kbHandler’. This ‘kbHandler’ function is a user defined function that enables return of preset numerical equivalents of the keys.

Lastly, the keyup event will be pasted on else-if statement when the key is released.

// keyup event
if (oKeyboard1[KbDown] != -1) kbUp(iKeyboard1, oKeyboard1) ;

The KbHandler Function

The function name KbHandler is part of the generated code. The user may choose to change this or keep this function name. The KbHandler() is an integral part of the keyboard widget codes. It has an argument 'Key' which output default ASCII or custom value for each pressed key.

An if-else-if condition is used to evaluate key presses.

The Back (0x08) key acts as a backspace button deleting the last input character. It will first check if the variable stringCtr is not zero then it will decrement both stringCtr and pointer. Using the function str_PutByte will put a null terminator (0) to the string buffer.

if (Key == 8)                   // Back Space
    if (stringCtr > 0)
        pointer--;
        stringCtr--;
        str_PutByte(pointer, 0);
        txt_MoveCursor(LINE, COLUMN + stringCtr);
        print(" ");
    else
        stringCtr := 0;
        txt_MoveCursor(LINE, COLUMN + stringCtr);
        print(" ");
    endif

The Tab key (0x09) adds 5 to the stringCtr, while Shift+Tab (0x15) subtracts 5 from the stringCtr.

else if (Key == 9)              // tab
    stringCtr := stringCtr + 5;
    if (stringCtr > MAX_STRING) stringCtr := 0;
else if (Key == 15)             // shift+tab
    stringCtr := stringCtr - 5;
    if (stringCtr < 0) stringCtr := 0;

Left and Right arrow keys decrements or increments the stringCtr and pointer by 1 respectively.

else if (Key == 28)             // left arrow
    if (stringCtr > 0)
        stringCtr--;
        pointer--;
    else
        stringCtr := 0;
        pointer := 0;
    endif
else if (Key == 29)             // right arrow
    if (stringCtr > MAX_STRING)
        stringCtr := 0;
        pointer := 0;
    else
        stringCtr++;
        pointer++;
    endif

The Clear (162) key will clear the textbox using a gfx_RectangleFiiled() and reset the string buffer.

else if (Key == 162)
    stringCtr := 0;
    // Rectangle2 1.0 
    gfx_RectangleFilled(8, 7, 310, 26, BLACK) ;
    mem_Set(buffer, 0, MAX_STRING);  // fill the entire string array with zeroes
    pointer := str_Ptr(buffer);      // reset pointer

Enter key (0x13) resets the stringCtr and terminates the pointer. The gfx_RectangleFilled is used to clear the textbox and the other rectangle will also clear the area where to display the stored text on the string buffer. The buffer then needs to be reset.

else if (Key == 13)             // enter
    stringCtr := 0;

    // Rectangle2 1.0 
    gfx_RectangleFilled(8, 7, 310, 26, BLACK) ;

    // Rectangle1 1.0 
    gfx_RectangleFilled(5, 40, 314, 64, GRAY) ;

    txt_FGcolour(LIME);        // set text font color to LIME
    txt_BGcolour(GRAY);        // set text background color to GRAY

    txt_MoveCursor(LINE + 3, COLUMN);
    putstr(buffer);            // print the String from string buffer
    mem_Set(buffer, 0, MAX_STRING);  // fill the entire string array with zeroes
    pointer := str_Ptr(buffer);      // reset pointer

If an Alphanumeric Key is pressed, it will display the ASCII character to the texbox as well as put the byte of the character to the string buffer. Then, it will increment the pointer and stringCtr value.

else
    txt_FGcolour(WHITE);
    txt_BGcolour(BLACK);
    txt_MoveCursor(LINE, COLUMN + stringCtr);
    print([CHR]Key);
    str_PutByte(pointer++, Key);
    stringCtr++;
    if (stringCtr > MAX_STRING) stringCtr := 0;
endif

Below is the complete code for the KbHandler functions

func KbHandler(var Key)
    if (Key == 8)
        if(stringCtr > 0)
            pointer--;
            stringCtr--;
            str_PutByte(pointer, 0);
            txt_MoveCursor(LINE, COLUMN + stringCtr);
            print(" ");
        else
            stringCtr := 0;
            txt_MoveCursor(LINE, COLUMN + stringCtr);
            print(" ");
        endif
    else if (Key == 9)              // tab
        stringCtr := stringCtr + 5;
        if (stringCtr > MAX_STRING) stringCtr := 0;
    else if (Key == 15)             // shift+tab
        stringCtr := stringCtr - 5;
        if (stringCtr < 0) stringCtr := 0;
    else if (Key == 28)             // left arrow
        if (stringCtr > 0)
            stringCtr--;
            pointer--;
        else
            stringCtr := 0;
            pointer := 0;
        endif
    else if (Key == 29)             // right arrow
        if (stringCtr > MAX_STRING)
            stringCtr := 0;
            pointer := 0;
        else
            stringCtr++;
            pointer++;
        endif
    else if (Key == 24)
        stringCtr := 0;
        // Rectangle2 1.0 
        gfx_RectangleFilled(8, 7, 310, 26, BLACK) ;
        mem_Set(buffer, 0, MAX_STRING);  // fill the entire string array with zeroes
        pointer := str_Ptr(buffer);      // reset pointer
    else if (Key == 13)             // enter
        stringCtr := 0;

        // Rectangle2 1.0 
        gfx_RectangleFilled(8, 7, 310, 26, BLACK) ;

        // Rectangle1 1.0 
        gfx_RectangleFilled(5, 40, 314, 64, GRAY) ;

        txt_FGcolour(LIME);        // set text font color to LIME
        txt_BGcolour(GRAY);        // set text background color to GRAY

        txt_MoveCursor(LINE + 3, COLUMN);
        putstr(buffer);            // print the String from string buffer
        mem_Set(buffer, 0, MAX_STRING);  // fill the entire string array with zeroes
        pointer := str_Ptr(buffer);      // reset pointer
    else
        txt_FGcolour(WHITE);
        txt_BGcolour(BLACK);
        txt_MoveCursor(LINE, COLUMN + stringCtr);
        print([CHR]Key);
        str_PutByte(pointer++, Key);
        stringCtr++;
        if (stringCtr > MAX_STRING) stringCtr := 0;
    endif
endfunc

For an in-depth detail of the functions used in this application note, please refer to the processor's Internal Functions Manual below.

Build and Upload the Project

For instructions on how to build and upload a ViSi project to the target display, please refer to the section Build and Upload the Project of the application note