Using Carets - Win32 apps (2023)

  • Article
  • 8 minutes to read

This section has code samples for the following tasks:

  • Creating and Displaying a Caret
  • Hiding a Caret
  • Destroying a Caret
  • Adjusting the Blink Time
  • Processing Keyboard Input

Creating and Displaying a Caret

Upon receiving the keyboard focus, the window should create and display the caret. Use the CreateCaret function to create a caret in the given window. You can then call SetCaretPos to set the current position of the caret and ShowCaret to make the caret visible.

The system sends the WM_SETFOCUS message to the window receiving keyboard focus; therefore, an application should create and display the caret while processing this message.

HWND hwnd, // window handle int x; // horizontal coordinate of cursor int y; // vertical coordinate of cursor int nWidth; // width of cursor int nHeight; // height of cursor char *lpszChar; // pointer to character case WM_SETFOCUS: // Create a solid black caret. CreateCaret(hwnd, (HBITMAP) NULL, nWidth, nHeight); // Adjust the caret position, in client coordinates. SetCaretPos(x, y); // Display the caret. ShowCaret(hwnd); break; 

To create a caret based on a bitmap, you must specify a bitmap handle when using CreateCaret. You can use a graphics application to create the bitmap and a resource compiler to add the bitmap to your application's resources. Your application can then use the LoadBitmap function to load the bitmap handle. For example, you could replace the CreateCaret line in the preceding example with the following lines to create a bitmap caret.

// Load the application-defined caret resource. hCaret = LoadBitmap(hinst, MAKEINTRESOURCE(120)); // Create a bitmap caret. CreateCaret(hwnd, hCaret, 0, 0); 

Alternatively, you can use the CreateBitmap or CreateDIBitmap function to retrieve the handle of the caret bitmap. For more information about bitmaps, see Bitmaps.

If your application specifies a bitmap handle, CreateCaret ignores the width and height parameters. The bitmap defines the size of the caret.

Hiding a Caret

Whenever your application redraws a screen while processing a message other than WM_PAINT, it must make the caret invisible by using the HideCaret function. When your application is finished drawing, redisplay the caret by using the ShowCaret function. If your application processes the WM_PAINT message, it is not necessary to hide and redisplay the caret, because this function does this automatically.

The following code sample shows how to have your application hide the caret while drawing a character on the screen and while processing the WM_CHAR message.

HWND hwnd, // window handle HDC hdc; // device context case WM_CHAR: switch (wParam) { case 0x08: // Process a backspace. break; case 0x09: // Process a tab. break; case 0x0D: // Process a carriage return. break; case 0x1B: // Process an escape. break; case 0x0A: // Process a linefeed. break; default: // Hide the caret. HideCaret(hwnd); // Draw the character on the screen. hdc = GetDC(hwnd); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); TextOut(hdc, x, y, lpszChar, 1); ReleaseDC(hwnd, hdc); // Display the caret. ShowCaret(hwnd); } 

If your application calls the HideCaret function several times without calling ShowCaret, the caret will not be displayed until the application also calls ShowCaret the same number of times.

Destroying a Caret

When a window loses the keyboard focus, the system sends the WM_KILLFOCUS message to the window. Your application should destroy the caret while processing this message by using the DestroyCaret function. The following code shows how to destroy a caret in a window that no longer has the keyboard focus.

case WM_KILLFOCUS: // The window is losing the keyboard focus, so destroy the caret. DestroyCaret(); break; 

Adjusting the Blink Time

In 16-bit Windows, a Windows-based application could call the GetCaretBlinkTime function to save the current blink time, then call the SetCaretBlinkTime function to adjust the blink time during its processing of the WM_SETFOCUS message. The application would restore the saved blink time for the use of other applications by calling SetCaretBlinkTime during its processing of the WM_KILLFOCUS message. However, this technique does not work in multithreaded environments. Specifically, the deactivation of one application is not synchronized with the activation of another application, so that if one application hangs, another application can still be activated.

Applications should respect the blink time chosen by the user. The SetCaretBlinkTime function should only be called by an application that allows the user to set the blink time.

Processing Keyboard Input

The following example demonstrates how to use a caret in a simple text editor. The example updates the caret position as the user types printable characters and uses various keys to move through the client area.

