Link to home
Start Free TrialLog in
Avatar of ciri
ciri

asked on

when I lose the focus

I have an small aplication in Visual Basic that shows a window. This window is set to hide (or invisible) when a concrete key is pressed. Then, when another key is pressed, this window appears again. This program runs well while it has the focus. But if any user press ALT+TAB, or run another program, I lose the focus, and my program not catch the keyboard events. How can I catch the keys pressed if another program is taking now the processor? Thanks.
Avatar of MikeP090797
MikeP090797

You can set a keyboard hook (WH_KEYBOARD) using SetWindowsHookEx. This can be done only in VB5, because it req. a callback function:

Dim hHook as long
'Set
hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf KbdProc, vbNull, 0)

Function KbdProc(code as long ,lParam as long, wParam as long) as long
'Proccess the keyboard message
end function

'Unhook
UnHookWindowsHookEx(hHook)

-----------------------------------------------------------------
Here is the referense on SetWindowsHookEx and KbdProc
-----------------------------------------------------------------
 
The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. An application installs a hook procedure to monitor the system for certain types of events. A hook procedure can monitor events associated either with a specific thread or with all threads in the system. This function supersedes the SetWindowsHook function.
HHOOK SetWindowsHookEx(
 

    int idHook,      // type of hook to install
    HOOKPROC lpfn,      // address of hook procedure
    HINSTANCE hMod,      // handle of application instance
    DWORD dwThreadId       // identity of thread to install hook for
   );      
Parameters
idHook
Specifies the type of hook procedure to be installed. This parameter can be one of the following values:
 
Value      Description

WH_CALLWNDPROC      Installs a hook procedure that monitors messages before the system sends them to the destination window procedure. For more information,  the CallWndProc hook procedure.
WH_CALLWNDPROCRET      Windows 95 only: Installs a hook procedure that monitors messages after they have been processed by the destination window procedure. For more information, see  the CallWndRetProc hook procedure.
WH_CBT      Installs a hook procedure that receives notifications useful to a computer-based training (CBT) application. For more information, see the CBTProc hook procedure.
WH_DEBUG      Installs a hook procedure useful for debugging other hook procedures. For more information, see the DebugProc hook procedure.
WH_GETMESSAGE      Installs a hook procedure that monitors messages posted to a message queue. For more information, see the GetMsgProc hook procedure.
WH_JOURNALPLAYBACK      Installs a hook procedure that posts messages previously recorded by a WH_JOURNALRECORD hook procedure. For more information, see the JournalPlaybackProc hook procedure.
WH_JOURNALRECORD      Installs a hook procedure that records input messages posted to the system message queue. This hook is useful for recording macros. For more information, see the JournalRecordProc hook procedure.
WH_KEYBOARD      Installs a hook procedure that monitors keystroke messages. For more information, see the KeyboardProc hook procedure.
WH_MOUSE      Installs a hook procedure that monitors mouse messages. For more information, see the MouseProc hook procedure.
WH_MSGFILTER      Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu, or scroll bar. For more information, see  the MessageProc hook procedure.
WH_SHELL      Installs a hook procedure that receives notifications useful to shell applications. For more information, see  the ShellProc hook procedure.
WH_SYSMSGFILTER      Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu, or scroll bar. The hook procedure monitors these messages for all applications in the system. For more information, see  the SysMsgProc hook procedure.
lpfn
Points to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a different process, the lpfn parameter must point to a hook procedure in a dynamic-link library (DLL). Otherwise, lpfn can point to a hook procedure in the code associated with the current process.
hMod
Identifies the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within the code associated with the current process.
dwThreadId
Specifies the identifier of the thread with which the hook procedure is to be associated. If this parameter is zero, the hook procedure is associated with all existing threads.
Return Values
If the function succeeds, the return value is the handle of the hook procedure.
If the function fails, the return value is NULL.
Remarks
An error may occur if the hMod parameter is NULL and the dwThreadId parameter is zero or specifies the identifier of a thread created by another process.
Chaining to the next hook procedure (that is, calling the CallNextHookEx function) is optional. An application or library can call the next hook procedure either before or after any processing in its own hook procedure.
Before terminating, an application must call the UnhookWindowsHookEx function to free system resources associated with the hook.
The scope of a hook depends on the hook type. Some hooks can be set only with system scope; others can also be set for only a specific thread, as shown in the following list:
 
