
//BEGIN: "inevent.h"

// Only want to include it once.
#ifndef _INEVENT_H
#define _INEVENT_H

#define TRUE    1
#define FALSE   0

typedef char BOOL;

typedef struct tagPOINT {
   int x;
   int y;
} POINT;



// The four types, returned by GETMESSAGE
// (TYPE field in the message-structure)
#define MSG_MOUSE        910
#define MSG_KEY          940
#define MSG_KEY_CONTROL  941
#define MSG_ERROR        999

// "Msg" types for Type = MSG_MOUSE;
// (MESSAGE field in the message-structure)
#define MSG_MOUSE_LEFT_CLICK       MSG_MOUSE + 1
#define MSG_MOUSE_RIGHT_CLICK      MSG_MOUSE + 4

typedef struct tagDOSMSG {
   int     Type;   // See "types" (above)
   int     Msg;    // KEYS.H if key, else mouse-id
   POINT pt;       // ALWAYS know where it is.
} DOSMSG;

class Event {

   public:

      DOSMSG DosMsg;

		// Class overhead and management;
      Event();      // Class constructor
      ~Event();     // Class destructor

		// Mouse-specific functions;
      BOOL    HasMouse();
      POINT   WhereMouseXY();
		BOOL    SetMouseXY(int, int);

		// Keyboard-specific functions;
      int     WhereX();
      int     WhereY();
      POINT   WhereXY();
      BOOL    GotoXY(int, int);

		// Message retreval;
      DOSMSG  *GetMessage(char *, int);
      DOSMSG  *GetMessage(BOOL);

		// Miscellaneous functions;
      void    BellAlert(BOOL);

   private:
      int     C1X;   // Keyboard cursor (cursor #1)
      int     C1Y;   // ibid.
      int     C2X;   // Mouse cursor (cursor #2)
      int     C2Y;   // ibid.
      int     BUTTON;     // 'L', 'R', NULL code
      int     CTRLKEY;    // 2nd value of scan code
      int     bx, cx, dx; // used for register calls

      BOOL    bMouseOn;   // TRUE = Mouse Installed
      BOOL    bBellOn;    // BEEP on error
      int     GetEvent();
      // inline 4speed;
      int     _mouse(int, int *, int *, int *);
      int     MouseStatus();
      // Ret FALSE (0) if no mouse
      BOOL    MouseReset();

      // Only used for graphics mode.
      void    install_cursor_image(void);
};


//END  : "inevent.h"

#endif
::::: END   :::::::::: INEVENT.H :::::::::: END   
::::: BEGIN :::::::::: MOUSE.H :::::::::: BEGIN 
/* ********************************************** */
/* File mouse.h: Adapted from the CUG, Sept/Oct   */
/* 1988 issue, Page 88-90.  These routines will   */
/* allow you to talk to the MICROSOFT mouse driver*/
/* ********************************************** */

#include <dos.h>

#define MOUSE_RESET     0       /* Mouse services */
#define MOUSE_ON        1
#define MOUSE_OFF       2
#define MOUSE_STATUS    3
#define MOUSE_SET       4
#define MOUSE_PRESSED   5
#define MOUSE_RELEASED  6
#define MOUSE_COLMAX    7
#define MOUSE_ROWMAX    8
#define MOUSE_GIMAGE    9
#define MOUSE_TIMAGE    10

/* Used to test BX after service 3 */
#define LEFTBUTTON      1
#define RIGHTBUTTON     2
#define BOTHBUTTONS     LEFTBUTTON | RIGHTBUTTON

/* Used with service 5 and 6       */
#define LEFT_STATUS     0
#define RIGHT_STATUS    1

union  REGS  inregs, outregs;
struct SREGS segregs;
::::: END   :::::::::: MOUSE.H :::::::::: END   
::::: BEGIN :::::::::: KEYS.H :::::::::: BEGIN 
/* KEYS.H:  Local definition
of keys for IBM PC/XT/AT family

Rev 89/10/18, R. Nagy
*/
#ifndef _KEYS

#define _KEYS 1

#define F1        0x3b
#define F2        0x3c
#define F3        0x3d
#define F4        0x3e
#define F5        0x3f
#define F6        0x40
#define F7        0x41
#define F8        0x42
#define F9        0x43
#define F10       0x44
#define F11       0x98
#define F12       0x99

