Groups | Search | Server Info | Login | Register
Groups > comp.lang.beta > #123
| From | John Doe <jdoe@usenetlove.invalid> |
|---|---|
| Newsgroups | comp.lang.beta |
| Subject | Re: Vocola 2 hook, PostMessage() from DLL to EXE |
| Date | 2014-02-20 18:16 +0000 |
| Organization | A noiseless patient Spider |
| Message-ID | <le5gpr$l84$1@dont-email.me> (permalink) |
| References | <le56lt$let$1@dont-email.me> |
[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.
Back to comp.lang.beta | Previous | Next — Previous in thread | Find similar
Vocola 2 hook, PostMessage() from DLL to EXE John Doe <jdoe@usenetlove.invalid> - 2014-02-20 15:23 +0000 Re: Vocola 2 hook, PostMessage() from DLL to EXE John Doe <jdoe@usenetlove.invalid> - 2014-02-20 18:16 +0000
csiph-web