Category : Files from Magazines
Archive   : PCTJ8805.ZIP
Filename : CHARMENU.C

 
Output of file : CHARMENU.C contained in archive : PCTJ8805.ZIP
/* CharMenu.C OS/2 Popup Menu for Characters
Pops up and displays a menu of hard-to-type characters.

Press Alt-C, move the cursor to a character, and press Enter.
Press Alt-spacebar to reuse the previous selection.

To compile: CL -Lp -Zp timepop.c
To execute: DETACH CHARMENU
To remove: Press [Q] while it is popped up.
*/

#include
#include
#include

#define FRONT 1 /* position code for DosMonReg */
#define OVRHD 20 /* overhead needed in monitor buffers */
#define HOT_CHAR_1 0 /* Alt-C char code and scan code */
#define HOT_SCAN_1 46
#define HOT_CHAR_2 32 /* the spacebar */
#define ALT 8 /* bit in Kp.shift, set when Alt is down */
#define RELEASE 0x40 /* Kp.ddflags bit indicates key release */
#define MENU_NO_KEY 0 /* returned from DoMenu() and DoPopup() */
#define MENU_QUIT -1
#define NORMAL 0x07 /* screen attributes used */
#define REVERSE 0x70
#define BOLD 0x0F

struct KeyPacket { /* keyboard monitor data record */
unsigned monflags;
unsigned char ascii; /* a translated ASCII value */
unsigned char scan; /* a translated scan code value */
unsigned nls; /* National Language Support stuff */
unsigned shift; /* shift-key flags */
unsigned long keytime;
unsigned ddflags; /* indicates make/break, et.al. */
} Kp; /* allocate one instance as Kp */

char far *MonInBuf; /* addresses of monitor buffers */
char far *MonOutBuf;
int CurX=0, CurY=0; /* initial menu defaults */
unsigned char CurChar=32;

main()
{
unsigned monhandle, kplen, grpid, retcode, err;
unsigned tmpib[2], tmpob[2]; /* used to determine size */

DOSMONOPEN ( "KBD$", &monhandle ); /* get a monitor handle */
tmpib[0] = tmpob[0] = 0;
grpid = CurGrp(); /* get current screen group for 'index' */
DOSMONREG( monhandle, (char *)tmpib,(char *)tmpob, FRONT, grpid );

/* assume failure and use resulting values as the correct size */

MonInBuf = (char far *)malloc( tmpib[1] + OVRHD );
MonOutBuf = (char far *)malloc( tmpob[1] + OVRHD );
MonInBuf[0] =tmpib[1]+OVRHD; MonInBuf[1] =0; /* set first WORD */
MonOutBuf[0]=tmpob[1]+OVRHD; MonOutBuf[1]=0; /* to buffer size */

err = DOSMONREG( monhandle, MonInBuf, MonOutBuf, FRONT, grpid );

InstallMsg( err ); /* announce installation sucess or failure */
if ( err != 0 )
DOSEXIT( 1, 0 ); /* terminate if unable to register */

/* -------------- Monitor Read/Process/Write Loop ------------ */
while ( 1 ) {
kplen = sizeof(Kp); /* read a key packet */
DOSMONREAD( MonInBuf, 0, (char *)&Kp, &kplen );
/* ignore all key releases */
if ( (Kp.ddflags & RELEASE) == 0 ) {
if ( (Kp.ascii == HOT_CHAR_1) && (Kp.scan == HOT_SCAN_1) ) {
retcode = DoPopup();
if (retcode == MENU_NO_KEY ) /* Esc in menu? */
continue; /* yes, no action */
if (retcode == MENU_QUIT ) { /* Q in menu? */
DOSMONCLOSE( monhandle );
DOSEXIT ( 1, 0 ); /* terminate CharMenu */
}
/* else, write the key */
Kp.ascii = retcode; Kp.scan = 0;
Kp.ddflags = Kp.monflags = 0;
DOSMONWRITE( MonOutBuf, (char *)&Kp, kplen );
continue; /* read next key */
}
/* Alt-spacebar is an undefined packet. If the character is
a space and the Alt-key is down, we use it.
*/

if ( (Kp.ascii==HOT_CHAR_2) && ((Kp.shift & ALT)==ALT) ) {
Kp.ascii = CurChar; Kp.scan = 0;
Kp.ddflags = Kp.monflags = 0;
DOSMONWRITE( MonOutBuf, (char *)&Kp, kplen );
continue; /* read next key */
}
} /* all other packets get written immediately */
DOSMONWRITE( MonOutBuf, (char *)&Kp, kplen );
}
}

