Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Vocola 2 hook, PostMessage() from DLL to EXE

32 views
Skip to first unread message

John Doe

unread,
Feb 20, 2014, 10:23:42 AM2/20/14
to
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
















John Doe

unread,
Feb 20, 2014, 1:16:27 PM2/20/14
to
[This is a repost of similar stuff for the record]

automatic, self-regulating playback timing
5/28/09

This is about system wide macro/script playback, not specifically
about Dragonfly.

From July 2004, the following was my best attempt at automatic,
self-regulating script playback timing, so that there is no need to
manually add pauses to the script ahead of time. For example... When
you switch to another window, open an application, delete lots of
files in Windows Explorer, or just enter keystrokes... the script
playback should automatically slow down. The script should playback
fast as possible without making mistakes. The trick is to get the
operating system to tell you when it is ready for more input.

Automatic timing is elusive but probably just requires some good
guessing about how to do it. I apparently got it down or at least
got very close, but then I noticed speech activated scripting.
Speech activated scripting made my script playback program useless,
otherwise I would be doing it (or at least still trying) now.

A small part of the following code might be voodoo, but I did not
have time to correct it before moving on to speech activated
scripting.

DLL
DLL
DLL
DLL

LRESULT CALLBACK KeyHook(int nCode,WPARAM wParam,LPARAM lParam)
{//system wide keyboard hook
if(nCode==HC_ACTION)
{//USEABLE KEY MESSAGE
if(playing)
{//KEYSTROKE DURING MACRO PLAYBACK
if((wParam==176)||(GetKeyState(VK_NUMLOCK)&0x0001))
{//KEYPAD LOCKED OR END OF FILE (fast forward key)
playing=false;
PostMessage(FindWindow(NULL,"system wide hook"),WM_SPOOLERSTATUS,3,wParam);
}//KEYPAD LOCKED OR END OF FILE (fast forward key)
else
{//TELL EXE TO CONTINUE PLAYING
PostMessage(FindWindow(NULL,"system wide hook"),WM_SPOOLERSTATUS,2,wParam);
}//TELL EXE TO CONTINUE PLAYING
return::CallNextHookEx(g_hHookKey,nCode,wParam,lParam);
}//KEYSTROKE DURING MACRO PLAYBACK
if(recording)
{//RECORDING, CONTINUE OR CLOSE
ZeroMemory(input,sizeof(input));
if(lParam&0x80000000)
{//UPSTROKE
//log every upstroke
for(int ShiftBuffer=5;ShiftBuffer>0;ShiftBuffer--)
KeyUp[ShiftBuffer]=KeyUp[ShiftBuffer-1];
KeyUp[0].Code=wParam;
KeyUp[0].Info=lParam;
GetCursorPos(&KeyUp[0].PtrPos);
KeyUp[0].Time=GetTickCount();
//log every upstroke
switch(wParam)
{//record or close
case 12:
{//hot key 5 up, close file
if(fclose(stream))
{//error closing file
PlaySound("C:\\Program Files\\SysHook\\vuut1.wav"...);
}//error closing file
else
{//file closed
PlaySound("C:\\Program Files\\SysHook\\whadok1.wav"...);
}//file closed
recording=false;
break;
}//hot key 5 up, close file
case 35:
{//pad1, button up
input[0].type=INPUT_MOUSE;
input[0].mi.dwFlags=MOUSEEVENTF_LEFTUP;
SendInput(1,input,sizeof(INPUT));
//write to file
fputs(_ltoa(KeyUp[0].PtrPos.x,buffer,10),stream);
fputc('\n',stream);
fputs(_ltoa(KeyUp[0].PtrPos.y,buffer,10),stream);
fputc('\n',stream);
fputs("LeftButtonUp",stream);
fputc('\n',stream);
//write to file
break;
}//pad1, button up
}//record or close
}//UPSTROKE
else
{//REPEAT KEY OR DOWNSTROKE
if(lParam&0x40000000)
{//REPEAT KEY
return 1;
}//REPEAT KEY
else
{//DOWNSTROKE
//log every downstroke
for(int ShiftBuffer=5;ShiftBuffer>0;ShiftBuffer--)
KeyDn[ShiftBuffer]=KeyDn[ShiftBuffer-1];
KeyDn[0].Code=wParam;
KeyDn[0].Info=lParam;
GetCursorPos(&KeyDn[0].PtrPos);
KeyDn[0].Time=GetTickCount();
//log every downstroke
switch(wParam)
{//switch on downstroke while recording
case 35:
{//pad 1 down, button down
input[0].type=INPUT_MOUSE;
input[0].mi.dwFlags=MOUSEEVENTF_LEFTDOWN;
SendInput(1,input,sizeof(INPUT));
//write to file
fputs(_ltoa(KeyDn[0].PtrPos.x,buffer,10),stream);
fputc('\n',stream);
fputs(_ltoa(KeyDn[0].PtrPos.y,buffer,10),stream);
fputc('\n',stream);
fputs("LeftButtonDown",stream);
fputc('\n',stream);
//write to file
break;
}//pad 1 down, button down
}//switch on downstroke while recording
}//DOWNSTROKE
}//REPEAT KEY OR DOWNSTROKE
return 1;
}//RECORDING, CONTINUE OR CLOSE
//NOT RECORDING OR PLAYING
if(lParam&0x80000000)
{//UPSTROKE
//log every upstroke
for(int ShiftBuffer=5;ShiftBuffer>0;ShiftBuffer--)
KeyUp[ShiftBuffer]=KeyUp[ShiftBuffer-1];
KeyUp[0].Code=wParam;
KeyUp[0].Info=lParam;
GetCursorPos(&KeyUp[0].PtrPos);
KeyUp[0].Time=GetTickCount();
//log every upstroke
EatRep=false;
switch(wParam)
{//seeking hot key upstroke
case 12:
case 33:
case 34:
case 35:
case 36:
case 37:
case 38:
case 39:
case 40:
case 45:
case 46:
{//correct key code
if(!(lParam&0x01000000))
{//extended hot key
_itoa(wParam,FileName,10);
strcpy(FilePath,"C:\\Program Files\\SysHook\\");
strncat(FilePath,FileName,2);
strncat(FilePath,".txt",4);
if(KeyUp[0].Time-KeyDn[0].Time>500&&!PtrMov(KeyDn[0].PtrPos,KeyUp[0].PtrPos))
{//slow click no movement
//open file for recording
if((stream=fopen(FilePath,"w"))==NULL)
{//error opening file
PlaySound("C:\\Program Files\\SysHook\\vuut1.wav"...);
return 1;
}//error opening file
//file opened
PlaySound("C:\\Program Files\\SysHook\\whadok1.wav"...);
recording=true;
return 1;
//file opened
//open file for recording
}//slow click no movement
//begin playing
PostMessage(FindWindow(NULL,"system wide hook"),WM_SPOOLERSTATUS,1,wParam);
playing=true;
return 1;
//begin playing
}//extended hot key
}//correct key code
}//seeking hot key upstroke
return::CallNextHookEx(g_hHookKey,nCode,wParam,lParam);
}//UPSTROKE
if(lParam&0x40000000)
{//REPEAT KEY
if(EatRep)
return 1;
return::CallNextHookEx(g_hHookKey,nCode,wParam,lParam);
}//REPEAT KEY
//DOWNSTROKE
//log every downstroke
for(int ShiftBuffer=5;ShiftBuffer>0;ShiftBuffer--)
KeyDn[ShiftBuffer]=KeyDn[ShiftBuffer-1];
KeyDn[0].Code=wParam;
KeyDn[0].Info=lParam;
GetCursorPos(&KeyDn[0].PtrPos);
KeyDn[0].Time=GetTickCount();
//log every downstroke
switch(wParam)
{//if hot key downstroke
case 12:
case 33:
case 34:
case 35:
case 36:
case 37:
case 38:
case 39:
case 40:
case 45:
case 46:
{//correct key code
if(!(lParam&0x01000000))
{//extended hot key
EatRep=true;//disable repeat
return 1;
}//extended hot key
}//correct key code
}//if hot key downstroke
return::CallNextHookEx(g_hHookKey,nCode,wParam,lParam);
//DOWNSTROKE
//NOT RECORDING OR PLAYING
//NOT RECORDING OR PLAYING
//NOT RECORDING OR PLAYING
//NOT RECORDING OR PLAYING
//NOT RECORDING OR PLAYING
//NOT RECORDING OR PLAYING
//NOT RECORDING OR PLAYING
//NOT RECORDING OR PLAYING
//NOT RECORDING OR PLAYING
//NOT RECORDING OR PLAYING
}//usuable key message
return::CallNextHookEx(g_hHookKey,nCode,wParam,lParam);
}//system wide keyboard hook
LRESULT CALLBACK MyMouseHook(int code,WPARAM wParam,LPARAM lParam)
{//system wide mouse hook
if(code==HC_ACTION)
{//USEABLE MOUSE MESSAGE
if(playing)
{//TELL EXE TO CONTINUE PLAYING
PostMessage(FindWindow(NULL,"system wide hook"),WM_SPOOLERSTATUS,2,wParam);
}//TELL EXE TO CONTINUE PLAYING
}//USEABLE MOUSE MESSAGE
return::CallNextHookEx(g_hHookMouse,code,wParam,lParam);
}//system wide mouse hook