#define SHIFT_F1  0x54
#define SHIFT_F2  0x55
#define SHIFT_F3  0x56
#define SHIFT_F4  0x57
#define SHIFT_F5  0x58
#define SHIFT_F6  0x59
#define SHIFT_F7  0x5a
#define SHIFT_F8  0x5b
#define SHIFT_F9  0x5c
#define SHIFT_F10 0x5d
#define SHIFT_F11 0xa2
#define SHIFT_F12 0xa3
#define SHIFT_I   0x0f

#define ALT_F1    0x68
#define ALT_F2    0x69
#define ALT_F3    0x6a
#define ALT_F4    0x6b
#define ALT_F5    0x6c
#define ALT_F6    0x6d
#define ALT_F7    0x6e
#define ALT_F8    0x6f
#define ALT_F9    0x70
#define ALT_F10   0x71
#define ALT_F11   0xb6
#define ALT_F12   0xb7

#define CTRL_F1   0x5e
#define CTRL_F2   0x5f
#define CTRL_F3   0x60
#define CTRL_F4   0x61
#define CTRL_F5   0x62
#define CTRL_F6   0x63
#define CTRL_F7   0x64
#define CTRL_F8   0x65
#define CTRL_F9   0x66
#define CTRL_F10  0x67
#define CTRL_F11  0xac
#define CTRL_F12  0xad

#define UP        0x48
#define DOWN      0x50
#define PGUP      0x49
#define PGDN      0x51
#define LEFT      0x4b
#define RIGHT     0x4d
#define HOME      0x47
#define END       0x4f
#define DEL       0x53
#define INS       0x52

/* Non-scan code keys,
flagged as NULL scan-codes.
(Makes a CP/M'er feel at home!)
*/
#define CTRL_H    0x08
#define CTRL_M    0x0d
#define CTRL_J    0x0a
#define CTRL_L    0x0c
#define CTRL_C    0x03
#define CTRL_I    0x09
#define CR        CTRL_M
#define LF        CTRL_J
#define TAB       CTRL_I
#define ESC       0x1B
#define PLUS      '+'
#define MINUS     '-'

#endif
::::: END   :::::::::: KEYS.H :::::::::: END   
::::: BEGIN :::::::::: INEVENT.CPP :::::::::: BEGIN 
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>

#include "mouse.h"

// Used to run the TEST program, else is a library.
#define TEST

#include "inevent.h"


/* ********************************************** */
// Since only members of this class will be talking
// to the mouse, we have placed this inline function
// in this file.  However, it is not unusal for
// inline functions to be placed in the class header
// file, to share with other programs that will be
// using the class.
/* ********************************************** */
inline int Event::_mouse(int service, int *bx_reg,
  int *cx_reg, int *dx_reg)
{
  inregs.x.ax = service;
  inregs.x.bx = *bx_reg;
  inregs.x.cx = *cx_reg;
  inregs.x.dx = *dx_reg;
  int86(0x33, &inregs, &outregs);
  *bx_reg = outregs.x.bx;
  *cx_reg = outregs.x.cx;
  *dx_reg = outregs.x.dx;
  return(outregs.x.ax);
} /* _mouse() */



/* ********************************************** */
/* ********************************************** */
Event::Event(){

  CTRLKEY = NULL;

  bBellOn  = TRUE;
  // Ret T if mouse installed
  bMouseOn = MouseReset();

  if(bMouseOn == TRUE) {
    bx = cx = dx = 0;

    // Turn the mouse on
    _mouse(MOUSE_ON, &bx, &cx, &dx);

    // Set C2X, C2Y, and BUTTON
    MouseStatus();
	}

  // init keyboard stuff
  WhereXY();
	_setcursortype(_NOCURSOR);

} //Event()


/* ********************************************** */
/* ********************************************** */
Event::~Event(){
  if(bMouseOn == TRUE) {

    // Turn the mouse off
    bx = cx = dx = 0;
    _mouse(MOUSE_OFF, &bx, &cx, &dx);

  } else {
    // destruct keyboard stuff
    // (not needed on DOS)
  }
	_setcursortype(_NORMALCURSOR);
} //~Event()


/* ********************************************** */
// MouseReset(): Used to reset mouse or to check if
// mouse is installed. Returns 0 TRUE or FALSE.
/* ********************************************** */
BOOL Event::MouseReset() {
  bx = cx = dx = 0;

  if(_mouse(MOUSE_RESET, &bx, &cx, &dx))
    return TRUE;

  return FALSE;

} // MouseReset()


