Low-Level Management of Multi-Control Screens Under BREW

Low-Level Management of Multi-Control Screens Under BREW

Most BREW applications require some kind of user interface, consisting of various screens. A developer essentially has two choices when confronted with the task of implementing any screen design:

1.) Use a dialog to contain the required controls, and live with the dialogs somewhat restrictive nature, or

2.) Fly without a net, using only the controls themselves.

In this article, youll learn how to implement the latter option, the most flexible and powerful of the two approaches.

The application we’re going to cover consists of a generic user-interface(UI), and nothing more. The intent is to show you how to code your own,low-level navigation for a collection of BREW controls residing on a singlescreen. Specifically, our single screen UI will consist of 3 text controlsand a related soft key menu residing at the bottom of the screen.

When we’re done and we run it on the emulator, the application should appearexactly as shown in Figure 1, when it opens. As you can see, you really canfit more than one control on a single screen and still get a reasonablyattractive result. As you might have guessed, the rectangle surrounding thefirst control indicates that it currently has the input focus.

Figure 1

What you need to get started
The example contained herein assumes the use of BREW SDK 1.x and BREWEmulator version If you intend to work along with the example, you mustcreate a module information file, consistent with the file / directorynaming scheme covered in the SDK User’s Guide. Copy this file to ...yourBREWdirExamplesmif256Color,or to whatever directory you’ve chosen to designate as your mif directory within theBREW Emulator. For more information, please consult the BREW SDK User’sGuide provided with the BREW SDK.

For ease of exposition, I’ve hard-coded therequired strings in the application’s source file. I really should haveused the BREWResource Editor to create a resource file containing all of the strings used inthe application. ISHELL_LoadResString() would then be used toprogrammatically retrieve each of these strings from the resource file.For more information on using the Resource Editor and the ISHELL_LoadResString()function, please see “The BREW Resource Editor Guide” and”The BREW API Reference”, respectively. Both of these documentsare included with the BREW SDK.

How screen navigation works
As you will see, when the developer assumes control over screen navigation, (s)hecan specify the means by which this navigation should take place. Both a text control anda soft key menu provide default behaviors in response toleft and right key presses. A text control responds by moving the insertion point (i.e. the cursor) left or rightwithin thetext string. By default, a left key press has no effect ifthe insertion point is already at the front of the string and a right key presshas no effect if the insertion point is at the end of the string. We willalter this default behavior.

The soft key menumoves the current command selection to the menu item on the immediate left orright, consistent with the key pressed. Note that plain menus and listcontrols (please see the SDK User’s guide) exhibit this item selection behaviorin response to the up and down keys, while the select, left and rightkeys,are typically used for moving between menus on the samescreen. We’ll learn more about this when we examine dialogs in a laterarticle.

Intuitively, within the UI shown in Figure 1, a user should move from controlto control by thumbing the up or down arrow keys. This scheme is mypersonal favorite as it dovetails nicely with the actual layout and defaultfunctioning of the controls. The BREWUser Interface Design Guidelines provide some excellent advice on thissubject and a developer would be well advised to read through this documentbefore starting to code an application’s UI.Thus, to be consistent with the guidelines,and avoid conflicting with the default behavior of the various controls, it appears thatwe must navigate by means of theup and down keys. An example of such an implementation is included in thearchive file available for download at the end of this article.

A recent post inthe BREW Developers’ Forum sought advice on how to navigate a UI similar to theone shown in Figure 1. Apparently the poster was required to use the left and right arrowkeys to move from text control to text control, and from text control 3 to themenu. Since this is more of a challenge, and thus more interesting thanimplementing the up and down solution, we will code this unusual case.Before we start, you should note that this solution runs contrary to the spirit,if not the letter, of the BREWUser Interface Design Guidelines.

