如何检测没有焦点的控件中的修改键更改?

TLa*_*ama 14 delphi winapi delphi-xe3

背景:

我正在研究一个从TCustomControl类派生的控件,它可以获得焦点,并且里面有一些内部元素.如果用户使用光标悬停它们,则可以突出显示这些内部元素,您可以选择它们,移动它们等等.现在问题......

问题:

如果用户持有或使用修饰符CTRL,我会使用(比如说)聚焦元素执行不同的操作.我想要的是如果用户悬停元素并保持例如键,则更改鼠标光标.非常简单,你只需覆盖和方法,并检查它们的参数是否等于.在这样的代码中:ALTSHIFTCTRLKeyDownKeyUpKeyVK_CONTROL

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;
Run Code Online (Sandbox Code Playgroud)

即使这不是检查CTRL按键是否被按下和释放的最佳方式(例如,由于现有的Shift状态参数),它可以按预期工作,控制具有焦点,甚至可以获得,但......

我的目标是当用户悬停控件时(或者确切地说,它内部的某个元素)更改鼠标光标,并且CTRL即使我的控件没有焦点也保持例如该键.可以说,所以只需覆盖MouseMove方法并在那里询问修饰符状态.这将是方式,但......

如果用户将鼠标光标停留在我的控件上并按下并释放该CTRL键,该怎么办?对于我的控制,这不会产生任何鼠标移动或按键事件,或者我错了?那么,我的问题很明显......

题:

如果控件没有焦点且用户没有用鼠标移动,如何检测修改键更改?我在想这两个选项,但我希望有一些我错过的东西:

  • 键盘钩 - 可靠,但看起来对我来说太过分了
  • 用定时器定期检查修改器状态 - 我不能忍受延迟

那么,您如何检测当前未关注的控件的修改键更改?

Rem*_*eau 8

如果您的控件没有聚焦,则不会触发其自己的键事件.但是,您可以执行的操作是让控件在TApplicationEvents内部实例化一个私有组件,并使用其OnMessage事件来检测从主消息队列中检索的关键事件,然后再将这些事件调度到任何控件进行处理.然后,您可以检查鼠标是否在您的控件之上(更好地使用GetMessagePos()而不是GetCursorPos()或者Screen.CursorPos在生成消息时获取鼠标坐标,以防它们被延迟)并更新控件自己的Cursor属性(不是Screen.Cursor属性)如所须.

  • @MarjanVenema但是如果"响应"意味着即使窗口处于非活动状态也会在鼠标上移动鼠标光标,那么几乎每个Windows应用都会这样做. (2认同)

Ond*_*lle 5

我会编写一个消息处理程序,WM_SETCURSOR用于调用GetKeyboardState以获取键盘状态(在Delphi中,您只需调用KeyboardStateToShiftState)并根据该结果(和命中测试)调用SetCursor相应的游标.

对于处理WM_SETCURSOR,VCL中有一个例子:TCustomGrid.WMSetCursorGrids单元中.