/* ********************************************** */
/* ********************************************** */
int Event::MouseStatus() {
int x, y, button;

  if(bMouseOn == TRUE) {
    _mouse(MOUSE_STATUS, &button, &x, &y);
    C2Y = y /8;
    C2X = x /8;

    switch(button) {
    case LEFTBUTTON:
      BUTTON = MSG_MOUSE_LEFT_CLICK;

    break;

    case RIGHTBUTTON:
      BUTTON = MSG_MOUSE_RIGHT_CLICK;

    break;

    default:
      BUTTON = NULL;
    break;

    }
  }
  return button;
} // MouseStatus()



/* ********************************************** */
// Returns X position of cursor #1 
/* ********************************************** */
int Event::WhereX() {

  if(bMouseOn == TRUE) {
    MouseStatus();
  }

	C1X = wherex();

  return C1X;
} // WhereX()



/* ********************************************** */
// Returns Y position of cursor #1
/* ********************************************** */
int Event::WhereY() {

  if(bMouseOn == TRUE) {
    MouseStatus();
  }

	C1Y = wherey();

  return C1Y;
} // WhereY()



/* ********************************************** */
// Sets the global X and Y positons && returns their
// values.  Cursor #1, only.
/* ********************************************** */
POINT Event::WhereXY() {
POINT result;

  C1X = result.x = wherex();
  C1Y = result.y = wherey();
  return result;  // The two ints become a long

} // WhereXY()



/* ********************************************** */
// Returns TRUE is the user has a mouse, else FALSE.
/* ********************************************** */
BOOL Event::HasMouse(){
  return bMouseOn;
} // HasMouse()



/* ********************************************** */
// Sets the global X and Y positons && returns their
// values.  If !mouse, then you get cursor #1.
/* ********************************************** */
POINT Event::WhereMouseXY() {
POINT result;

  if(bMouseOn == TRUE) {
    result.x = C2X;
    result.y = C2Y;
  } else {
    C1X = result.x = wherex();
    C1Y = result.y = wherey();
  }
  return result;  // The two ints become a long

} // WhereMouseXY()



/* ********************************************** */
// Positions the mouse-cursor. (Cursor #2).
/* ********************************************** */
BOOL Event::SetMouseXY(int x, int y) {
int xx, yy;

  if(bMouseOn == TRUE) {
	  xx = x*8;
    yy = y*8;
    _mouse(MOUSE_SET, 0, &xx, &yy);
  } else {
    gotoxy(x, y);
  }

  C2X = x;
  C2Y = y;
  return TRUE;
} // GotoXY()



/* ********************************************** */
// Positions the screen-cursor. (Cursor #1).
/* ********************************************** */
BOOL Event::GotoXY(int x, int y) {
int xx, yy;

  gotoxy(x, y);

  C1X = x;
  C1Y = y;
  return TRUE;
} // GotoXY()



/* ********************************************** */
// Toggles the BELL on and off for string-overflow
// errors.
/* ********************************************** */
void Event::BellAlert(BOOL setit) {
  bBellOn = setit;
} // BellAlert()



/* ********************************************** */
// This is the interface into the system area.  It
// is the "clearing house" from which we get all
// our events.
// For BOTH mouse && keyboard. Returns MSG_* upon
// MOUSE or CONTROL activity, else a single key.
/* ********************************************** */
int Event::GetEvent() {
int ch;

  // Discard result of last MouseStatus().
  BUTTON = NULL;

  // Loop until info
  while( (!kbhit()) && (BUTTON == NULL) )
    {
    // This would be a great place to hook-up
    // a multi-taking routine.  The routine could
    // merely execute a "hook" function, or do some
    // sophisticated round-robin processing.  The
    // idea here is that, since we're "polling", we
    // could be doing something more "fun".  For
    // example, in Windows, this point is analogous
    // to the "GetMessage" loop which allows Windows
    // to run other processes.
    if (bMouseOn) MouseStatus();
    }

  // Flag MOUSE activity (set by lower driver).
  if(BUTTON) return MSG_MOUSE;

  ch=getch();
  if(ch==NULL) {
    // Save the scan code.
    // Flag CTRL activity.
    CTRLKEY=getch();
    WhereXY();  // Exact position of function keyin
    return MSG_KEY_CONTROL;
  }

  // If we're here, then it's a simple keystroke;

  // Read the keyboard cursor;
  WhereXY();

  return(ch);
} // GetEvent()



