Title: Keyboard Hook
Question: You want to catch keystrokes. Your main form "keypreview=true" only works when a control has focus. How do you catch keystrokes? Included below is a component you can drop on any form to catch keystrokes.
Answer:
Catching a keyboard stroke for your application requires a call to the windows api function SetWindowsHookEx.
Using this function will allow you to specify a callback procedure for the keystrokes.
You have 2 options, you can make a system wide hook or a hook for a particular thread.
If you make a system wide hook or specify a thread that exists in a different process then you must use a seperate DLL.
In this artical I will only provide source for your applications main thread, therefore is not a system wide hook.
Install the below component, drop it on your form, then assign the OnCallback event.
You can look into windows help for "KeyboardProc" and it will explain the parameters.
Here is an implementation I am using in a production application that responds to the space bar:
procedure TForm_LibraryImageSelect.KeyboardHook1Callback(code, wparam,
lparam: Integer);
begin
if (wParam = VK_SPACE) and ((lparam and (1 shl 30)) 0) then
SendMoveNextLibImage(dNext);
end;
Good luck,
Here is the source for the component:
----------------------------------------
unit KeyboardHook;
{
By William Egge
Sep 20, 2002
egge@eggcentric.com
http://www.eggcentric.com
This code may be used/modified however you wish.
}
interface
uses
Windows, Classes;
type
TCallbackThunk = packed record
POPEDX: Byte;
MOVEAX: Byte;
SelfPtr: Pointer;
PUSHEAX: Byte;
PUSHEDX: Byte;
JMP: Byte;
JmpOffset: Integer;
end;
// See windows help on KeyboardProc
// Or press F1 while your cursor is on "KeyboardProc"
TKeyboardCallback =
procedure(code: Integer; wparam: WPARAM; lparam: LPARAM) of object;
TKeyboardHook = class(TComponent)
private
{ Private declarations }
FHook: HHook;
FThunk: TCallbackThunk;
FOnCallback: TKeyboardCallBack;
function CallBack(code: Integer; wparam: WPARAM; lparam: LPARAM): LRESULT
stdcall;
procedure SetOnCallback(const Value: TKeyboardCallBack);
protected
{ Protected declarations }
public
{ Public declarations }
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
{ Published declarations }
property OnCallback: TKeyboardCallBack read FOnCallback write SetOnCallback;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('EggMisc', [TKeyboardHook]);
end;
{ TKeyboardHook }
function TKeyboardHook.CallBack(code: Integer; wparam: WPARAM;
lparam: LPARAM): LRESULT;
begin
if Code Result:= CallNextHookEx(FHook, Code, wparam, lparam)
else
begin
if Assigned(FOnCallback) then
FOnCallback(Code, wParam, lParam);
Result:= 0;
end;
end;
constructor TKeyboardHook.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FThunk.POPEDX:= $5A;
FThunk.MOVEAX:= $B8;
FThunk.SelfPtr:= Self;
FThunk.PUSHEAX:= $50;
FThunk.PUSHEDX:= $52;
FThunk.JMP:= $E9;
FThunk.JmpOffset:= Integer(@TKeyboardHook.Callback)-Integer(@FThunk.JMP)-5;
FHook:= SetWindowsHookEx(WH_KEYBOARD, TFNHookProc(@FThunk), 0, MainThreadID);
end;
destructor TKeyboardHook.Destroy;
begin
UnhookWindowsHookEx(FHook);
inherited;
end;
procedure TKeyboardHook.SetOnCallback(const Value: TKeyboardCallBack);
begin
FOnCallback := Value;
end;
end.