6.5.7 Adding WM_KEYDOWN and WM_KEYUP Cases

To let the user control the cursor by using the keyboard, add WM_KEYDOWN and WM_KEYUP cases to your application's window procedure. The statements in the WM_KEYDOWN case retrieve the current position of the cursor and update the position when an arrow key is pressed. Add the following statements to the window procedure:

POINT ptCursor;    /* x and y coordinates of cursor */
int repeat = 1;    /* repeat count of keystroke     */
RECT Rect;         /* selection rectangle           */
    .
    .
    .

case WM_KEYDOWN:
    if (wParam != VK_LEFT && wParam != VK_RIGHT
        && wParam != VK_UP && wParam != VK_DOWN)
        break;



    GetCursorPos(&ptCursor);

    /* Convert screen coordinates to client coordinates. */

    ScreenToClient(hwnd, &ptCursor);

    switch (wParam) {

        /*
         * Adjust the cursor position according to which key
         * was pressed. Accelerate the movement by adding the
         * repeat variable to the cursor position.
         */

        case VK_LEFT:
            ptCursor.x -= repeat;
            break;

        case VK_RIGHT:
            ptCursor.x += repeat;
            break;

        case VK_UP:
            ptCursor.y -= repeat;
            break;

        case VK_DOWN:
            ptCursor.y += repeat;
            break;

        default:
            return NULL;
    }

    repeat++;       /* increases repeat rate */

    /* Ensure that the cursor doesn't go outside client area. */

    GetClientRect(hwnd, &Rect);

    if (ptCursor.x >= Rect.right)
        ptCursor.x = Rect.right - 1;
    else
        if (ptCursor.x < Rect.left)
            ptCursor.x = Rect.left;

    if (ptCursor.y >= Rect.bottom)
        ptCursor.y = Rect.bottom - 1;
    else
        if (ptCursor.y < Rect.top)
            ptCursor.y = Rect.top;


    /* Convert the coordinates to screen coordinates. */

    ClientToScreen(hwnd, &ptCursor);
    SetCursorPos(ptCursor.x, ptCursor.y);
    break;

In this example, the GetCursorPos function retrieves the cursor position in screen coordinates. To check the position of the cursor within the client area, the coordinates are converted to client coordinates by using the ScreenToClient function. The switch statement then checks for the arrow keys; each time it encounters an arrow key, the statement adds the current contents of the repeat variable to the appropriate coordinate of the cursor location.

The example then checks the new position to make sure it is still in the client area (adjusting it if necessary), using the GetClientRect function to retrieve the dimensions of the client area. Finally, the ClientToScreen function converts the position back to screen coordinates, and the SetCursorPos function sets the new position.

The WM_KEYUP case restores the initial value of the repeat variable when the user releases the key, as follows:

case WM_KEYUP:
    repeat = 1; /* clears repeat count */
    break;