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 strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Intercepting key strokes 3

Status
Not open for further replies.

Alt255

Programmer
May 14, 1999
1,846
US
My program uses the GetAsyncKeyState API call to record the keystrokes sent to other applications. The problem with this call, unless I am doing something terribly wrong, is that it doesn't seem able to intercept combination keystrokes. It returns codes for the uppercase version of letters A-Z regardless of the shift-state. When Shift+"A" is pressed it returns the SHIFT key code rather than the code for "a". When ALT+F12 is pressed it returns the code for the ALT key.

I have tried a variety of Jerry-Rigs trying to guess the actual key presses (e.g., set a flag when CAPSLOCK is pressed and assume everything that follows is UPPERCASE... unless the SHIFT key is pressed, etc). Nothing seems solve the problem.

Does anybody know of a different function to derive the true keystrokes or a way to coerce GetAsyncKeyState into telling the truth?

Here's the tiny bit of code I'm using....
[tt]
Private Declare Function GetAsyncKeyState Lib "user32.dll" (ByVal vKey As Long) As Integer

Public Function GetInput()
For Rep = 0 To 255
If (GetAsyncKeyState(Rep) And &H8001) <> 0 Then
GetInput = Rep
Exit Function
End If
Next i
End Function
[/tt]


I know there must be a way to do this. I'm probably blinded by a solution that is so close I can't see it.
VCA.gif
 
Gosh, did I do something good? ;-)

Well here it is


Option Explicit

Private Declare Sub SetKeyHook Lib &quot;ldbkeycap.dll&quot; (ByVal hWnd As Long, ByVal hHook As Long)
Private Declare Sub GetKeyInfo Lib &quot;ldbkeycap.dll&quot; (szChars As Any, nLastPos As Long)

