Groups | Search | Server Info | Login | Register


Groups > comp.lang.beta > #130

VoiceWorks Vocola 2 macro recorder files

From John Doe <jdoe@usenetlove.invalid>
Newsgroups comp.lang.beta
Subject VoiceWorks Vocola 2 macro recorder files
Date 2014-03-10 17:30 +0000
Organization A noiseless patient Spider
Message-ID <lfksqu$kf$1@dont-email.me> (permalink)

Show all headers | View raw


All Visual Studio 2013 files except the icons/resource file. 
Recently included window switching by titlebar text. All actions
are recorded on separate lines except for strings of text. 
Includes DirectX headers and some communications functions that 
are unused. Sound file paths are processed on startup, so they 
should play regardless of location. 

hookEXE.cpp
hookDLL.cpp
definitions.h

#define DLLIMPORT __declspec(dllimport)
#include <afxwin.h>//MFC core and standard components
//#include <d3d9.h>
#include <mmsystem.h>
#include "definitions.h"
#include "resource.h"//UI ID's
//#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"winmm.lib")//was in Properties/Linker/Input...
char StringOut[256]={};
HWND hWndoCurrent=NULL;
POINT PointCurrent={};
static const UINT DLL_INPUT_NOTICE=::RegisterWindowMessage(_T("DLL_INPUT_NOTICE"));
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 paints message
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
  DECLARE_MESSAGE_MAP()
  afx_msg LRESULT OnDLLInputNotice(WPARAM wParam,LPARAM lParam);
};//main frame window paints message
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()
DLLIMPORT BOOL hookDLLInit();//call when your app starts
BOOL CMyApp::InitInstance()
{//app starting, initialize DLL and load main window
  CMainFrame* pMainFrame=new CMainFrame;//create main frame
  if(!pMainFrame->LoadFrame(IDR_MAINFRAME))
    return FALSE;
  pMainFrame->ShowWindow(m_nCmdShow);//show main frame
  pMainFrame->UpdateWindow();
  m_pMainWnd=pMainFrame;
  //RUN, initialize DLL last so DLL startup code can see window
  if(!hookDLLInit())
  {//RUN, initialize DLL
    AfxMessageBox(_T("Error initializing DLL"));
  }//RUN, initialize DLL
  return TRUE;
}//app starting, initialize DLL and load main window
DLLIMPORT void hookDLLTerm();//call when your app terminates
int CMyApp::ExitInstance()
{//app shutting down
  hookDLLTerm();//terminate DLL (unhook)
  return CWinApp::ExitInstance();
}//app shutting down
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()
  //}}AFX_MSG_MAP
  ON_REGISTERED_MESSAGE(DLL_INPUT_NOTICE,&CMainFrame::OnDLLInputNotice)