/* ********************************************** */
// This is the preferred interface into events.
// No strings are ever returned.
// Keyboard strings are echoed upon demand (note
// that the default is to echo, if none supplied).
/* ********************************************** */
DOSMSG *Event::GetMessage(BOOL bEcho = TRUE) {
DOSMSG *pDm;

pDm = &DosMsg;


pDm->Type = GetEvent();

switch(pDm->Type)
  {

  case MSG_MOUSE:
    pDm->pt.x = C2X;
    pDm->pt.y = C2Y;
    pDm->Msg  = BUTTON;
  break;

  case MSG_KEY_CONTROL:
    pDm->pt.x = C1X;
    pDm->pt.y = C1Y;
    pDm->Msg  = CTRLKEY;
  break;

  default:
    // signal <= KEYBOARD message (character).
    pDm->pt.x = C1X;
    pDm->pt.y = C1Y;
    pDm->Msg  = pDm->Type;
    pDm->Type = MSG_KEY;

    if(bEcho == TRUE) printf("%c",pDm->Msg);

  break;
  }

return pDm;

} // GetMessage()



/* ********************************************** */
// Builds Zstring or mouse message.  Returns a
// populated "buf" string <= bufsz, as well as the
// last DOSMSG received.
/* ********************************************** */
DOSMSG *Event::GetMessage(char *buf, int bufsz) {
int nelem = 0;
DOSMSG *pDm;

	// Here we want to be sure to save the position of
	// the string as we enter the module.  If we get
 	// interrupted with control-code activity, then
	// we will use the apropriate message position.
	// If not, then we want to return the XY pair of
	// the BEGINNING of the string, not at the last
	// character keyed-in.
  pDm       = &DosMsg;
  pDm->pt.x = WhereX();
  pDm->pt.y = WhereY();

  while((pDm->Type  != 0x0d))
    {

    *buf = pDm->Type = GetEvent();


    // BUTTON Mouse activity.  Mk message.
    if(pDm->Type  == MSG_MOUSE)
      {
      pDm->Msg    = BUTTON;
      pDm->pt.x   = C2X;
      pDm->pt.y   = C2Y;

      *buf = NULL;
      return pDm;    // signal MOUSE message.

      }

    // FUNCTION key activity.  Mk message.
    if(pDm->Type  == MSG_KEY_CONTROL)
      {
      pDm->Msg    = CTRLKEY;
      pDm->pt.x   = C1X;
      pDm->pt.y   = C1Y;

      *buf = NULL;
      return pDm;  // signal CTRLKEY message.
      }

    // NORMAL string building activity.  Note that
	  // on normal-size strings (ie: no overflow),
	  // we will get a \r (0x0a) just before the
	  // NULL.  This is the universal "newline"
	  // character on all C platforms, and is
	  // easily removed here if you don't want it.
    buf++;
    nelem++;
    printf("%c",pDm->Type);
    if(nelem >= (bufsz -1))
      {
      if(bBellOn == TRUE)
        printf("%c",0x07);  // Sound a bell

      break;
      }
    }

  if(nelem)    // good insurance.
    {
    pDm->Type = MSG_KEY;
    *buf = NULL;
    }

  // signal <= KEYBOARD message (string).
  return pDm;

} // GetMessage()



/* ********************************************** */
// This is used to support graphics screens, only.
// It is included for illustrative puropses only.
// Since we are running in TEXT mode, it is not
// used.
/* ********************************************** */
void Event::install_cursor_image(void)
{
    static int immage[16][2] = {
      {0xe1ff, 0xe1ff},  /* Screen Mask  */
      {0xe1ff, 0xe1ff},
      {0xe1ff, 0xe000},
      {0xe000, 0xe000},
      {0x0000, 0x0000},
      {0x0000, 0x0000},
      {0x0000, 0x0000},
      {0x0000, 0x0000},
      {0x1e00, 0x1200},  /* Image Mask  */
      {0x1200, 0x1200},
      {0x1200, 0x13ff},
      {0x1249, 0x1249},
      {0x1249, 0x9001},
      {0x9001, 0x9001},
      {0x8001, 0x8001},
      {0x8001, 0xffff}
    };

    segread(&segregs);
    segregs.es  = segregs.ds;
    inregs.x.ax = MOUSE_GIMAGE;
    inregs.x.bx = 5;
    inregs.x.cx = 0;
    inregs.x.dx = (int) immage;
    int86x(0x33, &inregs, &outregs, &segregs);

} /* install_cursor_image() */



#ifdef TEST

#define STRING_SZ 30

class Event DosEvent;

void TestPointer(void *pClass)
{
class Event *pEClass;

	pEClass = (class Event *)pClass;

  clrscr();
  pEClass->GotoXY(1,0);
  puts("Keyin \"BYE\" to Exit");
  printf("Mouse is %s",
          pEClass->HasMouse() ? "ON" : "OFF"
  );

} // TestPointer()


