home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cenvi23.zip / TEXTBOSS.LIB < prev    next >
Text File  |  1995-09-13  |  18KB  |  453 lines

  1. // TextBoss.lib - Functions for controlling a windowed DOS or windowed OS/2
  2. // ver.5          session. Read the screen and send keystrokes.  These
  3. //                routines work with both OS/2 and DOS windows alike, except
  4. //                SendDosKey() and SendOS2Key(), and specific routines
  5. //                for full-screen OS/2 sessions.
  6. //
  7. //**** KeyStroke(): Press and release a key or combination of keys
  8. // See KeyStroke in KEYPUSH.LIB.  KeyStroke() can be used in most
  9. // situations to send keystrokes to windowed DOS sessions.
  10. //
  11. //***** ReadTextWindow(): Return contents of Text window in buffer
  12. // SYNTAX: string ReadTextWindow(int TextWindowHandle[,int DataLen])
  13. //         string ReadTextWindow(string WindowTitle[,int DataLen])
  14. // WHERE: TextWindowHandle: Integer identifier for this window
  15. //        TextWindowTitle: Partial text title of the window (case-insensitive)
  16. //        DataLen: Length of string returned if not NULL
  17. // RETURN: Returns NULL if failed to read, else returns string containing the
  18. //         contents of the Text window.
  19. //
  20. //
  21. //***** CopyTextBufferToLines(): Convert Text window string to lines
  22. // SYNTAX: string[] CopyTextBufferToLines(string Buffer,int LineCount)
  23. // WHERE: Buffer: Text buffer as returned by ReadTextWindow()
  24. //        LineCount: Return number of lines in the returned array
  25. // MODIFY: Linecount is set to number of returned lines
  26. // RETURN: Returns an array of strings where each element represents
  27. //         the next row of the Text screen.
  28. //
  29. //
  30. //**** ReadTextWindowAt(): read specific string at window location
  31. // SYNTAX: string ReadTextWindowAt(int/string TextWindowSpec,int TextRow,
  32. //                                 int TextCol,int Length)
  33. // WHERE: TextWindowSpec: Window name or integer andle
  34. //        TextRow, TextCol; screen position from 0 to max height/width
  35. //        Length: Length (in characters) of screen to read
  36. // RETURN: Return text read, or NULL if window not found
  37. //
  38. //
  39. //***** PasteToTextWindow(): Send characters to a Text window's keyboard
  40. // SYNTAX: void PasteToTextWindow(int TextWindowHandle,string String)
  41. //         void PasteToTextWindow(string WindowTitle,string String)
  42. // WHERE: TextWindowHandle: Integer identifier for this window
  43. //        TextWindowTitle: Partial text title of the window (case-insensitive)
  44. //        String: String of characters to paste into the Text window
  45. // NOTE: If this function fails after about 15 calls, and won't work again,
  46. //       then call IBM at 1-800-992-4777 and ask for fix for APAR PJ11939.
  47. // new report # 3X128,PSZ
  48. //
  49. //
  50. //**** SendDosKey(): Send keystrokes (key and scancode) to DOS window running ServeOS2
  51. // SYNTAX: bool SendDosKey(string ServerSpec,string AsciiBuffer)
  52. //         bool SendDosKey(string ServerSpec,int KeyCode)
  53. //         bool SendDosKey(string ServerSpec,int[] KeyCodes,KeyCount)
  54. //         bool SendDosKey(string ServerSpec,int KeyCode,K_CTRL or K_ALT or K_SHIFT)
  55. // WHERE: ServerSpec: Unique 8.3 name that ServeOS2 was started with
  56. //        AsciiBuffer: Character string to send, will translate to KeyCode
  57. //        KeyCode: ScanCode is high byte, and CharCode is low byte; if not ScanCode
  58. //                 then this function will determine one
  59. //        KeyCodes: An array of ScanCode/CharCode key codes
  60. //        KeyCount: How many keys in the KeyCodes array
  61. //        K_CTRL or K_ALT or K_SHIFT: Use one of these pre-defined values to send code that
  62. //                 this key was held while Key is pressed 
  63. // RETURN: Return True if communication with DOS works, else False
  64. // NOTE: You cannot send more than 255 keys in one call
  65. //
  66. //
  67. //**** SendOS2Key(): Send keystrokes (key and scancode) to OS/2 window
  68. // SYNTAX: bool SendOS2Key(WindowSpec,string AsciiBuffer)
  69. //         bool SendOS2Key(WindowSpec,int KeyCode)
  70. //         bool SendOS2Key(WindowSpec,int[] KeyCodes,KeyCount)
  71. //         bool SendOS2Key(WindowSpec,int KeyCode,K_CTRL or K_ALT or K_SHIFT)
  72. // WHERE: WindowSpec: integer window handle, or partial title string
  73. //        AsciiBuffer: Character string to send, will translate to KeyCode
  74. //        KeyCode: ScanCode is high byte, and CharCode is low byte; if not ScanCode
  75. //                 then this function will determine one
  76. //        KeyCodes: An array of ScanCode/CharCode key codes
  77. //        KeyCount: How many keys in the KeyCodes array
  78. //        K_CTRL | K_ALT | K_SHIFT: Use one of these pre-defined values to send code that
  79. //                 this key was held while Key is pressed
  80. // RETURN: Return True if communication with window works, else False
  81. //
  82. //
  83. //**** SendFullOS2Key(): Send keystrokes (key and scancode) to full-screen OS/2
  84. //****                   session running FSSlave.cmm
  85. // SYNTAX: bool SendFullOS2Key(string FSSlaveSpec,string AsciiBuffer)
  86. //         bool SendFullOS2Key(string FSSlaveSpec,int KeyCode)
  87. //         bool SendFullOS2Key(string FSSlaveSpec,int[] KeyCodes,KeyCount)
  88. //         bool SendFullOS2Key(string FSSlaveSpec,int KeyCode,K_CTRL or K_ALT or K_SHIFT)
  89. // WHERE: FSSlaveSpec: Unique 8.3 name that FSSlave.cmm was started with
  90. //        AsciiBuffer: Character string to send, will translate to KeyCode
  91. //        KeyCode: ScanCode is high byte, and CharCode is low byte; if not ScanCode
  92. //                 then this function will determine one
  93. //        KeyCodes: An array of ScanCode/CharCode key codes
  94. //        KeyCount: How many keys in the KeyCodes array
  95. //        K_CTRL or K_ALT or K_SHIFT: Use one of these pre-defined values to send code that
  96. //                 this key was held while Key is pressed
  97. // RETURN: Return True if communication with FSSlave.cmm works, else False
  98. // NOTE: This function returns before all keystrokes have been removed by
  99. //       FSServer.cmm
  100. //
  101. //
  102. //**** ReadFullOS2Text(): Read contents of OS/2 full-screen text window
  103. // SYNTAX: string ReadFullOS2Text(string FSSlaveSpec[,int Col,int Row[,int Timeout]])
  104. // WHERE: FSSlaveSpec: Unique 8.3 name that FSSlave.cmm was started with
  105. //        Col,Row: If specified, set how many columns and rows of data
  106. //        Timeout: Time to wait, in milliseconds, for data to be filled, if
  107. //                 not supplied then use a long default
  108. // RETURN: Returns NULL if failed to read, else returns string containing the
  109. //         contents of the full-screen OS/2 text window.
  110. //
  111. //
  112.  
  113. #define K_CTRL    1
  114. #define K_ALT     2
  115. #define K_SHIFT   3
  116.  
  117. #define K_F1   0x3B00
  118. #define K_F2   0x3C00
  119. #define K_F3   0x3D00
  120. #define K_F4   0x3E00
  121. #define K_F5   0x3F00
  122. #define K_F6   0x4000
  123. #define K_F7   0x4100
  124. #define K_F8   0x4200
  125. #define K_F9   0x4300
  126. #define K_F10  0x4400
  127. #define K_INS  0x5200
  128. #define K_DEL  0x4300
  129. #define K_UP   0x4800
  130. #define K_DOWN 0x5000
  131. #define K_LEFT 0x4B00
  132. #define K_RIGHT 0x4D00
  133. #define K_PGUP 0x4900
  134. #define K_PGDN 0x5100
  135. #define K_END  0x4F00
  136. #define K_HOME 0x4700
  137.  
  138. #define K_ESC  0x011B
  139. #define K_SHIFT_TAB 0x0F00
  140.  
  141.  
  142. #include <WinTools.lib>
  143. #include <ClipBrd.lib>
  144. #include <WinMsg.lib>
  145. #include <FileIO.lib>
  146. #include <NamePipe.lib>
  147. #include <ScanCode.lib>
  148. #include <GiveMem.lib>
  149.  
  150. ReadTextWindow(pWindowSpec,pDataLen)
  151. {
  152.    lTextWindowData = NULL;  // assume failure
  153.    lDataLen = 0;
  154.    if ( (lReadHandle = GetWindowHandle(pWindowSpec)) ) {
  155.  
  156.       // Clear the clipboard, so we'll know when new data is here
  157.       PutClipboardData(NULL);
  158.  
  159.       // Send MENU message to the Window to paste all data into the clipboard
  160.       #define WM_SYSCOMMAND      0x0021
  161.       #define CMDSRC_MENU        2
  162.       #define COPY_ALL_COMMAND   0x9E
  163.       WinSendMsg(lReadHandle,WM_SYSCOMMAND,COPY_ALL_COMMAND,CMDSRC_MENU);
  164.  
  165.       if ( NULL != (lTextWindowData = GetClipboardData(CF_TEXT,lDataLen)) )
  166.          lDataLen = strlen(lTextWindowData);
  167.  
  168.    }
  169.    if ( 1 < va_arg() )
  170.       pDataLen = lDataLen;
  171.    return lTextWindowData;
  172. }
  173.  
  174.  
  175. CopyTextBufferToLines(pBuffer,pLineCount)
  176. {
  177.    for ( lBuf = pBuffer, pLineCount = 0; lBuf[0];
  178.          pLineCount++, lBuf += lStringLen + 1 ) {
  179.       lStringLen = strcspn(lBuf,"\n");
  180.       strncpy(lLines[pLineCount],lBuf,lStringLen);
  181.    }
  182.    return lLines;
  183. }
  184.  
  185. ReadTextWindowAt(pWinSpec,pRow,pCol,pLen)
  186. {
  187.    lResult = NULL; // assume failure
  188.    if ( lFullText = ReadTextWindow(pWinSpec) ) {
  189.       lLines = CopyTextBufferToLines(lFullText,lLineCount);
  190.       if ( pRow < lLineCount ) {
  191.          // copy to result buffer, with blanks beyond end of string
  192.          memset(lResult,' ',pLen);
  193.          memcpy(lResult,lLines[pRow]+pCol,strlen(lLines[pRow]+pCol));
  194.          lResult[pLen] = 0; // null terminate beyond part read
  195.       }
  196.    }
  197.    return lResult;
  198. }
  199.  
  200. PasteToTextWindow(pWindowSpec,pString)
  201. {
  202.    if ( (lTypeHandle = GetWindowHandle(pWindowSpec)) ) {
  203.  
  204.       // Put the pString data into the clipboard
  205.       PutClipboardData(pString,1+strlen(pString),CF_TEXT);
  206.  
  207.       // Send menu message to paste from the clipboard
  208.       #define PASTE_COMMAND   0x9F
  209.       WinPostMsg(lTypeHandle,WM_SYSCOMMAND,PASTE_COMMAND,CMDSRC_MENU,False);
  210.    }
  211. }
  212.  
  213. BuildScanCharBuffer(pArgCount,pKeyCode,pHoldKey,pKeyCount)
  214.    // return buffer containing scan-code/keycode, or NULL if error.
  215.    // pArgCount shows how many; set pKeyCount to keys in buffer
  216. {
  217.    // Build lBuffer based on type of input
  218.    lHoldAKeyDown = ( 2 < pArgCount );
  219.    lBuffer[0] = '\0';   // initialize lBuffer as a byte buffer
  220.    if ( 1 == DataDimension(pKeyCode) ) {
  221.       if ( CMM_BYTE == DataType(pKeyCode) ) {
  222.          // pKeyCode is an ascii string, for all of string add this key code
  223.          // and look up its scan code too
  224.          for ( pKeyCount = 0; pKeyCode[pKeyCount]; pKeyCount++ ) {
  225.             // char code is written first, then scan code
  226.             lBuffer[pKeyCount*2] = pKeyCode[pKeyCount];
  227.             lBuffer[1+(pKeyCount*2)] = GetScanCode(pKeyCode[pKeyCount]);
  228.          }
  229.       } else {
  230.          // this is an array of pkeycode, scancode and charcode
  231.          for ( pKeyCount = 0; pKeyCount < pHoldKey; pKeyCount++ ) {
  232.             // char code is written first, then scan code
  233.             lBuffer[pKeyCount*2] = pKeyCode[pKeyCount] & 0xFF;
  234.             lBuffer[1+(pKeyCount*2)] = (pKeyCode[pKeyCount] >> 8) & 0xFF;
  235.          }
  236.       }
  237.    } else {
  238.       // pKeyCode is a single key if no scan code then must get it
  239.       pKeyCount = 1;
  240.       lCharCode = pKeyCode & 0xFF;
  241.       lScanCode = (pKeyCode & 0xFF00) >> 8;
  242.       if ( 0 == lScanCode )
  243.          lScanCode = GetScanCode(lCharCode);
  244.       if ( lHoldAKeyDown ) {
  245.          // adjust keys for pHoldKey
  246.          switch( pHoldKey ) {
  247.             case K_CTRL:
  248.                if ( 'A' <= toupper(lCharCode) && toupper(lCharCode) <= 'Z' )
  249.                   lCharCode -= 'A' - 1;
  250.                else if ( K_F1 <= pKeyCode  &&  pKeyCode <= K_F10 )
  251.                   lScanCode += 0x23;
  252.                else {
  253.                   switch ( lScanCode ) {
  254.                      case K_LEFT:  lScanCode = 0x73; break;
  255.                      case K_RIGHT: lScanCode = 0x74; break;
  256.                      case K_PGUP:  lScanCode = 0x84; break;
  257.                      case K_PGDN:  lScanCode = 0x76; break;
  258.                      case K_END:   lScanCode = 0x77; break;
  259.                      case K_HOME:  lScanCode = 0x75; break;
  260.                   }
  261.                }
  262.                break;
  263.             case K_ALT:
  264.                if ( 'A' <= toupper(lCharCode) && toupper(lCharCode) <= 'Z' )
  265.                   lCharCode = 0;
  266.                else if ( K_F1 <= pKeyCode  &&  pKeyCode <= K_F10 )
  267.                   lScanCode += 0x2D;
  268.                else if ( 0x02 <= ScanCode  &&  ScanCode <= 0x0D )
  269.                   lScanCode += 0x76, lCharCode = 0;
  270.                break;
  271.             case K_SHIFT:
  272.                if ( islower(lCharCode) )
  273.                   lCharCode = toupper(lCharCode);
  274.                else if ( K_F1 <= pKeyCode  &&  pKeyCode <= K_F10 )
  275.                   lScanCode += 0x19;
  276.                break;
  277.             default:
  278.                printf("\aHoldKey = %d unknown!\a\n",pHoldKey); abort();
  279.          }
  280.       }
  281.       lBuffer[0] = lCharCode;
  282.       lBuffer[1] = lScanCode;
  283.    }
  284.    return ( 0 == pKeyCount ) ? NULL : lBuffer ;
  285. }
  286.  
  287. SendDosKey(pServerSpec,pKeyCode,pHoldKey)
  288. {
  289.    lArgCount = va_arg();
  290.    lBuffer = BuildScanCharBuffer(lArgCount,pKeyCode,2<lArgCount?pHoldKey:NULL,lKeyCount);
  291.    if ( !lBuffer || 255 < lKeyCount ) return False;
  292.    return SendKeyBufferToDOSServer(pServerSpec,lBuffer,lKeyCount);
  293. }
  294.  
  295. SendKeyBufferToDOSServer(pPipeName,pBuffer,pBufferLen/*max 255*/)
  296. {
  297.    bool lSuccess = False;   // assume failure
  298.    sprintf(lFullName,"\\PIPE\\%s",pPipeName);
  299.  
  300.    if ( !DosCreateNPipe(lFullName,lPipeHandle,
  301.                         NP_ACCESS_DUPLEX | NP_NOINHERIT,
  302.                         NP_NOWAIT | NP_TYPE_BYTE | NP_UNLIMITED_INSTANCES | NP_READMODE_BYTE,
  303.                         4096, 0, 0) ) {
  304.       // Give the DOS program up to 10 seconds to open the file
  305.       for ( lrepeat =  10 * 10; lRepeat--; ) {
  306.          suspend(100);
  307.          if ( !DosConnectNPipe(lPipeHandle) ) {
  308.             lSuccess = True;
  309.             break;
  310.          }
  311.       }
  312.       if ( lSuccess ) {
  313.  
  314.          // change pipe to blocking state to make sure reads and writes are
  315.          // finished
  316.          DosSetNPHState(lPipeHandle,NP_WAIT | NP_READMODE_BYTE);
  317.  
  318.          _SendBuf[0] = byte(pBufferLen);
  319.          memcpy(_SendBuf+1,pBuffer,2*pBufferLen);
  320.          if ( DosWrite(lPipeHandle,_SendBuf,2*pBufferLen+1,lBytesSent)
  321.            || lBytesSent != 2*pBufferLen+1 ) {
  322.             lSuccess = False;
  323.          } else {
  324.             // Will be finished when DOS closes the file, which will
  325.             // break the pipe.  A READ will hang until pipe is broken.
  326.             lDummyBuf[0] = '\0';
  327.             DosRead(lPipeHandle,lDummyBuf,1,lByteRead);
  328.          }
  329.          DosDisconnectNPipe(lPipeHandle);
  330.       }
  331.       DosClose(lPipeHandle);
  332.    }
  333.    return(lSuccess);
  334. }
  335.  
  336. SendOS2Key(pWindowSpec,pKeyCode,pHoldKey)
  337. {
  338.    lArgCount = va_arg();
  339.    lBuffer = BuildScanCharBuffer(lArgCount,pKeyCode,2<lArgCount?pHoldKey:NULL,lKeyCount);
  340.    if ( !lBuffer ) return False;
  341.  
  342.    lWindowHandle = GetWindowHandle(pWindowSpec);
  343.    if ( !lWindowHandle ) return False;
  344.    lIsActive = (GetActiveWindow() == lWindowHandle);
  345.  
  346.    // the window to send keystrokes to is the FID_CLIENT window
  347.    #define FID_CLIENT      0x8008
  348.    #define ORD_WIN32WINDOWFROMID 899
  349.    lWindowHandle = DynamicLink("PMWIN",ORD_WIN32WINDOWFROMID,BIT32,CDECL,
  350.                                lWindowHandle,FID_CLIENT);
  351.    if ( !lWindowHandle ) return False;
  352.    #define ORD_WIN32QUERYFOCUS   817
  353.  
  354.    // temporarily get focus if not running a VIO shell, else WM_CHAR is ignored
  355.    #define WM_SETFOCUS  0x0f
  356.    if ( lFocus = DynamicLink("PMWIN",ORD_WIN32QUERYFOCUS,BIT32,CDECL,HWND_DESKTOP) ) {
  357.       if ( lFocus == lWindowHandle || ShieldOrSeamless(lFocus) )
  358.          lFocus = NULL;
  359.       else
  360.          WinPostMsg(lWindowHandle,WM_SETFOCUS,NULL,True);
  361.    }
  362.  
  363.    lParam1 = 1 << 16;
  364.    for ( lKey = 0; lKey < lKeyCount; lKey++, lBuffer += 2 ) {
  365.       #define WM_CHAR   0x7a
  366.       WinPostMsg(lWindowHandle,WM_CHAR,lParam1,BLObGet(lBuffer,0,UWORD16));
  367.    }
  368.    if ( lFocus )
  369.       WinPostMsg(lWindowHandle,WM_SETFOCUS,NULL,False);
  370.    return True;
  371. }
  372.  
  373. ShieldOrSeamless(pHwnd)  // true if Shield or SeamlessClass window
  374. {
  375.    #define ORD_WIN32QUERYCLASSNAME  805
  376.    lString[1000] = '\0';
  377.    lString[DynamicLink("PMWIN",ORD_WIN32QUERYCLASSNAME,BIT32,CDECL,pHwnd,999,lString)] = 0;
  378.    return !stricmp(lString,"Shield") || !stricmp(lString,"SeamlessClass");
  379. }
  380.  
  381. SendFullOS2Key(pFSSlaveSpec,pKeyCode,pHoldKey)
  382. {
  383.    lArgCount = va_arg();
  384.    lBuffer = BuildScanCharBuffer(lArgCount,pKeyCode,2<lArgCount?pHoldKey:NULL,lKeyCount);
  385.    return SendKeyBufferToFullOS2Server(pFSSlaveSpec,lBuffer,lKeyCount);
  386. }
  387.  
  388. SendKeyBufferToFullOS2Server(pQueueName,pBuffer,pBufferLen,pReadTimeout)
  389. { // if ReadTimeout then waiting for text to be passed back
  390.    sprintf(lQueueName,"\\QUEUES\\%s",pQueueName);
  391.  
  392.    // open queue to send messages
  393.    #define ORD_DOS32OPENQUEUE    15
  394.    if ( DynamicLink("QUECALLS",ORD_DOS32OPENQUEUE,BIT32,CDECL,
  395.                     lQueueProcess,lQueueHandle,lQueueName) )
  396.       return False;
  397.  
  398.    lKeyBuffer = GiveMemoryToProcess(lQueueProcess);
  399.  
  400.    // if timeout then reading from screen
  401.    lTimeout = (ReadingScreen = (3 < va_arg())) ? pReadTimeout : 20000;
  402.    poke(lKeyBuffer,ReadingScreen ? 0xFACE : 0xFEED,UWORD16);
  403.  
  404.    // add keystroke as big buffer; but must first give memory to server
  405.    poke(lKeyBuffer+2,pBuffer,pBufferLen*2);
  406.    #define ORD_DOS32WRITEQUEUE   14
  407.    lRc = DynamicLink("QUECALLS",ORD_DOS32WRITEQUEUE,BIT32,CDECL,
  408.                      lQueueHandle,0,2+pBufferLen*2,lKeyBuffer,0);
  409.  
  410.    // close the queue
  411.    #define ORD_DOS32CLOSEQUEUE  11
  412.    assert( !DynamicLink("QUECALLS",ORD_DOS32CLOSEQUEUE,BIT32,CDECL,lQueueHandle) );
  413.  
  414.    if ( !lRc ) {
  415.       // wait until timeout for buffer to change from 0xFEEF
  416.       EndTime = clock() + lTimeout*CLOCKS_PER_SEC/1000;
  417.       lRc = 1; // assume failure
  418.       do {
  419.          suspend(334);  // wait 1/3 second
  420.          if ( !peek(lKeyBuffer,UWORD16) ) {
  421.             pBuffer = peek(lKeyBuffer+2,pBufferLen*2);
  422.             lRc = 0;
  423.             break;
  424.          }
  425.       } while ( clock() <= EndTime )
  426.    }
  427.  
  428.    TerminateGMSharedMemoryPointer();
  429.    return !lRc;
  430. }
  431.  
  432. ReadFullOS2Text(pFSSlaveSpec,pCol,pRow,pTimeout)
  433. {
  434.    lArgCount = va_arg();
  435.    lTimeout = lArgCount < 4 ? 15000 : pTimeout ;
  436.    #define MAX_ROWCOUNT    50
  437.    #define MAX_COLCOUNT    80
  438.    lBufferLen = MAX_ROWCOUNT * MAX_COLCOUNT + 2 + 2;
  439.    BLObSize(lBLOb,lBufferLen);
  440.    if ( !SendKeyBufferToFullOS2Server(pFSSlaveSpec,lBLOb,lBufferLen/2,lTimeout) )
  441.       return NULL;
  442.    lColCount = BLObGet(lBLOb,0,UWORD16);
  443.    lRowCount = BLObGet(lBLOb,2,UWORD16);
  444.    lDataLength = lColCount * lRowCount;
  445.    lData = BLObGet(lBLOb,4,lColCount * lRowCount);
  446.    if ( 1 < lArgCount ) {
  447.       pCol = lColCount;
  448.       pRow = lRowCount;
  449.    }
  450.    return lData;
  451. }
  452.  
  453.