END_MESSAGE_MAP()
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{//before creating window, set size
  BOOL bRet=CFrameWnd::PreCreateWindow(cs);
  cs.cx=800;
  cs.cy=800;
  return bRet;
}//before creating window, set size
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{//create main window
  if(CFrameWnd::OnCreate(lpCreateStruct)==-1)
    return -1;
  return 0;
}//create main window
void CMainFrame::OnPaint()
{//paint message
  CPaintDC dc(this);
  SetTextColor(dc,GetSysColor(COLOR_WINDOWTEXT));
  SetBkColor(dc,GetSysColor(COLOR_WINDOW));
  CString s
  (
  "This free utility helps expert users write scripts for Vocola 2/DNS. I disclaim any responsibility for your use of this program. If you are confused, ask in the forums or email me.\r\n"
  "\r\n"
  "Usage...\r\n"
  "\r\n"
  "The numeric keypad must be OFF while recording. It may be ON while not recording.\r\n"
  "\r\n"
  "Start and stop recording...\r\n"
  "\r\n"
  "To start recording, press keypad Delete/point. To stop, press keypad Delete/point again. You should hear a sound when recording starts and stops. Then, your recorded actions are in the clipboard ready for pasting into a VCL file.\r\n"
  "\r\n"
  "Recording mouse actions...\r\n"
  "\r\n"
  "To record a click without positioning, don't move the mouse before the click. The position will be recorded if the mouse moves more than 12 pixels after the last action. Hold ALT and click to record a point and click relative to the current window. All dragging is relative to the button down position.\r\n"
  "\r\n"
  "Window switching...\r\n"
  "\r\n"
  "Recorded automatically. The titlebar search text is case sensitive but not an exact match. You may remove text from the beginning and/or end of the recorded text but the carrot symbols must remain. Adjust the WaitForWindow() line according to Vocola rules.\r\n"
  "\r\n"
  "Recording a text string on one line...\r\n"
  "\r\n"
  "Press keypad 4 to start recording text on one line. Press keypad 6 to stop that and continue recording other stuff.\r\n"
  "\r\n"
  "Changes to the program will be made without changes to this description. \r\n"
  "\r\n"
  "This is extra...\r\n"
  "\r\n"
  "When the keypad is disabled, keypad zero is a global double-click. While recording, the keypad number keys 1-9 are additional functions. A second set is available by holding control/Ctrl while pressing 1-9 (currently for timing). To see the list of functions, just start a recording and press those nine numbers (except 4 and 6) one after another. Then stop the recording and paste the results."
  );
  CRect rc;
  GetClientRect(&rc);
  dc.DrawText(s,&rc,DT_LEFT|DT_VCENTER|DT_WORDBREAK);
}//paint message
INPUT SI[10]={};
DLLIMPORT void ContinuePlaying(BOOL status);
afx_msg LRESULT CMainFrame::OnDLLInputNotice(WPARAM wParam,LPARAM lParam)
{//message from DLL
  switch(wParam)
  {//MSG, match input with action
    case Pad3PgDn://AoE2
    {//MSG-MACT, collect idle workers
      ZeroMemory(SI,sizeof(INPUT));
      SI[0].type=INPUT_KEYBOARD;
      //release current object
      SI[0].ki.wVk=VK_0;
      SI[0].ki.dwFlags=0;//press
      SendInput(1,&SI[0],sizeof(INPUT));
      SI[0].ki.dwFlags=KEYEVENTF_KEYUP;
      SendInput(1,&SI[0],sizeof(INPUT));
      //find idle worker
      SI[0].ki.wVk=VK_OEM_PERIOD;
      SI[0].ki.dwFlags=0;//press
      SendInput(1,&SI[0],sizeof(INPUT));
      SI[0].ki.dwFlags=KEYEVENTF_KEYUP;
      SendInput(1,&SI[0],sizeof(INPUT));
      Sleep(100);
      //ungarrison
      SI[0].ki.wVk=VK_Z;
      SI[0].ki.dwFlags=0;//press
      SendInput(1,&SI[0],sizeof(INPUT));
      SI[0].ki.dwFlags=KEYEVENTF_KEYUP;
      SendInput(1,&SI[0],sizeof(INPUT));
      //add to group 1
      SI[0].ki.wVk=VK_SHIFT;
      SI[0].ki.dwFlags=0;//press
      SendInput(1,&SI[0],sizeof(INPUT));
      SI[0].ki.wVk=VK_1;
      SI[0].ki.dwFlags=0;//press
      SendInput(1,&SI[0],sizeof(INPUT));
      SI[0].ki.dwFlags=KEYEVENTF_KEYUP;
      SendInput(1,&SI[0],sizeof(INPUT));
      SI[0].ki.wVk=VK_SHIFT;
      SI[0].ki.dwFlags=KEYEVENTF_KEYUP;
      SendInput(1,&SI[0],sizeof(INPUT));
      //assign to group 1
      SI[0].ki.wVk=VK_CONTROL;
      SI[0].ki.dwFlags=0;//press
      SendInput(1,&SI[0],sizeof(INPUT));
      SI[0].ki.wVk=VK_1;
      SI[0].ki.dwFlags=0;//press
      SendInput(1,&SI[0],sizeof(INPUT));
      SI[0].ki.dwFlags=KEYEVENTF_KEYUP;
      SendInput(1,&SI[0],sizeof(INPUT));
      SI[0].ki.wVk=VK_CONTROL;
      SI[0].ki.dwFlags=KEYEVENTF_KEYUP;
      SendInput(1,&SI[0],sizeof(INPUT));
      //return view
      SI[0].ki.wVk=VK_BACK;
      SI[0].ki.dwFlags=0;//press
      SendInput(1,&SI[0],sizeof(INPUT));
      SI[0].ki.dwFlags=KEYEVENTF_KEYUP;
      SendInput(1,&SI[0],sizeof(INPUT));
    }//MSG-MACT, collect idle workers
  }//MSG, match input with action
  return 0;
}//message from DLL

