How can I make hotkey hooks to my application so that, for example, if I press CTRL + F2 it shows message "hello world", even if the application is minimized or working on other apps, etc? Please show me example or source.
1 Answers
One option is to use RegisterHotKey()
.
This method will register a hotkey or hotkey combination with Windows. While your application is running, it will be notified by the system if this hotkey combination is pressed. To act on this notification, you need to catch the WM_HOTKEY
message in the window procedure attached to the handle you registered the hotkey with.
The easiest and least error-prone way to implement this is to create a dedicated handle using AllocateHWND
. I've used a form as an example here but this can be applied to non-windowed classes as well :
TForm1 = class(TForm)
private
FHotkeyWnd : HWND;
procedure HandleHotkey(var msg : TMessage);
public
constructor Create(AOwner : TComponent); override;
destructor Destroy; override;
end;
which you could implement as :
const
HOTKEY1_ID = 1;
constructor TForm1.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
FHotkeyWnd := AllocateHWND(HandleHotkey);
RegisterHotKey(FHotkeyWnd, HOTKEY1_ID, MOD_CONTROL, VK_F2);
end;
destructor TForm1.Destroy;
begin
UnregisterHotKey(FHotkeyWnd, HOTKEY1_ID);
DeallocateHWND(FHotkeyWnd);
inherited;
end;
procedure TForm1.HandleHotkey(var msg: TMessage);
begin
if msg.Msg = WM_HOTKEY then begin
ShowMessage('hello world')
else
Msg.Result := DefWindowProc(FHotkeyWnd, msg.Msg, msg.wParam, msg.lParam);
end;
- Caveats
Keep in mind that with modern versions of Windows (Vista, 7, 8...) where UIPI is in force, registered hotkeys will not fire when an elevated application (with respect to yours) is active. If your application, for example, is running as a user-level application and the logged-in user is currently working in an elevated (ie: administrator privilege) application then you will not be sent hotkey notifications. This is an important security measure that prevents higher-privilege applications from leaking information to applications of lower privilege. Example.
If this is an important consideration for you then there are ways around this restriction. The easiest is to simply force administrator privilege for your application. This is obviously not always the best answer. The alternative is more involved, requires authenticode signing your application, and is beyond the scope of this answer.
-
3Since `RegisterHotKey()` is tied to a specific HWND, but a Form's HWND is not persistent, the Form's `OnCreate` event is not the best option when you want to use the Form's HWND. You should instead override the Form's virtual `CreateWnd()` method to call `RegisterHotKey()`, and override the virtual `DestroyWnd()` method to call `UnregisterHotKey()`. That way, the hotkey gets registered every time the Form's HWND is recreated. Otherwise, create a dedicated HWND instead, such as with `AllocateHWnd()`. – Remy Lebeau Jul 03 '14 at 01:35
-
@RemyLebeau I've gone back and rewritten this example. I'd previously only ever done this with a dedicated handle (using `AllocateHWND`) and hadn't realized how tricky it is to manage this with a component's handle. Somehow I thought that using a form's handle would be more straightforward for OP but it turns out not! – J... Jul 03 '14 at 11:00
-
1@J...: `TForm` already has an `FHandle` member, so you should give your HWND a more unique name. Also, `AllocateHWnd ()` window procedures MUST pass unhandled messages, especially system messages, to `DefWindowProc()` or bad things can happen. – Remy Lebeau Jul 03 '14 at 14:53
-
How would one do this in FireMonkey? – Shaun Roselt Jan 12 '19 at 17:26