EXE
EXE
EXE
EXE

void CMainFrame::OnSpoolerStatus(UINT Action,UINT FileID)
{//HANDLE SCRIPT PLAYBACK
//clear SendInput memory
ZeroMemory(input,sizeof(input));
//clear SendInput memory
switch(Action)
{//open file, continue playing, or close
case 1:
{//open file for playback
_itoa(FileID,FileName,10);
strcpy(FilePath,"C:\\Program Files\\SysHook\\");
strncat(FilePath,FileName,2);
strncat(FilePath,".txt",4);
if((stream=fopen(FilePath,"r"))==NULL)
{//error opening file
PlaySound("C:\\Program Files\\SysHook\\vuut1.wav"...);
//stop DLL from sending input
input[0].type=INPUT_KEYBOARD;
input[0].ki.wVk=16;
input[0].ki.dwFlags=KEYEVENTF_KEYUP;
SendInput(1,input,sizeof(INPUT));
//stop DLL from sending input
}//error opening file
else
{//file opened for playback
//playback, original pointer position
GetCursorPos(&CrntPos);
//playback, original pointer position
//instruct DLL to notify upon input
input[0].type=INPUT_MOUSE;
input[0].mi.dx=CrntPos.x;
input[0].mi.dy=CrntPos.y;
input[0].mi.dwFlags=MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE;
SendInput(1,input,sizeof(INPUT));
//instruct DLL to notify upon input
}//file opened for playback
break;
}//open file for playback
case 2:
{//PLAYING
if(SendAgain)
{//PLAY REDUNDANT (position)
SendAgain=false;
input[0].type=INPUT_MOUSE;
input[0].mi.dx=(PtrPosX*81.92)+81.92;
input[0].mi.dy=(PtrPosY*109.2)+109.2;
input[0].mi.dwFlags=MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE;
SendInput(1,input,sizeof(INPUT));
}//PLAY REDUNDANT (position)
else
{//PLAY UNTIL END OF FILE
if(fgets(buffer,sizeof(buffer),stream))
{//PLAY ANOTHER LINE FROM FILE
p=buffer+strlen(buffer)-1;
*p=0;//replace newline character
if(strcmp(buffer,ButtonDown)==0)
{//play button down
input[0].type=INPUT_MOUSE;
input[0].mi.dwFlags=MOUSEEVENTF_LEFTDOWN;
}//play button down
else
{//play button up or pointer position
if(strcmp(buffer,ButtonUp)==0)
{//play button up
input[0].type=INPUT_MOUSE;
input[0].mi.dwFlags=MOUSEEVENTF_LEFTUP;
}//play button up
else
{//play pointer position
//translate pointer coordinates
PtrPosX=atoi(buffer);
fgets(buffer,sizeof(buffer),stream);
p=buffer+strlen(buffer)-1;
*p=0;//replace newline character
PtrPosY=atoi(buffer);
//translate pointer coordinates
input[0].type=INPUT_MOUSE;
input[0].mi.dx=(PtrPosX*81.92)+81.92;
input[0].mi.dy=(PtrPosY*109.2)+109.2;
input[0].mi.dwFlags=MOUSEEVENTF_ABSOLUTE|MOUSEEVENTF_MOVE;
}//play pointer position
}//play button up or pointer position
SendAgain=true;
SendInput(1,input,sizeof(INPUT));
}//PLAY ANOTHER LINE FROM FILE
else
{//END OF FILE
//TELL DLL PLAYBACK IS OVER
input[0].type=INPUT_KEYBOARD;
input[0].ki.wVk=176;
input[0].ki.dwFlags=KEYEVENTF_KEYUP;
SendInput(1,input,sizeof(INPUT));
//TELL DLL PLAYBACK IS OVER
}//END OF FILE
}//PLAY UNTIL END OF FILE
break;
}//PLAYING
case 3:
{//END OF FILE OR DLL NOTIFICATION DURING PLAYBACK
//CLOSE FILE
if(fclose(stream))
{//ERROR CLOSING FILE
PlaySound("C:\\Program Files\\SysHook\\vuut1.wav"...);
}//ERROR CLOSING FILE
//CLOSE FILE
break;
}//END OF FILE OR ERROR DURING PLAYBACK
}//OPEN FILE, CONTINUE PLAYING, OR CLOSE
Sleep(0);
Sleep(0);
CFrameWnd::OnSpoolerStatus(Action,FileID);
}//HANDLE SCRIPT PLAYBACK

