Tutorial: Create the Keyboard application

In this tutorial, we'll show you how to use the glview library and OpenGL ES to capture and process input from the keyboard of your BlackBerry 10 device and to render graphics to the screen.

The app also shows you how to:

  • show or hide the touch screen keyboard
  • change the keyboard layout
  • rotate the displayed square
  • change the rotation speed of the square

If you are using a device with a physical keyboard, such as the BlackBerry Q10, the touch screen keyboard doesn't apply. The Keyboard sample app lets you use the physical keyboard to:

  • rotate the displayed square
  • change the rotation speed of the square

Device image showing the Keyboard sample app.

You will learn to:

  • Configure your project
  • Show the touch screen keyboard
  • Process keyboard input

Before you begin

You should have the following things ready:
  • The BlackBerry 10 Native SDK
  • Your BlackBerry 10 device or simulator
  • A basic understanding of the C language and some experience running apps with the Native SDK

Configure your project

To import the complete project:

  1. From the NDK-Samples repository in GitHub, download and extract the sample app.
  2. Start the Momentics IDE for BlackBerry.
  3. On the File menu, click Import.
  4. Expand General, then select Existing Projects into Workspace. Click Next.
  5. Browse to the location where you extracted the sample app and click OK.
  6. Click Finish to import the project into your workspace

Using the keyboard

The event handling framework for BlackBerry 10 is BlackBerry Platform Services (BPS). This framework allows you to register for and receive events from the underlying OS. The events cover things such as the virtual keyboard, screen, and device sensors. In this sample, we use the BPS library to set up the virtual keyboard.

To use any virtual keyboard function, we must include the appropriate header file at the beginning of main.c:

#include <bps/virtualkeyboard.h>

This application draws a colored square on the screen and uses OpenGL ES to update and render the graphics. The Glview library provided with the BlackBerry 10 Native SDK makes it easy to develop apps with OpenGL ES. It provides an execution loop as well as API functions for an application to register callbacks at different points of execution. We use Glview to set up and run the application.

#include <glview/glview.h>

In main(), all we need to do is register three callback functions with Glview and then call glview_loop().

int
main(int argc, char *argv[])
{
    glview_initialize(GLVIEW_API_OPENGLES_11, &render);
    glview_register_initialize_callback(&initialize);
    glview_register_event_callback(&event);
    return glview_loop();
}

Now let's take a closer look at the callbacks.

Initialization callback

We register the initialization callback to initialize the square and display the virtual keyboard. This callback is called before Glview enters the main loop.

glview_register_initialize_callback(&initialize);

In initialize(), we request virtual keyboard events so that we know when someone presses a key.

virtualkeyboard_request_events(0);

Next, we display the virtual keyboard on the screen:

virtualkeyboard_show();

The initialization code then uses calls to OpenGL ES functions to set up the display area, the background color and smooth shading, and initialize a simple orthographic projection for rendering:

unsigned int surface_width, surface_height;
glview_get_size(&surface_width, &surface_height);

glShadeModel(GL_SMOOTH);

glClearColor(1.0f, 1.0f, 1.0f, 1.0f);

glViewport(0, 0, surface_width, surface_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();

glOrthof(0.0f, (float) (surface_width) / (float) (surface_height), 0.0f,
         1.0f, -1.0f, 1.0f);

glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glTranslatef((float) (surface_width) / (float) (surface_height) / 2, 0.5f,
             0.0f);

Display callback

We need to register a callback to render the square. This callback is required for using Glview and is called frequently to refresh the graphics to ensure the smooth rotation of the square.

Our display callback is render() and we register it using glview_initialize(). We also specify the use of OpenGL ES version 1.1:

glview_initialize(GLVIEW_API_OPENGLES_11, &render);

To draw the square, we initialize an array of vertices and an array of colors for the vertices at the beginning of main.c:

static const GLfloat vertices[] = {
    -0.25f, -0.25f,
     0.25f, -0.25f,
    -0.25f,  0.25f,
     0.25f,  0.25f
};

static const GLfloat colors[] = {
    1.0f, 0.0f, 1.0f, 1.0f,
    1.0f, 1.0f, 0.0f, 1.0f,
    0.0f, 1.0f, 1.0f, 1.0f,
    0.0f, 1.0f, 1.0f, 1.0f
};

We also define a variable angle, which denotes the rotation angle for the square:

static float angle = 0.0;

Our callback must first call glClear() to clear the color buffer:

glClear(GL_COLOR_BUFFER_BIT);

Then it enables the GL_VERTEX_ARRAY state and provides an array of vertices that describe our simple square:

glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, vertices);

