home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c070 / 2.ddi / TOOLS.2 / EXAMPLES / CMKEY.C next >
Encoding:
C/C++ Source or Header  |  1989-03-31  |  9.1 KB  |  352 lines

  1. /**
  2. *    CMKEY.C     Example of a keyboard macro processor.
  3. *
  4. *  CMKEY is a terminate and stay resident program that recognizes
  5. *  certain "hot keys," and stuffs expansion strings into the
  6. *  keyboard buffer when these hot keys are pressed.  It stuffs
  7. *  the string into the keyboard buffer, then gives control back
  8. *  to the foreground process.  All of the interrupt support for
  9. *  running the keyboard enhancer is provided by Turbo C TOOLS
  10. *  intervention code (IV) routines.
  11. *
  12. *  CMKEY requests that the scheduler give it control every timer
  13. *  tick, so that if it can only stuff a portion of the
  14. *  specified string, it can stuff more of it on the next timer
  15. *  tick, until the whole string has been stuffed.
  16. *
  17. *  If CMKEY receives a hot key when another hot key is being
  18. *  processed, the second hot key is ignored.
  19. *
  20. *  CMKEY retrieves the hot key pressed from the IV_EVENT structure
  21. *  passed to it by the intervention code scheduler.
  22. *
  23. *  The command line format is as follows:
  24. *
  25. *    cmkey [-r]
  26. *
  27. *  CMKEY is a self-removing interrupt service routine.    If CMKEY is
  28. *  invoked with no arguments, it installs itself (if not already
  29. *  installed); if it is invoked with the "-r" argument, it
  30. *  removes a running copy of CMKEY (if present).
  31. *
  32. *  The purpose of CMKEY is to exhibit the intervention capabilities
  33. *  of Turbo C TOOLS, and to provide an example of construction and
  34. *  use of intervention code in a moderately complex program.
  35. *
  36. *  Version    6.00 (C)Copyright Blaise Computing Inc. 1987-1989
  37. *
  38. **/
  39.  
  40.  
  41. #include <dos.h>
  42. #include <stdio.h>
  43.  
  44. #include <binterv.h>
  45. #include <bintrupt.h>
  46. #include <bkeybrd.h>
  47. #include <bkeys.h>
  48.  
  49.         /* The declaration of the intervention function.    */
  50.         /* It will be called on every timer tick, and also  */
  51.         /* when a hot key is pressed.                */
  52. void tickhandler (IV_EVENT *);
  53.  
  54. #define TRUE  1
  55. #define FALSE 0
  56. #define NUL   '\0'
  57.  
  58. #define STKSIZE  2000
  59. #define OK     0
  60. #define FALL_OUT 101
  61.  
  62. #define NOT_FOUND      1
  63. #define ERROR_DISABLING   2
  64. #define ERROR_REMOVING      3
  65. #define ALREADY_INSTALLED 4
  66.  
  67.         /* Definitive signature for this version of CMKEY.  */
  68. #define CMKEY_SIGN "CMKEY  03/31/89"
  69.  
  70.         /* Allocation of stack space for the intervention   */
  71.         /* scheduler and user function.             */
  72. char schedstk [STKSIZE];
  73.  
  74.         /* This is the data structure to pass to the        */
  75.         /* scheduler so that it will give control every     */
  76.         /* clock tick.                        */
  77. IV_TIME timetab   = {1, IV_TM_INTERVAL};
  78.  
  79.         /* This is the data structure to pass to the        */
  80.         /* scheduler so that it will give control every     */
  81.         /* time ALT 1, 2, or 3 is pressed, and will put the */
  82.         /* intervention code to sleep when ALT-minus is     */
  83.         /* detected, and will wake it up again when ALT-    */
  84.         /* equals is selected.                    */
  85. IV_KEY    keytab [] =
  86. {
  87.     {KB_C_A_1,        KB_S_A_1,       IV_KY_SERVICE},
  88.     {KB_C_A_2,        KB_S_A_2,       IV_KY_SERVICE},
  89.     {KB_C_A_3,        KB_S_A_3,       IV_KY_SERVICE},
  90.     {KB_C_A_MINUS,  KB_S_A_MINUS,  IV_KY_SLEEP    },
  91.     {KB_C_A_EQUALS, KB_S_A_EQUALS, IV_KY_WAKE    }
  92. };
  93.  
  94. #define k(c) kbscanof(c)
  95. static char *string_table [] =
  96.     {
  97.     "cls\r",
  98.     "dir /w /p *.c\rdir /w /p *.asm\r",
  99.     "<this is a test of the emergency broadcast system>"
  100.     };
  101.  
  102. static char *pstuff = NIL;
  103. static int   awake  = TRUE;
  104.  
  105.  
  106.         /* Internal functions -- install and remove        */
  107.         /* intervention function.                */
  108. int install_iv (void);
  109. int remove_iv  (void);
  110.  
  111. void main(int, char **);
  112.  
  113.  
  114. void main (argc, argv)
  115. int   argc;
  116. char *argv [];
  117. {
  118.     if (argc == 1)
  119.     exit (install_iv ());
  120.  
  121.     if ((argc == 2)                       &&
  122.     (((argv [1][0] == '-') || (argv [1][0] == '/')) &&
  123.      ((argv [1][1] == 'r') || (argv [1][1] == 'R'))))
  124.     exit (remove_iv ());
  125.  
  126.     printf ("usage: cmkey [-r]\n");
  127.     exit (0);
  128. }
  129.  
  130.  
  131.  
  132. /**
  133. *
  134. * Name        INSTALL_IV -- Install interrupt vectors for CMKEY, then
  135. *                  terminate and stay resident.
  136. *
  137. * Synopsis    ret = install_iv ();
  138. *
  139. *        int ret     Return code from IVINSTAL if an
  140. *                error condition was encountered.
  141. *
  142. * Description    This function installs CMKEY if another copy of
  143. *        CMKEY is not already installed.
  144. *
  145. * Returns    ret    ALREADY_INSTALLED (4)
  146. *                A copy of CMKEY is already installed.
  147. *            FALL_OUT (101)
  148. *                ISRESEXT() failed.
  149. *            IV_INSTALLED (5)
  150. *                A copy of CMKEY is already installed.
  151. *
  152. **/
  153.  
  154. int install_iv ()
  155. {
  156.     int        ercode;
  157.     IV_VECTORS vecs;
  158.  
  159.         /* Check to see if CMKEY already installed.        */
  160.     ivvecs (IV_RETVEC, &vecs);
  161.     if (ivsense (&vecs, CMKEY_SIGN) != FARNIL)
  162.     {
  163.     puts ("CMKEY already installed.");
  164.     return (ALREADY_INSTALLED);
  165.     }
  166.  
  167.         /* Install the interrupt service routine--i.e. tell */
  168.         /* the scheduler about our tick and keypress        */
  169.         /* handler routine.                    */
  170.     if (0 !=
  171.     (ercode =
  172.      ivinstal (tickhandler, CMKEY_SIGN, schedstk, STKSIZE,
  173.            keytab,
  174.            sizeof(keytab) / sizeof(IV_KEY),
  175.            &timetab,
  176.            sizeof(timetab) / sizeof(IV_TIME),
  177.         /* Neither DOS services nor DOS "key" services nor  */
  178.         /* TURBO C floating point support is needed.        */
  179.            IV_NO_DOS_NEED | IV_NO_DKEY_NEED | IV_NO_FLOAT_NEED)))
  180.     {        /* Error!                        */
  181.     printf ("IVINSTAL error %d.\n", ercode);
  182.     return (ercode);
  183.     }
  184.  
  185.         /* Terminate and stay resident.             */
  186.     isresext (OK);
  187.  
  188.         /* Should never get here.                */
  189.     return (FALL_OUT);
  190. }
  191.  
  192.  
  193.  
  194. /**
  195. *
  196. * Name        REMOVE_IV -- Remove a previously installed copy of CMKEY.
  197. *
  198. * Synopsis    ret = remove_iv ();
  199. *
  200. *        int ret     Return code.
  201. *                  NO_ERROR  (0)-
  202. *                      No error encountered.
  203. *                  NOT_FOUND (1)-
  204. *                      CMKEY not found.
  205. *                  ERROR_DISABLING (2)-
  206. *                      CMKEY could not be disabled.
  207. *                      This error should *never* be
  208. *                      seen.
  209. *                  ERROR_REMOVING (3)--
  210. *                      CMKEY could not be removed (most
  211. *                      likely overwritten MALLOC
  212. *                      pointers).
  213. *
  214. * Description    This function removes a currently-active copy of CMKEY
  215. *        from memory, restoring interrupt vectors and freeing
  216. *        memory in the process.
  217. *
  218. * Returns    ret (nonzero if error--see above).
  219. *
  220. **/
  221.  
  222. int remove_iv ()
  223. {
  224.     IV_VECTORS     vecs;
  225.     IV_CTRL far *pivctrl;
  226.  
  227.         /* Check to see if CMKEY installed.            */
  228.     ivvecs (IV_RETVEC, &vecs);
  229.     if ((pivctrl = ivsense (&vecs, CMKEY_SIGN)) == FARNIL)
  230.     {
  231.     puts ("CMKEY not found.");
  232.     return (NOT_FOUND);
  233.     }
  234.  
  235.     if (ivdisabl (pivctrl))
  236.     {
  237.     puts ("Error disabling CMKEY.");
  238.     return (ERROR_DISABLING);
  239.     }
  240.  
  241.     if (isremove (pivctrl->psp))
  242.     {
  243.     puts ("Error removing CMKEY.");
  244.     return (ERROR_REMOVING);
  245.     }
  246.  
  247.     return (0);
  248. }
  249.  
  250.  
  251.  
  252. /**
  253. *
  254. * Name        TICKHANDLER -- Handle clock tick and hot key
  255. *                   events.
  256. *
  257. * Synopsis    (To be called only by intervention code scheduler)
  258. *
  259. *        tickhandler (pevent);
  260. *
  261. *        IV_EVENT *pevent    Pointer to intervention event
  262. *                    structure.  The structure
  263. *                    contains the hot key which
  264. *                    was detected (if any), as
  265. *                    well as other data.
  266. *
  267. * Description    This function accepts control from the scheduler
  268. *        every timer tick, and also every time one of the
  269. *        defined hot keys is pressed.  The two cases are
  270. *        dissimilar:
  271. *            1.    Hot key: Ignore it if we are already
  272. *            processing another hot key.  If not, CMKEY
  273. *            stuffs as much of the hot key expansion
  274. *            as it can into the keyboard buffer, then
  275. *            leaves a pointer to the remainder for the
  276. *            timer tick invocation to clean up.
  277. *            2.    Timer tick: CMKEY tries to stuff any
  278. *            remaining hot key expansions into the
  279. *            keyboard buffer.  If it cannot stuff the
  280. *            complete string, it schedules the rest for
  281. *            the next timer tick.
  282. *
  283. * Returns    None.
  284. *
  285. **/
  286.  
  287. void tickhandler (pevent)
  288. IV_EVENT *pevent;
  289. {
  290.         /* Do a key action, if one exists.            */
  291.     switch (pevent->key.action)
  292.     {
  293.         /* If there is no key action, ignore the hot key    */
  294.         /* part of the handler.                 */
  295.     case IV_KY_NONE:
  296.         break;
  297.  
  298.         /* If the user typed a "service" key, start stuffing*/
  299.         /* the appropriate string.                */
  300.     case IV_KY_SERVICE:
  301.         /* If we are already stuffing a string, discard this*/
  302.         /* hot key.  If we are asleep, ignore it.        */
  303.         if ((pstuff == NIL) && awake)
  304.         switch (pevent->key.keycode)
  305.         {
  306.             case KB_S_A_1:
  307.             pstuff = string_table [0];
  308.             break;
  309.  
  310.             case KB_S_A_2:
  311.             pstuff = string_table [1];
  312.             break;
  313.  
  314.             case KB_S_A_3:
  315.             pstuff = string_table [2];
  316.             break;
  317.         }
  318.         break;
  319.  
  320.         /* If we get a message to go to sleep, do it.        */
  321.     case IV_KY_SLEEP:
  322.         awake = FALSE;
  323.         utsound (800, 1);
  324.         break;
  325.  
  326.         /* If we get a message to wake up, do it.        */
  327.     case IV_KY_WAKE:
  328.         awake = TRUE;
  329.         utsound (1600, 1);
  330.         break;
  331.     }
  332.  
  333.         /* No we do the actual stuffing of the string, if   */
  334.         /* any.                         */
  335.     if (pstuff != NIL)
  336.     {
  337.         /* Use KBPLACE to stuff them in, character by        */
  338.         /* character, until full.                */
  339.     for (;
  340.          (*pstuff != NUL) &&
  341.          (kbplace (KB_TAIL, (int) *pstuff, kbscanof (*pstuff)) == 0);
  342.          pstuff++)
  343.         ;
  344.  
  345.         /* If we have come to the end of the string, we     */
  346.         /* must set pstuff to NIL so that we know we can    */
  347.         /* accept another hot key now.                */
  348.     if (*pstuff == NUL)
  349.         pstuff = NIL;
  350.     }
  351. }
  352.