Hook      Scope

WH_CALLWNDPROC      Thread or system
WH_CBT      Thread or system
WH_DEBUG      Thread or system
WH_GETMESSAGE      Thread or system
WH_JOURNALPLAYBACK      System only
WH_JOURNALRECORD      System only
WH_KEYBOARD      Thread or system
WH_MOUSE      Thread or system
WH_MSGFILTER      Thread or system
WH_SHELL      Thread or system
WH_SYSMSGFILTER      System only
For a specified hook type, thread hooks are called first, then system hooks.
The system hooks are a shared resource, and installing one affects all applications. All system hook functions must be in libraries. System hooks should be restricted to special-purpose applications or to use as a development aid during application debugging. Libraries that no longer need a hook should remove the hook procedure.
See Also
CallNextHookEx, CallWndProc, CBTProc, DebugProc, GetMsgProc, JournalPlaybackProc, JournalRecordProc, KeyboardProc, MouseProc, MessageProc, ShellProc, SysMsgProc, UnhookWindowsHookEx

 
 
The KeyboardProc hook procedure is an application-defined or library-defined callback function the system calls whenever an application calls the GetMessage or PeekMessage function and there is a keyboard message (WM_KEYUP or WM_KEYDOWN) to be processed.
LRESULT CALLBACK KeyboardProc(
 

    int code,      // hook code
    WPARAM wParam,      // virtual-key code
    LPARAM lParam       // keystroke-message information
   );      
Parameters
code
Specifies a code the hook procedure uses to determine how to process the message. This parameter can be one of the following values:
 
Value      Meaning

HC_ACTION      The wParam and lParam parameters contain information about a keystroke message.
HC_NOREMOVE      The wParam and lParam parameters contain information about a keystroke message, and the keystroke message has not been removed from the message queue. (An application called the PeekMessage function, specifying the PM_NOREMOVE flag.)
If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx.
wParam
Specifies the virtual-key code of the key that generated the keystroke message.
lParam
Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag. This parameter can be a combination of the following values:
 
Value      Description

0-15      Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user's holding down the key.
16-23      Specifies the scan code. The value depends on the original equipment manufacturer (OEM).
24      Specifies whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is 1 if the key is an extended key; otherwise, it is 0.
25-28      Reserved.
29      Specifies the context code. The value is 1 if the ALT key is down; otherwise, it is 0.
30      Specifies the previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up.
31      Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released.
For more information about the lParam parameter, see Keystroke Message Flags.
Return Values
To prevent Windows from passing the message to the rest of the hook chain or to the target window procedure, the return value must be a nonzero value. To allow Windows to pass the message to the target window procedure, bypassing the remaining procedures in the chain, the return value must be zero.
Remarks
An application installs the hook procedure by specifying the WH_KEYBOARD hook type and the address of the hook procedure in a call to the SetWindowsHookEx function.
KeyboardProc is a placeholder for the application-defined or library-defined function name.
See Also
CallNextHookEx, GetMessage, PeekMessage, SetWindowsHookEx, WM_KEYUP, WM_KEYDOWN

 

ASKER CERTIFIED SOLUTION
Avatar of MikeP090797
MikeP090797

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 ciri

ASKER

I push the line
      hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf KbdProc, vbNull, 0)
when my main form loads, and when I tried to run the program, the following error ocurred
WH_KEYBOARD : variable not defined. I supose that I must load a library, perhaps using the option references in the menu project. What do you think about this error?

Ahh!!. Another questions... . When can I call the function KbdProc??. Is in this function when I study the key pressed??.

I think a small example could explain me this doubts...
Thanks.
Public Const WH_KEYBOARD = 2

KbdProc is called by windows each time when a key is pressed, no matter what window is active

The topic has already been discussed, unfortunately without success in:
https://www.experts-exchange.com/topics/comp/lang/visualbasic/Q.10039526
Avatar of ciri

ASKER

Now the error is the following:
   
        SetWindowsHookEx: Sub or Function not defined
