
/*
        NAME = MOUSE.C
        This program demonstrates the fundamentals of using a mouse to
        select options in a menu-driven application.  Uses two "dummy"
        functions: genledg() and payroll().
        Note:  Function chkdrv() taken from page 7-16 of "Microsoft
               Mouse Programmer's Reference Guide"
*/

#include <stdio.h>
#include <dos.h>                /* required for BIOS calls, etc.        */
#include <string.h>
#include <signal.h>             /* disable & enable control break       */

#define RED_BACK 74             /* display using a red background       */

extern void pascal far mouse(int*, int*, int*, int*);    /*declare mouse*/

void txtcursor(char cur), cls(), outstr(), genledg(), payroll(), heading();
void chkdrv();                  /* checks for existence of mouse driver */

int i, handler();               /* handler() part of control-break      */
int m1, m2, m3, m4;             /* mouse parameters                     */
struct menu                     /* structure for our sample menu        */
{
        char text[20];                  /* text of options              */
        int x;                          /* horiz. screen coordinate     */
        int y;                          /* vert. screen coordinate      */
        int mh,mh2,mv;                  /* mouse horiz/vert. coordinates*/
}options[3];                            /* 3 options in our sample prog.*/

main()
{

        int  choice, loop;

                /* disable Control-Break interrupt      */

        if(signal(SIGINT,handler) == (int(*) ())-1)
        {
                cls();
                printf("Fatal error - could not disable Control-Break\n");
                abort();
        }

                /* check for mouse hardware & driver    */

        m1=0;
        mouse(&m1,&m2,&m3,&m4);         /* check hardware here  */
        if(m1 != -1)
        {
                cls();
                printf("Fatal error - no mouse found..\n");
                abort();
        }
        chkdrv();                       /* check for mouse driver       */

        /*      "Populate" our structure with data      */

        strcpy(options[0].text,"General Ledger");
               options[0].x = 6;
               options[0].y = 30;
               options[0].mh = 240;     /* mh & mh2 define the horiz.   */
               options[0].mh2= 344;     /* limits of option's "hot spot"*/
               options[0].mv = 48;      /* define vertical limit here   */

        strcpy(options[1].text,"Payroll");
               options[1].x = 8;
               options[1].y = 30;
               options[1].mh = 240;
               options[1].mh2= 288;
               options[1].mv = 64;

        strcpy(options[2].text,"Exit");
               options[2].x = 10;
               options[2].y = 30;
               options[2].mh = 240;
               options[2].mh2= 264;
               options[2].mv = 80;

        heading();                      /* display menu, etc.   */
        m1=m2=m3=m4=i=0;                /* initialize variables */
        mouse(&m1,&m2,&m3,&m4);         /* init mouse           */
        txtcursor(0);                   /* turn off text cursor */
        m1=1;                           /* show cursor          */
        mouse(&m1,&m2,&m3,&m4);

        /*      now set up infinite loop which processes the
                user's requests                                 */

        loop=1;
        while(loop)
        {
                m1=3;                   /* read mouse cursor position   */
                m2=m3=m4=0;
                mouse(&m1,&m2,&m3,&m4);

                for(i=0; i < 3; ++i)    /* is cursor in 1 of 3 options? */
                {
                   if((m3 >=options[i].mh && m3 <= options[i].mh2) &&
                      (m4 == options[i].mv))
                   {
                        outstr(options[i].x,options[i].y,options[i].text,RED_BACK);
                        break;
                   }
                   else
                        outstr(options[i].x,options[i].y,options[i].text,10);
                }

                m1=6;                   /* read left button     */
                m2=m3=m4=0;
                mouse(&m1,&m2,&m3,&m4);
                if(m2)                  /* user pressed left button     */
                {
                        choice= -1;     /* reset from last choice made  */
                        for(i=0; i < 3; i++)
                        {
                                if((m3 >= options[i].mh && m3 <= options[i].mh2)
                                  && (m4 == options[i].mv))
                                        choice = i;
                        }
                        switch(choice)
                        {
                                case 0:         /* selected GEN. LEDGER */
                                        genledg();
                                        break;
                                case 1:         /* selected PAYROLL     */
                                        payroll();
                                        break;
                                case 2:         /* selected EXIT        */
                                        loop=0; /* ends infinite loop   */
                                        break;
                                default:        /* meaningless "click"  */
                                        break;
                        }
                        m1=m2=m3=m4=i=0;
                        mouse(&m1,&m2,&m3,&m4);         /* init mouse    */
                        m1=1;                           /* show cursor   */
                        mouse(&m1,&m2,&m3,&m4);
                }
        }
                /* perform housekeeping chores before exiting   */

        m1=2;                           /* hide mouse cursor    */
        mouse(&m1,&m2,&m3,&m4);
        txtcursor(1);                   /* restore text cursor  */
        cls();                          /* clear screen         */
        signal(SIGINT, SIG_IGN);        /* enable control-break */
        exit(0);                        /* return to DOS        */

}                       /*  END MAIN PROGRAM    */


