home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / msysjour / ms / s12364 / monitor.c < prev    next >
C/C++ Source or Header  |  1989-05-18  |  11KB  |  280 lines

  1. /* monitor.c  - Switch through screen groups
  2.  *
  3.  *  Operation Note :
  4.  *
  5.  *
  6.  *      In order to successfully switch between PM screen groups, this
  7.  *      monitor MUST be started from within a windowed screen group. It
  8.  *      functions in both detached and foreground modes.
  9.  *
  10.  *  General Monitor Notes:
  11.  *
  12.  *
  13.  *      The first 16 bytes of a monitor buffer are devoted to the
  14.  *      header, as described by the MonBuff structure below.  Prior to
  15.  *      registering, the first word (bufflen) must be set to the size
  16.  *      of the entire buffer itself.  The entire buffer includes the
  17.  *      header (16 bytes) and room for at least one data record (16 bytes
  18.  *      in the case of the keyboard device driver), so the minimum size
  19.  *      for this example would be 32 bytes (see MINBUFFSIZE above);
  20.  *      however, some drivers may have slightly different requirements,
  21.  *      in which case you should use the method described next, rather than
  22.  *      assuming some fixed length.
  23.  *
  24.  *      If you wish to monitor a device driver whose data record size
  25.  *      is unknown, pick a convenient size and attempt a call to DosMonReg.
  26.  *      If it fails due to ERROR_NOT_ENOUGH_MEMORY, examine the 2nd word
  27.  *      of your buffer, since it will now contain the size of the driver's
  28.  *      buffer (ddbufflen in the example).  Allocate buffer(s) which can
  29.  *      hold a data record of that size (in addition to the 16-byte header)
  30.  *      and re-register your buffer(s).  If the same error occurs, then
  31.  *      there is simply insufficient resources to support another monitor.
  32.  *
  33.  *      Note the MonBuff header structure does not define the monitor buffer
  34.  *      beyond the header, because data records (KeyPackets in this example)
  35.  *      are transferred to and from the buffers by DosMonRead and DosMonWrite.
  36.  *      You should not attempt to read or write that area directly, nor should
  37.  *      you modify any part of the header after a successful DosMonReg.
  38.  *
  39.  *      To maintain a rapid flow of data through any chain of monitors,
  40.  *      DosMonRead and DosMonWrite operations should be done without any
  41.  *      intervening slow operations or system calls. If necessary, dedicate
  42.  *      a thread to the monitor stream, and raise its priority.
  43.  *
  44.  * Makefile:
  45.  *
  46.  *     LIB=\lib
  47.  *     INC=\include
  48.  *     OPT=-AL -G2 -Zi -Lp -Ox -Zp -I$(INC)
  49.  *
  50.  *     monitor.exe:   monitor.c monitor
  51.  *                   cl $(OPT) monitor.c
  52.  *
  53.  *
  54.  * To Run:
  55.  *
  56.  *      a) Start in Windowed Screen Group
  57.  *      b) either  i) monitor
  58.  *                ii) detach monitor
  59.  *
  60.  *
  61.  * Created by Microsoft Corp. 1989
  62.  */
  63.  
  64. #define INCL_DOSPROCESS
  65. #define INCL_SUB
  66. #define INCL_DOSMONITORS
  67. #define INCL_DOSINFOSEG
  68. #define INCL_DOSSEMAPHORES
  69.  
  70. #include <malloc.h>             /* for malloc() declaration */
  71. #include <os2def.h>
  72. #include <bse.h>
  73.  
  74.  
  75. #define THREAD_STK_SIZE 2048            /* Monitor Thread Stack Size */
  76.  
  77. #define NOPREFERENCE    0               /* DosMonReg constants - */
  78. #define FRONT           1               /* where in the monitor chain */
  79. #define BACK            2               /* do we want to be installed? */
  80.  
  81. #define WAIT            0               /* DOSMONREAD and KBDCHARIN constants - */
  82. #define NOWAIT          1                /* should we wait for a key? */
  83.  
  84. #define NOERROR         0               /* DOSEXIT constants - */
  85. #define ERROR           1               /* what to return for error code? */
  86.  
  87.  
  88. #define MINBUFFSIZE     64              /* size for monitor buffers */
  89.                                         /* 64 is minimum, 128 recommended */
  90.  
  91.  
  92. struct KeyPacket {              /* KBD monitor data record */
  93.         unsigned       mnflags;
  94.         KBDKEYINFO     cp;
  95.         unsigned       ddflags;
  96. };
  97.  
  98. struct MonBuff {                        /* generic monitor buffer header */
  99.         unsigned        bufflen;
  100.         unsigned        ddbufflen;
  101.         unsigned char   dispatch[12];
  102. };
  103.  
  104.  
  105. HKBD    KBDHandle;           /* keyboard handle from monitor open */
  106.  
  107. struct MonBuff  *InBuff, *OutBuff;     /* buffers for monitor read/writes */
  108.  
  109. /*                                MonFlag S.C.  Char  Shift NLSSh State   Time Stamp  DDFlag */
  110. struct KeyPacket Alt_Down     = { 0x3800, 0x00, 0x00, 0x40, 0x00, 0x0208, 0x00000000, 0x0007 };
  111. struct KeyPacket Alt_Up       = { 0xb800, 0x00, 0x00, 0x40, 0x00, 0x0000, 0x00000000, 0x0047 };
  112. struct KeyPacket Ctl_Down     = { 0x1d00, 0x00, 0x00, 0x40, 0x00, 0x0104, 0x00000000, 0x0007 };
  113. struct KeyPacket Ctl_Up       = { 0x9d00, 0x00, 0x00, 0x40, 0x00, 0x0000, 0x00000000, 0x0047 };
  114. struct KeyPacket ESC_Down_Alt = { 0x0100, 0x00, 0x01, 0x40, 0x00, 0x0208, 0x00000000, 0x003f };
  115. struct KeyPacket ESC_Up_Alt   = { 0x8100, 0x00, 0x01, 0x40, 0x00, 0x0208, 0x00000000, 0x004c };
  116. struct KeyPacket ESC_Down_Ctl = { 0x0100, 0x00, 0x01, 0x40, 0x00, 0x0104, 0x00000000, 0x003f };
  117. struct KeyPacket ESC_Up_Ctl   = { 0x8100, 0x00, 0x01, 0x40, 0x00, 0x0104, 0x00000000, 0x004c };
  118.  
  119. unsigned short  BuffLength;     /* chars in monitor read/write buffer */
  120. unsigned long    sem;           /* ram semaphore */
  121.  
  122. void Session_Switch()
  123. {
  124.         DosSemRequest( &sem,SEM_INDEFINITE_WAIT);  /* Sem Block to make sure */
  125.                                                    /* that block goes out    */
  126.                                                    /* uninterrupted          */
  127.  
  128.         DosMonWrite ( (PBYTE)OutBuff,           /* Depress the Alt Key */
  129.                       (PBYTE)&Alt_Down, BuffLength );
  130.  
  131.         DosMonWrite ( (PBYTE)OutBuff,           /* Depress the ESC Key */
  132.                       (PBYTE)&ESC_Down_Alt, BuffLength );
  133.  
  134.         DosMonWrite ( (PBYTE)OutBuff,           /* Release the ESC Key */
  135.                       (PBYTE)&ESC_Up_Alt, BuffLength );
  136.  
  137.         DosMonWrite ( (PBYTE)OutBuff,           /* Release the Alt Key */
  138.                       (PBYTE)&Alt_Up, BuffLength );
  139.  
  140.         DosSemClear( &sem);
  141. }
  142.  
  143. void Task_Manager()
  144. {
  145.         DosSemRequest( &sem,SEM_INDEFINITE_WAIT);  /* Sem Block to make sure */
  146.                                                    /* that block goes out    */
  147.                                                    /* uninterrupted          */
  148.  
  149.         DosMonWrite ( (PBYTE)OutBuff,              /* Depress the Ctl Key */
  150.                       (PBYTE)&Ctl_Down, BuffLength );
  151.  
  152.         DosMonWrite ( (PBYTE)OutBuff,              /* Depress the ESC Key */
  153.                       (PBYTE)&ESC_Down_Ctl, BuffLength );
  154.  
  155.         DosMonWrite ( (PBYTE)OutBuff,              /* Release the ESC Key */
  156.                       (PBYTE)&ESC_Up_Ctl, BuffLength );
  157.  
  158.         DosMonWrite ( (PBYTE)OutBuff,              /* Release the Ctl Key */
  159.                       (PBYTE)&Ctl_Up, BuffLength );
  160.  
  161.         DosSemClear( &sem);
  162. }
  163.  
  164. void MonChain()
  165. {
  166.         struct KeyPacket keybuff;   /* struct to read a write Kbd monitor data */
  167.         unsigned short  count;      /* chars in monitor read/write buffer */
  168.  
  169.  
  170.         count = sizeof(keybuff);    /* get the size of the KBD Monitor Struct */
  171.  
  172.         for (;;) {                   /* repeat ad noseum */
  173.  
  174.  
  175.  
  176.            DosMonRead ( (unsigned char *)InBuff, WAIT, /* Wait for any Mon input */
  177.                         (unsigned char *)&keybuff, &count );
  178.  
  179.            DosSemRequest( &sem, SEM_INDEFINITE_WAIT);  /* yes - block the Mon Out */
  180.  
  181.            DosMonWrite ( (unsigned char *)OutBuff,     /* Pass Mon Packet as is   */
  182.                          (unsigned char *)&keybuff, count );
  183.  
  184.            DosSemClear( &sem);                          /* re-enable task/session switch */
  185.  
  186.            DosSleep(100L);                              /* Allow Task Switch */
  187.         }
  188. }
  189.  
  190. void main()
  191. {
  192.         struct KeyPacket  keybuff;
  193.         PGINFOSEG gdt;
  194.         SEL gdt_descriptor, ldt_descriptor;   /* infoseg descriptors */
  195.  
  196.         unsigned short  i;                         /* loop counter */
  197.  
  198.         void far MonChain();            /* address of Monitor Chain Loop */
  199.         char far *MonChainStack;        /* far pointer to Monitor Chain Loop stack */
  200.         unsigned MonChainID;            /* thread ID */
  201.         unsigned rc;                    /* return code */
  202.  
  203.  
  204.         /* allocate space for monitor read/write buffers */
  205.         InBuff = (struct MonBuff *)malloc(MINBUFFSIZE);
  206.         OutBuff = (struct MonBuff *)malloc(MINBUFFSIZE);
  207.  
  208.         if ((InBuff == NULL) || (OutBuff == NULL))
  209.             DosExit ( EXIT_PROCESS, ERROR ); /*terminate all threads and return error */
  210.  
  211.         /* prepare buffer headers for registration process */
  212.         InBuff->bufflen = MINBUFFSIZE;
  213.         OutBuff->bufflen = MINBUFFSIZE;
  214.  
  215.         /* obtain a handle for registering buffers */
  216.         rc = DosMonOpen ( "KBD$", &KBDHandle );
  217.         if (rc != NOERROR)
  218.             DosExit ( EXIT_PROCESS, ERROR ); /*terminate all threads and return error */
  219.  
  220.         /* get the descriptor of global infoseg */
  221.         /* and convert to far pointer so we can */
  222.         /* get ID of current foreground screen group */
  223.         DosGetInfoSeg(&gdt_descriptor, &ldt_descriptor);
  224.         gdt = MAKEPGINFOSEG(gdt_descriptor);
  225.  
  226.         /* register the buffers to be used for monitoring */
  227.         rc = DosMonReg ( KBDHandle, (PBYTE)InBuff, (PBYTE)OutBuff, FRONT,
  228.                      gdt->sgCurrent);
  229.         if (rc != NOERROR)
  230.             DosExit ( EXIT_PROCESS, ERROR ); /*terminate all threads and return error */
  231.  
  232.         BuffLength = sizeof(keybuff);
  233.  
  234.         /* Monitor Loop Thread setup */
  235.         /* Monitors are part of the data flow path through a device */
  236.         /* driver. Monitors should be written so that a thread actually */
  237.         /* performs rapid I/O and passes the data flowing into the */
  238.         /* monitor chain back into this same chain. This imperative so that */
  239.         /* monitor control characters (if not processed by all monitors) are */
  240.         /* available through the monitor chain. */
  241.  
  242.         sem = 0L;                       /* init semaphore */
  243.  
  244.         /* allocate stack space for MonChain thread */
  245.         /* since this is written in C, DOSALLOCSEG cannot be used here */
  246.  
  247.         if ((MonChainStack = malloc(THREAD_STK_SIZE)) == NULL) {
  248.  
  249.                 DosMonClose ( KBDHandle );       /* Close KBD Monitor */
  250.                 DosExit ( EXIT_PROCESS, ERROR ); /*terminate all threads and return error */
  251.  
  252.         }
  253.         MonChainStack += THREAD_STK_SIZE;        /* since stack grows down */
  254.  
  255.         /* start another thread */
  256.         if (rc = DosCreateThread( MonChain, &MonChainID,
  257.                                   MonChainStack ))  {
  258.  
  259.                 DosMonClose ( KBDHandle );       /* Close KBD Monitor */
  260.                 DosExit ( EXIT_PROCESS, ERROR ); /*terminate all threads and return error */
  261.  
  262.         }
  263.  
  264.         /* Sample Code for Session Switch */
  265.  
  266.         for (i = 0; i < 10; ++i) {  /* Session Switch Screen 10 times */
  267.  
  268.            Session_Switch();        /* Perform a Session Switch       */
  269.            DosSleep(3000L);         /* Sleep for 5 seconds            */
  270.  
  271.         } /* end for */
  272.  
  273.         Task_Manager();             /* Call Task Manager              */
  274.  
  275.         /* close connection with keyboard */
  276.         DosMonClose ( KBDHandle );
  277.  
  278.         DosExit ( EXIT_PROCESS, NOERROR );
  279. }
  280.