Some explanation to go with the previous code...

I sent a redundant mouse position SendInput one time for each SendInput
sent to Windows. I used Sleep() and maybe SetPriority() too, whether or
not those functions made any difference (in all my trying, much trying,
Sleep/SetPriority made no apparent significant difference when used
without a redundant SendInput).

My Visual C++ code involved in EXE and a DLL. My EXE was doing
SendInput. My DLL hooked Windows input. After my EXE sent input to
Windows, that input would pass through my DLL. When my DLL received
input from Windows, my DLL sent a message to my EXE telling it to send
another input (besides sending that message, my DLL did nothing except
allow Windows input to continue through the system).

Immediately before the SendInput line in my EXE, a boolean variable
"SendAgain" is set to true. The input is sent from the EXE, the input
passes through the DLL, the DLL sends a message to the EXE to allow it
to continue, and the first thing the EXE does after receiving the
continue playing message from the DLL is to check whether SendAgain is
true. If SendAgain is true, the EXE sets it to false and sends a
redundant pointer position SendInput through Windows (the DLL gets it,
and sends another continue playing message back to the EXE). If
SendAgain is false, a redundant pointer position SendInput is not sent,
instead the EXE sends the next meaningful SendInput to Windows.

SendInput sends very small instructions (as small as possible) each
time.

0 new messages