Groups | Search | Server Info | Login | Register


Groups > comp.lang.beta > #123

Re: Vocola 2 hook, PostMessage() from DLL to EXE

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>

Show all headers | View raw


[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 | NextPrevious in thread | Find similar


Thread

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