You should use a Low Level Keyboard Hook, because then you can get notified for every keystroke even if you application does not have focus.
I've create a small example for you
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Vcl.ExtCtrls;
const
WM_UpdateScreen = WM_USER + 1;
type
TForm1 = class(TForm)
PanelCapsLock: TPanel;
PanelNumlock: TPanel;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
FHook: hHook;
KeyState: TKeyboardState;
public
procedure UpdateScreen(var message: TMessage); message WM_UpdateScreen;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
type
pKBDLLHOOKSTRUCT = ^KBDLLHOOKSTRUCT;
KBDLLHOOKSTRUCT = packed record
vkCode: DWORD;
scanCodem: DWORD;
flags: DWORD;
time: DWORD;
dwExtraInfo: ULONG_PTR;
end;
var
hkHook: hHook;
function LowLevelKeyboardProc(code: Integer; WParam: WParam; LParam: LParam): LRESULT stdcall;
const
LLKHF_UP = $0080;
var
Hook: pKBDLLHOOKSTRUCT;
bControlKeyDown: Boolean;
begin
try
Hook := pKBDLLHOOKSTRUCT(LParam);
case code of
HC_ACTION:
begin
if (Hook^.flags and LLKHF_UP) <> 0 then
if Hook.vkCode in [VK_NUMLOCK, VK_CAPITAL] then
PostMessage(Form1.Handle, WM_UpdateScreen, Hook.vkCode, 0);
end;
end;
finally
Result := CallNextHookEx(hkHook, code, WParam, LParam);
end;
end;
procedure HookIt;
begin
hkHook := SetWindowsHookEx(WH_KEYBOARD_LL, @LowLevelKeyboardProc, hInstance, 0);
end;
procedure UnHookIt;
begin
UnHookWindowsHookEx(hkHook);
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
UnHookIt;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
GetKeyboardState(KeyState);
PostMessage(Handle, WM_UpdateScreen, VK_CAPITAL, 1);
PostMessage(Handle, WM_UpdateScreen, VK_NUMLOCK, 1);
HookIt;
end;
procedure TForm1.UpdateScreen(var message: TMessage);
begin
if message.LParam = 0 then
if KeyState[message.WParam] = 0 then
KeyState[message.WParam] := 1
else
KeyState[message.WParam] := 0;
if KeyState[VK_NUMLOCK] = 0 then
PanelNumlock.Color := clSilver
else
PanelNumlock.Color := clLime;
if KeyState[VK_CAPITAL] = 0 then
PanelCapsLock.Color := clSilver
else
PanelCapsLock.Color := clLime;
end;
end.
Basically on formCreate
I hook the Keyboard, and tells my program in which function I need my notification. In my example I called it LowLevelKeyboardProc
Then you just need to test fot which key is pressed and if it is one of CapsLock of Num lock then nofify the form.
GetCursorPos
andSendMessage(..., WM_MOUSEMOVE, ...)
to force the message loop to update the current keyboard status in your application if it's in the background. – Deprived