Using the Keyboard to Move the Cursor

You can use the SetCursorPos function to move the cursor directly from your application. This function is typically used to let the user move the cursor by using the keyboard.

To move the cursor, use the WM_KEYDOWN message and filter for the virtual-key values of the ARROW keys: VK_LEFT, VK_RIGHT, VK_UP, and VK_DOWN. On each keystroke, the application should update the position of the cursor. The following example shows how to retrieve the cursor position and convert the coordinates to client coordinates:

POINT ptCursor; /* these are global variables */

int repeat = 1;

RECT Rect;

.

.

.

case WM_KEYDOWN:

1 if(wParam != VK_LEFT && wParam != VK_RIGHT

&& wParam != VK_UP && wParam != VK_DOWN)

break;

2 GetCursorPos(&ptCursor);

/* Convert screen coordinates to client coordinates */

3 ScreenToClient(hWnd, &ptCursor);

4 repeat++; /* Increases the repeat rate */

switch (wParam) {

/* Adjust cursor position according to which key was pressed. */

/* Accelerate 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);

}

/* ensure that cursor doesn't go outside client area */

5 GetClientRect(hWnd, &Rect);

6 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;

7 ClientToScreen(hWnd, &ptCursor);

8 SetCursorPos(ptCursor.x, ptCursor.y);

break;

case WM_KEYUP:

9 repeat = 1; /* Clears the repeat rate */

break;

In this example:

1 The first if statement filters for the virtual-key values of the ARROW keys VK_LEFT, VK_RIGHT, VK_UP, and VK_DOWN.
2 The GetCursorPos function retrieves the current cursor position. If the mouse is available, the user could potentially move the cursor with the mouse at any time; therefore, there is no guarantee that the position values you saved on the last keystroke are correct.
3 The ScreenToClient function converts the cursor position to client coordinates. The application does this for two reasons: mouse messages give the mouse position in client coordinates, and client coordinates do not need to be updated if the window moves. In other words, it is convenient to use client coordinates because the system uses them and because it usually means less work for the application.
4 The repeat variable provides accelerated cursor motion. Advancing the cursor one unit for each keystroke can be frustrating for users if they need to move to the other side of the screen. You can accelerate the cursor motion by increasing the number of units the cursor advances when the user holds down a key. When the user holds down a key, Windows sends multiple WM_KEYDOWN messages without matching WM_KEYUP messages. To accelerate the cursor, you simply increase the number of units to advance on each WM_KEYDOWN message.
5 The GetClientRect function retrieves the current size of the client area and stores it in the Rect structure. You then use that information to ensure that the cursor motion remains within the client area.
6 These if statements check the current cursor position to ensure that it is within the client area. If necessary, the application then adjusts the cursor position.
7 In preparation for the SetCursorPos function, the ClientToScreen function converts the values in the ptCursor structure from client coordinates to screen coordinates. Because SetCursorPos requires screen coordinates rather than client coordinates, you must convert the coordinates before calling SetCursorPos.
8 The SetCursorPos function moves the cursor to the desired location.
9 Within the WM_KEYUP case, the application restores the initial value of the repeat variable when the user releases the key.