Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect modifier key change in a control which doesn't have focus?

Background:

I'm working on a control derived from TCustomControl class which can get focus and which has some inner elements inside. Those inner elements are highlighted if the user hovers them with the cursor, you can select them, move them and so on. Now to the problem...

Problem:

I'm doing different actions with the (let's say) focused element if the user holds CTRL, ALT or SHIFT modifiers. What I would like is to change the mouse cursor if the user hovers the element and holds for instance CTRL key. Pretty simple, you just override the KeyDown and KeyUp methods and check if their Key parameter equals to VK_CONTROL. In code like this way:

procedure TMyCustomControl.KeyDown(var Key: Word; Shift: TShiftState);
begin
  inherited;
  if Key = VK_CONTROL then
    Screen.Cursor := crSizeAll;
end;

procedure TMyCustomControl.KeyUp(var Key: Word; Shift: TShiftState);
begin
  inherited;
  if Key = VK_CONTROL then
    Screen.Cursor := crDefault;
end;

Even if that wouldn't be the best way to check if the CTRL key was pressed and released (e.g. because of the existing Shift state parameter), it works as expected whe the control has focus, which can even get, but...

My aim is to change the mouse cursor when user hovers the control (or to be precise, a certain element inside it) and holds e.g. that CTRL key even when my control doesn't have focus. One can say, so just override the MouseMove method and ask for the modifier states there. And it would be the way, but...

What if the user stays with the mouse cursor over my control and press and release that CTRL key ? That won't generate any mouse move nor key press event for my control, or am I wrong ? Well, so my question is quite obvious...

Question:

How can I detect modifier key changes if the control doesn't have focus and the user doesn't move with the mouse ? I was thinking about these two options, but I hope there is something I missed:

  • keyboard hook - reliable, but looks quite overkill to me
  • periodical check of the modifier states with a timer - I couldn't live with a delay

So, how would you detect modifier key changes of a control which isn't currently focused ?

like image 321
TLama Avatar asked Oct 24 '13 15:10

TLama


2 Answers

If your control is not focused, its own key events will not be triggered. However, what you can do instead is have your control instantiate a private TApplicationEvents component internally, and use its OnMessage event to detect key events being retrieved from the main message queue before they are dispatched to any control for processing. You can then check if the mouse is over your control (better to use GetMessagePos() instead of GetCursorPos() or Screen.CursorPos so that you get the mouse coordinates at the time the messages were generated, in case they are delayed) and update your control's own Cursor property (not the Screen.Cursor property) as needed.

like image 172
Remy Lebeau Avatar answered Oct 05 '22 23:10

Remy Lebeau


I would write a message handler for WM_SETCURSOR message to call GetKeyboardState to get the keyboard state (in Delphi you can just call KeyboardStateToShiftState) and based on the result of that (and the hit test) call SetCursor with the appropriate cursor.

For handling WM_SETCURSOR, there's an example in the VCL: TCustomGrid.WMSetCursor in the Grids unit.

like image 29
Ondrej Kelle Avatar answered Oct 05 '22 22:10

Ondrej Kelle