In the case of the menu control, theleft and right keys change the menu selection exclusively. Separate softkey items are provided so that the user can directly move from the menu control toany of the text controls . Clearly, it might be desirable topermit the user to move from the menu to either text control 1 or text control 3by using the down or up key, respectively. Note that this functionality isincluded in the alternate source file mentioned above.

Clearly stated, our goal is to provide a user interface consisting of 3 textcontrols and a soft key menu. The user navigation scheme is summarized inthe following two tables:

 Active Text Control
Key PressedText Control 1 (Txt1)Text Control 2 (Txt2)Text Control 3 (Txt3)
AVK_LEFTIf cursor is not at front of string, move cursor to left within string?.If cursor is at front of string, move focus to Txt1. Else, move cursor to left within string?.If cursor is at front of string, move focus to Txt2. Else, move cursor to left within string?.
AVK_RIGHTIf cursor at end of string, move focus to Txt2. Else, move cursor to right within string?.If cursor at end of string, move focus to Txt3. Else, move cursor to right within string?.If cursor at end of string, move focus to Soft Key. Else, move cursor to right within string?.
AVK_CLRIf cursor at front of string, ITEXTCTL_HandleEvent() will cause application to exit?. Else, it will delete character to left of cursor?.

Exit Application. AVK_END is automatically handled by the Application Execution Environment (AEE)


?ITEXTCTL_HandleEvent() automatically moves the cursor within the string and handles AVK_CLR (clear key). In short, to realize this default behavior, pass the related events to ITEXTCTL_HandleEvent(). The programmer must handle moving the focus between controls.

? The emulator showed this behavior while the same code running on a Sharp Z800 handset did not. Other handsets were not tested.


Selected Soft Key Menu Item

Key Pressed

Edit OneEdit TwoEdit ThreeExit

Handled by IMENUCTL_HandleEvent(). Moves menu selection left or right.


Move focus to indicated text control in EVT_COMMAND handler for menu item associated with key press.

Exit Application


Exit application. Programmer must return FALSE from EVT_KEY‘s AVK_CLR handler.


Exit application. AVK_END is automatically handled by the Application Execution Environment (AEE).

Now let’s walk through the code:

#include "AEEModGen.h"          // Module interface definitions#include "AEEAppGen.h"          // Applet interface definitions#include "AEEShell.h"           // Shell interface definitions#include "AEEMenu.h"#include "AEEText.h"#include "AEEStdLib.h"#include ""// menu item IDs#define IDLI_ONE      1#define IDLI_TWO      2#define IDLI_THREE   3#define IDLI_EXIT      4// screen layout parameters#define TEXT_X_ORIGIN 5#define TEXT_X_WIDTH 100#define VERT_SPC 10#define FONT_PAD 2#define MAX_TXT_LEN   255   // MAX number of characters in ITextCtltypedef struct _txtctl{   ITextCtl *m_ptxtctl;   byte m_spcToEnd;   // num spaces to end of txt ctl's string (cursor location)} txtctl;typedef struct _screenapp{   AEEApplet a;   IMenuCtl *m_pMnu;   txtctl m_Txt1;   txtctl m_Txt2;   txtctl m_Txt3;   txtctl *m_pActiveTxt;   // tracks currently active textctl} screenapp;/*-------------------------------------------------------------------Function Prototypes-------------------------------------------------------------------*/static boolean screen_HandleEvent(IApplet * pi, AEEEvent eCode,         uint16 wParam, uint32 dwParam);static boolean initData(screenapp *papp);static void closeapp(screenapp *papp);

