WEBINAR:
On-Demand
Application Security Testing: An Integral Part of DevOps
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 single
screen. Specifically, our single screen UI will consist of 3 text controls
and 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 appear
exactly as shown in Figure 1, when it opens. As you can see, you really can
fit more than one control on a single screen and still get a reasonably
attractive result. As you might have guessed, the rectangle surrounding the
first 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 BREW
Emulator version 2.0.0.38. If you intend to work along with the example, you must
create a module information file, consistent with the file / directory
naming scheme covered in the SDK User's Guide. Copy this file to ...yourBREWdir\Examples\mif\256Color\
,
or to whatever directory you've chosen to designate as your mif directory within the
BREW Emulator. For more information, please consult the BREW SDK User's
Guide provided with the BREW SDK.
For ease of exposition, I've hard-coded the
required strings in the application's source file. I really should have
used the BREW
Resource Editor to create a resource file containing all of the strings used in
the application. ISHELL_LoadResString()
would then be used to
programmatically 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 documents
are included with the BREW SDK.
How screen navigation works
As you will see, when the developer assumes control over screen navigation, (s)he
can specify the means by which this navigation should take place. Both a text control and
a soft key menu provide default behaviors in response to
left and right key presses. A text control responds by moving the insertion point (i.e. the cursor) left or right
within thetext string. By default, a left key press has no effect if
the insertion point is already at the front of the string and a right key press
has no effect if the insertion point is at the end of the string. We will
alter this default behavior.
The soft key menu
moves the current command selection to the menu item on the immediate left or
right, consistent with the key pressed. Note that plain menus and list
controls (please see the SDK User's guide) exhibit this item selection behavior
in response to the up and down keys, while the select, left and right
keys,
are typically used for moving between menus on the same
screen. We'll learn more about this when we examine dialogs in a later
article.
Intuitively, within the UI shown in Figure 1, a user should move from control
to control by thumbing the up or down arrow keys. This scheme is my
personal favorite as it dovetails nicely with the actual layout and default
functioning of the controls. The BREW
User Interface Design Guidelines provide some excellent advice on this
subject and a developer would be well advised to read through this document
before 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 that
we must navigate by means of the
up and down keys. An example of such an implementation is included in the
archive file available for download at the end of this article.
A recent post in
the BREW Developers' Forum sought advice on how to navigate a UI similar to the
one shown in Figure 1. Apparently the poster was required to use the left and right arrow
keys to move from text control to text control, and from text control 3 to the
menu. Since this is more of a challenge, and thus more interesting than
implementing 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 BREW
User Interface Design Guidelines.
In the case of the menu control, the
left and right keys change the menu selection exclusively. Separate soft
key items are provided so that the user can directly move from the menu control to
any of the text controls . Clearly, it might be desirable to
permit the user to move from the menu to either text control 1 or text control 3
by using the down or up key, respectively. Note that this functionality is
included in the alternate source file mentioned above.
Clearly stated, our goal is to provide a user interface consisting of 3 text
controls and a soft key menu. The user navigation scheme is summarized in
the following two tables:
|
Active Text Control |
Key Pressed |
Text Control 1 (Txt1) |
Text Control 2 (Txt2) |
Text Control 3 (Txt3) |
AVK_LEFT |
If 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_RIGHT |
If 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_CLR |
If cursor at front of string, ITEXTCTL_HandleEvent()
will cause application to exit. Else, it will delete character to left of
cursor. |
AVK_END |
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 One |
Edit Two |
Edit Three |
Exit |
AVK_LEFT |
Handled by IMENUCTL_HandleEvent() . Moves menu
selection left or right. |
AVK_RIGHT |
AVK_SELECT |
Move focus to indicated text control in EVT_COMMAND
handler for menu item associated with key press.
|
Exit Application
|
AVK_CLR |
Exit application. Programmer must return FALSE from
EVT_KEY 's
AVK_CLR handler. |
AVK_END |
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 "screenapp.bid"
// 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 ITextCtl
typedef 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 we
come to is the typedef
for txtctl
. As you can see, a
txtctl
consists of a
pointer to an ITextCtl
and a single byte
used to track the position of the
cursor within each of the text controls in our UI. In BREW 1.X, there is
no API function to supply the developer with the current cursor position (BREW
2.0 has ITEXTCTL_GetCursorPos()
). The m_spcToEnd
member is necessary since
each ITextCtl
instance remembers the location of its own insertion point each
time it loses the input focus. Since different text controls can contain
strings of differing length, we need to keep track of how far we are from each
end of a given text control's string. For example, if the user last exited
a given text control by using the left direction key to move to the text control
above, the insertion point will be left at the leftmost end of the control that
is losing the focus. If / when the user returns to the original text
control, it will remember its cursor location and place the insertion point at
its leftmost end. As the number of spaces to the rightmost end of the text
control depends on the length of the string, we need to track the cursor
position so that we know when a left key press means "move up" and
when a right key press means "move down".
As an aside, the txtctl
type could be used to implement cursor
placement functionality for SDK 1.x applications. True BREW test case
4.1.4 (see "The
Application Developer's TRUE BREW Test Guide") requires that the cursor
be 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 a
later article.
The Applet Data Structure
Next, we have the applet data structure for the application itself. You
can see that it contains the mandatory AEEApplet
as its first member.
Additionally, it holds an IMenuCtl *
for the soft key menu and a txtctl
instance
for each of the 3 text controls. Lastly, m_pActiveTxt
maintains a pointer to the currently active text control. This pointer
will 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 FREE
ing takes place in EVT_APP_STOP
.
Always use freeAppData()
(or whatever name you choose to assign to
the 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
and
sets each m_spcToEnd
to 0. The latter aspect captures the fact that
all of the text controls will be initialized with null strings, making the
cursor 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 for
the possibility that, on shutdown, an applet may need to perform some special
housecleaning tasks before exiting. By providing a closeapp()
function, the shutdown operation is centralized, making it easy to accommodate
any 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 screenapp
pointer by casting the passed in IApplet
*
. At
the top of EVT_APP_START
, I declare a rectangle that is used to set
the control rectangles for each of the 3 text controls. Note that we need
not bother setting a control rectangle for the soft key menu since it appears at
the bottom of the screen by default.
Next I obtain the height, in pixels, of each of the bold and normal
fonts. These heights are used to set control rectangles and provide vertical,
inter-control spacing. Next, the soft key instance is created and its menu
items are added. Once more, the title strings should really be loaded from
a resource file, but hard-coding them is of little consequence for an example
such as this. The 3 text controls are then added and set up by means of
various 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 the
first text control when the application starts up. Note that, had we
passed TRUE
in the call to IMENUCTL_SetActive()
(instead of to the first text
control), 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 of
a key event, the event handler's wParam
parameter contains the virtual key code
of the key that was pressed.
As it stands, the up and down keys do nothing in this
application. So why include the events in the event handler? I
wanted 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 the
control's native event handler. Thus, as discussed earlier in this
article, these two key events are available for use in the inter-control
navigation scheme. The archive, available for download via a link at the
end of this article, contains a version of the source file that implements this
alternative.
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 discussion
to AVK_LEFT
.
First note that, if there is no active text control, the menu must
be active and IMENUCTL_HandleEvent()
should therefore be given a
chance to process the direction key (it will look after moving the menu
selection to the left).
If m_pActiveTxt
is not NULL
, then the active text
control's insertion point is either at the front of the string or it is
not. 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
from
m_Txt2
or m_Txt3
to either m_Txt1
or m_Txt2
,
respectively. Recall that a left key press at the start of m_Txt1
has 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 of
its own cursorthat's just how it was built. When it becomes active
again, the text control will place the cursor exactly where it was left.
The m_spcToEnd
parameter merely allows the application to remember
this cursor location for each text control instance, from one activation to the
next.
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()
does
nothing in response to AVK_SELECT
. Thus, only the call to IMENUCTL_HandleEvent()
is necessary here. If the menu control has the focus when AVK_SELECT
is pressed, it will dispatch an EVT_COMMAND
event with
the current menu selection ID (e.g. IDLI_ONE
, #defined
at 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 upon
the position of the cursor. If the cursor is at the front of the text
control (i.e. there are no characters on the left for the control to delete), AVK_CLR
will cause the application to exit (note that this behavior was reproducible in
version 2.0.0.38 of the BREW Emulator but not on a Sharp Z800 handset -- other
handsets were not tested). Otherwise, the text control's native
handler 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 simply
return FALSE
to the AEE which also causes the application to exit.
The default
handler for EVT_KEY
catches all the character events
produced by the multi-tap input method and ensures that they are processed by a
text control, if one is presently active. This handler causes characters
to 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) and
the menu control is active, the AEE generates EVT_COMMAND
events in
response to the user pressing AVK_SELECT
. With the EVT_COMMAND
event, the wParam
passed in to the event handler contains the item
ID for the current menu selection. Thus, the EVT_COMMAND
handler above provides the user with the ability to move the focus from the menu
control to any of the text controls by simply selecting the menu item
corresponding to the desired text control. Note that command sending can
be 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 each
ITextCtl without having to maintain a pointer to the one that is currently
active.
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 allocated
resources are released, in preparation for the application to exit.
Download project files: screensource.zip (5 KB).
Originally published in the BREW Wireless Resource Center