home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 11 Util / 11-Util.zip / HOTKEY10.ZIP / HOTKEY.C next >
C/C++ Source or Header  |  1991-05-01  |  12KB  |  361 lines

  1. /*
  2.          HOTKEY -- hot key between full-screen OS/2 sessions
  3.  
  4.    By David Burton (Burton Systems Software) and Peter Fitzsimmons (A:Ware).
  5.  
  6.          A:Ware BBS: (416)867-9663 or (416)867-9664
  7.          Burton BBS: (919)233-0106
  8.  
  9.    This program is uncopyrighted (public domain).
  10.  
  11. ----------------------------------------------------------------------------
  12. makefile excerpt (Opus Make):
  13.  
  14.   hotkey.obj:
  15.      cl /W4 /MT /AL /Osxaz /G2r /Lp /Zp /BATCH hotkey.c
  16.  
  17.   hotkey.exe : hotkey.obj
  18.      link /PM:VIO /STACK:2048 hotkey.obj, hotkey.exe,, /A:16 /BA /E /F /PACKC;
  19.  
  20. ----------------------------------------------------------------------------
  21. */
  22.  
  23. /*-=>keyflag<=-- "&(#)%n #%v %f"  (TLIB Version Control keyword format str) */
  24. char embedded_id[] = "&(#)HOTKEY.C #19 1-May-91,3:09:30";
  25.  
  26. #define INCL_DOSPROCESS
  27. #define INCL_SUB
  28. #define INCL_DOSMONITORS
  29. #define INCL_DOSINFOSEG
  30. #define INCL_WIN
  31. #define INCL_WINSWITCHLIST
  32. #include <os2.h>
  33.  
  34. #include <stdio.h>
  35. #include <string.h>
  36. #include <stdlib.h>
  37. #include <process.h>
  38.  
  39. /* Bit mask to distinguish key press from key release */
  40. enum {RELEASE=0x40};
  41.  
  42. /* Maximum number of task list sessions we can examine */
  43. enum {MAXNUMSESS=32};
  44.  
  45. enum {MINSES=2, MAXSES=9};  /* we'll monitor sessions numbered 2..9 */
  46. /* Note: start with session 2 to skip dos box (session 0) and PM (session 1) */
  47.  
  48. /* KBD monitor data record */
  49. struct KeyPacket
  50.   {
  51.     unsigned mnflags;
  52.     KBDKEYINFO cp;
  53.     unsigned ddflags;
  54.   };
  55.  
  56.  
  57. /* keyboard handle from monitor open */
  58. HKBD KBDHandle;
  59.  
  60. /* RAM semaphore cleared to kill program when any thread dies */
  61. static ULONG semDead = 0;
  62.  
  63. /* Global copies of the command-line parameters passed to main(),
  64.    except that the "/" switch(es) have been removed.  */
  65. char **sav_argv;
  66. int sav_argc;
  67.  
  68. /* ThreadProc_t is the type of the pointer-to-function parameter
  69.    expected by _beginthread() */
  70. typedef void (_cdecl _far * ThreadProc_t)(void _far *);
  71.  
  72.  
  73. /* HotKeyBits is set by command-line switch according to how you wish to
  74.    activate HOTKEY.  The three choices are:
  75.  
  76.      /RA  = RIGHTALT   - to hold Right-Alt and press number
  77.      /RAS = sticky RIGHTALT
  78.      /SL  = SCROLLLOCK - to hold Scroll-Lock and press number
  79.      /SLS = sticky SCROLLLOCK
  80.      /SR  = SYSREQ     - to hold SysReq and press number
  81.      /SRS = sticky SYSREQ
  82.  
  83.    Default is /SL (Scroll-Lock), which works reasonably well on both 84-key and
  84.    101-key keyboards, though you may find the silly Scroll-Lock LED annoying.
  85.  
  86.    /SR or /SRS (SysReq) may be preferable for 84-key keyboards, but is awkward
  87.    with 101-key keyboards.
  88.  
  89.    /RA or /RAS (Right-ALT) may be preferable for 101-key keyboards, but it
  90.    doesn't work with 84-key keyboards.
  91.  
  92.    Note that you can combine 2 or three of these options to enable multiple
  93.    hot-key methods (though I don't know why you'd ever want to).
  94. */
  95. USHORT HotKeyBits = SCROLLLOCK;  /* default is Scroll-Lock */
  96. USHORT StickyHotKeyBits = 0;  /* default is non-sticky (you must it down) */
  97.  
  98.  
  99. void GiveHelp()
  100.   {
  101.    int i;
  102.    static char * (msg[]) = {
  103.    "",
  104.    "HOTKEY 1.0 -- A program to let you switch directly to any OS/2 session from",
  105.    "              any other full-screen session without using the Task Manager.",
  106.    "",
  107.    "By Peter Fitzsimmons (A:Ware) and David Burton (Burton Systems Software).",
  108.    "This program is uncopyrighted (public domain).",
  109.    "",
  110.    "Use command-line parameters to associate a number key (1-9) with each session",
  111.    "to which you may wish to \"hot-key\" (switch).  The syntax is:",
  112.    "     DETACH HOTKEY [option] <N>=<title> [<N>=<title>]... (etc.)",
  113.    "where:",
  114.    "     <N>       Is the chosen number key, 1-9",
  115.    "     <title>   Is the title of a session in your task list.  If the title",
  116.    "               contains blanks, you must enclose that parameter in quotes.",
  117.    "     [option]  Determines what you press in combination with the number keys:",
  118.    "         /RA or /RAS  --  Right-Alt key (/RA = regular, /RAS = \"sticky\")",
  119.    "         /SR or /SRS  --  Regular or sticky SysReq key (good for 84 keys)",
  120.    "         /SL or /SLS  --  Regular or sticky Scroll-Lock (/SL is default)",
  121.    "Example:",
  122.    "     detach hotkey 1=Mono \"2=OS/2 Full Screen\" 3=MyThirdSession 9=DOS",
  123.    "",
  124.    "After you've installed HOTKEY, you can press Scroll-Lock (or SysReq or Rt-ALT)",
  125.    "and a number key to switch to the first task in the task list that has <title>",
  126.    "anywhere in its name.  Pressing Scroll-Lock,0 terminates HOTKEY.",
  127.    0};
  128.     for (i=0; msg[i]; i++)
  129.         puts( msg[i] );
  130.   } /* GiveHelp */
  131.  
  132.  
  133. /* Switch to a named OS/2 session */
  134. void switchit( char * toName )
  135.   {
  136.    USHORT num,i;
  137.    static struct
  138.      {
  139.        USHORT cswentry;
  140.        SWENTRY aswentry[ MAXNUMSESS ];
  141.      } swblk;
  142.  
  143.     strupr( toName );
  144.     num = WinQuerySwitchList(0L, (PSWBLOCK)&swblk, sizeof(swblk) );
  145.     if (num > MAXNUMSESS)
  146.         num = MAXNUMSESS;
  147.     for (i=0; i<num; i++)
  148.       {
  149.         if( strstr(strupr(swblk.aswentry[i].swctl.szSwtitle), toName) )
  150.           {
  151.             WinSwitchToProgram(swblk.aswentry[i].hswitch);
  152.             return;
  153.           }
  154.       }/*for*/
  155.  
  156.     /* Double-beep says name was not found in the task list */
  157.     DosBeep( 300,60 );
  158.     DosSleep( 40L );
  159.     DosBeep( 300,60 );
  160.   } /* switchit */
  161.  
  162.  
  163. void far _loadds cdecl monitor( long session )
  164.   {
  165.    struct KeyPacket keybufr;
  166.    USHORT count;  /* number of chars in monitor read/write buffer */
  167.    int saw_sysreq;  /* non-zero if last character was our hot-key prefix key */
  168.    int handled;  /* non-zero if there is no need to pass the keystroke thru
  169.                     because it is being handled as one of our hot-key combos */
  170.    /* buffers for monitor read/writes: */
  171.    MONIN InBuff;
  172.    MONOUT OutBuff;
  173.    int i;
  174.    UCHAR ch; /* an ASCII character code */
  175.    USHORT prev_sysreq;
  176.  
  177.    saw_sysreq = keybufr.cp.chChar = ch = 0;
  178.    InBuff.cb = sizeof(InBuff);
  179.    OutBuff.cb = sizeof(OutBuff);
  180.  
  181.     /* register the buffers to be used for monitoring */
  182.     if (DosMonReg( KBDHandle, (PBYTE)&InBuff, (PBYTE)&OutBuff, MONITOR_BEGIN,
  183.                    (USHORT)session ))
  184.         return;
  185.  
  186.     /* Main loop: read key into monitor buffer, examine it and take action
  187.        if it is one of our hot keys, otherwise pass it on to device driver */
  188.     for(;;)
  189.       {
  190.         prev_sysreq = saw_sysreq;
  191.         count = sizeof(keybufr);
  192.         if (DosMonRead( (PBYTE)&InBuff, IO_WAIT, (PBYTE)&keybufr, (PUSHORT)&count ))
  193.             break;
  194.         handled = 0;
  195.         if ( ! ( keybufr.ddflags & RELEASE ) )
  196.           {
  197.             saw_sysreq |= (HotKeyBits & keybufr.cp.fsState);
  198.             if (saw_sysreq)
  199.               {
  200.                 ch = keybufr.cp.chChar;  /* the character they typed */
  201.                 /* If they were holding down the Alt or SysReq key, then
  202.                    we don't get back a proper character code; instead, we
  203.                    get a zero character code and an IBM-PC keyboard scan
  204.                    code.  So, we we see a zero character code, we translate
  205.                    it into the proper character according to the scan code: */
  206.                 if (   (0 == ch)
  207.                     && (keybufr.cp.chScan >= 0x78)    /* e.g., alt-1 */
  208.                     && (keybufr.cp.chScan <= 0x81) )  /* e.g., alt-0 */
  209.                   {
  210.                     if (keybufr.cp.chScan == 0x81)
  211.                         ch = '0';
  212.                     else
  213.                         ch = (UCHAR)(keybufr.cp.chScan - 0x78 + '1');
  214.                   }
  215.                 if ((ch >= '0') && (ch <= '9'))
  216.                   {
  217.                     /* Got a digit, 0..9! */
  218.                     handled = 1;  /* handle it as a hot-key */
  219.                     saw_sysreq = 0;  /* un-stick sticky key */
  220.                   }
  221.                  else
  222.                    {
  223.                      /* This last part is for implementing "sticky" hot keys: */
  224.                      if (ch)
  225.                          saw_sysreq = keybufr.cp.fsState;
  226.                      saw_sysreq &= StickyHotKeyBits;
  227.                    }
  228.               }
  229.           }
  230.         if (handled)
  231.           {
  232.             if ('0' == ch)
  233.                 break;  /* SysReq,0 ends program */
  234.             for (i=1; i<sav_argc; i++)
  235.               {
  236.                 if ((UCHAR)(sav_argv[i][0]) == ch)
  237.                   {
  238.                     handled = 2;
  239.                     switchit( sav_argv[i]+2 );
  240.                     break;
  241.                   }
  242.               }/*for*/
  243.             if (handled < 2)
  244.               {
  245.                 /* single beep if key wasn't defined on HOTKEY command line */
  246.                 DosBeep( 300,100 );
  247.               }
  248.           }
  249.         else /* !handled */
  250.           {
  251.             /* if it wasn't one of our hot keys, then pass it on */
  252.             if (DosMonWrite( (PBYTE)&OutBuff, (PBYTE)&keybufr, count ))
  253.                 break;
  254.           }
  255.       }/*for*/
  256.       DosSemClear(&semDead);
  257.   } /* monitor */
  258.  
  259.  
  260. int cdecl main (int argc, unsigned char **argv)
  261.   {
  262.    int i;
  263.  
  264.     /* process options */
  265.     if ((argc > 1) && ('/'==argv[1][0]))
  266.       {
  267.         HotKeyBits = StickyHotKeyBits = 0;
  268.         while ((argc > 1) && ('/'==argv[1][0]))
  269.           {
  270.            USHORT tmp,tmp2;
  271.             tmp = tmp2 = 0;
  272.             strupr(argv[1]);
  273.             if (!strcmp("/RA",argv[1]))
  274.                 tmp = RIGHTALT;
  275.             else if (!strcmp("/RAS",argv[1]))
  276.                 tmp2 = RIGHTALT;
  277.             else if (!strcmp("/SR",argv[1]))
  278.                 tmp = SYSREQ;
  279.             else if (!strcmp("/SRS",argv[1]))
  280.                 tmp2 = SYSREQ;
  281.             else if (!strcmp("/SL",argv[1]))
  282.                 tmp = SCROLLLOCK;
  283.             else if (!strcmp("/SLS",argv[1]))
  284.                 tmp2 = SCROLLLOCK;
  285.             else
  286.               {
  287.                 /* unrecognized option -- abort */
  288.                 GiveHelp();
  289.                 return 1;
  290.               }
  291.             HotKeyBits |= (tmp|tmp2);
  292.             StickyHotKeyBits |= tmp2;
  293.             argv++;
  294.             argc--;
  295.           }/*while*/
  296.       }/*if*/
  297.  
  298.     /* Validate the rest of the command-line parameters */
  299.     if (argc <= 1)
  300.       {
  301.         /* no hot-keys specified -- abort */
  302.         GiveHelp();
  303.         return 1;
  304.       }/*if*/
  305.     for (i=1; i<argc; i++)
  306.       {
  307.         if (   (argv[i][0] < '0')
  308.             || (argv[i][0] > '9')
  309.             || (argv[i][1] != '=')
  310.             || (!argv[i][2])  )
  311.           {
  312.             /* bad parameter -- abort */
  313.             GiveHelp();
  314.             return 1;
  315.           }
  316.       }/*for*/
  317.  
  318.     /* Initialize (note that argv and argc have been adjusted to "hide" the
  319.        /RA or /SR option, if any, so that monitor() needn't handle it. */
  320.     sav_argv = argv;
  321.     sav_argc = argc;
  322.  
  323.     /* Get a handle for registering buffers */
  324.     DosMonOpen ( "KBD$", &KBDHandle );
  325.  
  326.     /* Bump up the process priority so that Ctrl-Break (for instance) is
  327.        seen immediately */
  328.     (void)DosSetPrty( PRTYS_PROCESSTREE, PRTYC_TIMECRITICAL, 0, 0 );
  329.  
  330.     /* set semaphore (which will be cleared when the user presses SysReq,0) */
  331.     DosSemSet(&semDead);
  332.  
  333.     /* For each session, start a thread which installs itself as a keyboard
  334.        monitor to watch for hot-keys */
  335.     for (i=MINSES; i<=MAXSES; i++)
  336.       {
  337.         _beginthread( (ThreadProc_t)monitor, NULL, 2048, (void far *)(long)i);
  338.       }
  339.  
  340.     /* Wait until they press SysReq,0 (which is how the user can kill HOTKEY) */
  341.     DosSemWait(&semDead, -1L);
  342.  
  343.     /* Beep on exit, with distinctive descending tone */
  344.     for ( i=900; i>=400; i-=80 )
  345.         DosBeep( i, 40 );
  346.  
  347.     /* Close connection with keyboard */
  348.     DosMonClose ( KBDHandle );
  349.  
  350.     /* One last beep here because I once saw an earlier version of HOTKEY
  351.        "hang" (not exit) after beeping, and I wanted to see how far it
  352.        actually got.  Problem seems to have disappeared, though. */
  353.     DosSleep( 300 );
  354.     DosBeep( 350, 100 );
  355.  
  356.     /* Exit - kill all threads */
  357.     DosExit ( EXIT_PROCESS, 0 );
  358.     return 0;  /* shut up compiler warning */
  359.   } /*main*/
  360.  
  361.