2015-12-22 2 views
8

My Freundin neuen Laptop nicht Anzeige-LEDs für NumLock und CapsLock haben, so habe ich ein kleines Programm, das auf dem Bildschirm und deren Status:Wie kann ich den Tastaturstatus erfassen, wenn meine Anwendung nicht den Fokus hat?

procedure TForm1.Timer1Timer(Sender: TObject); 
var 
    KeyState: TKeyboardState; 
begin 
    GetKeyboardState(KeyState); 
    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; 

enter image description here

Das so lang wie mein Programm funktioniert hat der Fokus, aber wenn der Fokus auf andere Programmstatus gerichtet ist, werden diese nicht mehr aktualisiert. (Es genügt jedoch, nur die Maus über das Formular zu bewegen, ohne zu klicken.)

Wie kann ich das Programm aktualisieren lassen, wenn eine andere Anwendung den Fokus hat?

+0

Betriebssystem? –

+0

@JasonC Windows 7 –

+0

Ihr letzter Absatz schlägt bereits eine mögliche Lösung vor: Verwenden Sie 'GetCursorPos' und' SendMessage (..., WM_MOUSEMOVE, ...) ', um zu erzwingen, dass die Nachrichtenschleife den aktuellen Tastaturstatus in Ihrer Anwendung aktualisiert im Hintergrund. – mghie

Antwort

8

Sie können einfach GetKeyState in Ihrem Timer verwenden.

if GetKeyState(VK_NUMLOCK) = 1 then 
    PanelNumLock.Color := clLime 
else 
    PanelNumLock.Color := clSilver; 

if GetKeyState(VK_CAPITAL) = 1 then 
    PanelCapsLock.Color := clLime 
else 
    PanelCapsLock.Color := clSilver; 

Dies funktioniert auch, wenn Ihre Anwendung nicht den Fokus hat. Getestet auf XP.

+1

Funktioniert auch unter Win 7. Vielen Dank. (Ich höre sehr schlechte Dinge über Win 10, aber ich kann wärmstens empfehlen, von XP auf Win 7 zu aktualisieren. Es wird Unterstützung bis 2020 haben.) –

+1

Nur für den Datensatz funktionieren beide Lösungen unter Windows 10 –

3

Sie sollten eine Low Level Keyboard Hook verwenden, denn dann können Sie für jeden Tastenanschlag benachrichtigt werden, auch wenn Sie Anwendung nicht im Fokus haben.

Ich habe ein kleines Beispiel für Sie erstellen

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. 

Grundsätzlich auf formCreate ich den Tastatur-Hook und erzählt mein Programm in welcher Funktion ich meine Anmeldung benötigen. In meinem Beispiel nannte ich es LowLevelKeyboardProc

Dann müssen Sie nur testen, welche Taste gedrückt wird und wenn es eine der CapsLock Num Lock ist, dann noFify das Formular.

+0

Dies funktioniert nicht wie erwartet. Ihr Hook sendet eine WM_UpdateScreen-Nachricht. Welches dann GetKeyboardState aufruft. Wenn das Formular nicht fokussiert ist, wird der Status nicht reflektiert (zurück zum Anfangsproblem des OPs). getestet auf XP. – kobik

+0

Es hat auf meinem Computer –

+3

Ich kann nicht sehen, wie es gemacht hat. Der Timer hat das Gleiche gemacht. Das Problem ist "GetKeyboardState" in einem nicht fokussierten Fenster. – kobik

Verwandte Themen