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
 
Come on guys, there is really nothing sinister about what I am trying to do here.

My situation:

I am working with two systems that sit side-by-side on my desk, trying to develop and test one application on both of them simultaneously. One of the systems is NT and the other is Win98. The app is designed to behave differently, depending on whether it is executed on a domain controller (the NT system) or a workstation (the Win98 system). I'm just trying to keep minor code revisions synchronized on both systems. Faced with the inevitable problems involved in editing one file with two copies of VB, I am maintaining a copy on both machines.

It just seemed a bit frustrating that I couldn't work on one machine, reach over to the other keyboard and press F5 to test it. Why couldn't I position the mouse cursor on both machines, start typing and have the new code show up on the other monitor? Why couldn't I copy to the clipboard on one computer and paste it into a module on the other?

That's when I started playing around with GetAsyncKeyState. I had hoped to use the function to intercept my keystrokes and then use Winsock to send them to the other computer. It wasn't a bad idea, but GetAsyncKeyState only returned uppercase characters and Winsock was terribly diasappointing. I ended up with a crude little routine that allowed me to highlight some text, press F11 and have the text automatically insert itself at the current cursor position on the other computer. It's a pretty handy little function but it isn't what I had in mind. I really wanted to mirror my keystrokes and, possibly, mouse actions on the other computer.

Once again... does anybody know a practical way to retrieve the true value of a key press when another application has the focus?

VCA.gif

Alt255@Vorpalcom.Intranets.com
 
Thanks, Mike. I've been digging, too, but I can't even find a &quot;hard way&quot; to do this with consistent results.

There *has* to be a way.
VCA.gif

Alt255@Vorpalcom.Intranets.com
 
I do similar things using 2 copies of VB runing on 2 monitors on 2 video cards on the one machine in Win98.
It is great for pasting between appls.
You can do most of the code in win 98 and only do the things that are different to the NT version when you switch to NT
 
Thanks for the response, Ted. I wish it was as simple as using one clipboard with two copies of VB... I guess, that is close to what I am doing now, except I am copying the clipboard across the network.

It just seemed that it would be more effective if I could send the individual keystrokes and mouse actions across the network, building mirror copies of the app that could be executed on demand. I can think of several other possible applications for the trick. Anybody else?
VCA.gif

Alt255@Vorpalcom.Intranets.com
 
Alt,

I (obviously) don't know enough to provide any actual help directly related to your inquiry.

But, I can't stop myself from asking the crude question(s). Why aren't you just using the conditional compilation function on a single copy of the code?



MichaelRed
mred@duvallgroup.com
There is never time to do it right but there is always time to do it over
 
Michael,

I am or, rather, will... it will be a while before I try to run this outside the VB IDE. I am trying to avoid coding on one copy and then compiling it to run on the other machine for the same reason I am trying to avoid copying the project directory back and forth. It takes too much time to test minor revisions that way.

But thanks for the reply.
VCA.gif

Alt255@Vorpalcom.Intranets.com
 
Alt,

O.K., but are you really saving time/effort? You are off the track of the 'mission' and pushing the envelope. Look at the time already invested in the 'work-around' as opposed to just using the tool embedded in the environment. I am not criticizing, just asking. I have a problem in this area - I often need to remind myself that the generation of the 'tool' needs to have a real 'pay-back'. And, it needs to be relatively quick and relatively large. I have done a fair ammount of contract/independent development. This has given me (at an extremely high cost!) a sensitivity to the issue/need for development to proceed on a path toward the &quot;end point objective&quot;, and the awareness of the cost of development of the 'tools'. Sometimes you just really NEED the tool. Other times, I just get started with a concept - and don't recognise the cost/benefit ratio just isn't there - untill I realise that I'm still doing the tool building but that the Job could have been finished if I had just done it 'by the book'.



MichaelRed
mred@duvallgroup.com
There is never time to do it right but there is always time to do it over
 