Once we get past the #includes and #defines, the first interesting part wecome to is the typedef for txtctl. As you can see, a txtctl consists of apointer to an ITextCtl and a single byte used to track the position of thecursor within each of the text controls in our UI. In BREW 1.X, there isno API function to supply the developer with the current cursor position (BREW2.0 has ITEXTCTL_GetCursorPos()). The m_spcToEndmember is necessary sinceeach ITextCtl instance remembers the location of its own insertion point eachtime it loses the input focus. Since different text controls can containstrings of differing length, we need to keep track of how far we are from eachend of a given text control’s string. For example, if the user last exiteda given text control by using the left direction key to move to the text controlabove, the insertion point will be left at the leftmost end of the control thatis losing the focus. If / when the user returns to the original textcontrol, it will remember its cursor location and place the insertion point atits leftmost end. As the number of spaces to the rightmost end of the textcontrol depends on the length of the string, we need to track the cursorposition so that we know when a left key press means “move up” andwhen a right key press means “move down”.

As an aside, the txtctl type could be used to implement cursorplacement functionality for SDK 1.x applications. True BREW test case4.1.4 (see “TheApplication Developer’s TRUE BREW Test Guide“) requires that the cursorbe positioned to the right of the right-most character in a text entry field,when that field comes into focus. I’ll cover such an implementation in alater article.

The Applet Data Structure
Next, we have the applet data structure for the application itself. Youcan see that it contains the mandatory AEEApplet as its first member.Additionally, it holds an IMenuCtl * for the soft key menu and a txtctl instancefor each of the 3 text controls. Lastly, m_pActiveTxtmaintains a pointer to the currently active text control. This pointerwill be NULL whenever the menu control is active.

int AEEClsCreateInstance(AEECLSID ClsId, IShell *pIShell, IModule *po,         void ** ppObj){   *ppObj = NULL;         if(ClsId == AEECLSID_SCREEN)   {      if(AEEApplet_New(sizeof(screenapp), ClsId, pIShell,po,(IApplet**)ppObj,         (AEEHANDLER)screen_HandleEvent,NULL) == TRUE)      {         if(initData((screenapp*)*ppObj))            return (AEE_SUCCESS);      }   }   return (EFAILED);}static boolean initData(screenapp *papp){   papp->m_pMnu = NULL;   papp->m_Txt1.m_ptxtctl = NULL;   papp->m_Txt2.m_ptxtctl = NULL;   papp->m_Txt3.m_ptxtctl = NULL;   papp->m_pActiveTxt = NULL;   papp->m_Txt1.m_spcToEnd = 0;   papp->m_Txt2.m_spcToEnd = 0;   papp->m_Txt3.m_spcToEnd = 0;   return TRUE;}static void closeapp(screenapp *papp){   ISHELL_CloseApplet(papp->a.m_pIShell, TRUE);}

The only unusual thing about the AEEClsCreateInstance() function is the lack of a freeAppData()function in the call to AEEAppletNew(). Since no memory is allocated in the initData()function, there is nothing for a freeData() function to free.As you’ll see, all the dynamic allocation takes place in the event handler’s EVT_APP_START.Thus all the FREEing takes place in EVT_APP_STOP.Always use freeAppData() (or whatever name you choose to assign tothe function) to release what you allocate in initAppData() and use EVT_APP_STOP to release what you allocate in EVT_APP_START.

The initData()function simply initializes all the pointer members to NULL andsets each m_spcToEnd to 0. The latter aspect captures the fact thatall of the text controls will be initialized with null strings, making thecursor distance from the end of each string equal to 0.

The closeApp()function serves as a wrapper for a call to ISHELL_CloseApplet().Why incur the overhead of an extra function call when I could simply call ISHELL_CloseApplet()directly? The only reason I like to add this extra layer is to allow forthe possibility that, on shutdown, an applet may need to perform some specialhousecleaning tasks before exiting. By providing a closeapp()function, the shutdown operation is centralized, making it easy to accommodateany housekeeping tasks that emerge as an application evolves.

