home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / S12518.ZIP / PMACCESS.C < prev    next >
Text File  |  1989-12-11  |  19KB  |  550 lines

  1. /* pmaccess.c RHS 7/14/89
  2.  *
  3.  * application that uses PMSERVER for accessing PM services
  4.  *
  5.  *
  6.     This application is a VIO app that offers the following services:
  7.     1. It allows the user to position the cursor any where in the input screen
  8.     2. It allows the user to type text into any part of the input screen
  9.     3. It allows the user to mark any text in the input screen
  10.     4. It allows the user to copy, cut or paste any part of the input screen.
  11.  *
  12.  */
  13.  
  14. #define    INCL_SUB
  15. #define    INCL_DOSERRORS
  16. #define    INCL_DOS
  17. #include<os2.h>
  18. #include<mt\stdio.h>
  19. #include<mt\string.h>
  20. #include<mt\stdlib.h>
  21. #include<mt\process.h>
  22. #include<mt\dos.h>
  23. #include"mou.h"
  24. #include"kbd.h"
  25. #include"pmserver.h"
  26. #include"moudefs.h"
  27. #include"kbddefs.h"
  28. #include"msgq.h"
  29. #include"button.h"
  30. #include"errexit.h"
  31. #include"msgs.h"
  32.  
  33. #define     MAINMSGQUEUE    "\\QUEUES\\PMACCESS.QUE"
  34.  
  35. #define     VIOHDL                  0
  36. #define     KEYTHREADSTACK          500         // keyboard thread stack
  37. #define     REQUESTTHREADSTACK      500         // request thread stack
  38. #define     MOUTHREADSTACK          800         // mouse thread stack
  39.  
  40. #define     BORDERCOL               79
  41. #define     BORDERROW               21
  42. #define     STARTROW                0
  43. #define     ENDROW                  20
  44.  
  45. #define     BUTTON_ON               0x70
  46. #define     BUTTON_OFF              0x0f
  47. #define     NORMAL                  BUTTON_OFF
  48. #define     HIGHLIGHT               BUTTON_ON
  49.  
  50. #define     beep()                  DosBeep(440,200)
  51. #define     Lastchar(str)           (str[strlen(str)-1])
  52.  
  53. #define     MAXREQUESTCOUNT         10
  54. #define     REQUESTTHREADSLEEPTIME  3000L
  55.  
  56.     /********************* Buttons ****************************/
  57.  
  58. #define     BUTTONLIST              6
  59. BUTTON buttonlist[BUTTONLIST] =
  60.     {
  61. /* text  title  row,col,row,col,attr,     type    left val,   right val,
  62.         accelerator    */
  63. {" Copy ","",   22, 0, 0, 0,  BUTTON_OFF, BPRESS, MSG_COPY,   MSG_COPY,
  64.         ALT_O,  0},
  65. {" Cut ","",    22, 9, 0, 0,  BUTTON_OFF, BPRESS, MSG_CUT,    MSG_CUT,
  66.         ALT_U,  0},
  67. {" Paste ","",  22,17, 0, 0,  BUTTON_OFF, BPRESS, MSG_PASTE,  MSG_PASTE,
  68.         ALT_P,  0},
  69.  
  70. {" Clear ","",  22,63, 0, 0,  BUTTON_OFF, BPRESS, MSG_CLR,    MSG_CLR,
  71.         ALT_C,  0},
  72. {" Esc ","",    22,73, 0, 0,  BUTTON_OFF, BPRESS, MSG_ESCAPE, MSG_ESCAPE,
  73.         ESC,    0},
  74.  
  75. {NULL,           0, 0, 0, 0,  0,          0,      0,          0,
  76.                 0,      0}
  77.     };
  78.  
  79.     /**********************************************************/
  80.  
  81. typedef struct _screen_label
  82.     {
  83.     PCHAR   text;
  84.     SHORT   row;
  85.     SHORT   column;
  86.     } SCREEN_LABEL;
  87.  
  88. #define SCREEN_LABELS 2
  89. SCREEN_LABEL screen_labels[SCREEN_LABELS] =
  90.     {
  91.     {"Clipboard Functions",     BORDERROW,     3},
  92.     {"General Functions",       BORDERROW,     63}
  93.     };    
  94.  
  95. PCHAR mainmsgqueue = MAINMSGQUEUE;
  96. BYTE MouThreadStack[MOUTHREADSTACK];
  97. BYTE KbdThreadStack[KEYTHREADSTACK];
  98. BYTE RequestThreadStack[REQUESTTHREADSTACK];
  99.  
  100. long MouSem = 0L, KbdSem = 0L;
  101.  
  102. unsigned    BlankCell = 0x0f20;
  103. USHORT  dirrow = BORDERROW;
  104.  
  105. USHORT  DDEstartrow,DDEstartcol,DDEendrow,DDEendcol;
  106. USHORT  rowBlockBeg,colBlockBeg,startBlock,ScreenRows,ScreenCols,blocksize;
  107. USHORT  startrow,startcol,endrow,endcol;
  108. BYTE    highlight_att = HIGHLIGHT,normal_att = NORMAL;
  109. PBYTE   blockptr, bufptr;
  110. HQUEUE  pmshdl;
  111.  
  112. BYTE    tempbuffer[8192];
  113. USHORT  clipboard_data = TRUE;
  114. PIDINFO pidinfo;
  115.  
  116.     /********************* Function Prototypes ********************/
  117.  
  118. void    main(void);
  119. void    RequestThread(void);
  120.  
  121. void    InitScreen(void);
  122. void    SetBlock(USHORT row, USHORT col);
  123. void    ResetScreen(void);
  124. void    BlankBlock(void);
  125. void    ResetBlock(void);
  126.  
  127. void    ButtonPress(USHORT *eventcode);
  128. USHORT  prepare_CLPBRDblock(void);
  129. void    PMS_Init(HQUEUE serverhandle,char *qname);
  130. void    PMS_Terminate(HQUEUE serverhandle);
  131. USHORT  readtextblock(PCHAR buffer,
  132.         USHORT srow, USHORT scol, USHORT erow, USHORT ecol);
  133.  
  134. void main(void)
  135.     {
  136.     USHORT pause = 0, msg, capture, valid_block, msgsize, retval, i,j;
  137.     USHORT post_on = FALSE,row,col;
  138.     HQUEUE qhandle;
  139.     PVOID  *msgdata;
  140.     BUTTON *b;
  141.     PBYTE   p;
  142.  
  143.     DosGetPID(&pidinfo);                        // get process id
  144.     MsgQCreate(&qhandle,MAINMSGQUEUE);
  145.     if(retval = MsgQOpen(&pmshdl,PMSERVERQUE))
  146.         error_exit(retval,"MsgQOpen - PM Server probably hasn\'t started...");
  147.  
  148.     DosSemSet(&MouSem);
  149.     DosSemSet(&KbdSem);
  150.     
  151.                                                 // start other threads
  152.     if(_beginthread(MouThread,MouThreadStack,
  153.             sizeof(MouThreadStack),NULL) == -1)
  154.         error_exit(0,"_beginthread(Mouse)");
  155.     if(_beginthread(KbdThread,KbdThreadStack,
  156.             sizeof(KbdThreadStack),NULL) == -1)
  157.         error_exit(0,"_beginthread(Keyboard)");
  158.     if(_beginthread(RequestThread,RequestThreadStack,
  159.             sizeof(RequestThreadStack),NULL) == -1)
  160.         error_exit(0,"_beginthread(Request)");
  161.     
  162.     DosSemWait(&MouSem,SEM_INDEFINITE_WAIT);    // let threads get going
  163.     DosSemWait(&KbdSem,SEM_INDEFINITE_WAIT);
  164.  
  165.     InitButtons();
  166.     InitScreen();
  167.     DisplayButtons();
  168.     VioGetBuf((PULONG)&bufptr, &msg, VIOHDL);
  169.     PMS_Init(pmshdl,MAINMSGQUEUE);
  170.  
  171.     while(TRUE)
  172.         {
  173.         MsgQGet(qhandle, &msgdata, &msgsize, &msg);
  174.  
  175.         if(ButtonEvent(msg))
  176.             ButtonPress(&msg);
  177.  
  178.         switch(msg)
  179.             {
  180.             case MSG_ESCAPE:
  181.             case ESC:
  182.                 MsgQClose(qhandle);             // close the message queue
  183.                                                 // clear the screen
  184.                 VioScrollUp(0,0,-1,-1,-1,(char *)&BlankCell,VIOHDL);
  185.                 PMS_Terminate(pmshdl);
  186.                 DosExit(EXIT_PROCESS,0);        // get out of dodge
  187.                 break;
  188.  
  189.             case MSG_CLR:                       // user clearing screen
  190.                 VioScrollUp(0,0,BORDERROW-1,ScreenCols,0xffff,(char *)&BlankCell,VIOHDL);
  191.                 InitScreen();
  192.                 DisplayButtons();
  193.                 MsgQSend(pmshdl,&pidinfo.pid,sizeof(PID),PMS_CLPBRD_QUERY);
  194.                 VioSetCurPos(0,0,VIOHDL);
  195.                 break;
  196.  
  197.             // ************* Mouse Message handling
  198.             case MSG_B1DOWN:
  199.                 // clear any existing block and set up a new one
  200.                 valid_block = FALSE;
  201.                 ResetScreen();
  202.                 capture = TRUE;
  203.                 rowBlockBeg = MOUMSG(msgdata)->row;
  204.                 colBlockBeg = MOUMSG(msgdata)->col;
  205.                 startBlock = (rowBlockBeg * ScreenCols) + colBlockBeg;
  206.                 SetBlock(rowBlockBeg,colBlockBeg);
  207.                 break;
  208.  
  209.             case MSG_MOUSEMOVED:
  210.                 if(capture)
  211.                     SetBlock(MOUMSG(msgdata)->row,MOUMSG(msgdata)->col);
  212.                 break;
  213.  
  214.             case MSG_B1UP:
  215.                 if(capture)
  216.                     {
  217.                     capture = FALSE;
  218.                     valid_block = TRUE;
  219.                     SetBlock(MOUMSG(msgdata)->row,MOUMSG(msgdata)->col);
  220.                     }
  221.                 break;
  222.  
  223.             // ************* Keyboard message handling
  224.             case MSG_CHAR:
  225.                 VioWrtTTY(&(KBDMSG(msgdata)->chChar),1,VIOHDL);
  226.  
  227.                 switch(KBDMSG(msgdata)->chChar)
  228.                     {
  229.                     case '\b':
  230.                         VioWrtTTY(" \b",2,VIOHDL);
  231.                         break;
  232.  
  233.                     case '\r':
  234.                         VioGetCurPos(&row,&col,VIOHDL);
  235.                         if(row == ScreenRows)
  236.                             VioScrollUp(0,0,BORDERROW-1,ScreenCols,1,
  237.                                     (char *)&BlankCell,VIOHDL);
  238.                         else
  239.                             VioWrtTTY("\n",1,VIOHDL);
  240.                         break;
  241.  
  242.                     }
  243.  
  244.                 break;
  245.  
  246.             case MSG_UPARROW:
  247.             case MSG_DOWNARROW:
  248.             case MSG_LEFTARROW:
  249.             case MSG_RIGHTARROW:
  250.             case MSG_HOME:
  251.             case MSG_END:
  252.                 VioGetCurPos(&row,&col,VIOHDL); // get current cursor pos.
  253.                 switch(msg)
  254.                     {
  255.                     case MSG_UPARROW:
  256.                         if(row > 0)
  257.                             row--;
  258.                         break;
  259.  
  260.                     case MSG_DOWNARROW:
  261.                         if(row < ScreenRows)
  262.                             row++;
  263.                         break;
  264.  
  265.                     case MSG_LEFTARROW:
  266.                         if(col > 0)
  267.                             col--;
  268.                         break;
  269.  
  270.                     case MSG_RIGHTARROW:
  271.                         if(col < ScreenCols)
  272.                             col++;
  273.                         break;
  274.  
  275.                     case MSG_HOME:
  276.                         col = 0;
  277.                         break;
  278.  
  279.                     case MSG_END:
  280.                         col = ScreenCols-1;
  281.                         break;
  282.                     }
  283.                 VioSetCurPos(row,col,VIOHDL);
  284.                 break;
  285.  
  286.             // *******************Clipboard handling*****************
  287.  
  288.             case MSG_COPY:                      // user copy to clipboard
  289.             case MSG_CUT:                       // user cut to clipboard
  290.                 if(!valid_block)                // if no block selected
  291.                     {
  292.                     beep();                     // warn user
  293.                     break;                      // forget it
  294.                     }
  295.                 i = prepare_CLPBRDblock();
  296.                                                 // pass data to server
  297.                 MsgQSend(pmshdl,tempbuffer,i,PMS_COPY);
  298.  
  299.                 if(msg == MSG_CUT)              // reset screen
  300.                     BlankBlock();
  301.                 else
  302.                     ResetBlock();
  303.                 valid_block = FALSE;
  304.                 break;
  305.  
  306.             case MSG_PASTE:                     // user wants to paste
  307.                 MsgQSend(pmshdl,&pidinfo.pid,sizeof(PID),PMS_PASTE);
  308.                 break;
  309.  
  310.             // **************** PMServer message handling ***********
  311.             case PMS_CLPBRD:                    // clpbrd data is available
  312.                 clipboard_data = TRUE;
  313.                 findbutton(" Paste ", &b);
  314.                 ButtonPaint(b,BUTTON_ON);
  315.                 break;
  316.  
  317.             case PMS_CLPBRD_EMPTY:              // clpbrd is empty
  318.                 clipboard_data = FALSE;
  319.                 findbutton(" Paste ", &b);
  320.                 ButtonPaint(b,BUTTON_OFF);
  321.                 break;
  322.  
  323.             case PMS_CLPBRD_DATA:               // clipboard data rec'd
  324.                 VioGetCurPos(&row,&col,VIOHDL); // get current cursor pos.
  325.                 for(i = 0, p = (PBYTE)msgdata; *p; p++)
  326.                     if(*p == 13)                // if a linefeed
  327.                         i++;                    // # of lines in text
  328.                 if(row+i >= ScreenRows)
  329.                     {
  330.                     VioScrollUp(0,0,BORDERROW-1,ScreenCols,(row+i)-ScreenRows,
  331.                             (char *)&BlankCell,VIOHDL);
  332.                     row -= i;
  333.                     VioSetCurPos(row,col,VIOHDL);
  334.                     }
  335.                 VioWrtTTY((PCH)msgdata,msgsize-1,VIOHDL);
  336.  
  337.                 MsgQSend(pmshdl,&pidinfo.pid,sizeof(PID),PMS_CLPBRD_QUERY);
  338.                 break;
  339.  
  340.             case PMS_NO_INIT:                   // server can't initialize
  341.                 error_exit(msg,"PMS_Init - unable to access PM Server");
  342.                 break;
  343.  
  344.             case PMS_INIT_ACK:                  // server initialized
  345.                 clipboard_data = FALSE;         // then fall thru
  346.  
  347.             default:
  348.                 break;
  349.             }
  350.         if(msgdata != NULL)
  351.             DosFreeSeg(SELECTOROF(msgdata));
  352.         }
  353.     }
  354.  
  355. // terminates PMServer connection
  356. void PMS_Terminate(HQUEUE serverhandle)
  357.     {
  358.                                                 // terminate connection
  359.     MsgQSend(serverhandle,&pidinfo.pid,sizeof(PID),PMS_TERMINATE);
  360.     MsgQClose(serverhandle);                    // close queue
  361.     }
  362.  
  363. // initializes PMServer connection
  364. void PMS_Init(HQUEUE serverhandle,char *qname)
  365.     {
  366.     CLIENTDATA clientdata;
  367.  
  368.     strcpy(clientdata.qname,qname);             // set up qname
  369.     clientdata.pid = pidinfo.pid;               // set up PID
  370.  
  371.                                                 // initialize connection
  372.     MsgQSend(serverhandle,&clientdata,sizeof(clientdata),PMS_INIT);
  373.     }
  374.  
  375. // prepare data for clipboard
  376. USHORT prepare_CLPBRDblock(void)
  377.     {
  378.     return readtextblock(tempbuffer,startrow,startcol,endrow,endcol);
  379.     }
  380.  
  381. // read text from screen
  382. USHORT readtextblock(PCHAR buffer,USHORT srow, USHORT scol, USHORT erow, USHORT ecol)
  383.     {    
  384.     USHORT    i,row,len,col;
  385.  
  386.     for( row = srow, col = scol, i = 0; row <= erow; row++)
  387.         {
  388.         len = ScreenCols;
  389.         if(row != srow)
  390.             col = 0;
  391.         if(row == erow)
  392.             len = ecol+1;
  393.         VioReadCharStr(&buffer[i],&len,row,col,VIOHDL);
  394.         i += len-1;
  395.         while(buffer[i] == ' ')
  396.             i--;
  397.         buffer[++i] = '\r';
  398.         buffer[++i] = '\n';
  399.         i++;
  400.         }
  401.     buffer[i] = '\0';
  402.     return i+1;                                 // return length of block
  403.     }
  404.  
  405. // set screen text block
  406. void SetBlock(USHORT row, USHORT col)
  407.     {
  408.     USHORT endBlock = (row * ScreenCols) + col;
  409.     USHORT presize,postsize,start;
  410.  
  411.     if(startBlock <= endBlock)                  // block end at/after start
  412.         {
  413.         // normal from top to startBlock-1, 
  414.         // highlight from startBlock to endBlock
  415.         // normal from endBlock+1 to bottom
  416.         presize = startBlock;
  417.         startrow = rowBlockBeg;
  418.         startcol = colBlockBeg;
  419.         blocksize = endBlock-startBlock+1;
  420.         endBlock++;
  421.         endrow = (endBlock/ScreenCols);
  422.         endcol = (endBlock%ScreenCols);
  423.         postsize = (ScreenRows*ScreenCols)-endBlock+1;
  424.         }
  425.     else                                        // block end before start
  426.         {
  427.         // normal from top to endBlock-1
  428.         // highlight from endBlock to startBlock
  429.         // normal from startBlock+1 to bottom
  430.         presize = endBlock;
  431.         startrow = row;
  432.         startcol = col;
  433.         blocksize = startBlock-endBlock+1;
  434.         start = startBlock+1;
  435.         endrow = (start/ScreenCols);
  436.         endcol = (start%ScreenCols);
  437.         postsize = (ScreenRows*ScreenCols)-start+1;
  438.         }
  439.  
  440.     blockptr = bufptr+presize;                  // set to beginning of block
  441.         // now write pre-block and post-block normal, highlight block
  442.     VioWrtNAttr(&normal_att,presize,0,0,VIOHDL);
  443.     VioWrtNAttr(&highlight_att,blocksize,startrow,startcol,VIOHDL);
  444.     VioWrtNAttr(&normal_att,postsize,endrow,endcol,VIOHDL);
  445.     }
  446.  
  447. // reset screen work area
  448. void ResetScreen(void)
  449.     {
  450.     USHORT i;
  451.  
  452.     for( i = STARTROW; i <= ENDROW; i++)
  453.         VioWrtNAttr(&normal_att,BORDERCOL,STARTROW,0,VIOHDL);
  454.     }
  455.  
  456. // blank screen text block
  457. void BlankBlock(void)
  458.     {
  459.     VioWrtNCell((PBYTE)&BlankCell,blocksize,startrow,startcol,VIOHDL);
  460.     }
  461.  
  462. // reset screen to normal
  463. void ResetBlock(void)
  464.     {
  465.     VioWrtNAttr(&normal_att,(ScreenCols*ScreenRows),0,0,VIOHDL);
  466.     }
  467.  
  468. // initialize screen
  469. void InitScreen(void)
  470.     {
  471.     SHORT i;
  472.  
  473.     VIOMODEINFO modeinfo;
  474.  
  475.     VioGetMode(&modeinfo,VIOHDL);               // get screen mode, rows, cols
  476.     ScreenCols = modeinfo.col;
  477.     ScreenRows = modeinfo.row;
  478.     if(ScreenRows > BORDERROW-1)
  479.         ScreenRows = BORDERROW-1;
  480.  
  481.     VioScrollUp(0,0,-1,-1,-1,(char *)&BlankCell,VIOHDL);    // clear screen
  482.     VioSetCurPos(0,0,VIOHDL);                   // set cursor
  483.     VioWrtNChar("─",ScreenCols,BORDERROW,0,VIOHDL); // draw border line
  484.     for( i = 0; i < SCREEN_LABELS; i++)         // write labels
  485.         VioWrtCharStr(screen_labels[i].text,strlen(screen_labels[i].text),
  486.                 screen_labels[i].row,screen_labels[i].column,VIOHDL);
  487.     }
  488.  
  489. // manipulate buttons for specific event code and button type
  490. void ButtonPress(USHORT *eventcode)
  491.     {
  492.     BUTTON *b = &buttonlist[0];
  493.  
  494.     MOUSECODEOFF(*eventcode);                   // turn off mouse bit
  495.  
  496.     for( ; b->text; b++)                        // find the button            
  497.         if((b->left_button_val == *eventcode) ||
  498.                 (b->right_button_val == *eventcode) ||
  499.                 (b->accelerator == *eventcode))
  500.             {
  501.             switch(b->type)
  502.                 {
  503.                 case BPRESS:                    // if a press button            
  504.                     ButtonPaint(b,BUTTON_ON);   // turn it on                   
  505.                     DosSleep(100L);             // wait                            
  506.                     ButtonPaint(b,BUTTON_OFF);  // turn it off                    
  507.                     break;
  508.  
  509.                 case BTOGGLE:                   // if a toggle button        
  510.                     b->state = !b->state;       // toggle it                    
  511.                                                 // and toggle the color        
  512.                     ButtonPaint(b,(b->state ? (BYTE)BUTTON_ON : b->attribute));
  513.                     break;
  514.  
  515.                 default:
  516.                     break;
  517.                 }
  518.             return;
  519.             }
  520.     }
  521.     /******* end of main thread code **************************/
  522.  
  523.     /******* start of request thread code *********************/
  524.  
  525. // periodically wakes up and queries PMServer about Clipboard
  526. void RequestThread(void)
  527.     {
  528.     USHORT count = 0;
  529.  
  530.     while(TRUE)
  531.         {
  532.         if(!clipboard_data)                     // if flag invalidated
  533.                                                 // ask if pasting possible
  534.             MsgQSend(pmshdl,&pidinfo.pid,sizeof(PID),PMS_CLPBRD_QUERY);
  535.         DosSleep(REQUESTTHREADSLEEPTIME);       // sleep a while
  536.         count++;
  537.         if(count >= MAXREQUESTCOUNT)            // if count exceeded limit
  538.             {
  539.             clipboard_data = FALSE;             // invalidate flag
  540.             count = 0;                          // reset count
  541.             }
  542.         }
  543.     }
  544.  
  545.     /******* end of request thread code ***********************/
  546.  
  547.  
  548.     /********************** end of pmaccess.c ********************/
  549.  
  550.