Excellent points, Michael. But I'm not obsessing on this one. My priorities for finding a simple solution are proportionate to my priorities for completing the project.

Thanks again.
VCA.gif

Alt255@Vorpalcom.Intranets.com
 
hello alt255,

i dont know if this reply is of any help,i dont have the setup of 2 comps.

i think sendkeys() function could be of some use here.i had used it to send whatever i typed to Notepad,but have never tried using it on a network.

aniket
 
Thanks, Aniket. Actually, I'm using sendkeys to insert the text at current cursor pos on the remote. My basic problem is detecting the correct keystroke locally.

Of course, if anybody knows a way to automate this process, then... pardon my projections but... may I assume you are God?
VCA.gif

Alt255@Vorpalcom.Intranets.com
 
Microsoft Visual Sourcesafe

I use this tool because I belong to a team of developers all busy on one project.

It works well for us.

(For those who don't know it comes free with VB Enterprise-
&amp; I think professional as well)
 
Hello:
I would like to know if you ever received a good solution
to the following:

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

I have used the GetAsyncKeyState API to recognized keystrokes in external applications. It works sporadically, but doesn't always recognise keystrokes unless they are pressed repititiously. Do you have a better resolution?
 
ronaldburdette,
The GetAsyncKeyState works sporadically because another process may clear the flag that is used to indicate that the key was pressed . . . its all in the timing and when you check a specific key.
I have always felt that a better method to monitor key presses is to install a hook in the specific process' mesage queue. There is also a way to monitor every keystroke for every process on the PC, but that requires some C++ code . . . not complicated though.

Alt255,
Are you still trying to get your original idea to work? - Jeff Marler B-)
 
I have a working version in C++... I found some code here and there and combined with Jeff's code I made this working piece :) Only one problem, which Jeff might (will ;-))actually fix is that it doesn't log the 'syskeys', like shift and ctrl and the F-keys and del, etc. I know it's possible, I even had it to work, but I screwed it up again and I'm really no good in C++ so please fix it! ;-)

And it would be neat if you tell me how to detect the difference between the keydown and the keyup event (to make visual basic know, when keydown and when keyup occured).

Here's the code I have so far (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 _DllMainCRTStartup( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
return DllMain( hinstDLL, fdwReason, lpvReserved );
}


and (main.h):


#include &quot;windows.h&quot;

void WINAPI SetValuesKey(HWND hWnd, HHOOK hk);


Enjoy Jeff, I would even more appreciate if you could give me a step by step tour through this code (I get the most of it though ;-))

LuCkY
 
LuckyLuke,

To determine if it is a key down, or a key up, you need to look to the end bit (2^31) of lParam on the call back function. Here is the BitMask that lParam returns with . . .


lParam Bit Mask
Bit 00-15 :: The Repeat Count.
Bit 16-23 :: The Scan Code.
Bit 24 :: Extended key. Set to 1 if the
key is an extended key;
otherwise, it is 0.
Bit 25-28 :: Reserved
Bit 29 :: The Context code. Set to 1 if
the ALT key is down;
otherwise, it is 0.
Bit 30 :: The Previous Key State. Set to
1 if the key was down before
the message is sent;
otherwise, it is 0 if the key
is up.
Bit 31 :: The transistion state. Set to
0 if the key is being pressed
and 1 if it is being released.





I'm off to work now, but when I get a chance, I'll glance at your code. - Jeff Marler B-)
 
OK, I had to look b4 I left . . . where in your code are you actually setting the message queue hook? Or maybe its there and I am just blind. For the hook to work correctly, you need a call to SetWindowsHookEx somewhere. Something like this . . .

============================================================

Code:
hHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, (HINSTANCE)m_hModule, 0 );

============================================================

If I had to guess from your code, I would say that you would want it in your exported SetKeyHook method. - Jeff Marler B-)
 
How are you directing your hook to use your KeyProc in the C++ code? Or are you using it at all? Post your VB code that pertains to the C++ code. - Jeff Marler B-)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top