Programming Microsoft Windows Ce Net 3Rd [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Programming Microsoft Windows Ce Net 3Rd [Electronic resources] - نسخه متنی

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید






The Keyboard

While keyboards play a lesser role in Windows CE, they're still the best means of entering large volumes of information. Even on systems without a physical keyboard such as the Pocket PC, soft keyboards—controls that simulate keyboards on a touch screen—will most likely be available to the user. Given this, proper handling of keyboard input is critical to all but the most specialized of Windows CE applications. While I'll talk at length about soft keyboards later in the book, one point should be made here. To the application, input from a soft keyboard is no different from input from a traditional "hard" keyboard.


Input Focus


Under Windows operating systems, only one window at a time has the input focus. The focus window receives all keyboard input until it loses focus to another window. The system assigns the keyboard focus using a number of rules, but most often the focus window is the current active window. The active window, you'll recall, is the top-level window, the one with which the user is currently interacting. With rare exceptions, the active window also sits at the top of the Z-order; that is, it's drawn on top of all other windows in the system. In the Explorer, the user can change the active window by pressing Alt-Esc to switch between programs or by tapping on another top-level window's button on the task bar. The focus window is either the active window or one of its child windows.

Under Windows, a program can determine which window has the input focus by calling

HWND GetFocus (void);

The focus can be changed to another window by calling

HWND SetFocus (HWND hWnd);

Under Windows CE, the target window of SetFocus is limited. The window being given the focus by SetFocus must have been created by the thread calling SetFocus. An exception to this rule occurs if the window losing focus is related to the window gaining focus by a parent/child or sibling relationship; in this case, the focus can be changed even if the windows were created by different threads.

When a window loses focus, Windows sends a WM_KILLFOCUS message to that window informing it of its new state. The wParam parameter contains the handle of the window that will be gaining the focus. The window gaining focus receives a WM_SETFOCUS message. The wParam parameter of the WM_SETFOCUS message contains the handle of the window losing focus.

Now for a bit of motherhood. Programs shouldn't change the focus window without some input from the user. Otherwise, the user can easily become confused. A proper use of SetFocus is to set the input focus to a child window (more than likely a control) contained in the active window. In this case, a window would respond to the WM_SETFOCUS message by calling SetFocus with the handle of a child window contained in the window to which the program wants to direct keyboard messages.


Keyboard Messages


Windows CE practices the same keyboard message processing as its larger desktop relations with a few small exceptions, which I cover shortly. When a key is pressed, Windows sends a series of messages to the focus window, typically beginning with a WM_KEYDOWN message. If the key pressed represents a character such as a letter or number, Windows follows the WM_KEYDOWN with a WM_CHAR message. (Some keys, such as function keys and cursor keys, don't represent characters, so WM_CHAR messages aren't sent in response to those keys. For those keys, a program must interpret the WM_KEYDOWN message to know when the keys are pressed.) When the key is released, Windows sends a WM_KEYUP message. If a key is held down long enough for the auto-repeat feature to kick in, multiple WM_KEYDOWN and WM_CHAR messages are sent for each auto-repeat until the key is released when the final WM_KEYUP message is sent. I used the word typically to qualify this process because if the Alt key is being held when another key is pressed, the messages I've just described are replaced by WM_SYSKEYDOWN, WM_SYSCHAR, and WM_SYSKEYUP messages.

For all of these messages, the generic parameters wParam and lParam are used in mostly the same manner. For WM_KEYxx and WM_SYSKEYxx messages, the wParam value contains the virtual key value, indicating the key being pressed. All versions of Windows provide a level of indirection between the keyboard hardware and applications by translating the scan codes returned by the keyboard into virtual key values. You see a list of the VK_xx values and their associated keys in Table 3-1. While the table of virtual keys is extensive, not all keys listed in the table are present on Windows CE devices. For example, function keys, a mainstay on PC keyboards and listed in the virtual key table, aren't present on most Windows CE keyboards. In fact, a number of keys on a PC keyboard are left off the space-constrained Windows CE keyboards. A short list of the keys not typically used on Windows CE devices is presented in Figure 3-1. This list is meant to inform you that these keys might not exist, not to indicate that the keys never exist on Windows CE keyboards.











































































































































































































































































































Table 3-1: Virtual Keys

Constant


Value


Keyboard Equivalent


VK_LBUTTON


01


Stylus tap


VK_RBUTTON


02


Mouse right button[*]


VK_CANCEL


03


Control-break processing


VK_RBUTTON


04


Mouse middle button[*]


--


05–07


Undefined


VK_BACK


08


Backspace key


VK_TAB


09


Tab key


--


0A–0B


Undefined


VK_CLEAR


0C


Clear key


Constant


Value


Keyboard Equivalent


VK_RETURN


0D


Enter key


--


0E–0F


Undefined


VK_SHIFT


10


Shift key


VK_CONTROL


11


Ctrl key


VK_MENU


12


Alt key


VK_CAPITAL


14


Caps Lock key


--


15–19


Reserved for Kanji systems


--


1A


Undefined


VK_ESCAPE


1B


Escape key


--


1C–1F


Reserved for Kanji systems


VK_SPACE


20


Spacebar


VK_PRIOR


21


Page Up key


VK_NEXT


22


Page Down key


VK_END


23


End key


VK_HOME


24


Home key


VK_LEFT


25


Left Arrow key


VK_UP


26


Up Arrow key


VK_RIGHT


27


Right Arrow key


VK_DOWN


28


Down Arrow key


VK_SELECT


29


Select key


--


2A


Original equipment manufacturer (OEM)–specific


VK_EXECUTE


2B


Execute key


VK_SNAPSHOT


2C


Print Screen key for Windows 3.0 and later


[*]Mouse right and middle buttons are defined but are relevant only on a Windows CE system equipped with a mouse.

[]On some Windows CE systems, Delete is simulated with Shift-Backspace

[]Many Windows CE Systems don’t have this key

[\]These constants can be used only with GetKeyState and GetAsyncKeyState.

[]These codes are used by the application launch keys on systems that have them.


Constant


Value


Keyboard Equivalent


VK_INSERT


2D


Insert[]


VK_DELETE


2E


Delete[]


VK_HELP


2F


Help key


VK_0–VK_9


30–39


0–9 keys


--


3A–40


Undefined


VK_A–VK_Z


41–5A


A through Z keys


VK_LWIN


5B


Windows key


VK_RWIN


5C


Windows key[]


VK_APPS


5D


--


5E–5F


Undefined


VK_NUMPAD0–9


60–69


Numeric keypad 0–9 keys


VK_MULTIPLY


6A


Numeric keypad Asterisk (*) key


VK_ADD


6B


Numeric keypad Plus sign (+) key


VK_SEPARATOR


6C


Separator key


VK_SUBTRACT


6D


Numeric keypad Minus sign (-) key


VK_DECIMAL


6E


Numeric keypad Period (.) key


VK_DIVIDE


6F


Numeric keypad Slash mark (/) key


VK_F1–VK_F24


70–87


F1–F24[]


--


88–8F


Unassigned


VK_NUMLOCK


90


Num Lock[]


VK_SCROLL


91


Scroll Lock[]


--


92–9F


Unassigned


VK_LSHIFT


A0


Left Shift[\]


VK_RSHIFT


A1


Right Shift[\]


VK_LCONTROL


A2


Left Control[\]


VK_RCONTROL


A3


Right Control[\]


VK_LMENU


A4


Left Alt[\]


VK_RMENU


A5


Right Alt[\]


--


A6–B9


Unassigned


VK_SEMICOLON


BA


; key


VK_EQUAL


BB


= key


VK_COMMA


BC


, key


VK_HYPHEN


BD


- key


VK_PERIOD


BE


. key


VK_SLASH


BF


/ key


[*]Mouse right and middle buttons are defined but are relevant only on a Windows CE system equipped with a mouse.

[]On some Windows CE systems, Delete is simulated with Shift-Backspace

[]Many Windows CE Systems don’t have this key

[\]These constants can be used only with GetKeyState and GetAsyncKeyState.

[]These codes are used by the application launch keys on systems that have them.


Constant


Value


Keyboard Equivalent


VK_BACKQUOTE


C0


` key


--


C1–DA


Unassigned[]


VK_LBRACKET


DB


[ key


VK_BACKSLASH


DC


\ key


VK_RBRACKET


DD


] key


VK_APOSTROPHE


DE


' key


VK_OFF


DF


Power button


--


E5


Unassigned


--


E6


OEM-specific


--


E7–E8


Unassigned


--


E9–F5


OEM-specific


VK_ATTN


F6


VK_CRSEL


F7


VK_EXSEL


F8


VK_EREOF


F9


VK_PLAY


FA


VK_ZOOM


FB


VK_NONAME


FC


VK_PA1


FD


VK_OEM_CLEAR


FE


[*]Mouse right and middle buttons are defined but are relevant only on a Windows CE system equipped with a mouse.

[]On some Windows CE systems, Delete is simulated with Shift-Backspace

[]Many Windows CE Systems don’t have this key

[\]These constants can be used only with GetKeyState and GetAsyncKeyState.

[]These codes are used by the application launch keys on systems that have them.


For the WM_CHAR and WM_SYSCHAR messages, the wParam value contains the Unicode character represented by the key. Most often an application can simply look for WM_CHAR messages and ignore WM_KEYDOWN and WM_ KEYUP. The WM_CHAR message allows for a second level of abstraction so that the application doesn't have to worry about the up or down state of the keys and can concentrate on the characters being entered by means of the keyboard.

The lParam value of any of these keyboard messages contains further information about the pressed key. The format of the lParam parameter is shown in Figure 3-2.


Figure 3-1: Keys on a PC keyboard that are rarely on a Windows CE keyboard

The low word, bits 0 through 15, contains the repeat count of the key. Sometimes keys on a Windows CE device can be pressed faster than Windows CE can send messages to the focus application. In these cases, the repeat count contains the number of times the key has been pressed. Bit 29 contains the context flag. If the Alt key was being held down when the key was pressed, this bit will be set. Bit 30 contains the previous key state. If the key was previously down, this bit is set; otherwise, it's 0. Bit 30 can be used to determine whether the key message is the result of an auto-repeat sequence. Bit 31 indicates the transition state. If the key is in transition from down to up, Bit 31 is set. Bits 16 through 28 are used to indicate the key scan code. In many cases, Windows CE doesn't support this field. However, on some of the newer Windows CE platforms where scan codes are necessary, this field does contain the scan code. You shouldn't plan on the scan code field being available unless you know it's supported on your specific platform.


Figure 3-2: The layout of the lParam value for key messages

One additional keyboard message, WM_DEADCHAR, can sometimes come into play. You send it when the pressed key represents a dead character, such as an umlaut, that you want to combine with a character to create a different character. In this case, the WM_DEADCHAR message can be used to prevent the text entry point (the caret) from advancing to the next space until the second key is pressed so that you can complete the combined character.

The WM_DEADCHAR message has always been present under Windows, but under Windows CE it takes on a somewhat larger role. With the internationalization of small consumer devices that run Windows CE, programmers should plan for, and if necessary use, the WM_DEADCHAR message that is so often necessary in foreign language systems.


Keyboard Functions


You'll find useful a few other keyboard state–determining functions for Windows applications. Among the keyboard functions, two are closely related but often confused: GetKeyState and GetAsyncKeyState.

GetKeyState, prototyped as

SHORT GetKeyState (int nVirtKey);

returns the up/down state of the shift keys, Ctrl, Alt, and Shift, and indicates whether any of these keys is in a toggled state. If the keyboard has two keys with the same function—for example, two Shift keys, one on each side of the keyboard—this function can also be used to differentiate which of them is being pressed. (Most keyboards have left and right Shift keys, and some include left and right Ctrl and Alt keys.)

You pass to the function the virtual key code for the key being queried. If the high bit of the return value is set, the key is down. If the least significant bit of the return value is set, the key is in a toggled state; that is, it has been pressed an odd number of times since the system was started. The state returned is the state at the time the most recent message was read from the message queue, which isn't necessarily the real-time state of the key. An interesting aside: notice that the virtual key label for the Alt key is VK_MENU, which relates to the windows convention that the Alt-Shift key combination works in concert with other keys to access various menus from the keyboard.

Note that the GetKeyState function is limited under Windows CE to querying the state of the shift keys. Under other versions of Windows, GetKeyState can determine the state of every key on the keyboard.

To determine the real-time state of a key, use

SHORT GetAsyncKeyState (int vKey);

As with GetKeyState, you pass to this function the virtual key code for the key being queried. The GetAsyncKeyState function returns a value subtly different from the one returned by GetKeyState. As with the GetKeyState function, the high bit of the return value is set while the key is being pressed. However, the least significant bit is then set if the key was pressed after a previous call to GetAsyncKeyState. Like GetKeyState, the GetAsyncKeyState function can distinguish the left and right Shift, Ctrl, and Alt keys. In addition, by passing the VK_LBUTTON virtual key value, GetAsyncKeyState determines whether the stylus is currently touching the screen.

An application can simulate a keystroke using the keybd_event function:

VOID keybd_event (BYTE bVk, BYTE bScan, DWORD dwFlags,
DWORD dwExtraInfo);

The first parameter is the virtual key code of the key to simulate. The bScan code should be set to NULL under Windows CE. The dwFlags parameter can have two possible flags: KEYEVENTF_KEYUP indicates that the call is to emulate a key up event, while KEYEVENTF_SILENT indicates that the simulated key press won't cause the standard keyboard click that you normally hear when you press a key. So to fully simulate a key press, keybd_event should be called twice, once without KEYEVENTF_KEYUP to simulate a key down, and then once again, this time with KEYEVENTF_KEYUP to simulate the key release. When simulating a shift key, specify the specific left or right VK code, as in VK_LSHIFT or VF_RCONTROL.

A function unique to Windows CE is

BOOL PostKeybdMessage (HWND hwnd, UINT VKey, 
KEY_STATE_FLAGS KeyStateFlags,
UINT cCharacters, UINT *pShiftStateBuffer,
UINT *pCharacterBuffer );

This function sends a series of keys to the specified window. The hwnd parameter is the target window. This window must be owned by the calling thread. The VKey parameter should be zero. KeyStateFlags specifies the key state for all the keys being sent. The cCharacters parameter specifies the number of keys being sent. The pShiftStateBuffer parameter points to an array that contains a shift state for each key sent, while pCharacterBuffer points to the VK codes of the keys being sent. Unlike keybd_event, this function doesn't change the global state of the keyboard.

One final keyboard function, MapVirtualKey, translates virtual key codes to characters. MapVirtualKey in Windows CE doesn't translate keyboard scan codes to and from virtual key codes, although it does so in other versions of Windows. The prototype of the function is the top of the following page.

UINT MapVirtualKey (UINT uCode, UINT uMapType);

Under Windows CE, the first parameter is the virtual key code to be translated, while the second parameter, uMapType, indicates how the key code is translated. MapVirtualKey is dependent on the keyboard device driver implementing a supporting function. Many OEMs don't implement this supporting function, so on their systems, MapVirtualKey fails.

Testing for the Keyboard


To determine whether a keyboard is even present in the system, you can call

DWORD GetKeyboardStatus (VOID);

This function returns the KBDI_KEYBOARD_PRESENT flag if a hardware keyboard is present in the system. This function also returns a KBDI_KEYBOARD_ENABLED flag if the keyboard is enabled. To disable the keyboard, a call can be made to

BOOL EnableHardwareKeyboard (BOOL bEnable);

with the bEnable flag set to FALSE. You might want to disable the keyboard in a system for which the keyboard folds around behind the screen; in such a system, a user could accidentally hit keys while using the stylus.


The KeyTrac Example Program


The following example program, KeyTrac, displays the sequence of keyboard messages. Programmatically, KeyTrac isn't much of a departure from the earlier programs in the book. The difference is that the keyboard messages I've been describing are all trapped and recorded in an array that's then displayed during the WM_PAINT message. For each keyboard message, the message name is recorded along with the wParam and lParam values and a set of flags indicating the state of the shift keys. The key messages are recorded in an array because these messages can occur faster than the redraw can occur. Figure 3-3 shows the KeyTrac window after a few keys have been pressed.


Figure 3-3: The KeyTrac window after a Shift-A key combination followed by a lowercase a key press

The best way to learn about the sequence of the keyboard messages is to run KeyTrac, press a few keys, and watch the messages scroll down the screen. Pressing a character key such as the a results in three messages: WM_KEYDOWN, WM_CHAR, and WM_KEYUP. Holding down the Shift key while pressing the a and then releasing the Shift key produces a key-down message for the Shift key followed by the three messages for the a key followed by a key-up message for the Shift key. Because the Shift key itself isn't a character key, no WM_CHAR message is sent in response to it. However, the WM_CHAR message for the a key now contains a 0x41 in the wParam value, indicating that an uppercase A was entered instead of a lowercase a.

Listing 3-1 shows the source code for the KeyTrac program.

Listing 3-1: The KeyTrac program







KeyTrac.h
//======================================================================
// Header file
//
// Written for the book Programming Windows CE
// Copyright (C) 2003 Douglas Boling
//======================================================================
// Returns number of elements
#define dim(x) (sizeof(x) / sizeof(x[0]))
//----------------------------------------------------------------------
// Generic defines and data types
//
struct decodeUINT { // Structure associates
UINT Code; // messages
// with a function.
LRESULT (*Fxn)(HWND, UINT, WPARAM, LPARAM);
};
struct decodeCMD { // Structure associates
UINT Code; // menu IDs with a
LRESULT (*Fxn)(HWND, WORD, HWND, WORD); // function.
};
//----------------------------------------------------------------------
// Program-specific defines and structures
//
typedef struct {
UINT wKeyMsg;
INT wParam;
INT lParam;
LPCTSTR pszMsgTxt;
TCHAR szShift[20];
} MYKEYARRAY, *PMYKEYARRAY;
// Structure to associate messages with text name of message
typedef struct {
UINT wMsg;
LPCTSTR pName;
} KEYNAMESTRUCT;
//----------------------------------------------------------------------
// Function prototypes
//
HWND InitInstance (HINSTANCE, LPWSTR, int);
int TermInstance (HINSTANCE, int);
// Window procedures
LRESULT CALLBACK MainWndProc (HWND, UINT, WPARAM, LPARAM);
// Message handlers
LRESULT DoCreateMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoPaintMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoKeysMain (HWND, UINT, WPARAM, LPARAM);
LRESULT DoDestroyMain (HWND, UINT, WPARAM, LPARAM);


KeyTrac.cpp
//======================================================================
// KeyTrac - displays keyboard messages
//
// Written for the book Programming Windows CE
// Copyright (C) 2003 Douglas Boling
//======================================================================
#include <windows.h> // For all that Windows stuff
#include <commctrl.h> // Command bar includes
#include "keytrac.h" // Program-specific stuff
// The include and lib files for the Pocket PC are conditionally
// included so that this example can share the same project file. This
// is necessary since this example must have a menu bar on the Pocket
// PC to have a SIP button.
#if defined(WIN32_PLATFORM_PSPC)
#include <aygshell.h> // Add Pocket PC includes.
#pragma comment( lib, "aygshell" ) // Link Pocket PC lib for menu bar.
#endif
//----------------------------------------------------------------------
// Global data
//
const TCHAR szAppName[] = TEXT ("KeyTrac");
HINSTANCE hInst; // Program instance handle
// Program-specific global data
MYKEYARRAY ka[16];
int nKeyCnt = 0;
int nFontHeight;
// Array associates key messages with text tags
KEYNAMESTRUCT knArray[] = {{WM_KEYDOWN, TEXT ("WM_KEYDOWN")},
{WM_KEYUP, TEXT ("WM_KEYUP")},
{WM_CHAR, TEXT ("WM_CHAR")},
{WM_SYSCHAR, TEXT ("WM_SYSCHAR")},
{WM_SYSKEYUP, TEXT ("WM_SYSKEYUP")},
{WM_SYSKEYDOWN, TEXT ("WM_SYSKEYDOWN")},
{WM_DEADCHAR, TEXT ("WM_DEADCHAR")},
{WM_SYSDEADCHAR, TEXT ("WM_SYSDEADCHAR")}};
// Message dispatch table for MainWindowProc
const struct decodeUINT MainMessages[] = {
WM_CREATE, DoCreateMain,
WM_PAINT, DoPaintMain,
WM_KEYUP, DoKeysMain,
WM_KEYDOWN, DoKeysMain,
WM_CHAR, DoKeysMain,
WM_DEADCHAR, DoKeysMain,
WM_SYSCHAR, DoKeysMain,
WM_SYSDEADCHAR, DoKeysMain,
WM_SYSKEYDOWN, DoKeysMain,
WM_SYSKEYUP, DoKeysMain,
WM_DESTROY, DoDestroyMain,
};
//======================================================================
// Program entry point
//
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPWSTR lpCmdLine, int nCmdShow) {
MSG msg;
int rc = 0;
HWND hwndMain;
// Initialize this instance.
hwndMain = InitInstance (hInstance, lpCmdLine, nCmdShow);
if (hwndMain == 0)
return 0x10;
// Application message loop
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
// Instance cleanup
return TermInstance (hInstance, msg.wParam);
}
//----------------------------------------------------------------------
// InitInstance - Instance initialization
//
HWND InitInstance (HINSTANCE hInstance, LPWSTR lpCmdLine, int nCmdShow) {
WNDCLASS wc;
HWND hWnd;
#if defined(WIN32_PLATFORM_PSPC)
// If Pocket PC, allow only one instance of the application
hWnd = FindWindow (szAppName, NULL);
if (hWnd) {
SetForegroundWindow ((HWND)(((DWORD)hWnd) | 0x01));
return 0;
}
#endif
hInst = hInstance; // Save program instance handle
// Register application main window class.
wc.style = 0; // Window style
wc.lpfnWndProc = MainWndProc; // Callback function
wc.cbClsExtra = 0; // Extra class data
wc.cbWndExtra = 0; // Extra window data
wc.hInstance = hInstance; // Owner handle
wc.hIcon = NULL, // Application icon
wc.hCursor = LoadCursor (NULL, IDC_ARROW);// Default cursor
wc.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
wc.lpszMenuName = NULL; // Menu name
wc.lpszClassName = szAppName; // Window class name
if (RegisterClass(&wc) == 0) return 0;
// Create main window.
hWnd = CreateWindowEx (WS_EX_NODRAG, szAppName, TEXT ("KeyTrac"),
WS_VISIBLE | WS_CAPTION | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
// Fail if window not created
if (!IsWindow (hWnd)) return 0;
// Standard show and update calls
ShowWindow (hWnd, nCmdShow);
UpdateWindow (hWnd);
return hWnd;
}
//----------------------------------------------------------------------
// TermInstance - Program cleanup
//
int TermInstance (HINSTANCE hInstance, int nDefRC) {
return nDefRC;
}
//======================================================================
// Message handling procedures for MainWindow
//
//----------------------------------------------------------------------
// MainWndProc - Callback function for application window
//
LRESULT CALLBACK MainWndProc (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
INT i;
//
// Search message list to see if we need to handle this
// message. If in list, call procedure.
//
for (i = 0; i < dim(MainMessages); i++) {
if (wMsg == MainMessages[i].Code)
return (*MainMessages[i].Fxn)(hWnd, wMsg, wParam, lParam);
}
return DefWindowProc (hWnd, wMsg, wParam, lParam);
}
//----------------------------------------------------------------------
// DoCreateMain - Process WM_CREATE message for window.
//
LRESULT DoCreateMain (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
HDC hdc;
TEXTMETRIC tm;
#if defined(WIN32_PLATFORM_PSPC) && (_WIN32_WCE >= 300)
SHMENUBARINFO mbi; // For Pocket PC, create
memset(&mbi, 0, sizeof(SHMENUBARINFO)); // menu bar so that we
mbi.cbSize = sizeof(SHMENUBARINFO); // have a sip button
mbi.hwndParent = hWnd;
mbi.dwFlags = SHCMBF_EMPTYBAR; // No menu
SHCreateMenuBar(&mbi);
#endif
// Get the height of the default font.
hdc = GetDC (hWnd);
GetTextMetrics (hdc, &tm);
nFontHeight = tm.tmHeight + tm.tmExternalLeading;
ReleaseDC (hWnd, hdc);
return 0;
}
//----------------------------------------------------------------------
// DoPaintMain - Process WM_PAINT message for window.
//
LRESULT DoPaintMain (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
PAINTSTRUCT ps;
RECT rect, rectOut;
TCHAR szOut[256];
HDC hdc;
INT i, j;
LPCTSTR pKeyText;
GetClientRect (hWnd, &rect);
// Create a drawing rectangle for the top line of the window.
rectOut = rect;
rectOut.bottom = rectOut.top + nFontHeight;
hdc = BeginPaint (hWnd, &ps);
if (nKeyCnt) {
for (i = 0; i < nKeyCnt; i++) {
// Create string containing wParam, lParam, and shift data.
wsprintf (szOut, TEXT ("wP:%08x lP:%08x shift: %s"),
ka[i].wParam, ka[i].lParam, ka[i].szShift);
// Look up name of key message.
for (j = 0; j < dim (knArray); j++)
if (knArray[j].wMsg == ka[i].wKeyMsg)
break;
// See if we found the message.
if (j < dim (knArray))
pKeyText = knArray[j].pName;
else
pKeyText = TEXT ("Unknown");
// Scroll the window one line.
ScrollDC (hdc, 0, nFontHeight, &rect, &rect, NULL, NULL);
// See if wide or narrow screen.
if (GetSystemMetrics (SM_CXSCREEN) < 480) {
// If Pocket PC, display info on 2 lines
ExtTextOut (hdc, 10, rect.top, ETO_OPAQUE, &rectOut,
szOut, lstrlen (szOut), NULL);
// Scroll the window another line.
ScrollDC(hdc, 0, nFontHeight, &rect, &rect, NULL, NULL);
ExtTextOut (hdc, 5, rect.top, ETO_OPAQUE, &rectOut,
pKeyText, lstrlen (pKeyText), NULL);
} else {
// Wide screen, print all on one line.
ExtTextOut (hdc, 5, rect.top, ETO_OPAQUE, &rectOut,
pKeyText, lstrlen (pKeyText), NULL);
ExtTextOut (hdc, 100, rect.top, 0, NULL,
szOut, lstrlen (szOut), NULL);
}
}
nKeyCnt = 0;
}
EndPaint (hWnd, &ps);
return 0;
}
//----------------------------------------------------------------------
// DoKeysMain - Process all keyboard messages for window.
//
LRESULT DoKeysMain (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
if (nKeyCnt >= 16) return 0;
ka[nKeyCnt].wKeyMsg = wMsg;
ka[nKeyCnt].wParam = wParam;
ka[nKeyCnt].lParam = lParam;
// Capture the state of the shift flags.
ka[nKeyCnt].szShift[0] = TEXT ('\0');
if (GetKeyState (VK_LMENU))
lstrcat (ka[nKeyCnt].szShift, TEXT ("lA "));
if (GetKeyState (VK_RMENU))
lstrcat (ka[nKeyCnt].szShift, TEXT ("rA "));
if (GetKeyState (VK_MENU))
lstrcat (ka[nKeyCnt].szShift, TEXT ("A "));
if (GetKeyState (VK_LCONTROL))
lstrcat (ka[nKeyCnt].szShift, TEXT ("lC "));
if (GetKeyState (VK_RCONTROL))
lstrcat (ka[nKeyCnt].szShift, TEXT ("rC "));
if (GetKeyState (VK_CONTROL))
lstrcat (ka[nKeyCnt].szShift, TEXT ("C "));
if (GetKeyState (VK_LSHIFT))
lstrcat (ka[nKeyCnt].szShift, TEXT ("lS "));
if (GetKeyState (VK_RSHIFT))
lstrcat (ka[nKeyCnt].szShift, TEXT ("rS "));
if (GetKeyState (VK_SHIFT))
lstrcat (ka[nKeyCnt].szShift, TEXT ("S "));
nKeyCnt++;
InvalidateRect (hWnd, NULL, FALSE);
return 0;
}
//----------------------------------------------------------------------
// DoDestroyMain - Process WM_DESTROY message for window.
//
LRESULT DoDestroyMain (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam) {
PostQuitMessage (0);
return 0;
}











Here are a few more characteristics of KeyTrac to notice. After each keyboard message is recorded, an InvalidateRect functionChapter 2, a program should never attempt to send or post a WM_PAINT message to a window because Windows needs to perform some setup before it calls a window with a WM_PAINT message.

Another device context function used in KeyTrac is

BOOL ScrollDC (HDC hDC, int dx, int dy, const RECT *lprcScroll,
const RECT *lprcClip, HRGN hrgnUpdate,
LPRECT lprcUpdate);

which scrolls an area of the device context either horizontally or vertically, but under Windows CE, not both directions at the same time. The three rectangle parameters define the area to be scrolled, the area within the scrolling area to be clipped, and the area to be painted after the scrolling ends. Alternatively, a handle to a region can be passed to ScrollDC. That region is defined by ScrollDC to encompass the region that needs painting after the scroll.

Finally, if the KeyTrac window is covered up for any reason and then reexposed, the message information on the display is lost. This behavior occurs because a device context doesn't store the bit information of the display. The application is responsible for saving any information necessary to completely restore the client area of the screen. Since KeyTrac doesn't save this information, it's lost when the window is covered up.

/ 169