#define DLLEXPORT __declspec(dllexport)
#include <afxwin.h>//MFC core and standard components
#include <mmsystem.h>
#include "definitions.h"
#pragma comment(lib,"winmm.lib")//was in Properties/Linker/Input...
#pragma comment(linker,"/SECTION:.hookDLL,RWS")//replaced (hookDLL.def)
//the following global data is SHARED among all instances of the DLL
//(processes), these are system-wide globals
#pragma data_seg (".hookDLL")//defined above
BYTE KeyboardState[256]={};
HHOOK hKeyboardHook=NULL;//one instance for all processes
HHOOK hMouseHook=NULL;//one instance for all processes
HWND WndoCurrent=NULL;
HWND WndoEXE=NULL;
INPUT SI[10];
POINT PointContextDn={};
POINT PointCurrent={};
POINT PointScreenDn={};
POINT PointScreenUp={};
POINT PointStored={};
RECT WndoBorder={};
bool AfterFirstUpAction=true;
bool OnOneLine=false;
bool GetTitle=false;
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 KeyInput[2]={};
char KeyName[16]={};
char KeyString[256]={};
char Modifier[32]={};
char NumPad[16]={};
char PointDn[16]={};
char PointUp[16]={};
char Script[4096]={};
char SoundFolder[256]={};
char SoundPathError[256]={};
char SoundPathNotice[256]={};
char SoundPathStart[256]={};
char SoundPathStop[256]={};
char StringOut[256]={};
char TitleBar1[256]={};
char TitleBar2[256]={};
int LastParentheses=')';
#pragma data_seg ()
static const UINT DLL_INPUT_NOTICE=::RegisterWindowMessage(_T("DLL_INPUT_NOTICE"));
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
BOOL CALLBACK EnumWinHandle(HWND hWnd,LPARAM lparam)
{//look for matching window titlebar
  if(IsWindowVisible(hWnd))
  {//FND, normal window titles
    GetWindowText(hWnd,TitleBar1,256);
    if(strstr(TitleBar1,KeyString))
    {//FND-NRM, activate the destination window
      //FND-NRM-ACT, press alt key
      ZeroMemory(SI,sizeof(INPUT));
      SI[0].type=INPUT_KEYBOARD;
      SI[0].ki.wVk=VK_MENU;
      SI[0].ki.dwFlags=0;//press
      SendInput(1,SI,sizeof(INPUT));
      if(IsIconic(hWnd))
      {//FND-NRM-ACT, restore destination window if minimized
        OpenIcon((hWnd));
      }//FND-NRM-ACT, restore destination window if minimized
      else
      {//FND-NRM-ACT, switch to destination window
        SetForegroundWindow(hWnd);
      }//FND-NRM-ACT, switch to destination window
      //FND-NRM-ACT, release alt key
      SI[0].ki.dwFlags=KEYEVENTF_KEYUP;
      SendInput(1,SI,sizeof(INPUT));
      return FALSE;//stop enumerating
    }//FND-NRM, activate the destination window
  }//FND, normal window titles
  return TRUE;//continue enumerating
}//look for matching window titlebar
LRESULT CALLBACK KeyboardHook(int nCode,WPARAM wParam,LPARAM lParam)
{//key action
  if(UnknownAction)
  {//K, unusable message
    return::CallNextHookEx(hKeyboardHook,nCode,wParam,lParam);
  }//K, unusable message
  if(GetTitle)
  {//K, reading input for window switching
    if(KeyUp)
    {//K-READ, upstroke
      if((wParam==VK_6)&&(GetKeyState(VK_SHIFT)&0x8000))
      {//K-READ-UP, switch windows
        OutputDebugString(KeyString);
        OutputDebugString("The End\n");
        EnumWindows(EnumWinHandle,NULL);
        GetTitle=false;
        *KeyString='\0';
      }//K-READ-UP, switch windows
      else
      {//K-READ-UP, add characters to titlebar search string
        if(wParam!=VK_SHIFT)
        {//K-READ-UP-ADD, printable character
          GetKeyboardState(KeyboardState);
          ToAscii(wParam,MapVirtualKey(wParam,0),KeyboardState,(LPWORD)KeyInput,0);
          strcat(KeyString,KeyInput);
        }//K-READ-UP-ADD, printable character
      }//K-IN, add characters to titlebar search string
    }//K-READ, upstroke
    return 1;
  }//K, reading input for window switching
  if((wParam==VK_6)&&(GetKeyState(VK_SHIFT)&0x8000))
  {//K, begin reading titlebar text for window switching
    if(KeyUp)
    {//K-IN, upstroke
      GetTitle=true;
    }//K-IN, upstroke
    return 1;
  }//K, begin reading titlebar text for window switching
  if(!Extended)
  {//K, not extended
    switch(wParam)
    {//K-NEX, match input with action
      case Pad0Insert:
      {//K-NEX-MACT, global double-click
        if(KeyUp)
        {//K-NEX-MACT-DBL, upstroke
          return 1;
        }//K-NEX-MACT-DBL, upstroke
        if(KeyWasDn)
        {//K-NEX-MACT-DBL, repeat stroke
          return 1;
        }//K-NEX-MACT-DBL, repeat stroke
        //K-NEX-MACT-DBL, downstroke
        ZeroMemory(SI,sizeof(INPUT));
        SI[0].type=SI[1].type=SI[2].type=SI[3].type=INPUT_MOUSE;
        SI[0].mi.dwFlags=SI[2].mi.dwFlags=MOUSEEVENTF_LEFTDOWN;
        SI[1].mi.dwFlags=SI[3].mi.dwFlags=MOUSEEVENTF_LEFTUP;
        SendInput(4,SI,sizeof(INPUT));
        PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
        return 1;
      }//K-NEX-MACT, global double-click
      case PadPDelete:
      {//K-NEX-MACT, designated start/stop control key
        if(KeyUp)
        {//K-NEX-MACT-CON, upstroke
          if(Recording)
          {//K-NEX-MACT-CON-UP, stop recording in progress
            Recording=false;
            if(MouseDown)
            {//K-NEX-MACT-CON-UP-END, voiced "G" (button down from script)
              strcat(Script,"  Keys.SendInput({leftbutton_hold}) WAIT(1) \n");
            }//K-NEX-MACT-CON-UP-END, voiced "G" (button down from script)
            if(OpenClipboard(NULL))
            {//K-NEX-MACT-CON-UP-END, place script in clipboard
              _itoa(strlen(Script),StringOut,10);
              OutputDebugString(StringOut);
              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-MACT-CON-UP-END, place script in clipboard
            else
            {//K-NEX-MACT-CON-UP-END, error opening clipboard
              PlaySound(SoundPathError,NULL,SND_FILENAME|SND_ASYNC);
            }//K-NEX-MACT-CON-UP-END, error opening clipboard
          }//K-NEX-MACT-CON-UP, stop recording in progress
          else
          {//K-NEX-MACT-CON-UP, start recording
            AfterFirstUpAction=true;
            MouseDown=false;
            Recording=true;
            *Script='\0';
            *TitleBar2='\0';
            GetCursorPos(&PointScreenUp);
            WndoCurrent=GetForegroundWindow();
            GetWindowText(WndoCurrent,TitleBar1,255);
            PlaySound(SoundPathStart,NULL,SND_FILENAME|SND_ASYNC);
          }//K-NEX-MACT-CON-UP, start recording
        }//K-NEX-MACT-CON, upstroke
        return 1;//eat ctrl strokes
      }//K-NEX-MACT, designated start/stop control key
    }//K-NEX, match input with action
  }//K, not extended
  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(&PointCurrent);
      return::CallNextHookEx(hKeyboardHook,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, ctrl modified
        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;
        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, ctrl modified
      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;
        case Pad1End:
          if(KeyUp)
          {//K-R-NEX-NOD-SEK-PAD, upstroke
            strcat(Script,"  Keys.SendInput({scrolllock}) WAIT(1) #record point\n");
            GetCursorPos(&PointStored);
            PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
          }//K-R-NEX-NOD-SEK-PAD, upstroke
          return 1;
        case Pad2Dn:
          if(KeyUp)
          {//K-R-NEX-NOD-SEK-PAD, upstroke
            GetCursorPos(&PointCurrent);
            strcat(Script,"  SetMousePosition(0,");
            strcat(Script,_ltoa(PointCurrent.x,Coordinate,10));
            strcat(Script,",");
            strcat(Script,_ltoa(PointCurrent.y,Coordinate,10));
            strcat(Script,") WAIT(1) #set during recording\n");
            PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
          }//K-R-NEX-NOD-SEK-PAD, upstroke
          return 1;
        case Pad3PgDn:
          if(KeyUp)
          {//K-R-NEX-NOD-SEK-PAD, upstroke
            strcat(Script,"  Keys.SendInput({ctrl+scrolllock}) WAIT(1) #goto recorded point\n");
            SetCursorPos(PointStored.x,PointStored.y);
            PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
          }//K-R-NEX-NOD-SEK-PAD, upstroke
          return 1;
        case Pad4Left:
          if(KeyUp)
          {//K-R-NEX-NOD-SEK-PAD, start condensed recording mode
            OnOneLine=true;
            strcat(Script,"  \"");
            PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
          }//K-R-NEX-NOD-SEK-PAD, start condensed recording mode
          return 1;
        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;
        case Pad6Right:
          if(KeyUp)
          {//K-R-NEX-NOD-SEK-PAD, end condensed recording mode
            OnOneLine=false;
            strcat(Script,"\" WAIT(1) \n");
            PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);
          }//K-R-NEX-NOD-SEK-PAD, end condensed recording mode
          return 1;
        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;
        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;
        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;
        }//K-R-NEX-NOD, seeking numpad keys
      }//K-R-NEX, unmodified
    }//K-R, not extended
    if(OnOneLine)
    {//K, reading characters usually for a text box/field
      if(wParam!=VK_SHIFT)
      {//K-READ, printable characters
        if(KeyUp)
        {//K-READ-NFT, upstroke
          GetKeyboardState(KeyboardState);
          ToAscii(wParam,MapVirtualKey(wParam,0),KeyboardState,(LPWORD)KeyInput,0);
          strcat(Script,KeyInput);
        }//K-READ-NFT, upstroke
      }//K-READ, printable characters
      return::CallNextHookEx(hKeyboardHook,nCode,wParam,lParam);
    }//K, reading characters usually for a text box/field
    if(KeyUp)
    {//K-R, upstroke
      if(AfterFirstUpAction)
        return::CallNextHookEx(hKeyboardHook,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 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(hKeyboardHook,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(hKeyboardHook,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(hKeyboardHook,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;
      WndoCurrent=GetForegroundWindow();
      //check for new window
      GetWindowText(WndoCurrent,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,"  \"^");
            strcat(Script,TitleBar2);
            strcat(Script,"^\" WAIT(1) \n");
            strcat(Script,"  WaitForWindow(\"");
            strcat(Script,TitleBar2);
            strcat(Script,"\") WAIT(1) \n");
            return::CallNextHookEx(hKeyboardHook,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(hKeyboardHook,nCode,wParam,lParam);
        }//K-R-DN-DIF, task switching
      }//K-R-DN, different window
    }//K-R, downstroke, prepare to process next upstroke
    return::CallNextHookEx(hKeyboardHook,nCode,wParam,lParam);
  }//K, recording in progress
  if(!Extended)
  {//K, not extended
    switch(wParam)
    {//K-NEX, watch for the key
      case Pad3PgDn:
      {//K-NEX-MACT, collect idle workers
        if(KeyUp)
        {//K-NEX-MACT-IDLE, upstroke
          PostMessage(WndoEXE,DLL_INPUT_NOTICE,Pad3PgDn,lParam);
          PlaySound(SoundPathNotice,NULL,SND_FILENAME|SND_ASYNC);

        }//K-NEX-MACT-IDLE, upstroke
        return 1;//all strokes
      }//K-NEX-MACT, collect idle workers
      case GetOrSetPtrPos:
      {//K-NEX-MACT, get/set pointer position
        if(KeyUp)
        {//K-NEX-MACT-GSPOS, upstroke
          if(GetKeyState(VK_CONTROL)&0x8000)
          {//K-NEX-MACT-GSPOS-UP, ctrl modified
            SetCursorPos(PointStored.x,PointStored.y);
            AfterFirstUpAction=true;
          }//K-NEX-MACT-GSPOS-UP, ctrl modified
          else
          {//K-NEX-MACT-GSPOS-UP, not modified
            GetCursorPos(&PointStored);
          }//K-NEX-MACT-GSPOS-UP, not modified
        }//K-NEX-MACT-GSPOS, upstroke
        return 1;//all strokes
      }//K-NEX-MACT, get/set pointer position
    }//K-NEX, watch for the key
  }//K, not extended
  return::CallNextHookEx(hKeyboardHook,nCode,wParam,lParam);
}//key action
LRESULT CALLBACK MouseHook(int nCode,WPARAM wParam,LPARAM lParam)
{//mouse action
  if(MouseMoveMessage)
  {//M, ignore mouse movement
    return::CallNextHookEx(hMouseHook,nCode,wParam,lParam);
  }//M, ignore mouse movement
  if(UnknownAction)
  {//M, unusable mouse message
    return::CallNextHookEx(hKeyboardHook,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(hKeyboardHook,nCode,wParam,lParam);
    }//M-R, double-click
    if(BtnEitherDn)
    {//M-R, either button down
      AfterFirstUpAction=false;
      MouseDown=true;
      GetCursorPos(&PointScreenDn);
      WndoCurrent=GetForegroundWindow();
      //check for new window
      GetWindowText(WndoCurrent,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,"  \"^");
          strcat(Script,TitleBar2);
          strcat(Script,"^\" WAIT(1) \n");
          strcat(Script,"  WaitForWindow(\"");
          strcat(Script,TitleBar2);
          strcat(Script,"\") WAIT(1) \n");
          return::CallNextHookEx(hKeyboardHook,nCode,wParam,lParam);
        }//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(WndoCurrent,&WndoBorder);
        PointContextDn={PointScreenDn.x-WndoBorder.left,PointScreenDn.y-WndoBorder.top};
      }//M-R-DN, use window coordinates
      else
      {//M-R-DN, use screen coordinates
        strcpy(ClickContext,"  SetMousePosition(0,");
        PointContextDn=PointScreenDn;
      }//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(PointContextDn.x,Coordinate,10));
        strcat(PointDn,",");
        strcat(PointDn,_ltoa(PointContextDn.y,Coordinate,10));
      }//M-R-DN, pointer moved before button down
      return::CallNextHookEx(hKeyboardHook,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(hMouseHook,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(hMouseHook,nCode,wParam,lParam);
      }//M-R-UP, voiced "X" (button up from script)
      MouseDown=false;
      GetCursorPos(&PointScreenUp);
      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(PointScreenUp.x-PointScreenDn.x,Coordinate,10));
        strcat(PointUp,",");
        strcat(PointUp,_ltoa(PointScreenUp.y-PointScreenDn.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(hMouseHook,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(hMouseHook,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(hMouseHook,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(hMouseHook,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(hMouseHook,nCode,wParam,lParam);
}//mouse action
DLLEXPORT BOOL hookDLLInit()
{//initialize DLL
  if(hKeyboardHook==NULL)
  {//RUN, install keyboard & mouse hooks
    HINSTANCE hInst=theDll.m_hInstance;
    hKeyboardHook=SetWindowsHookEx(WH_KEYBOARD,KeyboardHook,hInst,0);
    hMouseHook=SetWindowsHookEx(WH_MOUSE,MouseHook,hInst,0);
  }//RUN, install keyboard & mouse hooks
  //RUN, enable program sounds
  GetCurrentDirectory(256,SoundFolder);
  char*pch;
  pch=strchr(SoundFolder,'\\');
  while(pch!=NULL)
  {//RUN, format program path
    *pch='/';
    pch=strchr(pch+1,'\\');
  }//RUN, 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");
  //RUN, get a handle on program window
  WndoEXE=FindWindow(NULL,"hookEXE");
  return TRUE;
}//initialize DLL
DLLEXPORT void hookDLLTerm()
{//terminate DLL, remove hooks
  BOOL bRet1=UnhookWindowsHookEx(hKeyboardHook);
  BOOL bRet2=UnhookWindowsHookEx(hMouseHook);
}//terminate DLL, remove hooks
DLLEXPORT void ContinuePlaying(BOOL status)
{//continue playing or not
  if(status)
  {//continue playing
    PostMessage(WndoEXE,DLL_INPUT_NOTICE,0,0);
  }//continue playing
  return;
}//continue playing or not

#define UnknownAction    (nCode!=HC_ACTION)

#define BtnEitherDn      (wParam==WM_LBUTTONDOWN)||(wParam==WM_NCLBUTTONDOWN)||(wParam==WM_RBUTTONDOWN)||(wParam==WM_NCRBUTTONDOWN)
#define BtnEitherUp      (wParam==WM_LBUTTONUP)||(wParam==WM_NCLBUTTONUP)||(wParam==WM_RBUTTONUP)||(wParam==WM_NCRBUTTONUP)
#define BtnLeftDn        (wParam==WM_LBUTTONDOWN)||(wParam==WM_NCLBUTTONDOWN)
#define BtnLeftClick     (wParam==WM_LBUTTONUP)||(wParam==WM_NCLBUTTONUP)
#define BtnRightClick    (wParam==WM_RBUTTONUP)||(wParam==WM_NCRBUTTONUP)
#define BtnRightDn       (wParam==WM_RBUTTONDOWN)||(wParam==WM_NCRBUTTONDOWN)
#define DoubleClick      (wParam==WM_LBUTTONDBLCLK)
#define MouseMoveMessage (wParam==WM_MOUSEMOVE)||(wParam==WM_NCMOUSEMOVE)

#define PointerMoved     (abs(PointScreenUp.x-PointScreenDn.x)>12)||(abs(PointScreenUp.y-PointScreenDn.y)>12)

#define Extended         (lParam&0x01000000)
#define KeyUp            (lParam&0x80000000)
#define KeyWasDn         (lParam&0x40000000)

//#define StopPlaying      (wParam==VK_FINAL)//interprocess communication

#define GetOrSetPtrPos   VK_SCROLL//record or restore pointer position
#define SwitchToWindow   VK_LAUNCH_APP1//record or restore pointer position

#define Pad0Insert       VK_INSERT
#define Pad1End          VK_END
#define Pad2Dn           VK_DOWN
#define Pad3PgDn         VK_NEXT
#define Pad4Left         VK_LEFT
#define Pad5Clear        VK_CLEAR
#define Pad6Right        VK_RIGHT
#define Pad7Home         VK_HOME
#define Pad8Up           VK_UP
#define Pad9PgUp         VK_PRIOR
#define PadPDelete       VK_DELETE

#define VK_A             0x41
#define VK_B             0x42
#define VK_C             0x43
#define VK_D             0x44
#define VK_E             0x45
#define VK_F             0x46
#define VK_G             0x47
#define VK_H             0x48
#define VK_I             0x49
#define VK_J             0x4A
#define VK_K             0x4B
#define VK_L             0x4C
#define VK_M             0x4D
#define VK_N             0x4E
#define VK_O             0x4F
#define VK_P             0x50
#define VK_Q             0x51
#define VK_R             0x52
#define VK_S             0x53
#define VK_T             0x54
#define VK_U             0x55
#define VK_V             0x56
#define VK_W             0x57
#define VK_X             0x58
#define VK_Y             0x59
#define VK_Z             0x5A

#define VK_0             0x30
#define VK_1             0x31
#define VK_2             0x32
#define VK_3             0x33
#define VK_4             0x34
#define VK_5             0x35
#define VK_6             0x36
#define VK_7             0x37
#define VK_8             0x38
#define VK_9             0x39

Back to comp.lang.beta | Previous | Next | Find similar


Thread

VoiceWorks Vocola 2 macro recorder files John Doe <jdoe@usenetlove.invalid> - 2014-03-10 17:30 +0000

csiph-web