ID Number: Q67293
2.00 2.03 2.10 3.00
WINDOWS
Summary:
Some keys produce the same ASCII values as CTRL+key combinations.
These keys conflict with edit controls if one of the CTRL+key
combinations is used as a keyboard accelerator.
The following table lists some of the conflicting keys.
ASCII Value Key Combination Equivalent Windows Virtual Key
----------- --------------- ---------- -------------------
0x08 CTRL+H BACKSPACE VK_BACK
0x09 CTRL+I TAB VK_TAB
0x0D CTRL+M RETURN VK_RETURN
For example, consider the following scenario:
1. CTRL+H has been assigned as an accelerator keystroke to invoke Help
2. An edit control has the focus
3. BACKSPACE is pressed to erase the previous character in the edit
control
This results in Help being invoked because pressing BACKSPACE is
equivalent to pressing CTRL+H. The edit control does not receive the
BACKSPACE key press that it requires because TranslateAccelerator()
encounters the 0x08 ASCII value and invokes the action assigned to
that accelerator. This limitation is caused by the use of the ASCII
key code for accelerators instead of the system-dependent virtual key
code.
More Information:
When messages for the edit control are processed in a message loop
that translates accelerators, this translation conflict will occur.
Child windows and modeless dialog boxes are the most common situations
where this happens.
The affected keystrokes are translated during the processing of the
WM_KEYDOWN message for the letter. For example, when the user types
CTRL+H, a WM_KEYDOWN is processed for the CTRL key, then another
WM_KEYDOWN is processed for the letter "H". In response to this
message, TranslateAccelerator() posts a WM_COMMAND message to the
owner of the CTRL+H accelerator. Similarly, when the user presses the
BACKSPACE key, a WM_KEYDOWN is generated with VK_BACK as the key code.
Because the ASCII value of BACKSPACE is the same as that for CTRL+H,
TranslateAccelerator() treats them as the same character. Either
sequence will cause a WM_COMMAND message to be sent to the owner of
the CTRL+H accelerator, which deprives the child window with the input
focus of the BACKSPACE key message.
Because this conflict is inherent to ASCII, the safest way to avoid
the difficulty is to avoid using the conflicting sequences as
accelerators. Any other ways around the problem may be version
dependent rather than a permanent fix.
A second way around the situation is to subclass each edit control
that is affected. In the subclass procedure, watch for the desired key
sequence(s). The following code sample demonstrates this procedure:
/* This code subclasses a child window edit control to allow it to
* process the RETURN and BACKSPACE keys without interfering with the
* parent window's reception of WM_COMMAND messages for its CTRL+H
* and CTRL+M accelerator keys.
*/
/* forward declaration */
long FAR PASCAL NewEditProc(HWND, unsigned, WORD, LONG);
/* required global variables */
FARPROC lpfnOldEditProc;
HWND hWndOwner;
/* edit control creation in MainWndProc */
TEXTMETRIC tm;
HDC hDC;
HWND hWndEdit;
FARPROC lpProcEdit;
...
case WM_CREATE:
hDC = GetDC(hWnd);
GetTextMetrics(hDC, &tm);
ReleaseDC(hWnd, hDC);
hWndEdit = CreateWindow("Edit", NULL,
WS_CHILD | WS_VISIBLE | ES_LEFT | WS_BORDER,
50, 50, 50 * tm.tmAveCharWidth, 1.5 * tm.tmHeight,
hWnd, 1, hInst, NULL);
lpfnOldEditProc = (FARPROC) GetWindowLong (hWndEdit, GWL_WNDPROC);
lpProcEdit = MakeProcInstance ((FARPROC) NewEditProc, hInst);
SetWindowLong(hWndEdit, GWL_WNDPROC, (LONG) lpProcEdit);
break;
...
/* subclass procedure */
long FAR PASCAL NewEditProc(HWND hWndEditCtrl, unsigned iMessage,
WORD wParam, LONG lParam )
{
MSG msg;
switch (iMessage)
{
case WM_KEYDOWN:
switch (wParam)
{
case VK_BACK:
// This assumes that the next message in the queue will be a
// WM_COMMAND for the window which owns the accelerators. If
// this edit control were in a modeless dialog box, hWndOwner
// should be set to NULL. It may also be NULL in this case.
PeekMessage(&msg, hWndOwner, 0, 0, PM_REMOVE);
// Since TranslateAccelerator() processed this message as an
// accelerator, a WM_CHAR message must be supplied manually to
// the edit control.
SendMessage(hWndEditCtrl, WM_CHAR, wParam, MAKELONG(1, 14));
return 0L;
case VK_RETURN:
// Same procedures here.
PeekMessage(&msg, hWndOwner, 0, 0, PM_REMOVE);
SendMessage(hWndEditCtrl, WM_CHAR, wParam, MAKELONG(1, 28));
return 0L;
}
break;
}
return CallWindowProc(lpfnOldEditProc, hWndEditCtrl, iMessage,
wParam, lParam);
}
NOTE: Be sure to export the subclass function in the DEF file.