A customer was looking for a way to find the location of the caret (the blinking line that indicates where the next character will be inserted). They tried GetÂCaretÂPos, but it always failed.
Most window manager state functions that were global in 16-bit Windows became per-thread in 32-bit Windows, as part of the conversion to the asynchronous input model. The GetÂCaretÂPos function returns the caret position for your thread. (Specifically, the caret that belongs to the current thread and shared with all the other threads that the current thread has been AttachÂThreadÂInput‘d to, either explicitly or implicitly.)¹
To get the global state, you can call GetÂGUIÂThreadÂInfo with a thread ID of zero to say that you want the information of whatever thread owns the foreground window.
GUITHREADINFO info = { sizeof(info) };
if (GetGUIThreadInfo(0, &info)) {
if (info.flags & GUI_CARETBLINKING) {
⟦ info.rcCaret contains the location of the caret ⟧
⟦ relative to info.hwndCaret ⟧
}
}
The customer explained that they were writing an accessibility tool that moves the mouse to wherever keyboard focus is. So they filled in the code like this:
GUITHREADINFO info = { sizeof(info) };
if (GetGUIThreadInfo(0, &info)) {
if (info.flags & GUI_CARETBLINKING) {
// Convert rcCaret to screen coordinates
MapWindowPoints(info.hwndCaret, nullptr, (POINT*)&info.rcCaret, 2);
Â
// Move the cursor to the bottom right corner
SetCursorPos(info.rcCaret.right - 1, info.rcCaret.bottom - 1);
}
}
But there are times when the GUI_ flag is not set, even though you can see a blinking caret with your own eyes. These are cases where the program with keyboard focus is not using CreateÂCaret but are instead drawing a custom caret that blinks on a custom timer.
We’ll look at that next time.
¹ Things that are local to the current thread (and any other threads it is attached to) include
- The capture, focus, and active windows,
- The input queue and message queue,
- The mouse cursor shape and show count,
- The keyboard state,
- The caret.
In Windows 95, these things were kept in a structure called the “virtual window information” because it was taking what used to be global state in Windows 3.1 and making it local state, virtualizing each thread into thinking that it was controlling the show. The abbreviation for the virtual information was “vwi”, which was pronounced “vee-wee”. So you might overhear people on the window manager team saying something like “You can’t capture to a window that belongs to somebody else’s vee-wee.”
I’m guessing the solution will be related to IME, like how the emoji picker knows where to appear