Similarly, it enables the GL_COLOR_ARRAY state and provides an array that defines the color of each of our vertices:

glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(4, GL_FLOAT, 0, colors);

Next, it adds a rotation for the vertical axis and then renders the square. The rotation angle is initialized to 0 so that when the square is rendered initially, it doesn't rotate. In the event callback code, the value of angle changes according to the keyboard input we receive.

glRotatef(angle, 0.0f, 1.0f, 0.0f);
glDrawArrays(GL_TRIANGLE_STRIP, 0 , 4);

Finally, we disable all client states used by the current rendering logic as it's generally a good practice to do so. This simple step can save you a lot of time in front of the debugger as EGL code is typically difficult to debug.

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);

Event callback

To handle user input from the screen, we register an event callback, in which we check each incoming event and respond to it. When a user presses a key, for example, a screen event is generated and Glview invokes the event callback we register.

glview_register_event_callback(&event);

The event callback handles two types of events: virtual keyboard events and screen events. When receiving a virtual keyboard event, it sets the keyboard_visible flag accordingly. It checks this flag later to determine whether to display the virtual keyboard.

if (virtualkeyboard_get_domain() == domain) {
    switch (code) {
    case VIRTUALKEYBOARD_EVENT_VISIBLE:
        keyboard_visible = true;
        break;
    case VIRTUALKEYBOARD_EVENT_HIDDEN:
        keyboard_visible = false;
        break;
    }
}

When a user touches anywhere on the screen or presses a key, a screen event is sent to the application.  On detecting a touch on the screen, we display the virtual keyboard if it isn't already visible.

switch (screen_val) {
    case SCREEN_EVENT_MTOUCH_TOUCH:
        if (!keyboard_visible) {
            virtualkeyboard_show();
        }
    break;

When a key is pressed, we receive a keyboard event and perform the desired action. For example, we can change the layout of the keyboard so that it's more suited to some function the user wants to perform, such as sending an email or entering a phone number.

case SCREEN_EVENT_KEYBOARD:
    screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_FLAGS, &screen_val);

    if (screen_val & KEY_DOWN) {
        screen_get_event_property_iv(screen_event, SCREEN_PROPERTY_KEY_SYM,&screen_val);

        fprintf(stderr, "The '%c' key was pressed\n", (char)screen_val);

        switch (screen_val) {
        case KEYCODE_I:
            // Display the email layout with "Send" enter key
            virtualkeyboard_change_options(VIRTUALKEYBOARD_LAYOUT_EMAIL, VIRTUALKEYBOARD_ENTER_SEND);
            break;
        case KEYCODE_O:
            // Display the phone layout with "Connect" enter key
            virtualkeyboard_change_options(VIRTUALKEYBOARD_LAYOUT_PHONE, VIRTUALKEYBOARD_ENTER_CONNECT);
            break;
        case KEYCODE_P:
            // Display the default layout with default enter key
            virtualkeyboard_change_options(VIRTUALKEYBOARD_LAYOUT_DEFAULT, VIRTUALKEYBOARD_ENTER_DEFAULT);
            break;

On the screen, the layouts would look as follows:

Diagram showing the default, phone, and email keyboard layouts.

The fprintf() statement in the example above sends the keyboard character that was pressed to the console, in case you want to debug the application later.

We can also hide the virtual keyboard, which is useful when you want to use the full screen to display something. The user can pop up the virtual keyboard again by touching the screen.

case KEYCODE_H:
    // Hide the keyboard
    virtualkeyboard_hide();
    break;

Next, we specify how to rotate the squares using the a or z keys.

#define ANGLE_INCREMENT 3.0f
#define CIRCLE_DEGREES 360.0f

The rotation angle is incremented each time a is pressed, and decremented each time z is pressed.

case KEYCODE_A:
    // Increment rotation angle
    angle = fmod(angle + ANGLE_INCREMENT, CIRCLE_DEGREES );
    break;
case KEYCODE_Z:
    // Decrement rotation angle
    angle = fmod(angle - ANGLE_INCREMENT, CIRCLE_DEGREES );
    break;

Recall that the Glview library calls our display callback render() to refresh the graphic display. The incremented or decremented value of the angle variable causes the square to rotate at an increased or decreased speed.

glRotatef(angle, 0.0f, 1.0f, 0.0f);

That's it! You can now build and run your application. Try playing with the keyboard to see how the application changes or changing the event callback to map different functions to different keys. You can also explore other callbacks that Glview supports and try adding a new callback!

Last modified: 2015-03-31



Got questions about leaving a comment? Get answers from our Disqus FAQ.

comments powered by Disqus