Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations bkrike on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Geting keyboard input when program is not in focus

Status
Not open for further replies.

Zx

Programmer
Oct 22, 1999
2
US
does ne1 know how to do this without any seperate ocx files?
 
Hi Zx!<br>
<br>
This is unlikely to happen. Windows sends keystrokes to the program in the foreground (i.e. has focus).<br>
<br>
What you *can* do is install a system-wide keyboard hook. I doubt it can be done in VB, but if it can, it'll be listed in Daniel Appleman's book on the Win32 API. The Desaware Spyhook OCX might could do it too, but you said you didn't want any OCXs. Buy Dan's book -- it should be in there, and you should own it anyway if you're hardcore about VB.<br>
<br>
Chip H.<br>

 
Direct Input. Don't know the details but using Direct X 7 and direct input you can get any input (including joystick)when the app isn't active. It may be a mamoth download but try getting the D7 SDK. And just think, direct Draw, D3D etc in VB
 
The only way to do what you want in VB is to have a system-wide hook written into a dll which has to be written in c++. I have written such a dll, email me if you want it or have any questions
 
No need for a hook. Use GetAsyncKeyState in a timer control or procedure. You'll find more than one example in the forums. Here's another one, courtesy of API-Guide:
[tt]
'In a module
Public Const DT_CENTER = &H1
Public Const DT_WORDBREAK = &H10
Type RECT
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Declare Function DrawTextEx Lib &quot;user32&quot; Alias &quot;DrawTextExA&quot; (ByVal hDC As Long, ByVal lpsz As String, ByVal n As Long, lpRect As RECT, ByVal un As Long, ByVal lpDrawTextParams As Any) As Long
Declare Function SetTimer Lib &quot;user32&quot; (ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long
Declare Function KillTimer Lib &quot;user32&quot; (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long
Declare Function GetAsyncKeyState Lib &quot;user32&quot; (ByVal vKey As Long) As Integer
Declare Function SetRect Lib &quot;user32&quot; (lpRect As RECT, ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As Long) As Long
Global Cnt As Long, sSave As String, sOld As String, Ret As String
Dim Tel As Long

Function GetPressedKey() As String
For Cnt = 32 To 128
'Get the keystate of a specified key
If GetAsyncKeyState(Cnt) <> 0 Then
GetPressedKey = Chr$(Cnt)
Exit For
End If
Next Cnt
End Function

Sub TimerProc(ByVal hwnd As Long, ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long)
Ret = GetPressedKey
If Ret <> sOld Then
sOld = Ret
sSave = sSave + sOld
End If
End Sub

'In a form
Private Sub Form_Load()
'KPD-Team 1999
'URL: 'E-Mail: KPDTeam@Allapi.net
Me.Caption = &quot;Key Spy&quot;
'Create an API-timer
SetTimer Me.hwnd, 0, 1, AddressOf TimerProc
End Sub

Private Sub Form_Paint()
Dim R As RECT
Const mStr = &quot;Start this project, go to another application, type something, switch back to this application and unload the form. If you unload the form, a messagebox with all the typed keys will be shown.&quot;
'Clear the form
Me.Cls
'API uses pixels
Me.ScaleMode = vbPixels
'Set the rectangle's values
SetRect R, 0, 0, Me.ScaleWidth, Me.ScaleHeight
'Draw the text on the form
DrawTextEx Me.hDC, mStr, Len(mStr), R, DT_WORDBREAK Or DT_CENTER, ByVal 0&
End Sub

Private Sub Form_Resize()
Form_Paint
End Sub

Private Sub Form_Unload(Cancel As Integer)
'Kill our API-timer
KillTimer Me.hwnd, 0
'Show all the typed keys
MsgBox sSave
End Sub

[/tt]


Alt255@Vorpalcom.Intranets.com
 
Sorry, but I have to disagree with you Alt255 (nothing personal though :)). . . you have put a looping function to check each key for a key press that is going to run forever in the background. The repeated looping within the timer callback is a waste of CPU time.
Also, The GetAsyncKeyState must be called for each and every key on the keyboard. It will determine if the key is being pressed or has been pressed since the last time the function was called. Normally, this would work fine, but consider this . . . someone pushes the &quot;q&quot; right AFTER your for-next loop checks for it. Then, some other program calls GetAsyncKeyState on the &quot;q&quot; key (effectively clearing its flag) before your loop has a chance to recheck it. When your looping code comes back to check the &quot;q&quot; key, it will not know that it has been pressed.
ChipH is correct in this matter when he states that you need to hook into the OS's message queue system . . . all keystrokes for all processes MUST be passed through the OS's message queue. Also, hooking into that queue will not waste CPU time.

{Note to ChipH}
Yes ChipH, this hook can be established in VB, but it is a bit tricky as it involve writing the proper callback declaration to make it work. It took me a while (some time ago) to figure it out, but it can be done. If I can find the code, I'll post it. - Jeff Marler
(please note, that the page is under construction)
 
Yes ChipH, this hook can be established in VB, but it is a bit tricky as it involve writing the proper callback declaration to make it work. It took me a while (some time ago) to figure it out, but it can be done. If I can find the code, I'll post it.

OK, I see now. My opinion was based on an older version of VB that didn't have the AddressOf operator.

Thanks for pointing that out.

Chip H.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top