home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 11 Util
/
11-Util.zip
/
HOTKEY10.ZIP
/
HOTKEY.C
next >
Wrap
C/C++ Source or Header
|
1991-05-01
|
12KB
|
361 lines
/*
HOTKEY -- hot key between full-screen OS/2 sessions
By David Burton (Burton Systems Software) and Peter Fitzsimmons (A:Ware).
A:Ware BBS: (416)867-9663 or (416)867-9664
Burton BBS: (919)233-0106
This program is uncopyrighted (public domain).
----------------------------------------------------------------------------
makefile excerpt (Opus Make):
hotkey.obj:
cl /W4 /MT /AL /Osxaz /G2r /Lp /Zp /BATCH hotkey.c
hotkey.exe : hotkey.obj
link /PM:VIO /STACK:2048 hotkey.obj, hotkey.exe,, /A:16 /BA /E /F /PACKC;
----------------------------------------------------------------------------
*/
/*-=>keyflag<=-- "&(#)%n #%v %f" (TLIB Version Control keyword format str) */
char embedded_id[] = "&(#)HOTKEY.C #19 1-May-91,3:09:30";
#define INCL_DOSPROCESS
#define INCL_SUB
#define INCL_DOSMONITORS
#define INCL_DOSINFOSEG
#define INCL_WIN
#define INCL_WINSWITCHLIST
#include <os2.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <process.h>
/* Bit mask to distinguish key press from key release */
enum {RELEASE=0x40};
/* Maximum number of task list sessions we can examine */
enum {MAXNUMSESS=32};
enum {MINSES=2, MAXSES=9}; /* we'll monitor sessions numbered 2..9 */
/* Note: start with session 2 to skip dos box (session 0) and PM (session 1) */
/* KBD monitor data record */
struct KeyPacket
{
unsigned mnflags;
KBDKEYINFO cp;
unsigned ddflags;
};
/* keyboard handle from monitor open */
HKBD KBDHandle;
/* RAM semaphore cleared to kill program when any thread dies */
static ULONG semDead = 0;
/* Global copies of the command-line parameters passed to main(),
except that the "/" switch(es) have been removed. */
char **sav_argv;
int sav_argc;
/* ThreadProc_t is the type of the pointer-to-function parameter
expected by _beginthread() */
typedef void (_cdecl _far * ThreadProc_t)(void _far *);
/* HotKeyBits is set by command-line switch according to how you wish to
activate HOTKEY. The three choices are:
/RA = RIGHTALT - to hold Right-Alt and press number
/RAS = sticky RIGHTALT
/SL = SCROLLLOCK - to hold Scroll-Lock and press number
/SLS = sticky SCROLLLOCK
/SR = SYSREQ - to hold SysReq and press number
/SRS = sticky SYSREQ
Default is /SL (Scroll-Lock), which works reasonably well on both 84-key and
101-key keyboards, though you may find the silly Scroll-Lock LED annoying.
/SR or /SRS (SysReq) may be preferable for 84-key keyboards, but is awkward
with 101-key keyboards.
/RA or /RAS (Right-ALT) may be preferable for 101-key keyboards, but it
doesn't work with 84-key keyboards.
Note that you can combine 2 or three of these options to enable multiple
hot-key methods (though I don't know why you'd ever want to).
*/
USHORT HotKeyBits = SCROLLLOCK; /* default is Scroll-Lock */
USHORT StickyHotKeyBits = 0; /* default is non-sticky (you must it down) */
void GiveHelp()
{
int i;
static char * (msg[]) = {
"",
"HOTKEY 1.0 -- A program to let you switch directly to any OS/2 session from",
" any other full-screen session without using the Task Manager.",
"",
"By Peter Fitzsimmons (A:Ware) and David Burton (Burton Systems Software).",
"This program is uncopyrighted (public domain).",
"",
"Use command-line parameters to associate a number key (1-9) with each session",
"to which you may wish to \"hot-key\" (switch). The syntax is:",
" DETACH HOTKEY [option] <N>=<title> [<N>=<title>]... (etc.)",
"where:",
" <N> Is the chosen number key, 1-9",
" <title> Is the title of a session in your task list. If the title",
" contains blanks, you must enclose that parameter in quotes.",
" [option] Determines what you press in combination with the number keys:",
" /RA or /RAS -- Right-Alt key (/RA = regular, /RAS = \"sticky\")",
" /SR or /SRS -- Regular or sticky SysReq key (good for 84 keys)",
" /SL or /SLS -- Regular or sticky Scroll-Lock (/SL is default)",
"Example:",
" detach hotkey 1=Mono \"2=OS/2 Full Screen\" 3=MyThirdSession 9=DOS",
"",
"After you've installed HOTKEY, you can press Scroll-Lock (or SysReq or Rt-ALT)",
"and a number key to switch to the first task in the task list that has <title>",
"anywhere in its name. Pressing Scroll-Lock,0 terminates HOTKEY.",
0};
for (i=0; msg[i]; i++)
puts( msg[i] );
} /* GiveHelp */
/* Switch to a named OS/2 session */
void switchit( char * toName )
{
USHORT num,i;
static struct
{
USHORT cswentry;
SWENTRY aswentry[ MAXNUMSESS ];
} swblk;
strupr( toName );
num = WinQuerySwitchList(0L, (PSWBLOCK)&swblk, sizeof(swblk) );
if (num > MAXNUMSESS)
num = MAXNUMSESS;
for (i=0; i<num; i++)
{
if( strstr(strupr(swblk.aswentry[i].swctl.szSwtitle), toName) )
{
WinSwitchToProgram(swblk.aswentry[i].hswitch);
return;
}
}/*for*/
/* Double-beep says name was not found in the task list */
DosBeep( 300,60 );
DosSleep( 40L );
DosBeep( 300,60 );
} /* switchit */
void far _loadds cdecl monitor( long session )
{
struct KeyPacket keybufr;
USHORT count; /* number of chars in monitor read/write buffer */
int saw_sysreq; /* non-zero if last character was our hot-key prefix key */
int handled; /* non-zero if there is no need to pass the keystroke thru
because it is being handled as one of our hot-key combos */
/* buffers for monitor read/writes: */
MONIN InBuff;
MONOUT OutBuff;
int i;
UCHAR ch; /* an ASCII character code */
USHORT prev_sysreq;
saw_sysreq = keybufr.cp.chChar = ch = 0;
InBuff.cb = sizeof(InBuff);
OutBuff.cb = sizeof(OutBuff);
/* register the buffers to be used for monitoring */
if (DosMonReg( KBDHandle, (PBYTE)&InBuff, (PBYTE)&OutBuff, MONITOR_BEGIN,
(USHORT)session ))
return;
/* Main loop: read key into monitor buffer, examine it and take action
if it is one of our hot keys, otherwise pass it on to device driver */
for(;;)
{
prev_sysreq = saw_sysreq;
count = sizeof(keybufr);
if (DosMonRead( (PBYTE)&InBuff, IO_WAIT, (PBYTE)&keybufr, (PUSHORT)&count ))
break;
handled = 0;
if ( ! ( keybufr.ddflags & RELEASE ) )
{
saw_sysreq |= (HotKeyBits & keybufr.cp.fsState);
if (saw_sysreq)
{
ch = keybufr.cp.chChar; /* the character they typed */
/* If they were holding down the Alt or SysReq key, then
we don't get back a proper character code; instead, we
get a zero character code and an IBM-PC keyboard scan
code. So, we we see a zero character code, we translate
it into the proper character according to the scan code: */
if ( (0 == ch)
&& (keybufr.cp.chScan >= 0x78) /* e.g., alt-1 */
&& (keybufr.cp.chScan <= 0x81) ) /* e.g., alt-0 */
{
if (keybufr.cp.chScan == 0x81)
ch = '0';
else
ch = (UCHAR)(keybufr.cp.chScan - 0x78 + '1');
}
if ((ch >= '0') && (ch <= '9'))
{
/* Got a digit, 0..9! */
handled = 1; /* handle it as a hot-key */
saw_sysreq = 0; /* un-stick sticky key */
}
else
{
/* This last part is for implementing "sticky" hot keys: */
if (ch)
saw_sysreq = keybufr.cp.fsState;
saw_sysreq &= StickyHotKeyBits;
}
}
}
if (handled)
{
if ('0' == ch)
break; /* SysReq,0 ends program */
for (i=1; i<sav_argc; i++)
{
if ((UCHAR)(sav_argv[i][0]) == ch)
{
handled = 2;
switchit( sav_argv[i]+2 );
break;
}
}/*for*/
if (handled < 2)
{
/* single beep if key wasn't defined on HOTKEY command line */
DosBeep( 300,100 );
}
}
else /* !handled */
{
/* if it wasn't one of our hot keys, then pass it on */
if (DosMonWrite( (PBYTE)&OutBuff, (PBYTE)&keybufr, count ))
break;
}
}/*for*/
DosSemClear(&semDead);
} /* monitor */
int cdecl main (int argc, unsigned char **argv)
{
int i;
/* process options */
if ((argc > 1) && ('/'==argv[1][0]))
{
HotKeyBits = StickyHotKeyBits = 0;
while ((argc > 1) && ('/'==argv[1][0]))
{
USHORT tmp,tmp2;
tmp = tmp2 = 0;
strupr(argv[1]);
if (!strcmp("/RA",argv[1]))
tmp = RIGHTALT;
else if (!strcmp("/RAS",argv[1]))
tmp2 = RIGHTALT;
else if (!strcmp("/SR",argv[1]))
tmp = SYSREQ;
else if (!strcmp("/SRS",argv[1]))
tmp2 = SYSREQ;
else if (!strcmp("/SL",argv[1]))
tmp = SCROLLLOCK;
else if (!strcmp("/SLS",argv[1]))
tmp2 = SCROLLLOCK;
else
{
/* unrecognized option -- abort */
GiveHelp();
return 1;
}
HotKeyBits |= (tmp|tmp2);
StickyHotKeyBits |= tmp2;
argv++;
argc--;
}/*while*/
}/*if*/
/* Validate the rest of the command-line parameters */
if (argc <= 1)
{
/* no hot-keys specified -- abort */
GiveHelp();
return 1;
}/*if*/
for (i=1; i<argc; i++)
{
if ( (argv[i][0] < '0')
|| (argv[i][0] > '9')
|| (argv[i][1] != '=')
|| (!argv[i][2]) )
{
/* bad parameter -- abort */
GiveHelp();
return 1;
}
}/*for*/
/* Initialize (note that argv and argc have been adjusted to "hide" the
/RA or /SR option, if any, so that monitor() needn't handle it. */
sav_argv = argv;
sav_argc = argc;
/* Get a handle for registering buffers */
DosMonOpen ( "KBD$", &KBDHandle );
/* Bump up the process priority so that Ctrl-Break (for instance) is
seen immediately */
(void)DosSetPrty( PRTYS_PROCESSTREE, PRTYC_TIMECRITICAL, 0, 0 );
/* set semaphore (which will be cleared when the user presses SysReq,0) */
DosSemSet(&semDead);
/* For each session, start a thread which installs itself as a keyboard
monitor to watch for hot-keys */
for (i=MINSES; i<=MAXSES; i++)
{
_beginthread( (ThreadProc_t)monitor, NULL, 2048, (void far *)(long)i);
}
/* Wait until they press SysReq,0 (which is how the user can kill HOTKEY) */
DosSemWait(&semDead, -1L);
/* Beep on exit, with distinctive descending tone */
for ( i=900; i>=400; i-=80 )
DosBeep( i, 40 );
/* Close connection with keyboard */
DosMonClose ( KBDHandle );
/* One last beep here because I once saw an earlier version of HOTKEY
"hang" (not exit) after beeping, and I wanted to see how far it
actually got. Problem seems to have disappeared, though. */
DosSleep( 300 );
DosBeep( 350, 100 );
/* Exit - kill all threads */
DosExit ( EXIT_PROCESS, 0 );
return 0; /* shut up compiler warning */
} /*main*/