Custom Caret for Dark Mode (sorry a little long...)
Turns out it is not too difficult. There are a few point to clear up however.
The color of the caret is not going to be the color of the bitmap replacement.
It is some combination of the background and bitmap colors. Somewhere I read only
white bits are inverted. For example with a certain gray background a brown bitmap
gives a green caret change background the caret is red with same bitmap...See attachments
The bitmap caret is not automatically scaled with the font height. To look best
this would require building the caret bitmap in code on the fly after a font change
rather then using a predefined bit map. Still considering if worth it...
I'm using accelerator keys in the program so my main windows is created with
hwndMain= CreateDialog(hInstance, MAKEINTRESOURCE(DLG_MAIN),....
so that I can have TranslateAccelerator in the actual msg loop
IN/On the main window are edit boxes. for example
CONTROL "Middle", Text2, "Edit", ES_AUTOHSCROLL|WS_TABSTOP, 188, 72, 104, 12, WS_EX_STATICEDGE, 202
These controls are the ones needing the custom caret when in DarkMode
In main MainDlgProc I check the msg for what has current focus if one of the edit controls has it and it was not also the last control to have focus then I set the caret to the control. SO far so good everything appears to work as expected. If not in Dark Mode skip unless 1st transition out of DarkMode then set caret back to system original.
My concern is that -
MS says "The system provides one caret per queue. A window should create a caret only when it has the keyboard focus or is active. The window should destroy the caret before losing the keyboard focus or becoming inactive."
A new caret will always destroy the old one
If further says "the windows will be sent WM_KILLFOCUS before the actual focus is lost so that DestroyCaret(); can be used. The edit box child windows never send this message when they lose focus. It does appear that they automatically destroy my caret when leaving because the next time I go there I still need to set the caret to the new one even though I did it before.
I did add DestroyCaret to the CLOSE message routine for the main window just in case.
Did a lot of testing jumping to different programs and within my own everything appears to be ok but I'm not sure I'm not missing something....
/-----------------------------------------------------------------------
// Function : Set_one_Caret
// Task : Set the dark mode edit caret cursor to usable color
// : and set it back to the std caret as required
// Note :
// Input : context on state TRUE = Dark Mode caret, FALSE = Std
//-----------------------------------------------------------------------
void Set_one_Caret( BOOL context_on, HANDLE hwnd)
{ int ans;
static HANDLE last_hwnd=NULL;
static BOOL last_context=FALSE;
DWORD err;
RECT cwin;
int h=0;
if ((last_hwnd == hwnd) && (last_context == context_on))
{ return;}
// NOT really needed just for testing
GetClientRect(text[0].hctl,&cwin);// sizes std caret to control window
h = cwin.bottom-cwin.top-2; // only useful for built in caret
HBITMAP hCaret1=NULL;// caret bitmap handles
if (context_on)
{ hCaret1 = LoadBitmap(ghInstance,MAKEINTRESOURCE(CARET_W));
if (hCaret1 == NULL)
MessageBoxA(NULL,"Failed load bitmap","Set_One_Caret",MB_OK);
// no crash with NULL though just uses system caret - so ok fall through
ans = CreateCaret(hwnd,hCaret1,0,h); // new cursor, h ignored
err = GetLastError();
if (ans == 0)
{MessageBoxA(NULL,"Failed Create New","Set_one_Caret",MB_OK);
Show_Error(err, L"Set_one_Caret- creating"); //error display
}
ans = ShowCaret(hwnd);
err = GetLastError();
if (ans == 0)
{ MessageBoxA(NULL,"Failed Show New","Set_one_Caret",MB_OK);
Show_Error(err, L"Set_one_Caret- show"); //error display
}
}
else //revert to system caret
{ // test use edit box height (h) to the set system caret height - Works
ans = CreateCaret(hwnd,(HBITMAP) 1,2,h); // std Caret
err = GetLastError();
if (ans == FALSE)
{MessageBoxA(NULL,"Failed Re-Create Old","Set_one_Caret",MB_OK);
Show_Error(err, L"Set_one_Caret- Reset,Create"); //error display
}
ans = ShowCaret(hwnd);
err = GetLastError();
if (ans == FALSE)
{ MessageBoxA(NULL,"Failed Re-Show Old","Set_one_Caret",MB_OK);
Show_Error(err, L"Set_one_Caret- Reset,Apply"); //error display
}
}
last_hwnd = hwnd;
last_context = context_on;
return;
}/* end set_one_caret */
John Z