Home > OS >  Can I make the caret blink again after it stopped blinking?
Can I make the caret blink again after it stopped blinking?

Time:11-19

Normal behaviour for the caret in Windows 10 seems to be that as soon as a caret-capable control gets focus the caret will blink for about 5 seconds and then go solid (non-blinking). Whenever the left or right arrow keys are pressed it will move the caret and then it will start to blink again for the 5 second period, etc.

I cannot get the same behaviour on my custom control. Creation, displaying, moving and destruction of the caret seems to work fine but it will only blink for the 5 second duration after getting focus and perhaps one more time upon moving it with the arrow keys but never after that again. It stays solid (non-blinking) every time I move the caret with the arrow keys.

It will blink again if the control looses focus and regains it.

I noticed on another 3rd party control's source code that the authors used the SetCaretBlinkTime api call and I wonder if that was to get the desired effect but SetCaretBlinkTime's documenation encourages developers to only use it when actually wanting to set the blink rate similar to what the Keyboard Control Panel Applet does.

My custom control:

const
CCharWidth = 8;
CWidth = 200;
CInsideMargin = 2;
CCharsPerLine = (CWidth - (CInsideMargin * 2)) div CCharWidth;

type
TEditPane = class(TCustomControl)
private
  FCaretPosX : Integer;

  procedure SetCaretPosition(AXPos : Integer);

  procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN;
  procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
  procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
  procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
protected
  procedure Paint; override;
public
end;

implementation

procedure TEditPane.Paint;
begin
  Canvas.Brush.Style := bsSolid;
  Canvas.Brush.Color := clWindow;
  Canvas.FillRect(Rect(0,0,Width,Height));
end;

procedure TEditPane.SetCaretPosition(AXPos : Integer);
begin
  If AXPos < CInsideMargin then
    AXPos := CInsideMargin;

  If AXPos > CInsideMargin   (CCharsPerLine * CCharWidth) then
    AXPos := CInsideMargin   (CCharsPerLine * CCharWidth);

  FCaretPosX := AXPos;
  SetCaretPos(FCaretPosX,CInsideMargin);
end;

procedure TEditPane.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  inherited;
  Message.Result := Message.Result or DLGC_WANTARROWS;
end;

procedure TEditPane.WMKeyDown(var Message: TWMKeyDown);
begin
  inherited;
  Case Message.CharCode of
    VK_LEFT :
      SetCaretPosition(FCaretPosX - CCharWidth);
    VK_RIGHT :
      SetCaretPosition(FCaretPosX   CCharWidth);
  end;
end;

procedure TEditPane.WMKillFocus(var Message: TWMKillFocus);
begin
  inherited;
  HideCaret(Handle);
  DestroyCaret;
end;

procedure TEditPane.WMLButtonDown(var Message: TWMLButtonDown);
begin
  inherited;
  SetFocus;
end;

procedure TEditPane.WMSetFocus(var Message: TWMSetFocus);
begin
  inherited;
  CreateCaret(Handle,0,1,13);
  SetCaretPosition(CInsideMargin);
  ShowCaret(Handle);
end;

CodePudding user response:

Blinking is resumed after you show the caret. So you can

HideCaret(Handle); { assuming that show counter is 1 }
ShowCaret(Handle);

or repeat your code form WMSetFocus

CreateCaret(Handle,0,1,13);
SetCaretPosition(CInsideMargin);
ShowCaret(Handle);

Blinking also resumes after BeginPaint and EndPaint because it implicitly hides and shows caret if visible but it is side-effect and shouldn't be relied on.

  • Related