Link to home
Start Free TrialLog in
Avatar of olagutt
olagutt

asked on

Catching keyboard with SetWindowsHookEx

Hi everybody,

I'm struggling a bit with SetWindowsHookEx, from win32.dll. At the current stage, I have developed a custom component that acts as a Progressbar, but I want this to respond to keystrokes, even when the component doesn't have the focus.
I.e. when a user hits the Esc button.

My solution to the problem seems to be to hook the keyboard and analyse everything that the user presses with SetWindowsHookEx.

I have included some functions for this inside my component, but every time I hit the keyboard, I get an access violation error. Does this mean that it's impossible to trap the keyboard with a component?? Should I put this code in a DLL instead? Or do you have some other suggestions?  

Here's what it looks like :

function TProgressControl.SetupHook: boolean;
begin
        CurrentHook:=SetWindowsHookEx(WH_KEYBOARD,
                                      @TProgressControl.KeyBoardHook,
                                      0,
                                      GetCurrentThreadID()
                                      );
        SetupHook := (CurrentHook <> 0);
end;

function TProgressControl.RemoveHook: boolean;
begin
        RemoveHook:=UnhookWindowsHookEx(CurrentHook);
end;

function TProgressControl.KeyBoardHook(code: integer; wParam: word; lParam: longword): longword; stdcall;
begin
        if code < 0 then
        begin
                KeyBoardHook:=CallNextHookEx(CurrentHook,code,wParam,lparam);
                Exit;
        end;
        if Lo(wParam) = 27 then Stop   //here I'm stopping my Progressbar
        CallNextHookEx(CurrentHook,code,wParam,lparam);
        KeyBoardHook:=0;
end;

Regards,
Ola
Avatar of robert_marquardt
robert_marquardt

Hooking keys outside your application requires a DLL.

BTW your idea is silly. It is against all user interface conventions.
ALL keyboard input goes to the application which has the focus. So when i want to legitimately enter ESC in another app your progress will act upon it. This will infuriate any user.

For catching ESC inside your app it is easier to simply use OnKeyDown.
Could be also used a hook inside your app, a journal hook...

To catch keys (like in a keylogger) you can use something like the code below, in a timer with interval set to 1 :

   for i:=8 To 255 do
   begin
      if GetAsyncKeyState(i)=-32767 then
         begin
         case i of
         8: pressed_key:='{UNDO}';
         9: pressed_key:='{TAB}';
         //etc.
         end;
   end;

ESC is a dialog key like Tab so you can only get it if your Progressbar is a TWinControl. See TWinControl.CNKeyDown implementation for ways to specifically tell the VCL that your control wants to handle ESC.
Avatar of olagutt

ASKER

First of all, I'm not talking about application focus, but component focus.

>>For catching ESC inside your app it is easier to simply use OnKeyDown.

OnKeyDown will only be triggered if the component has got the focus, so that will not help me much... :(

Are you saying that TwinControl is able to provide me with event triggers for the whole form? Regardless of component focus?

Your comments are highly appreciated :)
Ola
You are right, but you do not need a hook for that. There are several ways to get the messages. Try Application.HookMainMainWindow and catch WM_KEYDOWN param VK_ESC. Call back if it does not work.
ASKER CERTIFIED SOLUTION
Avatar of Member_2_248744
Member_2_248744
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of olagutt

ASKER

That did the trick!

I just needed to know how to access my objects when the hook-function was outside my component-class.

Slick812 gave the answer, so the points will go to him.
Roberts last tip was also interesting...maybe I'll look into that later...


Best regards,
Ola