void main() {

int i = 0, result = TRUE;
char buf[STRING_SZ +1];
char blanker[] = "                                \
                                                  ";

DOSMSG *pDm;

  memset(buf, 0, STRING_SZ +1);

  TestPointer((void *) &DosEvent);

  while(result == TRUE) {

    DosEvent.GotoXY(1,3);

    printf("%02d, %02d", DosEvent.WhereX(),
               DosEvent.WhereY() );

    DosEvent.GotoXY(1,15);

    printf("%02d.) Message key-in: ", i++);

    // This is the main interface.  Notice that the
    // overloaded entry-point to the class allows us
    // to use either
    // pDm = DosEvent.GetMessage(TRUE);
    // to get a SINGLE event with character-echoing
    // or

    pDm = DosEvent.GetMessage(buf, STRING_SZ);

    // to build a string.
    // Of the two, the latter is used here to
    // illustrate how strings are gathered && how
    // function keys will interrupt the gathering of
    // strings.


    // Clean-up after the last-message;
    DosEvent.GotoXY(0, 20);
    puts(blanker);
    DosEvent.GotoXY(0, 21);
    puts(blanker);
    DosEvent.GotoXY(0, 22);
    puts(blanker);

    switch(pDm->Type)

      {
      case MSG_MOUSE:
        DosEvent.GotoXY(10, 20);
        printf("Mouse Message = %02d, %02d  ",
              pDm->pt.x, pDm->pt.y);
        DosEvent.GotoXY(40, 10);
        switch(pDm->Msg)
          {
          case MSG_MOUSE_LEFT_CLICK:
            puts("MSG_MOUSE_LEFT_CLICK: ");
          break;

          case MSG_MOUSE_RIGHT_CLICK:
            puts("MSG_MOUSE_RIGHT_CLICK:");
          break;

          default:
            puts("???????????????:      ");
          break;
          }
      break;

      case MSG_KEY:
        DosEvent.GotoXY(10, 20);
        printf("Last Key Message = %02d, %02d",
              pDm->pt.x, pDm->pt.y);

        DosEvent.GotoXY(10, 21);
        printf("Message Keys= \"%s\" ", &buf[0]);

			// Exit requested...
			if(!strcmp(&buf[0], "BYE\r"))
				result = FALSE;
      break;

      case MSG_KEY_CONTROL:
        DosEvent.GotoXY(10, 20);
        printf("Control Message = %02d, %02d ",
              pDm->pt.x, pDm->pt.y);

        DosEvent.GotoXY(10, 22);
        printf("Function Key = %c ", pDm->Msg);

        // Just to remind us that we may STILL have
        // something interesting in the 'ol key-buffer;
        DosEvent.GotoXY(10, 21);
        printf("Message Keys= \"%s\" ", &buf[0]);
      break;

      default:
        DosEvent.GotoXY(10, 20);
        printf("Error Message = %02d, %02d   ",
              pDm->pt.x, pDm->pt.y);

        DosEvent.GotoXY(10, 23);
        printf("Error!! \7");
      break;
    }

  }

} // main()

#endif

::::: END   :::::::::: INEVENT.CPP :::::::::: END   
::::: BEGIN :::::::::: INEVENT.MAK :::::::::: BEGIN 
.AUTODEPEND

#		*Translator Definitions*
CC = bcc +INEVENT.CFG
TASM = TASM
TLIB = tlib
TLINK = tlink
LIBPATH = \BC\LIB
INCLUDEPATH = \BC\INCLUDE


#		*Implicit Rules*
.c.obj:
  $(CC) -c {$< }

.cpp.obj:
  $(CC) -c {$< }

#		*List Macros*


EXE_dependencies =  \
 inevent.obj

#		*Explicit Rules*
inevent.exe: inevent.cfg $(EXE_dependencies)
  $(TLINK) /v/x/c/P-/L$(LIBPATH) @&&|
c0l.obj+
inevent.obj
inevent
		# no map file
graphics.lib+
emu.lib+
mathl.lib+
cl.lib
|


#		*Individual File Dependencies*
inevent.obj: inevent.cfg inevent.cpp 

#		*Compiler Configuration File*
inevent.cfg: inevent.mak
  copy &&|
-ml
-v
-vi-
-weas
-wpre
-I$(INCLUDEPATH)
-L$(LIBPATH)
-P-.C
| inevent.cfg


::::: END   :::::::::: INEVENT.MAK :::::::::: END   