You have to get all the declares from Api text viewer, but anyway:

Declare Function SetWindowsHookEx Lib "user32" Alias "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Public Const WH_KEYBOARD = 2

Avatar of ciri

ASKER

You tell me that the KbdProc function is called by Window when a key is pressed. Then, I supose that I only re-define this function, for example like a module, like this

Function KbdProc(code As Long, lParam As Long, wParam As Long) As Long
   
   If (Chr(code) = "i") Then
    Form1.Visible = False
  End If
  If (Chr(code) = "v") Then
    Form1.Visible = True
  End If
     'Proccess the keyboard message
End Function

Then, when a key was pressed, this code will be run.
But don't occurs nothing!!
What's the problem?? (I recognize that my Visual Basic is poor)

Or maybe I must have something different (like call the KbdProc in another procedure,...)

Or maybe this function shoudn't be re-defined??

Where can I push the code

   If (Chr(code) = "i") Then
    Form1.Visible = False
  End If
  If (Chr(code) = "v") Then
    Form1.Visible = True
  End If

You put that code in the KbdProc, but you must call SetWindowsHookEx on startup
Avatar of ciri

ASKER

Yes, I put the code
     hHook = SetWindowsHookEx(WH_KEYBOARD, AddressOf KeyboardProc, vbNull, 0)

in the procedure Form_Load() and I put the KbdProc function in a module (global.bas). But the aplicattion runs like the code didn't exist. Simply, I think that the KbdProc function isn't called  (I don't know why)
Place msgbox in KbdProc to make sure if it's called or not.
And it supposed to be AddressOf KbdProc (The same name as your function)
Avatar of ciri

ASKER

I placed a MsgBox in KbdProc function, but didn't show it when I pressed a key.
that's strange. try app.ThreadID as third atg in SetWindowsHookEx.
Where do you call UnhookWindowsHookEx?
Avatar of ciri

ASKER

Well, I tried with app.ThreadID, like you said me. I set a MesgBox in the KbdProc function, and when I pressed a letter, I saw the MesgBox in three times.

About the UnhookWindowsHookEx function, I call it just before the program finish (when a button is pressed). But I never can see this function, becouse it isn't stay in the user32 library. Can you say me in which library (DLL) this function is?
Avatar of ciri

ASKER

Well, I tried with app.ThreadID, like you said me. I set a MesgBox in the KbdProc function, and when I pressed a letter, I saw the MesgBox in three times.

About the UnhookWindowsHookEx function, I call it just before the program finish (when a button is pressed). But I never can see this function, becouse it isn't stay in the user32 library (like I thougth). Can you say me in which library (DLL) this function is?
Avatar of ciri

ASKER

If I press a key when another program is taking the processor, occurs a Windows error, and this program is closed (the mesagebox isn't displayed)
Declare Function UnhookWindowsHookEx Lib "user32" Alias "UnhookWindowsHookEx" (ByVal hHook As Long) As Long

Avatar of ciri

ASKER

MikeP, the UnhookWindowsHookEx function runs O.K.
Like I told you, I see the messagebox three times (only when my aplication is active). When another aplication is active, a Windows error occurs if I press a key.
So why you have accepted the answer if it's not working?
Avatar of ciri

ASKER

Well, the answer isn't good. So, I'll reopen the question to another experts. On the other hand, this question don't worry me now. But, if i know the answer, I'll be happy.
Avatar of ciri

ASKER

I can't reopen the question (i think). MikeP's answer appears like "Accepted answer". I don't understand it. I don't remember to accept this answer. I usually adds a comment like "good answer" when I accept an answer. Maybe the answer had been accepted becouse I hadn't reopen the question in 3 or 4 weeks (and I hadn't adds a comment). What can I do??
You could ask the webmaster.
Avatar of ciri

ASKER

How can I ask this doubt the webmaster??
Send me your project to michaelp@gezernet.co.ilm I'll try to figure it out, but it won't be ready til sunday, cause I won't be at home till then
Avatar of ciri

ASKER

MikeP, I tried to send you an e-mail,but an error occurs: unknown host or domain
michaelp@gezernet.co.il