Private Declare Function SetWindowsHookEx Lib &quot;user32&quot; Alias &quot;SetWindowsHookExA&quot; (ByVal idHook As Long, ByVal lpfn As Long, ByVal hMod As Long, ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib &quot;user32&quot; (ByVal hHook As Long) As Long
Private Declare Function LoadLibrary Lib &quot;kernel32&quot; Alias &quot;LoadLibraryA&quot; (ByVal lpLibFileName As String) As Long
Private Declare Function FreeLibrary Lib &quot;kernel32&quot; (ByVal hLibModule As Long) As Long
Private Declare Function GetProcAddress Lib &quot;kernel32&quot; (ByVal hModule As Long, ByVal lpProcName As String) As Long

Private Const WH_KEYBOARD = 2

Private m_hHookKey As Long
Private m_hMod As Long

Private Sub Form_Load()
Dim lpProcKey As Long

m_hMod = LoadLibrary(App.Path & &quot;\ldbkeycap.dll&quot;)
If m_hMod = 0 Then
MsgBox &quot;Missing DLL! Please reinstall.&quot;, vbOKOnly + vbExclamation, &quot;Error&quot;
End
End If

lpProcKey = GetProcAddress(m_hMod, &quot;KeyProc&quot;)
If lpProcKey = 0 Then
MsgBox &quot;Invalid DLL! Please reinstall.&quot;, vbOKOnly + vbExclamation, &quot;Error&quot;
End
End If

m_hHookKey = SetWindowsHookEx(WH_KEYBOARD, lpProcKey, m_hMod, 0)

SetValuesKey pctKeystroke.hWnd, m_hHookKey 'pctKeystroke is a picturebox i use for ease of getting the keydown etc...
End Sub

Private Sub Form_Unload(Cancel As Integer)
UnhookWindowsHookEx m_hHookKey

FreeLibrary m_hMod
End Sub

Private Sub pctKeystroke_KeyPress(KeyAscii As Integer)
Static nLastPos As Long
Static nNewPos As Long
Static szChars(0 To 49) As Byte
Static I As Long

GetKeyInfo szChars(0), nNewPos

If nNewPos = nLastPos Then
Exit Sub
End If

If nNewPos < nLastPos Then
nNewPos = nNewPos + 50
End If

For I = nLastPos To nNewPos - 1
lstLog.AddItem &quot;Pressed key - [ &quot; & Chr(szChars(I Mod 50)) & &quot; ]&quot;
Next
lstLog.ListIndex = lstLog.ListCount - 1

nLastPos = nNewPos Mod 50
End Sub
 
OK, you did what I thought you were doing (using the GetProcAddress function to get the memory address of the callback). Nice! I hadn't thought about that before. Normally I just call the SetHook from within the C++ DLL, but what you did is fine. I did like how you used the pic box to intercept the key presses messages that you were posting, but that might be part of the reason why you are not receiving fucntion keys and other system keys. - Jeff Marler B-)
 
How could I do this wrong lol, but I know why he doesn't got the system keys. The system keys aren't keystrokes, so they wont be 'detected' by a KeyPress event ^^ All you have to do is make a new sub for the picture box on a keydown or keyup event and you have the call and that also answeres my question about loggin keydown and keyup events...

LuCkY
 
Hello all. I have been trying to get this code to work on my own, but with no luck. I made a .def file for the c++ code (i am using Visual Studio 6) and that helped a bunch (before, the basic code wouldn't find the dll and all sorts of fun things), but i am still getting an error. SetValuesKey sub or function not defined. not sure if i missed anything, and i am rather new to c++, but here are the changes i have made to get it to the point it is at now..

.def file added

LIBRARY keyhooker
DESCRIPTION DLL FOR KEYLOGGING

EXPORTS
KeyProc @1

SECTIONS
.shared READ WRITE SHARED


and one change in the main.cpp file

extern &quot;C&quot; BOOL __stdcall _DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {


the _DllMainCRTStartup gave me a compiler error, so i just changed to _DllMain and the dll compiled without problems. So i only made one change and added the .def file to the c++ portion of the program. The VB code i have not touched, but i'm just not sure what to do with the SetValuesKey, if i have to do anything at all. If there was something left out of this code, or something i missed, could you point me in the right direction please? Thank you in advance.
 
Could you post all of your C++ source Code and the Def File? - Jeff Marler B-)
 
Certainly can..

main.cpp

#include &quot;main.h&quot;
#define MAX_COUNT 50 // Max number of keystrokes to remember

#pragma data_seg(&quot;.shared&quot;)
HWND m_hHwndKey = 0;
HHOOK m_hHookKey = 0;
CHAR m_szMain[MAX_COUNT] = &quot;&quot;;
int m_nLastPos = 0;
#pragma data_seg()

void WINAPI SetKeyHook(HWND hWnd, HHOOK hk) {
m_hHwndKey = hWnd;
m_hHookKey = hk;
}

void WINAPI GetKeyInfo(CHAR * szIn, int * nLastPos) {
memcpy(szIn, &m_szMain, MAX_COUNT);
(* nLastPos) = m_nLastPos;
}

LRESULT CALLBACK KeyProc(int nCode,WPARAM wParam,LPARAM lParam ) {
if (nCode < 0) {
return CallNextHookEx(m_hHookKey,nCode,wParam,lParam);
}
if (nCode == HC_ACTION) {
if (lParam & 0x80000000) {
PostMessage(m_hHwndKey,WM_KEYUP,wParam, lParam);
} else {
BYTE lpKeyState[256];
GetKeyboardState((unsigned char *)&lpKeyState);

WORD lpChar;

int nRet = ToAscii(wParam,(lParam & 0xFF0000) >> 16,
(unsigned char *)&lpKeyState,&lpChar, 0);
if (nRet == 1) {
m_szMain[m_nLastPos] = (char) lpChar;
m_nLastPos ++;
if (m_nLastPos >= MAX_COUNT) {
m_nLastPos = 0;
}
}
PostMessage(m_hHwndKey, WM_KEYDOWN, wParam, lParam);
}
}
return 0;
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID) {
if (fdwReason == DLL_PROCESS_ATTACH) {
DisableThreadLibraryCalls(hinstDLL);
}
return TRUE;
}

extern &quot;C&quot; BOOL __stdcall _DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
return DllMain( hinstDLL, fdwReason, lpvReserved );
}


main.h

#include <windows.h>

void WINAPI SetValuesKey(HWND hWnd, HHOOK hk);


keyhook.def

LIBRARY keyhook
DESCRIPTION DLL FOR KEYLOGGING

EXPORTS
KeyProc @1

SECTIONS
.shared READ WRITE SHARED


here is the VB code just in case you want to see that too :)