/* =========================== Code and data for the popup menu == */
char MTop[]= "ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»";
char MMid[]= "º º";
char MBtm[]= "ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ";
char MMsg1[]=" Enter to select and exit ";
char MMsg2[]=" Esc to exit ";
char MMsg3[]=" Q to remove CharMenu ";


#define MENU_HI 20
#define MENU_WIDE 8


unsigned char CharArray[ MENU_HI ][ MENU_WIDE ] = {
{ 0xcd, 0xc9, 0xcb, 0xbb, 0xda, 0xc2, 0xbf, 0xc4 }, /* Box-drawing */
{ 0xba, 0xcc, 0xce, 0xb9, 0xc3, 0xc5, 0xb4, 0xb3 }, /* characters */
{ 0xdb, 0xc8, 0xca, 0xbc, 0xc0, 0xc1, 0xd9, 0xdc }, /* 176 - 223 */
{ 0xb2, 0xd6, 0xd2, 0xb7, 0xd5, 0xd1, 0xb8, 0xdd }, /* in a sane */
{ 0xb1, 0xc7, 0xd7, 0xb6, 0xc6, 0xd8, 0xb5, 0xde }, /* layout */
{ 0xb0, 0xd3, 0xd0, 0xbd, 0xd4, 0xcf, 0xbe, 0xdf },
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 }, /* 0 - 31 */
{ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
{ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17 },
{ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
{ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87 }, /* 128-175 */
{ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f },
{ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97 },
{ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f },
{ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7 },
{ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf },
{ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7 }, /* 224-255 */
{ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef },
{ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 },
{ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }
};

/* ======= Popup, draw menu, get key, release popup == */

DoPopup()
{
unsigned waitflag, row, col, keycode, err;
char attr;

waitflag = 0; /* no wait */
err=VIOPOPUP( &waitflag, 0); /* get popup control */
if ( err ) { /* can't popup now */
DOSBEEP( 400,100 ); /* play a "sorry 'bout that" tune */
DOSBEEP( 300,200 );
DOSBEEP( 200,300 );
return( MENU_NO_KEY );
}
DrawMenu(); /* display the menu */
keycode = DoCharMenu(); /* get interactive input */
VIOENDPOPUP( 0 ); /* release popup control */
return( keycode ); /* send selected code back to caller */
}

/* ============================ This draws the menu == */

DrawMenu()
{
char row, col, attr;
struct CursorData cd; /* from subcalls.h */

attr = NORMAL; /* write the box around the menu */
VIOWRTCHARSTRATT( MTop, strlen(MTop), 0, 0, &attr, 0 );
for ( row=1; row <= MENU_HI; row++ ) {
VIOWRTCHARSTRATT( MMid, strlen(MMid), row, 0, &attr, 0 );
}

VIOWRTCHARSTRATT( MBtm, strlen(MBtm), MENU_HI+1, 0, &attr, 0 );


attr = BOLD;
VIOWRTCHARSTRATT( MMsg1, strlen(MMsg1), MENU_HI+2, 0, &attr, 0 );
VIOWRTCHARSTRATT( MMsg2, strlen(MMsg2), MENU_HI+3, 0, &attr, 0 );
VIOWRTCHARSTRATT( MMsg3, strlen(MMsg3), MENU_HI+4, 0, &attr, 0 );
attr = BOLD;

for ( row=0; row < MENU_HI; row++ ) { /* write menu contents */
for ( col=0; col < 8; col++ ) {
VIOWRTCHARSTRATT( &CharArray[row][col], 1,
row+1, (col*3)+2, &attr, 0);
}
}

VIOGETCURTYPE( &cd, 0 );
cd.cur_attribute = -1; /* turn off the blinking cursor */
VIOSETCURTYPE( &cd, 0 );
}

/* == This handles menu input; returns selection */

int DoCharMenu()
{
char attr;
char tmp[20];
int ch;

while ( 1 ) {
CurChar = CharArray[CurY][CurX];

/* ------------- display current value in hex and decimal -- */
sprintf( tmp, " %3u %2Xh ", CurChar, CurChar );
attr=NORMAL;
VIOWRTCHARSTRATT( tmp, strlen(tmp), MENU_HI+1, 14 , &attr, 0 );

/* --------------------- show cursor bar in reverse video -- */
attr = REVERSE;
VIOWRTNATTR( &attr, 3, 1+CurY, 1+(CurX*3), 0 );

/* --------------------------------- wait for a keystroke -- */
ch=getch(); /* handy getch() technique: */
if (ch == 0) ch = -getch(); /* make X-ASCII keys negative */

/* ------------------------------------ remove cursor bar -- */
attr = BOLD;
VIOWRTNATTR( &attr, 3, 1+CurY, 1+(CurX*3), 0 );

switch ( ch ) { /* ------------ process the input -- */
case 13: return( CurChar ); /* Enter */

case 27: return( MENU_NO_KEY ); /* Esc */

case 'q':
case 'Q': return( MENU_QUIT ); /* Quit */

case '8':
case -72: CurY--; /* up */
if ( CurY < 0 ) CurY = MENU_HI-1;
break;
case '2':
case -80: CurY++; /* down */
if ( CurY >= MENU_HI ) CurY = 0;
break;
case '4':
case -75: CurX--; /* left */
if ( CurX < 0 ) CurX = MENU_WIDE-1;
break;
case '6':
case -77: CurX++; /* right */
if ( CurX >= MENU_WIDE ) CurX = 0;
break;
case '7':
case -71: CurX=0; CurY=0; /* Home */
break;
case '1':
case -79: CurX=MENU_WIDE-1; CurY=MENU_HI-1; /* End */
break;

default: DOSBEEP( 100,100 ); /* unknown key */
}
}
}

/* == This pops up a message to announce installation ============
VioPopup is used here since we expect CharMenu to be
executed as a detached process.
*/

InstallMsg( err )
unsigned err; /* 0 means registered OK, else is error */
{
unsigned waitflag;
char attr;
static char msg[] =
" CharMenu is now active for the current screen group.\r\n"
"\r\n"
" Use Alt-C for the menu.\r\n"
" Alt-Spacebar to repeat the previous character.\r\n"
"\r\n"
" Now press any key...";

waitflag = 1; /* wait -- should always work here */
VIOPOPUP( &waitflag, 0); /* get popup control */
if ( err != 0 )
sprintf( msg, "Can't install Charmenu. Error %d\r\n", err );

VIOWRTTTY( msg, strlen(msg), 0 );
getch();
VIOENDPOPUP( 0 ); /* release the popup screen */
}

/* ============ This obtains the ID of the current screen group ==
The byte at offset 24 in the InfoSeg is the current screen group.
This function just extracts that one value.
*/

CurGrp()
{
unsigned infoseg, localseg, cg;
char far *gdt;

DOSGETINFOSEG( &infoseg, &localseg );
gdt = (char far *)( (long)infoseg << 16 );
return( gdt[24] );
}


  3 Responses to “Category : Files from Magazines
Archive   : PCTJ8805.ZIP
Filename : CHARMENU.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/