It might go something like in this...
EXE
EXE
EXE
EXE
EXE
EXE
EXE
EXE
EXE
EXE
EXE
EXE
#include <afxwin.h>// MFC core and standard components
#include "resource.h"// UI ID's
#include "hookDLL.h"// Idle UI DLL
static const UINT DLL_MESSAGE=::RegisterWindowMessage(_T
("DLL_MESSAGE"));
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#endif
class CMyApp: public CWinApp
{// CMyApp
public:
CMyApp() {}
virtual BOOL InitInstance();
virtual int ExitInstance();
protected:
//{{AFX_MSG(CMyApp)
afx_msg void OnAppAbout();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
}// CMyApp
;
class CMainFrame: public CFrameWnd
{// Main frame window sets timer and paints message of how long UI
has been idle.
public:
CMainFrame() {}
virtual ~CMainFrame() {}
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
DECLARE_DYNCREATE(CMainFrame)
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnPaint();
//afx_msg void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
afx_msg LRESULT OnDllMessage(WPARAM wParam,LPARAM lParam);
}// Main frame window sets timer and paints message of how long UI
has been idle
;
CMyApp theApp;
BEGIN_MESSAGE_MAP(CMyApp,CWinApp)
//{{AFX_MSG_MAP(CMyApp)
ON_COMMAND(ID_APP_ABOUT,OnAppAbout)
//}}AFX_MSG_MAP
ON_COMMAND(ID_FILE_NEW,CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN,CWinApp::OnFileOpen)
END_MESSAGE_MAP()
BOOL CMyApp::InitInstance()
{// App is starting up: initialize hookDLL DLL and load main window
if(!hookDLLInit())
{// Initialize DLL
AfxMessageBox(_T("Error initializing DLL -- Aborting"));
return FALSE;
}// Initialize DLL
// Create main frame and show it
CMainFrame* pMainFrame=new CMainFrame;
if(!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
m_pMainWnd=pMainFrame;
return TRUE;
}// App is starting up: initialize hookDLL DLL and load main window
int CMyApp::ExitInstance()
{// Application shutting down: terminate idle time DLL
hookDLLTerm(); // terminate DLL (unhook)
return CWinApp::ExitInstance();
}// Application shutting down: terminate idle time DLL
void CMyApp::OnAppAbout()
{// Run About dialog
CDialog(IDD_ABOUTBOX).DoModal();
}// Run About dialog
IMPLEMENT_DYNCREATE(CMainFrame,CFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame,CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_WM_PAINT()
//ON_WM_TIMER()
//}}AFX_MSG_MAP
ON_REGISTERED_MESSAGE(DLL_MESSAGE,&CMainFrame::OnDllMessage)
END_MESSAGE_MAP()
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{// Before creating window, set size to something reasonable
BOOL bRet=CFrameWnd::PreCreateWindow(cs);
cs.cx=610;
cs.cy=513;
return bRet;
}// Before creating window, set size to something reasonable
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{// Create main window: set a timer
if(CFrameWnd::OnCreate(lpCreateStruct)==-1)
return -1;
//SetTimer(1, 1000, NULL);// 1000 msec = 1 second
return 0;
}// Create main window: set a timer
void CMainFrame::OnPaint()
{// Paint: paint message showing number of seconds idle
CPaintDC dc(this);
//DWORD nsec=(GetTickCount()-hookDLLGetLastInputTime())/1000;
//CString s;
//s.Format("No mouse or keyboard input for %d seconds.",nsec);
SetTextColor(dc,GetSysColor(COLOR_WINDOWTEXT));
SetBkColor(dc,GetSysColor(COLOR_WINDOW));
CString s
(
"This is a macro/text recorder for Vocola 2, to help write your
scripts. It's especially useful for recording mouse actions.\r\n"
"\r\n"
"The numeric keypad must be OFF while recording. You may use the
keypad normally while not recording. But to benefit from saving and
restoring the pointer position (and other stuff), keep this program
running.\r\n"
"\r\n"
"To start recording, press keypad Delete/point.\r\n"
"To stop recording, press keypad Delete/point again.\r\n"
"You should hear a sound when recording starts or stops.\r\n"
"After that, your recorded actions are in the clipboard, ready
for pasting.\r\n"
"\r\n"
"Recording mouse actions is logical. If you want to record a
click without positioning, don't move the mouse before the click
(after the last action). To record a point and click relative to the
current window, hold Alt while clicking. All dragging is recorded
relative to the button down position.\r\n"
"\r\n"
"For further explanation, ask in the forums.\r\n"
"\r\n"
"This is extra...\r\n"
"\r\n"
"While recording, the keypad number keys (0-9, excluding delete)
provide additional functions while recording. To see the list is of
functions by starting a recording and pressing the keys one after
another, then stop the recording and paste the results. Another set
of functions is available by holding control/Ctrl while pressing the
same numbers. "
);
CRect rc;
GetClientRect(&rc);
dc.DrawText(s,&rc,DT_LEFT|DT_VCENTER|DT_WORDBREAK);
}// Paint: paint message showing number of seconds idle
//void CMainFrame::OnTimer(UINT nIDEvent)
//{// Got timer click: refresh
// Invalidate(); //
invalidate
// UpdateWindow(); // force repaint
//}// Got timer click: refresh
afx_msg LRESULT CMainFrame::OnDllMessage(WPARAM wParam,LPARAM
lParam)
{
INPUT input[2];
input[0].type=INPUT_MOUSE;
input[0].mi.dwFlags=MOUSEEVENTF_LEFTDOWN;
input[0].mi.mouseData=0L;
input[0].mi.time=0L;
input[0].mi.dwExtraInfo=0L;
input[1].type=INPUT_MOUSE;
input[1].mi.dwFlags=MOUSEEVENTF_LEFTUP;
input[1].mi.mouseData=0L;
input[1].mi.time=0L;
input[1].mi.dwExtraInfo=0L;
SendInput(1,&input[0],sizeof(input[0]));
SendInput(1,&input[1],sizeof(input[1]));
Sleep(40);
SendInput(1,&input[0],sizeof(input[0]));
SendInput(1,&input[1],sizeof(input[1]));
Beep(1300,100);
return 0;
}
EXE
EXE
EXE
EXE
EXE
EXE
EXE
EXE
EXE
EXE
EXE
EXE
DLL
DLL
DLL
DLL
DLL
DLL
DLL
DLL
DLL
DLL
DLL
DLL
#include <afxwin.h>// MFC core and standard components
#include <mmsystem.h>
#include "definitions.h"
static const UINT DLL_MESSAGE=::RegisterWindowMessage(_T
("DLL_MESSAGE"));
#define DLLEXPORT __declspec(dllexport)
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#endif
class ChookEXEDll: public CWinApp
{// App object for this DLL
public:
ChookEXEDll() {}
~ChookEXEDll() {}
}// App object for this DLL
theDll;// one-and-only, normal (per-process) static global
// The following global data is SHARED among all instances of the
DLL
// (processes); i.e., these are system-wide globals
#pragma data_seg (".hookDLL")// you must define as SHARED in .def
//DWORD g_dwLastInputTick=0;// tick time of last input event
HHOOK g_hHookKbd=NULL;// one instance for all processes
HHOOK g_hHookMouse=NULL;// one instance for all processes
HWND WindowHandle=NULL;
POINT CurrentPoint={};
POINT DnContextPoint={};
POINT DnScreenPoint={};
POINT RecPosPointer={};
POINT UpContextPoint={};
POINT UpScreenPoint={};
RECT WindowBorder={};
bool AfterFirstUpAction=true;
bool MouseDouble=false;
bool MouseDown=false;
bool Mouseshifted=false;
bool Printable=false;
bool Recording=false;
char BtnName[16]={};
char BtnNumber[2]={};
char ClickContext[32]={};
char Coordinate[8]={};
char KeyName[16]={};
char NumPad[16]={};
char PointDn[16]={};
char PointUp[16]={};
char Modifier[24]={};
char Script[10240]={};
char ScriptLine[280]={};
char SoundFolder[256]={};
char SoundPathError[280]={};
char SoundPathNotice[280]={};
char SoundPathStart[280]={};
char SoundPathStop[280]={};
char StringOut[256]={};
char TitleBar1[256]={};
char TitleBar2[256]={};
int LastParentheses=')';
#pragma data_seg ()
//DLLEXPORT DWORD hookDLLGetLastInputTime()
//{// Get tick count of last keyboard or mouse event
// return g_dwLastInputTick;
//}// Get tick count of last keyboard or mouse event
LRESULT CALLBACK MyKbdHook(int nCode,WPARAM wParam,LPARAM lParam)
{//key action
if(UnknownAction)
{//K, unusable message
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//K, unusable message
//g_dwLastInputTick=GetTickCount();
if(!Extended)
{//K, keypad
switch(wParam)
{//K-NEX, seek the key
case Pad0Insert://global double-click
{//K-NEX-SEK, macro key
if(KeyUp)
{//K-NEX-SEK-MAC, eat upstroke
return 1;
}//K-NEX-SEK-MAC, eat upstroke
if(KeyWasDn)
{//K-NEX-SEK-MAC, eat repeat stroke
return 1;
}//K-NEX-SEK-MAC, eat repeat stroke
else
{//K-NEX-SEK-MAC, downstroke=double-click
PostMessage(FindWindow
(NULL,"hookEXE"),DLL_MESSAGE,wParam,lParam);
return 1;
}//K-NEX-SEK-MAC, downstroke=double-click
}//K-NEX-SEK, macro key
case PadPDelete:
{//K-NEX-SEK, designated start/stop control key
if(KeyUp)
{//K-NEX-SEK-CON, upstroke
if(Recording)
{//K-NEX-SEK-CON-UP, stop recording in progress
Recording=false;
if(MouseDown)
{//K-NEX-SEK-CON-UP-END, voiced "G" (button down from
script)
strcat(Script," Keys.SendInput({leftbutton_hold})
WAIT(1) \n");
}//K-NEX-SEK-CON-UP-END, voiced "G" (button down from
script)
if(OpenClipboard(NULL))
{//K-NEX-SEK-CON-UP-END, place script in clipboard
OutputDebugString("SCRIPT\n");
OutputDebugString(Script);
OutputDebugString("END\n");
HGLOBAL clipbuffer;
char *buffer;
EmptyClipboard();
clipbuffer=GlobalAlloc(GMEM_DDESHARE,strlen(Script)+
1);
buffer=(char*)GlobalLock(clipbuffer);
strcpy(buffer,Script);
GlobalUnlock(clipbuffer);
SetClipboardData(CF_TEXT,clipbuffer);
CloseClipboard();
PlaySound(SoundPathStop,NULL,SND_FILENAME|SND_ASYNC);
}//K-NEX-SEK-CON-UP-END, place script in clipboard
else
{//K-NEX-SEK-CON-UP-END, error opening clipboard
PlaySound(SoundPathError,NULL,SND_FILENAME|SND_ASYNC);
}//K-NEX-SEK-CON-UP-END, error opening clipboard
}//K-NEX-SEK-CON-UP, stop recording in progress
else
{//K-NEX-SEK-CON-UP, start recording
Recording=true;
AfterFirstUpAction=true;
MouseDown=false;
GetCursorPos(&UpScreenPoint);
WindowHandle=GetForegroundWindow();
GetWindowText(WindowHandle,TitleBar1,255);
*Script='\0';
*TitleBar2='\0';
PlaySound(SoundPathStart,NULL,SND_FILENAME|SND_ASYNC);
}//K-NEX-SEK-CON-UP, start recording
}//K-NEX-SEK-CON, upstroke
return 1;//eat ctrl strokes
}//K-NEX-SEK, designated start/stop control key
}//K-NEX, seek the key
}//K, keypad
if(Recording)
{//K, recording in progress
if(!KeyUp)
{//K-R, key is down
if(KeyWasDn)
{//K-R-DN, eat repeat strokes
return 1;
}//K-R-DN, eat repeat strokes
}//K-R, key is down
if(Mouseshifted)
{//K-R, shift upstroke after modified click
Mouseshifted=false;
strcat(Script," Keys.SendInput({shift_release}) WAIT(1) \n");
GetCursorPos(&CurrentPoint);
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//K-R, shift upstroke after modified click
*NumPad='\0';
if(!Extended)
{//K-R, not extended
if(GetKeyState(VK_CONTROL)&0x8000)
{//K-R-NEX, modified by control
switch(wParam)
{//K-R-NEX-MOD, seeking numpad keys
case Pad0Insert:
if(KeyUp)
{//K-R-NEX-NOD-SEK-PAD, upstroke
//for double click
break;
}//K-R-NEX-NOD-SEK-PAD, upstroke
return 1;//eat all numpad strokes
case Pad1End:
strcat(NumPad,"10");
break;
case Pad2Dn:
strcat(NumPad,"20");
break;
case Pad3PgDn:
strcat(NumPad,"40");
break;
case Pad4Left:
strcat(NumPad,"80");
break;
case Pad5Clear:
strcat(NumPad,"160");
break;
case Pad6Right:
strcat(NumPad,"320");
break;
case Pad7Home:
strcat(NumPad,"640");
break;
case Pad8Up:
strcat(NumPad,"1280");
break;
case Pad9PgUp:
strcat(NumPad,"2560");
break;
}//K-R-NEX-MOD, seeking numpad keys
if(*NumPad)
{//K-R-NEX-MOD, function key
if(KeyUp)
{//K-R-NEX-MOD-NUM, upstroke
AfterFirstUpAction=true;
strcat(Script," Wait(");
strcat(Script,NumPad);
strcat(Script,") WAIT(1) \n");
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
}//K-R-NEX-MOD-NUM, upstroke
return 1;//eat all function keystrokes
}//K-R-NEX-MOD, function key
}//K-R-NEX, modified by control
else
{//K-R-NEX, unmodified
switch(wParam)
{//K-R-NEX-NOD, seeking numpad keys
case Pad0Insert:
if(KeyUp)
{//K-R-NEX-NOD-SEK-PAD, upstroke
strcat(Script," #unmodified keypad 0 is unused \n");
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
}//K-R-NEX-NOD-SEK-PAD, upstroke
return 1;//eat all numpad strokes
case Pad1End:
if(KeyUp)
{//K-R-NEX-NOD-SEK-PAD, upstroke, record current position
strcat(Script," Keys.SendInput({scrolllock}) WAIT(1)
#store pointer position \n");
GetCursorPos(&RecPosPointer);
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
}//K-R-NEX-NOD-SEK-PAD, upstroke, record current position
return 1;//eat all numpad strokes
case Pad2Dn:
if(KeyUp)
{//K-R-NEX-NOD-SEK-PAD, upstroke
GetCursorPos(&CurrentPoint);
strcat(Script," SetMousePosition(0,");
strcat(Script,_ltoa(CurrentPoint.x,Coordinate,10));
strcat(Script,",");
strcat(Script,_ltoa(CurrentPoint.y,Coordinate,10));
strcat(Script,") WAIT(1) #from recording \n");
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
}//K-R-NEX-NOD-SEK-PAD, upstroke
return 1;//eat all numpad strokes
case Pad3PgDn:
if(KeyUp)
{//K-R-NEX-NOD-SEK-PAD, upstroke
strcat(Script," Keys.SendInput({ctrl+scrolllock}) WAIT
(1) #restore pointer position \n");
SetCursorPos(RecPosPointer.x,RecPosPointer.y);
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
}//K-R-NEX-NOD-SEK-PAD, upstroke
return 1;//eat all numpad strokes
case Pad4Left:
if(KeyUp)
{//K-R-NEX-NOD-SEK-PAD, upstroke
strcat(Script," PlaySound(\"D:\\files\\wav\\special
effects\\beep1.wav\") WAIT(1) \n");
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
}//K-R-NEX-NOD-SEK-PAD, upstroke
return 1;//eat all numpad strokes
case Pad5Clear:
if(KeyUp)
{//K-R-NEX-NOD-SEK-PAD, upstroke
strcat(Script," PlaySound(\"D:\\files\\wav\\special
effects\\whadok1.wav\") WAIT(1) \n");
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
}//K-R-NEX-NOD-SEK-PAD, upstroke
return 1;//eat all numpad strokes
case Pad6Right:
if(KeyUp)
{//K-R-NEX-NOD-SEK-PAD, upstroke
strcat(Script," PlaySound(\"D:\\files\\wav\\special
effects\\boop.wav\") WAIT(1) \n");
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
}//K-R-NEX-NOD-SEK-PAD, upstroke
return 1;//eat all numpad strokes
case Pad7Home:
if(KeyUp)
{//K-R-NEX-NOD-SEK-PAD, upstroke
strcat(Script," Keys.SendInput({shift_hold}) WAIT(1)
\n");
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
}//K-R-NEX-NOD-SEK-PAD, upstroke
return 1;//eat all numpad strokes
case Pad8Up:
if(KeyUp)
{//K-R-NEX-NOD-SEK-PAD, upstroke
strcat(Script," #unmodified keypad 8 is unused \n");
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
}//K-R-NEX-NOD-SEK-PAD, upstroke
return 1;//eat all numpad strokes
case Pad9PgUp:
if(KeyUp)
{//K-R-NEX-NOD-SEK-PAD, upstroke
strcat(Script," Keys.SendInput({shift_release}) WAIT(1)
\n");
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
}//K-R-NEX-NOD-SEK-PAD, upstroke
return 1;//eat all numpad strokes
}//K-R-NEX-NOD, seeking numpad keys
}//K-R-NEX, unmodified
}//K-R, not extended
if(KeyUp)
{//K-R, upstroke
if(AfterFirstUpAction)
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
AfterFirstUpAction=true;
*Modifier='\0';
if(GetKeyState(VK_CONTROL)&0x8000)
strcat(Modifier,"ctrl+");
if(GetKeyState(VK_MENU)&0x8000)
strcat(Modifier,"alt+");
if(GetKeyState(VK_SHIFT)&0x8000)
strcat(Modifier,"shift+");
*KeyName='\0';
Printable=false;
switch(wParam)
{//K-R-UP-SW
case 0x08://8, REC
strcat(KeyName,"BackSpace");
break;
case 0x09://9, REC
strcat(KeyName,"Tab");
break;
case 0x0D://13, REC
strcat(KeyName,"Enter");
break;
case 0x13://19, REC
strcat(KeyName,"Break");
break;
case 0x14://20, REC
strcat(KeyName,"CapsLock");
break;
case 0x1B://27, REC
strcat(KeyName,"Esc");
break;
case 0x20://32, REC
strcat(KeyName," ");
Printable=true;
break;
case 0x21://33, REC
strcat(KeyName,"PgUp");
break;
case 0x22://34, REC
strcat(KeyName,"PgDn");
break;
case 0x23://35, REC
strcat(KeyName,"End");
break;
case 0x24://36, REC
strcat(KeyName,"Home");
break;
case 0x25://37, REC
strcat(KeyName,"Left");
break;
case 0x26://38, REC
strcat(KeyName,"Up");
break;
case 0x27://39, REC
strcat(KeyName,"Right");
break;
case 0x28://40, REC
strcat(KeyName,"Down");
break;
case 0x2C://44, REC
strcat(KeyName,"PrintScreen");
break;
case 0x2D://45, REC
strcat(KeyName,"Insert");
break;
case 0x2E://46, REC
strcat(KeyName,"Del");
break;
case 0x30://48, REC
strcat(KeyName,"0");
Printable=true;
break;
case 0x31://49, REC
strcat(KeyName,"1");
Printable=true;
break;
case 0x32://50, REC
strcat(KeyName,"2");
Printable=true;
break;
case 0x33://51, REC
strcat(KeyName,"3");
Printable=true;
break;
case 0x34://52, REC
strcat(KeyName,"4");
Printable=true;
break;
case 0x35://53, REC
strcat(KeyName,"5");
Printable=true;
break;
case 0x36://54, REC
strcat(KeyName,"6");
Printable=true;
break;
case 0x37://55, REC
strcat(KeyName,"7");
Printable=true;
break;
case 0x38://56, REC
strcat(KeyName,"8");
Printable=true;
break;
case 0x39://57, REC
strcat(KeyName,"9");
Printable=true;
break;
case 0x41://65, REC
strcat(KeyName,"a");
Printable=true;
break;
case 0x42://66, REC
strcat(KeyName,"b");
Printable=true;
break;
case 0x43://67, REC
strcat(KeyName,"c");
Printable=true;
break;
case 0x44://68, REC
strcat(KeyName,"d");
Printable=true;
break;
case 0x45://69, REC
strcat(KeyName,"e");
Printable=true;
break;
case 0x46://70, REC
strcat(KeyName,"f");
Printable=true;
break;
case 0x47://71, REC
strcat(KeyName,"g");
Printable=true;
break;
case 0x48://72, REC
strcat(KeyName,"h");
Printable=true;
break;
case 0x49://73, REC
strcat(KeyName,"i");
Printable=true;
break;
case 0x4A://74, REC
strcat(KeyName,"j");
Printable=true;
break;
case 0x4B://75, REC
strcat(KeyName,"k");
Printable=true;
break;
case 0x4C://76, REC
strcat(KeyName,"l");
Printable=true;
break;
case 0x4D://77, REC
strcat(KeyName,"m");
Printable=true;
break;
case 0x4E://78, REC
strcat(KeyName,"n");
Printable=true;
break;
case 0x4F://79, REC
strcat(KeyName,"o");
Printable=true;
break;
case 0x50://80, REC
strcat(KeyName,"p");
Printable=true;
break;
case 0x51://81, REC
strcat(KeyName,"q");
Printable=true;
break;
case 0x52://82, REC
strcat(KeyName,"r");
Printable=true;
break;
case 0x53://83, REC
strcat(KeyName,"s");
Printable=true;
break;
case 0x54://84, REC
strcat(KeyName,"t");
Printable=true;
break;
case 0x55://85, REC
strcat(KeyName,"u");
Printable=true;
break;
case 0x56://86, REC
strcat(KeyName,"v");
Printable=true;
break;
case 0x57://87, REC
strcat(KeyName,"w");
Printable=true;
break;
case 0x58://88, REC
strcat(KeyName,"x");
Printable=true;
break;
case 0x59://89, REC
strcat(KeyName,"y");
Printable=true;
break;
case 0x5A://90, REC
strcat(KeyName,"z");
Printable=true;
break;
case 0x5B://91, REC
strcat(KeyName,"Win");
break;
case 0x5C://92, REC
strcat(KeyName,"Win");
break;
case 0x5D://93, REC
strcat(KeyName,"Apps");
break;
case 0x61://97, REC
strcat(KeyName,"NumKey1");
Printable=true;
break;
case 0x62://98, REC
strcat(KeyName,"NumKey2");
Printable=true;
break;
case 0x63://99, REC
strcat(KeyName,"NumKey3");
Printable=true;
break;
case 0x64://100, REC
strcat(KeyName,"NumKey4");
Printable=true;
break;
case 0x65://101, REC
strcat(KeyName,"NumKey5");
Printable=true;
break;
case 0x66://102, REC
strcat(KeyName,"NumKey6");
Printable=true;
break;
case 0x67://103, REC
strcat(KeyName,"NumKey7");
Printable=true;
break;
case 0x68://104, REC
strcat(KeyName,"NumKey8");
Printable=true;
break;
case 0x69://105, REC
strcat(KeyName,"NumKey9");
Printable=true;
break;
case 0x70://112, REC
strcat(KeyName,"F1");
break;
case 0x71://113, REC
strcat(KeyName,"F2");
break;
case 0x72://114, REC
strcat(KeyName,"F3");
break;
case 0x73://115, REC
strcat(KeyName,"F4");
break;
case 0x74://116, REC
strcat(KeyName,"F5");
break;
case 0x75://117, REC
strcat(KeyName,"F6");
break;
case 0x76://118, REC
strcat(KeyName,"F7");
break;
case 0x77://119, REC
strcat(KeyName,"F8");
break;
case 0x78://120, REC
strcat(KeyName,"F9");
break;
case 0x79://121, REC
strcat(KeyName,"F10");
break;
case 0x7A://122, REC
strcat(KeyName,"F11");
break;
case 0x7B://123, REC
strcat(KeyName,"F12");
break;
case 0x90://144, REC
strcat(KeyName,"NumLock");
break;
case 0xBA://186, REC
strcat(KeyName,";");
Printable=true;
break;
case 0xBB://187, REC
strcat(KeyName,"=");
Printable=true;
break;
case 0xBC://188, REC
strcat(KeyName,",");
Printable=true;
break;
case 0xBD://189, REC
strcat(KeyName,"-");
Printable=true;
break;
case 0xBE://190, REC
strcat(KeyName,".");
Printable=true;
break;
case 0xBF://191, REC
strcat(KeyName,"/");
Printable=true;
break;
case 0xDB://219, REC
strcat(KeyName,"[");
Printable=true;
break;
case 0xDC://220, REC
strcat(KeyName,"\\");
Printable=true;
break;
case 0xDD://221, REC
strcat(KeyName,"]");
Printable=true;
break;
case 0xDE://222, REC
strcat(KeyName,"'");
Printable=true;
break;
default:
{//upstroke unknown
PlaySound
(SoundPathError,NULL,SND_FILENAME|SND_ASYNC);
return::CallNextHookEx
(g_hHookKbd,nCode,wParam,lParam);
}//upstroke unknown
}//K-R-UP-SW
if(*KeyName)
{//K-R-UP, regular key
if(Printable&&!*Modifier)
{//K-R-UP-REG, unmodified printable
strcat(Script," \"");
strcat(Script,KeyName);
strcat(Script,"\" WAIT(1) \n");
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//K-R-UP-REG, unmodified printable
else
{//K-R-UP-REG, modified or unprintable
strcat(Script," {");
if(*Modifier)
strcat(Script,Modifier);
strcat(Script,KeyName);
strcat(Script,"} WAIT(1) \n");
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//K-R-UP-REG, modified or unprintable
}//K-R-UP, regular key
}//K-R, upstroke
else
{//K-R, downstroke, prepare to process next upstroke
AfterFirstUpAction=false;
WindowHandle=GetForegroundWindow();
//check for new window
GetWindowText(WindowHandle,TitleBar2,255);
if(strcmp(TitleBar1,TitleBar2))
{//K-R-DN, different window
strcpy(TitleBar1,TitleBar2);
if(strcmp(TitleBar2,"Task Switching"))
{//K-R-DN-DIF, normal window
if(strcmp(TitleBar2,""))
{//K-R-DN-DIF-NRM, has title
strcat(Script," WaitForWindow(\"");
strcat(Script,TitleBar2);
strcat(Script,"\") WAIT(1) \n");
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//K-R-DN-DIF-NRM, has title
}//K-R-DN-DIF, normal window
else
{//K-R-DN-DIF, task switching
strcat(Script," SendSystemKeys({alt+Tab}) WAIT(1) \n");
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//K-R-DN-DIF, task switching
}//K-R-DN, different window
}//K-R, downstroke, prepare to process next upstroke
}//K, recording in progress
else
{//K, not recording
if(!Extended)
{//K-IDL, not extended
switch(wParam)
{//K-IDL-NEX, seek keypad function
case Pad3PgDn://AoE find worker
{//K-NEX-SEK, macro key
if(KeyUp)
{//K-NEX-SEK-MAC, pass upstroke
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//K-NEX-SEK-MAC, pass upstroke
if(KeyWasDn)
{//K-NEX-SEK-MAC, eat repeat stroke
return 1;
}//K-NEX-SEK-MAC, eat repeat stroke
//K-NEX-SEK-MAC, downstroke
//AoE2
INPUT ip;
ip.type=INPUT_KEYBOARD;
ip.ki.wScan=0;
ip.ki.time=0;
ip.ki.dwExtraInfo=0;
//release current object
ip.ki.wVk=VK_0;
ip.ki.dwFlags=0;//press
SendInput(1,&ip,sizeof(INPUT));
ip.ki.dwFlags=KEYEVENTF_KEYUP;
SendInput(1,&ip,sizeof(INPUT));
//find idle worker
ip.ki.wVk=VK_OEM_PERIOD;
ip.ki.dwFlags=0;//press
SendInput(1,&ip,sizeof(INPUT));
ip.ki.dwFlags=KEYEVENTF_KEYUP;
SendInput(1,&ip,sizeof(INPUT));
//add to group 1
ip.ki.wVk=VK_SHIFT;
ip.ki.dwFlags=0;//press
SendInput(1,&ip,sizeof(INPUT));
ip.ki.wVk=VK_1;
ip.ki.dwFlags=0;//press
SendInput(1,&ip,sizeof(INPUT));
ip.ki.dwFlags=KEYEVENTF_KEYUP;
SendInput(1,&ip,sizeof(INPUT));
ip.ki.wVk=VK_SHIFT;
ip.ki.dwFlags=KEYEVENTF_KEYUP;
SendInput(1,&ip,sizeof(INPUT));
//assign to group 1
ip.ki.wVk=VK_CONTROL;
ip.ki.dwFlags=0;//press
SendInput(1,&ip,sizeof(INPUT));
ip.ki.wVk=VK_1;
ip.ki.dwFlags=0;//press
SendInput(1,&ip,sizeof(INPUT));
ip.ki.dwFlags=KEYEVENTF_KEYUP;
SendInput(1,&ip,sizeof(INPUT));
ip.ki.wVk=VK_CONTROL;
ip.ki.dwFlags=KEYEVENTF_KEYUP;
SendInput(1,&ip,sizeof(INPUT));
//return view
ip.ki.wVk=VK_BACK;
ip.ki.dwFlags=0;//press
SendInput(1,&ip,sizeof(INPUT));
ip.ki.dwFlags=KEYEVENTF_KEYUP;
SendInput(1,&ip,sizeof(INPUT));
PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//K-NEX-SEK, macro key
case GetOrSetPtrPos:
{//K-IDL-NEX-SEK, get/set pointer position
if(KeyUp)
{//K-IDL-NEX-SEK-GSPOS, upstroke
if(GetKeyState(VK_CONTROL)&0x8000)
{//K-IDL-NEX-SEK-GSPOS-UP, set pointer position
SetCursorPos(RecPosPointer.x,RecPosPointer.y);
}//K-IDL-NEX-SEK-GSPOS-UP, set pointer position
else
{//K-IDL-NEX-SEK-GSPOS-UP, get pointer position
GetCursorPos(&RecPosPointer);
}//K-IDL-NEX-SEK-GSPOS-UP, get pointer position
}//K-IDL-NEX-SEK-GSPOS, upstroke
return 1;//eat all VK_SCROLL strokes
}//K-IDL-NEX-SEK, get/set pointer position
}//K-IDL-NEX, seek keypad function
}//K-IDL, not extended
}//K, not recording
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//key action
LRESULT CALLBACK MyMouseHook(int nCode,WPARAM wParam,LPARAM lParam)
{//mouse action
if(MouseMoveMessage)
{//M, ignore mouse movement
return::CallNextHookEx(g_hHookMouse,nCode,wParam,lParam);
}//M, ignore mouse movement
if(UnknownAction)
{//M, unusable mouse message
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//M, unusable mouse message
if(Recording)
{//M-R
if(DoubleClick)
{//M-R, double-click
if(strchr(Script,LastParentheses)!=NULL)
{//M-R-DCLK, ready to modify
MouseDouble=true;
*(strrchr(Script,'B'))='\0';
strcat(Script,"ButtonClick(1,2) WAIT(1) \n");
}//M-R-DCLK, ready to modify
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//M-R, double-click
if(BtnEitherDn)
{//M-R, either button down
AfterFirstUpAction=false;
MouseDown=true;
GetCursorPos(&DnScreenPoint);
WindowHandle=GetForegroundWindow();
//check for new window
GetWindowText(WindowHandle,TitleBar2,255);
if(strcmp(TitleBar1,TitleBar2))
{//M-R-DN, focus is new/different window
strcpy(TitleBar1,TitleBar2);
if(strcmp(TitleBar2,""))
{//M-R-DN-DIF, window has title
strcat(Script," WaitForWindow(\"");
strcat(Script,TitleBar2);
strcat(Script,"\") WAIT(1) \n");
}//M-R-DN-DIF, window has title
}//M-R-DN, focus is new/different window
if(GetKeyState(VK_MENU)&0x8000)
{//M-R-DN, use window coordinates
AfterFirstUpAction=true;
strcpy(ClickContext," SetMousePosition(1,");
GetWindowRect(WindowHandle,&WindowBorder);
DnContextPoint={DnScreenPoint.x-
WindowBorder.left,DnScreenPoint.y-WindowBorder.top};
}//M-R-DN, use window coordinates
else
{//M-R-DN, use screen coordinates
strcpy(ClickContext," SetMousePosition(0,");
DnContextPoint=DnScreenPoint;
}//M-R-DN, use screen coordinates
if(GetKeyState(VK_SHIFT)&0x8000)
{//M-R-DN, shift key held
if(!Mouseshifted)
{//M-R-DN-SHFDN, set/record shift downstroke only once
Mouseshifted=true;
strcat(Script," Keys.SendInput({shift_hold}) WAIT(1)
\n");
}//M-R-DN-SHFDN, set/record shift downstroke only once
}//M-R-DN, shift key held
*PointDn='\0';
if(PointerMoved)
{//M-R-DN, pointer moved before button down
strcat(PointDn,_ltoa(DnContextPoint.x,Coordinate,10));
strcat(PointDn,",");
strcat(PointDn,_ltoa(DnContextPoint.y,Coordinate,10));
}//M-R-DN, pointer moved before button down
return::CallNextHookEx(g_hHookKbd,nCode,wParam,lParam);
}//M-R, either button down
if(BtnEitherUp)
{//M-R, either button up
if(MouseDouble)
{//M-R-UP, second part of a double-click
MouseDouble=false;
return::CallNextHookEx(g_hHookMouse,nCode,wParam,lParam);
}//M-R-UP, second part of a double-click
if(!MouseDown)
{//M-R-UP, voiced "X" (button up from script)
strcat(Script," Keys.SendInput({leftbutton_release}) WAIT
(1) \n");
return::CallNextHookEx(g_hHookMouse,nCode,wParam,lParam);
}//M-R-UP, voiced "X" (button up from script)
MouseDown=false;
GetCursorPos(&UpScreenPoint);
if(BtnLeftClick)
{//M-R-UP, left button action
strcpy(BtnName,"leftbutton");
strcpy(BtnNumber,"1");
}//M-R-UP, left button action
if(BtnRightClick)
{//M-R-UP, right button action
strcpy(BtnName,"rightbutton");
strcpy(BtnNumber,"2");
}//M-R-UP, right button action
*PointUp='\0';
if(PointerMoved)
{//M-R-UP, pointer moved before button up
strcat(PointUp,_ltoa(UpScreenPoint.x-
DnScreenPoint.x,Coordinate,10));
strcat(PointUp,",");
strcat(PointUp,_ltoa(UpScreenPoint.y-
DnScreenPoint.y,Coordinate,10));
}//M-R-UP, pointer moved before button up
if(*PointDn)
{//M-R-UP, pointer moved before button down
strcat(Script,ClickContext);
strcat(Script,PointDn);
strcat(Script,") WAIT(1) \n");
if(*PointUp)
{//M-R-UP-MOV, point, click, and drag
strcat(Script," Keys.SendInput({");
strcat(Script,BtnName);
strcat(Script,"_hold}) WAIT(1) \n");
strcat(Script," SetMousePosition(2,");
strcat(Script,PointUp);
strcat(Script,") WAIT(1) \n");
strcat(Script," Keys.SendInput({");
strcat(Script,BtnName);
strcat(Script,"_release}) WAIT(1) \n");
return::CallNextHookEx(g_hHookMouse,nCode,wParam,lParam);
}//M-R-UP-MOV, point, click, and drag
else
{//M-R-UP-MOV, point and click
strcat(Script," ButtonClick(");
strcat(Script,BtnNumber);
strcat(Script,",1) WAIT(1) \n");
return::CallNextHookEx(g_hHookMouse,nCode,wParam,lParam);
}//M-R-UP-MOV, point and click
}//M-R-UP, pointer moved before button down
else
{//M-R-UP, action starts at current location
if(*PointUp)
{//M-R-UP-CUR, just drag
strcat(Script," Keys.SendInput({");
strcat(Script,BtnName);
strcat(Script,"_hold}) WAIT(1) \n");
strcat(Script," SetMousePosition(2,");
strcat(Script,PointUp);
strcat(Script,") WAIT(1) \n");
strcat(Script," Keys.SendInput({");
strcat(Script,BtnName);
strcat(Script,"_release}) WAIT(1) \n");
return::CallNextHookEx(g_hHookMouse,nCode,wParam,lParam);
}//M-R-UP-CUR, just drag
else
{//M-R-UP-CUR, just click
strcat(Script," ButtonClick(");
strcat(Script,BtnNumber);
strcat(Script,",1) WAIT(1) \n");
return::CallNextHookEx(g_hHookMouse,nCode,wParam,lParam);
}//M-R-UP-CUR, just click
}//M-R-UP, action starts at current location
}//M-R, either button up
}//M-R
return::CallNextHookEx(g_hHookMouse,nCode,wParam,lParam);
}//mouse action
DLLEXPORT BOOL hookDLLInit()
{//Initialize DLL: install kbd/mouse hooks
if(g_hHookKbd==NULL)
{//INIT, enable program sounds
HINSTANCE hInst=theDll.m_hInstance;
g_hHookKbd=SetWindowsHookEx(WH_KEYBOARD,MyKbdHook,hInst,0);
g_hHookMouse=SetWindowsHookEx(WH_MOUSE,MyMouseHook,hInst,0);
//g_dwLastInputTick=GetTickCount();// init count
GetCurrentDirectory(256,SoundFolder);
char*pch;
pch=strchr(SoundFolder,'\\');
while(pch!=NULL)
{//INIT-PREP, format program path
*pch='/';
pch=strchr(pch+1,'\\');
}//INIT-PREP, format program path
strcpy(SoundPathStart,SoundFolder);
strcat(SoundPathStart,"/titatoo1.wav");
strcpy(SoundPathStop,SoundFolder);
strcat(SoundPathStop,"/doedit1.wav");
strcpy(SoundPathError,SoundFolder);
strcat(SoundPathError,"/vuut1.wav");
strcpy(SoundPathNotice,SoundFolder);
strcat(SoundPathNotice,"/beep1.wav");
}//INIT, enable program sounds
ASSERT(g_hHookKbd);
ASSERT(g_hHookMouse);
return TRUE;
}//Initialize DLL: install kbd/mouse hooks
DLLEXPORT void hookDLLTerm()
{// Terminate DLL: remove hooks
BOOL bRet1=UnhookWindowsHookEx(g_hHookKbd);
BOOL bRet2=UnhookWindowsHookEx(g_hHookMouse);
ASSERT(bRet1 && bRet2);
}// Terminate DLL: remove hooks
DLL
DLL
DLL
DLL
DLL
DLL
DLL
DLL
DLL
DLL
DLL
DLL