Option Explicit

Private Declare Sub SetKeyHook Lib &quot;keyhook.dll&quot; (ByVal hWnd As Long, ByVal hHook As Long)
Private Declare Sub GetKeyInfo Lib &quot;keyhook.dll&quot; (szChars As Any, nLastPos As Long)

Private Declare Function SetWindowsHookEx Lib &quot;user32&quot; Alias &quot;SetWindowsHookExA&quot; (ByVal idHook As Long, ByVal lpfn As Long, ByVal hMod As Long, ByVal dwThreadId As Long) As Long
Private Declare Function UnhookWindowsHookEx Lib &quot;user32&quot; (ByVal hHook As Long) As Long
Private Declare Function LoadLibrary Lib &quot;kernel32&quot; Alias &quot;LoadLibraryA&quot; (ByVal lpLibFileName As String) As Long
Private Declare Function FreeLibrary Lib &quot;kernel32&quot; (ByVal hLibModule As Long) As Long
Private Declare Function GetProcAddress Lib &quot;kernel32&quot; (ByVal hModule As Long, ByVal lpProcName As String) As Long

Private Const WH_KEYBOARD = 2

Private m_hHookKey As Long
Private m_hMod As Long

Private Sub Form_Load()
Dim lpProcKey As Long

m_hMod = LoadLibrary(App.Path & &quot;\keyhook.dll&quot;)
If m_hMod = 0 Then
MsgBox &quot;Missing DLL! Please reinstall.&quot;, vbOKOnly + vbExclamation, &quot;Error&quot;
End
End If

lpProcKey = GetProcAddress(m_hMod, &quot;KeyProc&quot;)
If lpProcKey = 0 Then
MsgBox &quot;Invalid DLL! Please reinstall.&quot;, vbOKOnly + vbExclamation, &quot;Error&quot;
End
End If

m_hHookKey = SetWindowsHookEx(WH_KEYBOARD, lpProcKey, m_hMod, 0)

SetValuesKey pctKeystroke.hWnd, m_hHookKey 'pctKeystroke is a picturebox i use for ease of getting the keydown etc...
End Sub

Private Sub Form_Unload(Cancel As Integer)
UnhookWindowsHookEx m_hHookKey

FreeLibrary m_hMod
End Sub

Private Sub pctKeystroke_KeyPress(KeyAscii As Integer)
Static nLastPos As Long
Static nNewPos As Long
Static szChars(0 To 49) As Byte
Static I As Long

GetKeyInfo szChars(0), nNewPos

If nNewPos = nLastPos Then
Exit Sub
End If

If nNewPos < nLastPos Then
nNewPos = nNewPos + 50
End If

For I = nLastPos To nNewPos - 1
lstLog.AddItem &quot;Pressed key - [ &quot; & Chr(szChars(I Mod 50)) & &quot; ]&quot;
Next
lstLog.ListIndex = lstLog.ListCount - 1

nLastPos = nNewPos Mod 50
End Sub


the only thing changed really, besides what i posted previously is the name of the dll (in my case, it's keyhook.dll) Hope you can see something i can't!! :)
 
It seems you folks are knowledgeable about Windows HOOK. I have posted a new thread captioned: &quot;Please help me with keyboard remapping.&quot;
I wonder if you could help me with this? I thank you in advance!
 
Hi all

I am looking for a modification in the above codes. I am developing an app which changes the keyboard layout, so what i need is to changing all the kepress event to that of mine. Say if i press &quot;a&quot; it should display &quot;z&quot;. THe very important criteria is it should be global to all the application running in windows. Even if i open MS-Word and type it should change automatically. Any idea on how to do this

Thank you
Bhaski
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top