static boolean screen_HandleEvent(IApplet * pi, AEEEvent eCode, uint16 wParam, uint32 dwParam){   screenapp *papp = (screenapp*)pi;   switch (eCode)    {      case EVT_APP_START:      {         AEERect r;         int bold_h = IDISPLAY_GetFontMetrics(papp->a.m_pIDisplay, AEE_FONT_BOLD, NULL, NULL);         int norm_h = IDISPLAY_GetFontMetrics(papp->a.m_pIDisplay, AEE_FONT_NORMAL, NULL, NULL);         ISHELL_CreateInstance(papp->a.m_pIShell, AEECLSID_SOFTKEYCTL, (void**)&papp->m_pMnu);         IMENUCTL_AddItem(papp->m_pMnu, NULL, 0, IDLI_ONE, L"Edit One", 0);         IMENUCTL_AddItem(papp->m_pMnu, NULL, 0, IDLI_TWO, L"Edit Two", 0);         IMENUCTL_AddItem(papp->m_pMnu, NULL, 0, IDLI_THREE, L"Edit Three", 0);         IMENUCTL_AddItem(papp->m_pMnu, NULL, 0, IDLI_EXIT, L"Exit", 0);         ISHELL_CreateInstance(papp->a.m_pIShell, AEECLSID_TEXTCTL,(void**)&papp->m_Txt1.m_ptxtctl);         r.x = TEXT_X_ORIGIN;         r.y = VERT_SPC;         r.dx = TEXT_X_WIDTH;         r.dy = norm_h + FONT_PAD;         ITEXTCTL_SetRect(papp->m_Txt1.m_ptxtctl, &r);         ITEXTCTL_SetTitle(papp->m_Txt1.m_ptxtctl, NULL, 0, L"Title 1");         ITEXTCTL_SetMaxSize(papp->m_Txt1.m_ptxtctl, MAX_TXT_LEN);         ITEXTCTL_SetText(papp->m_Txt1.m_ptxtctl, L"", -1);         ITEXTCTL_SetProperties(papp->m_Txt1.m_ptxtctl, TP_FRAME);         ITEXTCTL_SetInputMode(papp->m_Txt1.m_ptxtctl, AEE_TM_LETTERS);         ITEXTCTL_Redraw(papp->m_Txt1.m_ptxtctl);         ISHELL_CreateInstance(papp->a.m_pIShell, AEECLSID_TEXTCTL, (void**)&papp->m_Txt2.m_ptxtctl);         r.y += r.dy + bold_h + VERT_SPC;         ITEXTCTL_SetRect(papp->m_Txt2.m_ptxtctl, &r);         ITEXTCTL_SetTitle(papp->m_Txt2.m_ptxtctl, NULL, 0, L"Title 2");         ITEXTCTL_SetMaxSize(papp->m_Txt2.m_ptxtctl, MAX_TXT_LEN);         ITEXTCTL_SetText(papp->m_Txt2.m_ptxtctl, L"", -1);         ITEXTCTL_SetProperties(papp->m_Txt2.m_ptxtctl, TP_FRAME);         ITEXTCTL_SetInputMode(papp->m_Txt2.m_ptxtctl, AEE_TM_LETTERS);         ITEXTCTL_Redraw(papp->m_Txt2.m_ptxtctl);                  ISHELL_CreateInstance(papp->a.m_pIShell, AEECLSID_TEXTCTL, (void**)&papp->m_Txt3.m_ptxtctl);         r.y += r.dy + bold_h + VERT_SPC;         ITEXTCTL_SetRect(papp->m_Txt3.m_ptxtctl, &r);         ITEXTCTL_SetTitle(papp->m_Txt3.m_ptxtctl, NULL, 0, L"Title 3");         ITEXTCTL_SetMaxSize(papp->m_Txt3.m_ptxtctl, MAX_TXT_LEN);         ITEXTCTL_SetText(papp->m_Txt3.m_ptxtctl, L"", -1);         ITEXTCTL_SetProperties(papp->m_Txt3.m_ptxtctl, TP_FRAME);         ITEXTCTL_SetInputMode(papp->m_Txt3.m_ptxtctl, AEE_TM_LETTERS);         ITEXTCTL_Redraw(papp->m_Txt3.m_ptxtctl);         ITEXTCTL_SetActive(papp->m_Txt1.m_ptxtctl, TRUE);         papp->m_pActiveTxt = &papp->m_Txt1;         ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, FALSE);         ITEXTCTL_SetActive(papp->m_Txt3.m_ptxtctl, FALSE);         IMENUCTL_SetActive(papp->m_pMnu, FALSE);         IMENUCTL_Redraw(papp->m_pMnu);         return(TRUE);      }

At the top of screenHandleEvent(), I obtain a screenapppointer by casting the passed in IApplet*. Atthe top of EVT_APP_START, I declare a rectangle that is used to setthe control rectangles for each of the 3 text controls. Note that we neednot bother setting a control rectangle for the soft key menu since it appears atthe bottom of the screen by default.

Next I obtain the height, in pixels, of each of the bold and normalfonts. These heights are used to set control rectangles and provide vertical,inter-control spacing. Next, the soft key instance is created and its menuitems are added. Once more, the title strings should really be loaded froma resource file, but hard-coding them is of little consequence for an examplesuch as this. The 3 text controls are then added and set up by means ofvarious API calls (please see the API Reference for more information). Lastly,calls to ITEXTCTL_SetActive() are used to cause the input focus to apply to thefirst text control when the application starts up. Note that, had wepassed TRUE in the call to IMENUCTL_SetActive() (instead of to the first textcontrol), the subsequent call to IMENUCTL_Redraw() would be redundant.

  case EVT_KEY:     switch(wParam)     {        case AVK_UP:        case AVK_DOWN:  // probably unnecessary.           IMENUCTL_HandleEvent(papp->m_pMnu, eCode, wParam, dwParam);           if(papp->m_pActiveTxt && papp->m_pActiveTxt->m_ptxtctl)              ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl, eCode, wParam, dwParam);           break;

In this section of the event handler, we start off by processing several EVT_KEY events.You need to remember that only an active control receives events. In the case ofa key event, the event handler’s wParam parameter contains the virtual key codeof the key that was pressed.

As it stands, the up and down keys do nothing in thisapplication. So why include the events in the event handler? Iwanted to show you that neither the menu nor the text controls do anything with AVK_UP or AVK_DOWN when the key codes are passed to thecontrol’s native event handler. Thus, as discussed earlier in thisarticle, these two key events are available for use in the inter-controlnavigation scheme. The archive, available for download via a link at theend of this article, contains a version of the source file that implements thisalternative.

  case AVK_LEFT:  {     // Move cursor to left within the current text ctl's string.  If we can't move      // further left, then move to the previous text ctl, unless we're already at m_Txt1,     // in which case we do nothing.     if(papp->m_pActiveTxt)     {        AECHAR *ptxt = NULL;        uint16 len;        ptxt = ITEXTCTL_GetTextPtr(papp->m_pActiveTxt->m_ptxtctl);        len = WSTRLEN(ptxt);   // see Helper Functions in API Reference        if(papp->m_pActiveTxt->m_spcToEnd < len)        {   // cursor can move further left in string before we go to previous control           ++papp->m_pActiveTxt->m_spcToEnd;   // increment m_spcToEnd           // now let the text ctl actually move the cursor left           ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl, eCode, wParam, dwParam);        }        else        {   // move up to previous control -- can't go up from m_Txt1           if(papp->m_pActiveTxt == &papp->m_Txt2)           {              ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, FALSE);              ITEXTCTL_SetActive(papp->m_Txt1.m_ptxtctl, TRUE);              papp->m_pActiveTxt = &papp->m_Txt1;           }           else if(papp->m_pActiveTxt == &papp->m_Txt3)           {              ITEXTCTL_SetActive(papp->m_Txt3.m_ptxtctl, FALSE);              ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, TRUE);              papp->m_pActiveTxt = &papp->m_Txt2;           }        }     }     else   // the menu has the focus...        IMENUCTL_HandleEvent(papp->m_pMnu, eCode, wParam, dwParam);     return TRUE;  }  case AVK_RIGHT:  {     // Move cursor to right within the current text ctl's string.  If we can't move      // further right, then move to the next text ctl, unless we're already at m_Txt3,     // in which case we move the focus to the menu ctl.     AECHAR *ptxt = NULL;     if(papp->m_pActiveTxt)     {        if(papp->m_pActiveTxt->m_spcToEnd > 0)        {   // we're not at the end of the string so move one closer           --papp->m_pActiveTxt->m_spcToEnd;           ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl,eCode, wParam, dwParam);        }        else        {   // move down to next control           if(papp->m_pActiveTxt == &papp->m_Txt1)           {              ITEXTCTL_SetActive(papp->m_Txt1.m_ptxtctl, FALSE);              ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, TRUE);              papp->m_pActiveTxt = &papp->m_Txt2;           }           else if(papp->m_pActiveTxt == &papp->m_Txt2)           {              ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, FALSE);              ITEXTCTL_SetActive(papp->m_Txt3.m_ptxtctl, TRUE);              papp->m_pActiveTxt = &papp->m_Txt3;           }           else if(papp->m_pActiveTxt == &papp->m_Txt3)           {              ITEXTCTL_SetActive(papp->m_Txt3.m_ptxtctl, FALSE);              IMENUCTL_SetActive(papp->m_pMnu, TRUE);              papp->m_pActiveTxt = NULL;           }        }     }     else        IMENUCTL_HandleEvent(papp->m_pMnu, eCode, wParam, dwParam);     return TRUE;  }            

Above, still in EVT_KEY, we have the handlers for the left and right arrow keys.Since the 2 handlers are essentially mirror images, we’ll limit our discussionto AVK_LEFT.

First note that, if there is no active text control, the menu mustbe active and IMENUCTL_HandleEvent() should therefore be given achance to process the direction key (it will look after moving the menuselection to the left).

If m_pActiveTxt is not NULL, then the active textcontrol’s insertion point is either at the front of the string or it isnot. If it’s at the front of the string (i.e. m_spcToEnd ==the length of the string), then we need to change m_pActiveTxt fromm_Txt2 or m_Txt3 to either m_Txt1 or m_Txt2,respectively. Recall that a left key press at the start of m_Txt1has no affect.

On the other hand, if the insertion point is not at the front of the string,we need to increment m_spcToEnd then pass the event on to ITEXTCTL_HandleEvent()so that the insertion point will move one space to the left. Note that ITEXTCTL_HandleEvent()will move the cursor, regardless of what we do with m_spcToEnd.Recall that an inactive ITextCtl instance remembers the location ofits own cursor?that’s just how it was built. When it becomes activeagain, the text control will place the cursor exactly where it was left.The m_spcToEnd parameter merely allows the application to rememberthis cursor location for each text control instance, from one activation to thenext.

The AVK_RIGHT key functions similarly.

  case AVK_SELECT:     if(papp->m_pActiveTxt)        ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl, eCode, wParam, dwParam);     else        IMENUCTL_HandleEvent(papp->m_pMnu, eCode, wParam, dwParam);     return TRUE;        

Since command sending is not implemented for SDK 1.x text controls , ITEXTCTL_HandleEvent() doesnothing in response to AVK_SELECT. Thus, only the call to IMENUCTL_HandleEvent()is necessary here. If the menu control has the focus when AVK_SELECTis pressed, it will dispatch an EVT_COMMAND event withthe current menu selection ID (e.g. IDLI_ONE, #definedat the top of the program listing) contained in the event handler’s wParam(more on EVT_COMMAND below).

    case AVK_CLR:       if(papp->m_pActiveTxt) // handle backspace          return ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl, eCode, wParam, dwParam);       else          return FALSE;   // exit app.    default:       if(papp->m_pActiveTxt) // handle char events          return ITEXTCTL_HandleEvent(papp->m_pActiveTxt->m_ptxtctl,eCode, wParam, dwParam); } return TRUE;

When the clear key is pressed, an active text control may respond in one of two ways, depending uponthe position of the cursor. If the cursor is at the front of the textcontrol (i.e. there are no characters on the left for the control to delete), AVK_CLRwill cause the application to exit (note that this behavior was reproducible inversion of the BREW Emulator but not on a Sharp Z800 handset — otherhandsets were not tested). Otherwise, the text control’s nativehandler will cause the next character to the left of the cursor to be deleted,moving the insertion point (cursor) one space closer to the front.

Since the menu control is not interested in AVK_CLR, we simplyreturn FALSE to the AEE which also causes the application to exit.

The default handler for EVT_KEY catches all the character eventsproduced by the multi-tap input method and ensures that they are processed by atext control, if one is presently active. This handler causes charactersto be displayed in the text control as the user presses the phone’s digit keys.

  case EVT_COMMAND:     switch(wParam)     {  // use evt_command to move from menu        case IDLI_ONE:           ITEXTCTL_SetActive(papp->m_Txt1.m_ptxtctl, TRUE);           IMENUCTL_SetActive(papp->m_pMnu, FALSE);           papp->m_pActiveTxt = &papp->m_Txt1;           break;        case IDLI_TWO:           ITEXTCTL_SetActive(papp->m_Txt2.m_ptxtctl, TRUE);           IMENUCTL_SetActive(papp->m_pMnu, FALSE);           papp->m_pActiveTxt = &papp->m_Txt2;           break;        case IDLI_THREE:           ITEXTCTL_SetActive(papp->m_Txt3.m_ptxtctl, TRUE);           IMENUCTL_SetActive(papp->m_pMnu, FALSE);           papp->m_pActiveTxt = &papp->m_Txt3;           break;        case IDLI_EXIT:           closeapp(papp);           break;     }     return TRUE;

When command sending is enabled for a menu control (enabled is the default) andthe menu control is active, the AEE generates EVT_COMMAND events inresponse to the user pressing AVK_SELECT. With the EVT_COMMANDevent, the wParam passed in to the event handler contains the itemID for the current menu selection. Thus, the EVT_COMMANDhandler above provides the user with the ability to move the focus from the menucontrol to any of the text controls by simply selecting the menu itemcorresponding to the desired text control. Note that command sending canbe controlled through the IMENUCTL_EnableCommand() API function;please see the API Reference for details.

If command sending were implemented for ITextCtl’s in SDK 1.x (it is implemented in SDK 2.0), we could simply give each text control its own unique ID. This ID would be sent to the application’s EVT_COMMAND handler(in the wParam parameter) every time the user pressed AVK_SELECT inside an active text control. Thus each text control could simply identify itself,permitting the programmer to implement control-specific functionality for eachITextCtl without having to maintain a pointer to the one that is currentlyactive.

  case EVT_APP_STOP:     IMENUCTL_Release(papp->m_pMnu);     papp->m_pMnu = NULL;     ITEXTCTL_Release(papp->m_Txt1.m_ptxtctl);     papp->m_Txt1.m_ptxtctl = NULL;     ITEXTCTL_Release(papp->m_Txt2.m_ptxtctl);     papp->m_Txt2.m_ptxtctl = NULL;     ITEXTCTL_Release(papp->m_Txt3.m_ptxtctl);     papp->m_Txt3.m_ptxtctl = NULL;     papp->m_pActiveTxt = NULL;     return TRUE;  default:     break;}return FALSE;}

Finally, this brings us to EVT_APP_STOP where the dynamically allocatedresources are released, in preparation for the application to exit.

Download project files: (5 KB).

Originally published in the BREW Wireless Resource Center


About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist