Click Here!
home account info subscribe login search My ITKnowledge FAQ/help site map contact us


 
Brief Full
 Advanced
      Search
 Search Tips
To access the contents, click the chapter and section titles.

Fast Track Visual C++ 6.0 Programming
(Publisher: John Wiley & Sons, Inc.)
Author(s): Steve Holzner
ISBN: 0471312908
Publication Date: 09/01/98

Bookmark It

Search this book:
 
Previous Table of Contents Next


Storing KeyDown and KeyUp Messages

We handle WM_KEYDOWN messages first.

LRESULT CALLBACK RecordProcedure(int nCode, WPARAM wParam, LPARAM lParam){

    LRESULT Result = CallNextHookEx(Hook, nCode, wParam, lParam);

    if (nCode != HC_ACTION)
        return(Result);

    if(((PEVENTMSG) lParam)->message == WM_KEYDOWN){               ⇐
        .
        .
        .
    }                                                              ⇐

If this is indeed a WM_KEYDOWN event, we store it in an array of events named EventArray[].

// JournalView.cpp : implementation of the CJournalView class
//

#include ”stdafx.h”
#include ”Journal.h”

#include ”JournalDoc.h”


Other Event Types

Although we’re storing WM_KEYDOWN and WM_KEYUP events only, you can use journal hooks for just about any type of system-wide event.


#include ”JournalView.h”

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

HHOOK Hook;
EVENTMSG EventArray[2048];                        ⇐
    .
    .
    .

We store the EVENTMSG structure pointed to by lParam in this array, increment the number of recorded events, and set the value passed back to Windows to 0, indicating that we’ve handled the event.

LRESULT CALLBACK RecordProcedure(int nCode, WPARAM wParam, LPARAM lParam){

    LRESULT Result = CallNextHookEx(Hook, nCode, wParam, lParam);

    if (nCode != HC_ACTION)
        return(Result);

    if(((PEVENTMSG) lParam)->message == WM_KEYDOWN){                  ⇐
        EventArray[RecordedEvents++] = *((PEVENTMSG) lParam);          ⇐
        Result = 0;                                                    ⇐
    }                                                                   ⇐

We record WM_KEYUP messages in the same way.

LRESULT CALLBACK RecordProcedure(int nCode, WPARAM wParam, LPARAM lParam){

    LRESULT Result = CallNextHookEx(Hook, nCode, wParam, lParam);

    if (nCode != HC_ACTION)
        return(Result);

    if(((PEVENTMSG) lParam)->message == WM_KEYDOWN){
        EventArray[RecordedEvents++] = *((PEVENTMSG) lParam);
        Result = 0;
    }

    if(((PEVENTMSG) lParam)->message == WM_KEYUP){                     ⇐
        EventArray[RecordedEvents++] = *((PEVENTMSG) lParam);          ⇐
        Result = 0;                                                    ⇐
    }                                                                  ⇐

Finally, we check to see if we’ve recorded as many events as we’ve put aside space for in the EventArray[] array. If so, unhook the hook with UnhookWindowsHookEx() to make sure we don’t go past our allocated memory. We also return the result we’ve set to Windows.

LRESULT CALLBACK RecordProcedure(int nCode, WPARAM wParam, LPARAM lParam){

    LRESULT Result = CallNextHookEx(Hook, nCode, wParam, lParam);

    if (nCode != HC_ACTION)
        return(Result);

    if(((PEVENTMSG) lParam)->message == WM_KEYDOWN){
        EventArray[RecordedEvents++] = *((PEVENTMSG) lParam);
        Result = 0;
    }

    if(((PEVENTMSG) lParam)->message == WM_KEYUP){
        EventArray[RecordedEvents++] = *((PEVENTMSG) lParam);
        Result = 0;
    }

    if (RecordedEvents >= 2048)                      ⇐
        UnhookWindowsHookEx(Hook);                     ⇐

    return(Result);                                    ⇐
}

That completes the recording process. Next, we play the keystrokes back in PlayProcedure().

Playing Events Back

When the user plays keystrokes back, we execute the code in the PlayProcedure() function that we’re about to write. Add its prototype to our project now.

// JournalView.h : interface of the CJournalView class
//
/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_JOURNALVIEW_H__6433B67B_A86C_11D1_887F_D42B07C10710__INCLUDED_)
#define AFX_JOURNALVIEW_H__6433B67B_A86C_11D1_887F_D42B07C10710__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
LRESULT CALLBACK RecordProcedure(int nCode, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK PlayProcedure(int nCode, WPARAM wParam, LPARAM lParam);    ⇐
    .
    .
    .

As we did in RecordProcedure(), we start PlayProcedure() by calling the next hook in the chain, if there is one, using CallNextHookEx().

LRESULT CALLBACK PlayProcedure(int nCode, WPARAM wParam, LPARAM lParam){

    LRESULT Result = CallNextHookEx(Hook, nCode, wParam, lParam);          ⇐
        .
        .
        .

We have to watch out for two event codes when playing back events: HC_GETNEXT and HC_SKIP.

When PlayProcedure() is called with HC_GETNEXT, we should pass the next event we’re playing back to Windows by placing a pointer to that event’s EVENTMSG structure in lParam. When we get an HC_SKIP code, Windows is notifying us to skip to the next event and to get ready to play that one back. We start by handling the HC_GETNEXT code.

Playing Back an Event

To play back an event, we first make sure the event code passed to us is HC_GETNEXT.

LRESULT CALLBACK PlayProcedure(int nCode, WPARAM wParam, LPARAM lParam){

    LRESULT Result = CallNextHookEx(Hook, nCode, wParam, lParam);

    switch(nCode){                      ⇐
        case HC_GETNEXT:                ⇐
            .
            .
            .

If so, we should play back an event. You may recall that one of the members of the EVENTMSG structure holds the time the event occurred. The time we’ve recorded is the time the key was originally struck, which might have been some time ago, so we reset that time member to the current time with the GetTick-Count() function (Windows event times are stored in timer ticks) in case the program we’re playing keystrokes into relies on the time in some way.

LRESULT CALLBACK PlayProcedure(int nCode, WPARAM wParam, LPARAM lParam){

    LRESULT Result = CallNextHookEx(Hook, nCode, wParam, lParam);

    switch(nCode){
        case HC_GETNEXT:
            EventArray[PlayedEvents].time = GetTickCount();        ⇐
                   .
                   .
                   .

Next, we “play back” the event by copying it to the location the point in lParam points to, then set the result of PlayProcedure() to 0, indicating we’ve handled the call.

LRESULT CALLBACK PlayProcedure(int nCode, WPARAM wParam, LPARAM lParam){

    LRESULT Result = CallNextHookEx(Hook, nCode, wParam, lParam);

    switch(nCode){
        case HC_GETNEXT:
            EventArray[PlayedEvents].time = GetTickCount();
            *((PEVENTMSG) lParam) = EventArray[PlayedEvents];          ⇐
            Result = 0;                                                ⇐
            break;                                                     ⇐
              .
              .
              .

We’ve played back the event. The next step is to handle the HC_SKIP event code, which means we should skip to the next event.

Skipping to the Next Event

If we get an HC_SKIP event code, we should skip on to the next event to play back. We do that simply by incrementing our PlayedEvents index.

LRESULT CALLBACK PlayProcedure(int nCode, WPARAM wParam, LPARAM lParam){

    LRESULT Result = CallNextHookEx(Hook, nCode, wParam, lParam);

    switch(nCode){
        case HC_GETNEXT:
            EventArray[PlayedEvents].time = GetTickCount();
            *((PEVENTMSG) lParam) = EventArray[PlayedEvents];
            Result = 0;
            break;

        case HC_SKIP:                        ⇐
            PlayedEvents++;                  ⇐
            Result = 0;                      ⇐
            break;                           ⇐
    }
    .
    .
    .


Previous Table of Contents Next


Products |  Contact Us |  About Us |  Privacy  |  Ad Info  |  Home

Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc.
All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.