Hardware Keys
The keyboard isn't necessarily the only way for the user to enter keystrokes to an application. All Pocket PCs and many embedded systems have additional buttons that can be assigned to launch an application or to send unique virtual key codes to applications. The Pocket PC has an additional set of buttons known as navigation buttons that mimic common navigation keys such as Line Up and Line Down. These navigation keys give the user shortcuts, which allow scrolling up and down as well as access to the services of the often-used key Enter. Because the scrolling buttons simply send Page Up, Page Down, Line Up, and Line Down key messages, your application doesn't have to take any special action to support these keys.The application launch buttons are another matter. When pressed, these keys cause the shell to launch the application registered for that key. Although a system is usually configured with default associations, you can override these settings by modifying the registry so that pressing a hardware control button launches your application. An application can also override the application launch ability of a specific key by having the key mapped directly to a window. In addition, you can use the hot key features of the Graphics Windowing and Event Subsystem (GWE) to override the hardware key assignment and send a hot key message to a window.
Virtual Codes for Hardware Keys
Since the hardware control buttons are treated as keyboard keys, pressing a hardware control key results in WM_KEYDOWN and WM_KEYUP messages as well as a WM_CHAR message if the virtual key matches a Unicode character. The system mapping of these keys employs two strategies. For the navigation keys, the resulting virtual key codes are codes known and used by Windows applications so that those applications can "use" the keys without even knowing that's what they're doing. The application-launching keys, on the other hand, need virtual key codes that are completely different from previously known keys so that they won't conflict with standard key events.
Navigation Key Codes
As I mentioned earlier, the navigation keys are mapped to common navigation keys. The actual virtual key code mapping for navigation keys is shown in the following table.
Key | Action | Key Message | Key Code |
---|---|---|---|
Action | Press | WM_KEYDOWN | OEM dependent[*] |
Action | Release | WM_KEYUP | OEM dependent[*] |
WM_KEYDOWN | VK_RETURN | ||
WM_CHAR | VK_RETURN | ||
WM_KEYUP | VK_RETURN | ||
Rock Up | Press | WM_KEYDOWN | OEM dependent[*] |
Release | WM_KEYUP | OEM dependent[*] | |
WM_KEYDOWN | VK_UP | ||
WM_KEYUP | VK_UP | ||
Rock Down | Press | WM_KEYDOWN | OEM dependent[*] |
Release | WM_KEYUP | OEM dependent[*] | |
WM_KEYDOWN | VK_DOWN | ||
WM_KEYUP | VK_DOWN | ||
Rock Left | Press | WM_KEYDOWN | OEM dependent[*] |
Release | WM_KEYUP | OEM dependent[*] | |
WM_KEYDOWN | VK_LEFT | ||
WM_KEYUP | VK_LEFT | ||
Rock Right | Press | WM_KEYDOWN | OEM dependent[*] |
Release | WM_KEYUP | OEM dependent[*] | |
WM_KEYDOWN | VK_RIGHT | ||
WM_KEYUP | VK_RIGHT | ||
[*] OEM-dependent key codes differ from system to system. Some OEMs might not send the messages. while others might send the messages with a virtual key code of 0. |
Unfortunately, there's no reliable way of determining whether a VK_RETURN key event came from the SIP or from a hardware button. Each OEM has a different method of assigning virtual key codes to the hardware navigation buttons.
Application Launch Key Codes
The shell manages the application launch keys named App1 through a possible App16. These keys produce a combination of virtual key codes that are interpreted by the shell. The codes produced are a combination of the left Windows key (VK_LWIN) and a virtual code starting with 0xC1 and continuing up, depending on the application key pressed. For example, the App1 key produces the virtual key sequence VK_LWIN followed by 0xC1, while the App2 key produces the sequence VK_LWIN followed by 0xC2.
Using the Application Launch Keys
Applications are bound to a specific application launch key through entries in the registry. Specifically, each key has an entry under [HKEY_LOCAL_MACHINE] \Software\Microsoft\Shell\Keys. The entry is the virtual key combination for that key, so for the App1 key, the entry is
[HKEY_LOCAL_MACHINE]\Software\Microsoft\Shell\Keys\40C1
The 40C1 comes from the code 0x40, which indicates the Windows key has been pressed and concatenated with the virtual key code of the application key, 0xC1. The default value assigned to this key is the fully specified path name of the application assigned to the key. A few other values are also stored under this key. The ResetCmd value is the path name of the application that is assigned to this key if the Restore Defaults button is pressed in the system's Button control panel applet. The Name value contains the friendly name of the key, such as Button 1 or Side Button.The only way to change the application assigned to a key is to manually change the registry entry to point to your application. Of course, you shouldn't do this without consulting your users because they might have already configured the application keys to their liking. The routine that follows assigns an application to a specific button and returns the name of the application previously assigned to that button. The vkAppKey parameter should be set to an application key virtual key code, 0xC1 through 0xCF. The pszNewApp parameter should point to the fully specified path name of the application you want to assign to the key.
//----------------------------------------------------------------------
// SetAppLaunchKey - Assigns an application launch key to an
// application.
//
int SetAppLaunchKey (LPTSTR pszNewApp, BYTE vkAppKey, LPTSTR pszOldApp,
INT nOldAppSize) {
TCHAR szKeyName[256];
DWORD dwType, dwDisp;
HKEY hKey;
INT rc;
// Construct the key name.
wsprintf (szKeyName,
TEXT ("Software\\Microsoft\\Shell\\Keys\\40%02x"), vkAppKey);
// Open the key.
rc = RegCreateKeyEx (HKEY_LOCAL_MACHINE, szKeyName, 0, TEXT ("),
0, 0, NULL, &hKey, &dwDisp);
if (rc != ERROR_SUCCESS)
return -1;
// Read the old application name.
rc = RegQueryValueEx (hKey, TEXT ("), 0, &dwType,
(PBYTE)pszOldApp, &nOldAppSize);
if (rc != ERROR_SUCCESS) {
RegCloseKey (hKey);
return -2;
}
// Set the new application name.
rc = RegSetValueEx (hKey, TEXT ("), 0, REG_SZ, (PBYTE)pszNewApp,
(lstrlen (pszNewApp)+1) * sizeof (TCHAR));
RegCloseKey (hKey);
if (rc != ERROR_SUCCESS)
return -3;
return 0;
}
When an application button is pressed, the system doesn't check to see whether another copy of the application is already running—it simply launches a new copy. You should design your application, especially on the Pocket PC, to check to see whether another copy of your application is already running and if so, to activate the first copy of the application and quietly terminate the newly launched copy.You can determine whether an application is assigned to a key by calling the function SHGetAppKeyAssoc, which is prototyped as
Byte SHGetAppKeyAssoc (LPCTSTR ptszApp);
The only parameter is the fully qualified name of your application. If a key is associated with your application, the function returns the virtual key code for that key. If no key is associated with your application, the function returns 0. This function is useful because most applications, when launched by an application key, override the default action of the key so that another copy of the application won't launch if the key is pressed again.
Dynamically Overriding Application Launch Keys
A running application can override a launch key in two ways. The first method is to use the function SHSetAppKeyWndAssoc, prototyped as
BOOL SHSetAppKeyWndAssoc (BYTE bVk, HWND hwnd);
The first parameter is the virtual key code of the hardware button. The second parameter is the handle of the window that's to receive the notices of button presses. For example, a program might redirect the App1 key to its main window with the following line of code:
SHSetAppKeyWndAssoc (0xC1, hwndMain);
The window that has redirected an application might receive key messages but the virtual key codes received and the type of key messages are OEM-specific. The chief reason for using SHSetAppKeyWndAssoc is to prevent the button from launching an application. When you no longer want to redirect the application launch key, you can call SHSetAppKeyWndAssoc specifying the virtual code of the key and NULL for the window handle.The second method of overriding an application launch key is to use the RegisterHotKey function. The advantage of using the RegisterHotKey function is that your window will receive known messages, albeit WM_HOTKEY instead of WM_KEYxxx messages, when the key is pressed, no matter what application currently has the keyboard focus. This function is prototyped as
BOOL RegisterHotKey (HWND hWnd, int id, UINT fsModifiers, UINT vk);
The first parameter is the handle of the window that receives the WM_HOTKEY messages. The second parameter is an application-defined identifier that's included with the WM_HOTKEY message to indicate which key caused the message. The fsModifiers parameter should be set with flags, indicating the shift keys that must also be pressed before the WM_HOTKEY message can be sent. These self-explanatory flags are MOD_ALT, MOD_CONTROL, MOD_SHIFT, and MOD_WIN. An additional flag, MOD_KEYUP, indicates that the window will receive WM_HOTKEY messages when the key is pressed and when the key is released. When using RegisterHotKey on application keys, you should always specify the MOD_WIN flag because application keys always are combined with the Windows shift-modifier key. The final parameter, vk, is the virtual key code for the key you want as your hot key. This key doesn't have to be a hardware key code; you can actually use almost any other virtual key code supported by Windows, although assigning Shift-F to your custom fax application might make Pocket Word users a bit irate when they tried to enter a capital F.When the key registered with RegisterHotKey is pressed, the system sends a WM_HOTKEY message to the window. The wParam parameter contains the ID code you specified when you called RegisterHotKey. The low word of lParam parameter contains the shift-key modifiers, MOD_xxx, that were set when the key was pressed, while the high word of lParam contains the virtual key code for the key.The disadvantage of using RegisterHotKey is that if another application has already registered the hot key, the function will fail. This can be problematic on the Pocket PC, where applications stay running until the system purges them to gain extra memory space. One strategy to employ when you want to use a hardware key temporarily—for example, in a game—would be to use SHGetAppKeyAssoc to determine what application is currently assigned to that key. It's a good bet that if RegisterHotKey failed due to some other program using it, the application assigned the application key is also the one currently running and has redirected the hot key to its window. You can then send a WM_CLOSE message to that application's main window to see whether it will close and free up the hardware key.When you no longer need the hot key, you can unregister the hot key with this function:
BOOL UnregisterHotKey (HWND hWnd, int id);
The two parameters are the window handle of the window that had registered the hot key and the ID value for that hot key you assigned with RegisterHotKey.The Game API, or GAPI, provides a method for applications to take control of all hardware keys in the system. GAPI lets an application take control of all the keys but not individual keys. Still, GAPI provides a convenient service for game developers. (For more information about GAPI, refer to Chapter 20.)The application launch buttons provide a handy way to make your applications easily accessible by the user. The only additional task required of the application is to assume control of the key when it's running so that users can't inadvertently launch multiple copies of the application.
I began this chapter by saying the Explorer shell is interesting in that, like many parts of Windows CE, it resembles its desktop counterparts but is implemented very differently. These differences show up the most in places, such as the COM interfaces the Explorer uses and in console applications, where the implementation is limited to supporting a subset of standard C library calls and little else.In the next chapter, I turn to the Pocket PC shell. This shell has dramatic differences in look and feel that affect the way you write Pocket PC applications. Throughout this book, the examples have contained small snippets of code that I mentioned were required for the Pocket PC, but I didn't explain why. It's time to explore the details of these extra pieces of code.