void txtcursor(char cur)                /* controls text cursor */
{
        union REGS r;                   /* prepare registers,etc*/
        r.h.ah = 1;
        if(cur)                         /* turn text cursor on  */
        {
                r.h.cl = 7;
                r.h.ch = 6;
        }
        else
        {
                r.h.ch = 113;           /* set bits 5,6         */
                r.h.cl = 0;             /* set lower bits       */
        }
        int86(0x10, &r, &r);            /* execute the interrupt*/
}

void cls()                              /* clears the screen    */
{
        union REGS r;
        r.h.ah = 6;                     /* screen scroll code   */
        r.h.al = 0;                     /* clear screen code    */
        r.h.ch = 0;                     /* start row            */
        r.h.cl = 0;                     /* start column         */
        r.h.dh = 24;                    /* end row              */
        r.h.dl = 79;                    /* end column           */
        r.h.bh = 7;
        int86(0x10, &r, &r);            /* execute interrupt    */
}

void outstr(x,y,s, color)       /* writes a string to video RAM */
char *s;                               /* string to write       */
char color;                            /* color of string       */
int x,y;                               /* where to start writing*/
{
        char far *vid_mem;             /* video memory pointer  */
        vid_mem= (char far *) 0xB8000000;       /* start of video memory */
        vid_mem=vid_mem+((x * 160) + (y * 2));  /* where to start output */
        while(*s)                               /* loop thru string...   */
        {

                *vid_mem=*s++;          /* move string into video memory*/
                ++vid_mem;              /* incr. to next byte=attribute */
                *vid_mem=color;         /* and set the color there      */
                ++vid_mem;              /* incr. for next character in  */
        }                               /* the string "s"....           */
}


void chkdrv()                   /* checks for presence of mouse driver  */
{
        union REGS inregs, outregs;
        struct SREGS segregs;
        long address;
        unsigned char first_byte;

        inregs.x.ax = 0x3533;
        intdosx(&inregs, &outregs, &segregs);

        address=(((long) segregs.es) << 16)+(long) outregs.x.bx;
        first_byte= * (long far *) address;

        if((address==0) || (first_byte==0xcf))
        {
                cls();
                printf("System has a mouse, but no mouse driver !\n");
                printf("Install file MOUSE.SYS and re-start this program.");
                exit(0);
        }
}

void genledg()                          /* "dummy" function     */
{
        m1=2;                                   /* hide cursor  */
        mouse(&m1,&m2,&m3,&m4);
        cls();
        printf("Perform Option 1, 'General Ledger'\nNow press 'ENTER'...");
        getchar();
        heading();
}

void payroll()                          /* "dummy" function     */
{
        m1=2;                                   /* hide cursor  */
        mouse(&m1,&m2,&m3,&m4);
        cls();
        printf("Perform Option 2, 'Payroll'\nNow press 'ENTER'...");
        getchar();
        heading();
}

void heading()                          /* menu heading         */
{
        cls();                          /* clear screen         */
        outstr(3,25,"Sample Mouse/Menu Program",14);
        for(i=0; i < 3; i++)
                outstr(options[i].x,options[i].y,options[i].text,10);
}

int handler()                   /* control-break function       */
{
        signal(SIGINT, SIG_IGN);
}