#define TEXTMATRIX(x, y) *(pTextMatrix + (y * nWindowCharsX) + x) // Global variables.HINSTANCE hinst; // current instance HBITMAP hCaret; // caret bitmap HDC hdc; // device context PAINTSTRUCT ps; // client area paint info static char *pTextMatrix = NULL; // points to text matrix static int nCharX, // width of char. in logical units nCharY, // height of char. in logical units nWindowX, // width of client area nWindowY, // height of client area nWindowCharsX, // width of client area nWindowCharsY, // height of client area nCaretPosX, // x-position of caret nCaretPosY; // y-position of caret static UINT uOldBlink; // previous blink rate int x, y; // coordinates for text matrix TEXTMETRIC tm; // font information LONG APIENTRY MainWndProc( HWND hwnd, // window handle UINT message, // type of message UINT wParam, // additional information LONG lParam) // additional information { switch (message) { case WM_CREATE: // Select a fixed-width system font, and get its text metrics. hdc = GetDC(hwnd); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); GetTextMetrics(hdc, &tm); ReleaseDC(hwnd, hdc); // Save the avg. width and height of characters. nCharX = tm.tmAveCharWidth; nCharY = tm.tmHeight; return 0; case WM_SIZE: // Determine the width of the client area, in pixels // and in number of characters. nWindowX = LOWORD(lParam); nWindowCharsX = max(1, nWindowX/nCharX); // Determine the height of the client area, in // pixels and in number of characters. nWindowY = HIWORD(lParam); nWindowCharsY = max(1, nWindowY/nCharY); // Clear the buffer that holds the text input. if (pTextMatrix != NULL) free(pTextMatrix); // If there is enough memory, allocate space for the // text input buffer. pTextMatrix = malloc(nWindowCharsX * nWindowCharsY); if (pTextMatrix == NULL) ErrorHandler("Not enough memory."); else for (y = 0; y < nWindowCharsY; y++) for (x = 0; x < nWindowCharsX; x++) TEXTMATRIX(x, y) = ' '; // Move the caret to the origin. SetCaretPos(0, 0); return 0; case WM_KEYDOWN: switch (wParam) { case VK_HOME: // Home nCaretPosX = 0; break; case VK_END: // End nCaretPosX = nWindowCharsX - 1; break; case VK_PRIOR: // Page Up nCaretPosY = 0; break; case VK_NEXT: // Page Down nCaretPosY = nWindowCharsY -1; break; case VK_LEFT: // Left arrow nCaretPosX = max(nCaretPosX - 1, 0); break; case VK_RIGHT: // Right arrow nCaretPosX = min(nCaretPosX + 1, nWindowCharsX - 1); break; case VK_UP: // Up arrow nCaretPosY = max(nCaretPosY - 1, 0); break; case VK_DOWN: // Down arrow nCaretPosY = min(nCaretPosY + 1, nWindowCharsY - 1); break; case VK_DELETE: // Delete // Move all the characters that followed the // deleted character (on the same line) one // space back (to the left) in the matrix. for (x = nCaretPosX; x < nWindowCharsX; x++) TEXTMATRIX(x, nCaretPosY) = TEXTMATRIX(x + 1, nCaretPosY); // Replace the last character on the // line with a space. TEXTMATRIX(nWindowCharsX - 1, nCaretPosY) = ' '; // The application will draw outside the // WM_PAINT message processing, so hide the caret. HideCaret(hwnd); // Redraw the line, adjusted for the // deleted character. hdc = GetDC(hwnd); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); TextOut(hdc, nCaretPosX * nCharX, nCaretPosY * nCharY, &TEXTMATRIX(nCaretPosX, nCaretPosY), nWindowCharsX - nCaretPosX); ReleaseDC(hwnd, hdc); // Display the caret. ShowCaret(hwnd); break; } // Adjust the caret position based on the // virtual-key processing. SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY); return 0; case WM_CHAR: switch (wParam) { case 0x08: // Backspace // Move the caret back one space, and then // process this like the DEL key. if (nCaretPosX > 0) { nCaretPosX--; SendMessage(hwnd, WM_KEYDOWN, VK_DELETE, 1L); } break; case 0x09: // Tab // Tab stops exist every four spaces, so add // spaces until the user hits the next tab. do { SendMessage(hwnd, WM_CHAR, ' ', 1L); } while (nCaretPosX % 4 != 0); break; case 0x0D: // Carriage return // Go to the beginning of the next line. // The bottom line wraps around to the top. nCaretPosX = 0; if (++nCaretPosY == nWindowCharsY) nCaretPosY = 0; break; case 0x1B: // Escape case 0x0A: // Linefeed MessageBeep((UINT) -1); break; default: // Add the character to the text buffer. TEXTMATRIX(nCaretPosX, nCaretPosY) = (char) wParam; // The application will draw outside the // WM_PAINT message processing, so hide the caret. HideCaret(hwnd); // Draw the character on the screen. hdc = GetDC(hwnd); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); TextOut(hdc, nCaretPosX * nCharX, nCaretPosY * nCharY, &TEXTMATRIX(nCaretPosX, nCaretPosY), 1); ReleaseDC(hwnd, hdc); // Display the caret. ShowCaret(hwnd); // Prepare to wrap around if you reached the // end of the line. if (++nCaretPosX == nWindowCharsX) { nCaretPosX = 0; if (++nCaretPosY == nWindowCharsY) nCaretPosY = 0; } break; } // Adjust the caret position based on the // character processing. SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY); return 0; case WM_PAINT: // Draw all the characters in the buffer, line by line. hdc = BeginPaint(hwnd, &ps); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); for (y = 0; y < nWindowCharsY; y++) TextOut(hdc, 0, y * nCharY, &TEXTMATRIX(0, y), nWindowCharsX); EndPaint(hwnd, &ps); case WM_SETFOCUS: // The window has the input focus. Load the // application-defined caret resource. hCaret = LoadBitmap(hinst, MAKEINTRESOURCE(120)); // Create the caret. CreateCaret(hwnd, hCaret, 0, 0); // Adjust the caret position. SetCaretPos(nCaretPosX * nCharX, nCaretPosY * nCharY); // Display the caret. ShowCaret(hwnd); break; case WM_KILLFOCUS: // The window is losing the input focus, // so destroy the caret. DestroyCaret(); break; default: return DefWindowProc(hwnd, message, wParam, lParam); } return NULL; } 
Top Articles
Latest Posts
Article information

Author: Fredrick Kertzmann

Last Updated: 02/17/2023

Views: 5277

Rating: 4.6 / 5 (46 voted)

Reviews: 85% of readers found this page helpful

Author information

Name: Fredrick Kertzmann

Birthday: 2000-04-29

Address: Apt. 203 613 Huels Gateway, Ralphtown, LA 40204

Phone: +2135150832870

Job: Regional Design Producer

Hobby: Nordic skating, Lacemaking, Mountain biking, Rowing, Gardening, Water sports, role-playing games

Introduction: My name is Fredrick Kertzmann, I am a gleaming, encouraging, inexpensive, thankful, tender, quaint, precious person who loves writing and wants to share my knowledge and understanding with you.