Keyboard.cpp


/*
	$RCSfile: Keyboard.cpp $
	$Revision: 1.3 $
	$Author: doomer $
	$Date: 1997/10/12 01:03:44 $
	Copyright (c) 1996 John Dumais
*/

#include "KeyBoard.h"

/*
	A vector is a self-expanding data structure used to hold an
	unkown number of elements.
*/
static vector<short, allocator<short> > KeyStrokeVector;

/*
	This DLL installs a hook function to intercept keystroke events.
	The hook function is identified using a handle.
*/
static HHOOK kbdHook;

/*
	The window system call this entry point when a process or thread
	attaches or detaches the DLL.  We use this to erase our keystroke
	buffer and remove our keyboard hook when an application detaches
	the DLL.
*/
BOOL WINAPI DllMain(HMODULE hModule, DWORD reason, LPVOID reserved){
	BOOL returnVal=TRUE;

	switch(reason){
		case DLL_PROCESS_DETACH:
			KeyStrokeVector.erase(KeyStrokeVector.begin(),
								  KeyStrokeVector.end());
			if(kbdHook){
				UnhookWindowsHookEx(kbdHook);
			}
			
			break;
		default:
			break;
	}
	
	return returnVal;
}

/*
	Return the number of keystrokes we have buffered.
*/
long nKeyStrokes(){
	return KeyStrokeVector.size();
}

/*
	This function fills the supplied array with key codes.  The
	calling appication needs to allocate the array and indicate the
	number of elements the array is capable of holding.  This
	function will indicate the number of elements inserted into the
	supplied array (which can be less than or equal to the number of
	elements the array is capable of holding) by changing the value
	of the NArrayElements variable,
*/
long getKeyStrokes(short *keyStrokeArray, long *nArrayElements){
	long returnVal=0;
	long i;
	long nReturned=0;

	/*
		An iterator is an STL construct that allows you to traverse
		through a container, regardless of the data structures used
		to to implement the container.
	*/
	vector<short, allocator<short> >::iterator j=KeyStrokeVector.begin();
	vector<short, allocator<short> >::iterator last=j;

	for(i=0; (i < *nArrayElements) && (j != KeyStrokeVector.end());
		i++, j++){

		nReturned++;
		keyStrokeArray[i] = *j;
	}

	last += nReturned;
	KeyStrokeVector.erase(KeyStrokeVector.begin(), last);
	
	*nArrayElements=nReturned;
	
	return returnVal;
}

/*
	After you install a keyboard hook (by calling the
	recordKeyStrokes function), the window system will call this
	function each time you press a key while the calling application
	has the keyboard focus.  We check to see if the event has been
	caused by a key press event.  If so, we append the key code to
	the end of the buffer, ten pass the event on.
*/
LRESULT CALLBACK MyKeyboardProc(int code, WPARAM wParam, LPARAM lParam){
	if(code >= 0){
		if(!(lParam & (1L << 31))){ /* key is being pressed */
			KeyStrokeVector.push_back(wParam);
		}
	}

	return CallNextHookEx(kbdHook, code, wParam, lParam);
}

/*
	This function installs a keyboard hook, specifying that a
	function named MyKeyboardProc is to be called each time a key is
	pressed while the calling application has the keyboard focus.
*/
long recordKeyStrokes(){
	long returnVal=0;
	HMODULE hThisModule;

	if(!kbdHook){
		hThisModule=GetModuleHandle("KeyBoard");
		if(!hThisModule){
			return -1;
		}

		kbdHook=SetWindowsHookEx(WH_KEYBOARD, MyKeyboardProc, hThisModule,
						   GetCurrentThreadId());
		if(!kbdHook){
			returnVal = -1;
		}
	}

	return returnVal;
}

/*
	This function removes our keyboard hook and erases the contents
	of our keystroke buffer.
*/
long stopRecording(){
	long returnVal=0;

	if(kbdHook){
		if(UnhookWindowsHookEx(kbdHook)){
			kbdHook=(HHOOK)0;
			KeyStrokeVector.erase(KeyStrokeVector.begin(),
								  KeyStrokeVector.end());
		}
		else{
			returnVal = -1;
		}
	}

	return returnVal;
}

/*
	$Log: Keyboard.cpp $
	Revision 1.3  1997/10/12 01:03:44  doomer
	comments.
	Revision 1.2  1996/10/23 03:09:24  doomer
	in recordKeyStrokes(), put in a check to prevent calling SetWindowsHookEx()
	if we already have a hook installed.
	Revision 1.1  1996/10/21 02:36:00  doomer
	Initial revision
*/