[comp.lang.c] Mouse - Ware

batman@watsci.uwaterloo.ca (Marcell Stoer) (01/23/90)

	First of all I'd like to thank everyone for their input, this goes to:

	Tom Hill			late@Sun.Com
	Darren Porter		porter@cssexb.ccs.csus.edu
	John Nelson			jpn@genrad.com
	Brian Helterline	brainh@hpcvia.cv.hp.com
	Stuart Kemp			kemp@umn-cs.cs.umn.edu
	Raymond Chen		raymond@math.berkley.edu
	Robert Adsett		semicon@watsci.waterloo.edu

I acquired a book call _MSDOS Extentions Programmers quick Reference_
by Microsoft Press, which contains all the interrupt calls for the expanded
and extended memory, CD-ROM and the Microsoft Mouse (which is very much
compatible with Logitech).  I've found that it seems to have all the
information I need.  There are other more extensive books, with routine
samples in C and some even supply a diskette withe Demos (I think its one
by Microsoft Press).  

Here is the summary, it is quite long, since Tom Hill (reply 1) was 
generous enough to include some sample mouse testing routines (in C).
I placed his last.  You may want to save this and read it later.

thanks, Marcell.
-----------------------------

Reply 2, Darren Porter writes :

Try  the  _Microsoft Mouse Programmer's Reference_  by Microsoft press.  I
wrote my own library of mouse functions in Pascal through this book.  It has
examples in C also.  I'm not sure of the compatibility with the Logitech mouse,
though.  Are they compatible?  I know my library works with an AT&T mouse
that uses the Logitech driver...


Reply 3, (jpn@genrad.com) John Nelson

The easiest (and most portable) way to write code that uses a mouse is to
install the mouse "driver", then use the standard mouse software interface.
All mouse functions are accessed via "int 33" when a driver is active.

There are too many functions for me to list them here.  The mouse interface
is documented in MANY places.  If you don't have a copy of "Advanced MSDOS
programming" by Ray Duncan, published by Microsoft Press, then I recommend
it.

-- 

Reply 4 , Brian Helterline (brianh@hpcvia.cv.HP.COM): 

	To access a mouse in C, you need to use int86() (MSC 5.1).  The
	interrupt you are interested in is INT 0x33 (BIOS mouse driver that
	is compatible with MS mouse).  By passing the correct info, you
	can turn on the mouse, read its position, determine status of
	buttons, position mouse, etc.  Check out a system BIOS manual
	for details.  I wrote a few basic routines to do this stuff.  If you
	are using MSC and would like them, let me know & I'll email them
	to you.

	Another approach is to use a canned package that has mouse support
	built into its library.  All you have to do is include their library
	at compile time & use their ready-made mouse functions.  These
	functions use the same idea as above (int 0x33).  One such company
	is:
		Greenleaf Software Inc.
		16479 Dallas Parkway, Suite 570
		Bent Tree Tower Two
		Dallas, TX 75248
		(214) 248-2561

	They have a lot more than the basic functions I wrote, but they
	also cost more.

NOTE:	I am not associated with or endorsing Greenleaf Software Inc. or
	any of its products.

---------------------------

Reply 5, Stuart Kemp writes :

The mouse stuff is all available via int 33h. The entire list
of options are available in some books; otherwise look
in the list of interrupts that appears here sometimes.
(As mainatined by Ralf Brown). Is available via anon ftp
from cs.cmu.edu (128.2.222.173). Look in directory
/afs/cs/user/ralf/pub (you must cd to that directory all at
once) File is interrup.zip.

-----------------------------

Reply 6, (raymond@math.berkeley.edu) Raymond Chen writes :

Grab the Interrupt List and read about Int 33h.  That's where all the
mouse information comes from.

--------------------- 

NOTE :
Although This was the first reply, I placed it last due to its length.

Reply 1 : From: late@Sun.COM (Tom Hill)

There are several books out that will tell you about the mouse.
My favorite is Advanced MS-DOS programming by ray duncan,
which is one of the best books on programming the pc. Covers
ms-dos, some bios stuff, mouse, EMS. Good book.

Microsoft press also has a book on programming the mouse too.

Let's see, I started writing  a program to test a mouse driver,
I'll tack it on the end. It's not really done, but if you're like
me you'd rather have something to play with now, until you can
find the books. It should give you some idea about 
how to access the driver.

Remember I just started this, bugs are virtually guaranteed!!!

Note :

In the example mouse program I sent, there was a call to 'mouse_disable'
(int 33, function 31). It turns out this turns off the mouse a little
more thoroughly than I intended, and you should probably take the
call to mouse_disable out, & replace it with a call to mouse_reset.

I had assumed that reseting the mouse would take it out of the 
disabled state. WRONG! So after you do a disable, most applications
won't even notice you have a mouse. You have to do an enable
(int 33, ax=32) before the mouse will work again. Or reboot.

/*
 * Program  to test the functionaliy of a microsoft compatible mouse driver
 * This program must be compiled under TurboC 2.0. Since one of the functions
 * below is called at interrupt time by the mouse irq service routine, the
 * Compiler options option/compiler/codegen/test stack and also
 * option/compiler/optimize/register vars must be off for the program to work
 */

/*------------------------------------------------------------------------*/
/* This routine provides some minimal mouse testing.                      */
/*------------------------------------------------------------------------*/

/* ------------------- Include files -------------------------------------*/
#include <conio.h>
#include <ctype.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>

/* ------------------- Constant declarations -----------------------------*/
#define N_FUNCTIONS 36	/* Number of functions supported by Microsoft	  */
			/* Mouse driver version 6 (current at this time)  */
#define SCREEN_ADDRESS 0xB8000

/* ------------------- Type declarations ---------------------------------*/

/* ------------------- Local function prototypes -------------------------*/
static int mouse_test_0(void);
static int mouse_test_1(void);
static int mouse_test_2(void);
static int mouse_test_3(void);
static int mouse_test_4(void);
static int mouse_test_5(void);
static int mouse_test_6(void);
static int mouse_test_7(void);
static int mouse_test_8(void);
static int mouse_test_9(void);
static int mouse_test_10(void);
static int mouse_test_11(void);
static int mouse_test_12(void);
static char get_key(void);
static int mouse_position(void);
static int mouse_reset(void);
static void mouse_disable(void);
static void mouse_setp(int x,int y);
static void mouse_getp(int *x,int *y);
static int test_handlers(void);
static void usage(void);
static void record_results(int function_number,int result);

/* ------------------- Global data ---------------------------------------*/

/* ------------------- Data local to this module -------------------------*/
static int data_segment;
struct
{
	int run;	/* Was this test run ? */
	int status;	/* Did function succeed (1) or fail (0) */
} results[N_FUNCTIONS];

static int (*functions[N_FUNCTIONS])(void) =
{
	mouse_test_0,
	mouse_test_1,
	mouse_test_2,
	mouse_test_3,
	mouse_test_4,
	mouse_test_5,
	mouse_test_6,
	mouse_test_7,
	mouse_test_8,
	mouse_test_9,
	mouse_test_10,
	mouse_test_11,
	mouse_test_12,
};

int main()
{
	int test;
	data_segment = _DS;	/* For mouse event handler */
	usage();
	record_results(0,mouse_test_0());
	if (!results[0].status)
	{
		printf("No mouse found\n");
		return(0);
	}
	for (test = 0; test< N_FUNCTIONS; test++)
	{
		if (functions[test] == NULL)
		{
			printf("Test #%3d not implemented\n",test);
			continue;
		}
		else
		{
			record_results(test,(*functions[test])());
		}
	}
	mouse_disable();
	clrscr();
	for (test = 0; test < N_FUNCTIONS; test++)
	{
		if (results[test].run)
		{
			printf("Test #%3d ",test);
			if (results[test].status)
				printf("passed\n");
			else
				printf("FAILED!!!!!\n");
		}
	}
	printf("Done.\n");
	return(1);
}

static void record_results(int function_number,int result)
{
	if (results[function_number].run)
		results[function_number].status &= result;
	else
		results[function_number].status = result;
	results[function_number].run = 1;
}

/* Throw away one keystroke. Function keys & the like read a two characters */
static void eat_key(void)
{
	int c;
	c = getch();
	if (c == 0)
		getch();
}
static void usage(void)
{
	clrscr();
	printf("This program tests the basic functionality of a\n");
	printf("Microsoft compatible mouse driver\n");
	printf("\nPlease follow the directions you see on the screen\n");
	printf("Press any key to continue\n");
	while (!kbhit())
		;
	eat_key();
}

/* Handler for mouse events, called directly from mouse interrupt handler. */
static void far mouse_info()
{
	char far * screen = (char far *)0xb8000000L;
	int ax = _AX;
	int x;
	int mask = 1;
	int bitcount = 0;
	_DS = data_segment;
	for (x =0; x < 0x5; x++)
	{
		if (mask & ax)
		{
			screen[2*(x+3)*80] = '1';
			bitcount++;
		}
		else
		{
			screen[2*(x+3)*80] = '0';
		}
		mask <<= 1;
	}
	/* Test for odd conditions. Multiple events on one tick (okay i think?) */
	/* or zero events, which I think should not happen */
	if (bitcount > 1)
		screen[2*(x +3)*80] = 'Y';
	x++;
	if (bitcount == 0)
		screen[2*(x +3)*80] = 'Y';
	x++;
	screen[2*(x +3)*80]++;		/* Provided visual indicator that */
					/* we are being called, even if the */
					/* button state is not changing */

}

/* Turn the mouse driver off */
static void mouse_disable()
{
	struct REGPACK reg;
	reg.r_ax = 31;
	intr(0x33,&reg);
}


static void mouse_display(void)
{
	struct REGPACK reg;
	reg.r_ax = 1;
	intr(0x33,&reg);
}

static void mouse_hide(void)
{
	struct REGPACK reg;
	reg.r_ax = 2;
	intr(0x33,&reg);
}

/* Set the mouse position */
static void mouse_setp(int x,int y)
{
	struct REGPACK reg;
	reg.r_ax = 4;
	reg.r_cx = x;
	reg.r_dx = y;
	intr(0x33,&reg);
}


/* Get the position of the mouse */
static void mouse_getp(int *x,int *y)
{
	struct REGPACK reg;
	reg.r_ax = 3;
	intr(0x33,&reg);
	if (reg.r_bx != 0)
	printf("Buttons are down.\n");
	*x = reg.r_cx;
	*y = reg.r_dx;
}

static char get_key(void)
{
	struct REGPACK reg;
	reg.r_ax = 0;
	intr(0x16,&reg);
	return(reg.r_ax & 0xff);
}


static void mouse_int(int ax,int bx,int cx,int dx,int es)
{
	struct REGPACK reg;
	reg.r_ax = ax;
	reg.r_bx = bx;
	reg.r_cx = cx;
	reg.r_dx = dx;
	reg.r_es = es;
	intr(0x33,&reg);
}


/* Since code to test functions 5 & 6 is almost identical, this
 * function handles both, based on the paramters passed
 */
static int mouse_press_release(
	int function,	/* Five for press test, six for release test */
	int button      /* 0,1,2 left, right center. We emulate a 2 button */
			/* mouse, so there is no center */
	)
{
	struct REGPACK reg;
	char *msg[2] = {"presses","releases"};
	char *button_names[3] = {"Left","Right","Center"};
	clrscr();
	if (!mouse_reset())
		return(0);
	mouse_display();
	if ((function != 5) && function !=6)
		return(0);
	printf("Test function %d, count button %s\n",function,msg[function-5]);
	printf("It will sample the %s button at two second intervals\n",button_names[button]);
	printf("And report count, location & state.\n");
	printf("Press any key to when you are done with this test.\n");

	while (!kbhit())
	{
		reg.r_ax = function;
		reg.r_bx = button;
		intr(0x33,&reg);
		printf("%d %s ",reg.r_bx,msg[function-5]);
		printf("at (%3d:%3d) ",reg.r_cx,reg.r_dx);
		printf("buttons down are %5s %5s %6s\n",
			(reg.r_ax & 1) ? "Left":"",
			(reg.r_ax & 2) ? "Right":"",
			(reg.r_ax & 4) ? "Center":"" );
		delay(1500);
	}
	eat_key();
	return(1);
}

static int mouse_reset()
{
	struct REGPACK reg;
	reg.r_ax = 0;
	intr(0x33,&reg);
	return(reg.r_ax == 0xFFFF);
}

static void set_graph_mode(void)
{
	struct REGPACK regs;
	regs.r_ax = 0x0006;
	intr(0x10,&regs);
	directvideo = 0;
}

static void set_text_mode(void)
{
	struct REGPACK regs;
	directvideo = 1;
	regs.r_ax = 0x0003;
	intr(0x10,&regs);
}


static void get_pos_and_motion(int *x,int *y,int *dx,int *dy)
{
	struct REGPACK regs;
	regs.r_ax = 3;
	intr(0x33,&regs);
	*x = regs.r_cx;
	*y = regs.r_dx;
	regs.r_ax = 0x0B;
	intr(0x33,&regs);
	*dx = regs.r_cx;
	*dy = regs.r_dx;
}

/*
 * Test functions for each mouse function follow in numerical order
 */

/* Mouse function 0 test, initialization & number of buttons */
static int mouse_test_0(void)
{
	struct REGPACK reg;

	reg.r_ax = 0;
	intr(0x33,&reg);
	if (reg.r_ax != 0xFFFF)
	{
		printf("Mouse support not available\n");
		return(0);
	}
	if (reg.r_bx != 2)
	{
		printf("Wrong number of mouse buttons.\n");
		return(0);
	}
	return(1);
}

static int mouse_test_1()
{
	int c;
	clrscr();
	mouse_reset();
	printf("This function tests cursor display & hide functionality\n");
	printf("The cursor should initialize to hidden\n");
	printf("Is the cursor HIDDEN now? (y or n)\n");
	do
	{
		c = getch();
		c = toupper(c);
	} while ((c != 'Y') && (c != 'N'));
	if (c == 'N')
	{
		printf("Error, should initialize to hidden\n");
		printf("Press any key to continue\n");
		eat_key();
		return(0);
	}
	mouse_display();
	printf("Is the cursor VISIBLE now? (Y or N)?\n");
	do
	{
		c = getch();
		c = toupper(c);
	} while ((c != 'Y') && (c != 'N'));
	if (c == 'N')
	{
		printf("Error, display (function 1) did not work\n");
		printf("Press any key to continue\n");
		eat_key();
		return(0);
	}
	mouse_hide();
	printf("Is the cursor HIDDEN now? (Y or N)?\n");
	do
	{
		c = getch();
		c = toupper(c);
	} while ((c != 'Y') && (c != 'N'));
	if (c == 'N')
	{
		printf("Error, hide (function #2) did not work\n");
		printf("Press any key to continue\n");
		eat_key();
		return(0);
	}
	printf("Test passed, press any key to continue\n");
	eat_key();
	return(1);
}

static int mouse_test_2()
{
	return(mouse_test_1());
}

static int mouse_test_3()
{
	printf("Function not implemented\n");
	printf("Test considered failed, press any key\n");
	eat_key();
	return(0);
}


/* Set the mouse position, then try to read it back */
static int mouse_test_4(void)
{
#define N_POINTS 6
	int index,x_read,y_read,x_set,y_set;
	int c;
	mouse_reset();
	clrscr();
	printf("Testing function 4, set mouse position\n");
	printf("It will set the position %d times, and prompt you to verify\n",N_POINTS);
	printf("Press any key to continue\n");
	eat_key();
	for (index = 0; index < N_POINTS; index++)
	{
		x_set = random(640);
		y_set = random(200);
		clrscr();
		mouse_display();
		printf("Moving to %3d,%3d\n",x_set,y_set);
		mouse_setp(x_set,y_set);
		mouse_getp(&x_read,&y_read);
		/*
		 * If we are in text mode on a PC these numbers should be
		 * rounded. In graphics mode, or using the sunview cursor
		 * These numbers are not rounded. I think we should round
		 * the numbers for the sunview cursor, so we look more like
		 * a PC.
		 */
		if (1)
		{
			x_set &= ~7;	/* In text mode, mouse position is rounded */
			y_set &= ~7;
		}
		if ((x_read != x_set) || (y_read != y_set))
		{
				printf("Position reported does not match position set\n");
			printf("Test failed, press any key\n");
			eat_key();
			return(0);
		}
		printf("Does the position look about right?\n");
		do
		{
			c = getch();
			c = toupper(c);
		} while ((c != 'Y') && (c != 'N'));
		if (c == 'N')
		{
			printf("Error, sunview cursor not moved to correct place.\n");
			printf("Press any key to continue\n");
			eat_key();
			return(0);
		}
	}
	return(1);
#undef N_POINTS
}


static int mouse_test_5()
{
	int result;
	result  = mouse_press_release(5,0);
	result &= mouse_press_release(5,1);
	return(result);
}


static int mouse_test_6()
{
	int result;
	result  = mouse_press_release(6,0);
	result &= mouse_press_release(6,1);
	return(result);
}


/* Test horizontal mouse motion limits, funtion 7 */
static int mouse_test_7()
{
	int min=320;
	int max=480;
	clrscr();
	mouse_test_0();
	mouse_display();
	printf("Testing function 7, horizontal motion limits\n");
	printf("Limiting motion to the range %3d to %3d\n",min,max);
	printf("Press any key when done\n");
	mouse_int(7,0,min,max,0);
	do
	{
	} while (!kbhit());
	eat_key();
	return(1);
}


/* Test vertical motion limitations function 8 */
static int mouse_test_8()
{
	int min=0;
	int max=100;
	clrscr();
	mouse_test_0();
	mouse_display();
	printf("Testing function 8, vertical motion limits\n");
	printf("Limiting motion to the range %3d to %3d\n",min,max);
	printf("Press any key when done\n");
	mouse_int(8,0,min,max,0);
	do
	{
	} while (!kbhit());
	eat_key();
	return(1);
}

/*
 * Check function 9, set graphics pointer shape
 */
static int mouse_test_9()
{
	int mask[32] =	/* and */ {0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,0,0, 0,
			/* or  */	0x0000,0x7FFE,0x4000,0x4000,
					0x4000,0x4000,0x4000,0x4000,
					0x7f00,0x4000,0x4000,0x4000,
					0x4000,0x4000,0x4000,0x0000};
	clrscr();
	set_graph_mode();
	mouse_reset();

	mouse_int(9,2,2,(int)mask,_DS);
	mouse_int(1,0,0,0,0); /* display the mouse */
	printf("Set the mouse shape. It should look like a \n");
	printf("large capital F, no reflections or rotations.\n");
	while (!kbhit())
		;
	eat_key();
	set_text_mode();
	return(1);
}


static int mouse_test_10()
{
	printf("Function not implemented\n");
	printf("Test considered failed, press any key\n");
	eat_key();
	return(0);
}


/* Read the mouse motion counters, and see if they correlate with the */
/* mouse position & mickey to pixel ratios */
static int mouse_test_11()
{
	struct REGPACK reg;
	int x,y,		/* Current mouse position */
	x1,y1,			/* Previous recorded mouse position */
	dx,dy,			/* Mickeys since last read. */
	x_mickey=8,y_mickey=8;	/* Mickeys per 8 pixels */
	mouse_test_0();
	mouse_int(0x0F,0,x_mickey,y_mickey,0);
	x_mickey /= 8;	/* convert to mickeys per pixel */
	y_mickey /= 8;	/* ditto */
	clrscr();
	set_graph_mode();
	mouse_int(1,0,0,0,0);
	printf("Check functions 3, 11 and 15, and 15\n");
	printf("Please move the mouse , then click, several times\n");
	printf("Press any key when you are done.\n");
	get_pos_and_motion(&x1,&y1,&dx,&dy);
	delay(2000);
	do
	{
		delay(1000);
		get_pos_and_motion(&x,&y,&dx,&dy);
		printf("New x: %3d, old x: %3d diff: %3d, xmickeys = %3d\n",x,x1,x-x1,dx);
		printf("New y: %3d, old y: %3d diff: %3d, ymickeys = %3d\n",y,y1,y-y1,dy);
		if ( ((x-x1)*x_mickey != ((dx / x_mickey) * x_mickey)  ) )
			goto exit;
		if ( ((y-y1)*y_mickey != ((dy / y_mickey) * y_mickey)  ) )
			goto exit;
		x1 = x;
		y1 = y;
	} while (!kbhit());
	set_text_mode();
	return(1);
exit:
	printf("Test failed - press any key\n");
	eat_key();
	set_text_mode();
	return(0);
}

static int mouse_test_12()
{
	struct REGPACK reg;
	long fp;
	reg.r_ax = 0xC;
	reg.r_cx = 0xFF;
	fp = (long)mouse_info;
	reg.r_dx = (int)fp;
	reg.r_es = (int) (fp >> 16);
	intr(0x33,&reg);
	clrscr();
	printf("\nTest event handlers\nPress a key when done.\n");
	printf("  Movement\n");
	printf("  Left pressed\n");
	printf("  Left released\n");
	printf("  Right pressed\n");
	printf("  Right released\n");
	printf("  Multiple events, one tick (Cumulative)\n");
	printf("  Zero events, one tick. Error if this occurs.\n");
	printf("  Counter. Increments on every call to event handler.\n");
	while (!kbhit())
		;
	return(1);
}

Reply 2: From: porterd@cssexb.ccs.csus.edu@cssexb.ccs.csus.edu  (darren porter)

Try  the  _Microsoft Mouse Programmer's Reference_  by Microsoft press.  I
wrote my own library of mouse functions in Pascal through this book.  It has
examples in C also.  I'm not sure of the compatibility with the Logitech mouse,
though.  Are they compatible?  I know my library works with an AT&T mouse
that uses the Logitech driver...

Reply 3: From: jpn@genrad.com (John P. Nelson)

The easiest (and most portable) way to write code that uses a mouse is to
install the mouse "driver", then use the standard mouse software interface.
All mouse functions are accessed via "int 33" when a driver is active.

There are too many functions for me to list them here.  The mouse interface
is documented in MANY places.  If you don't have a copy of "Advanced MSDOS
programming" by Ray Duncan, published by Microsoft Press, then I recommend
it.

Reply 4: From: brian_helterline <brianh@hpcvia.cv.hp.com>

	To access a mouse in C, you need to use int86() (MSC 5.1).  The
	interrupt you are interested in is INT 0x33 (BIOS mouse driver that
	is compatible with MS mouse).  By passing the correct info, you
	can turn on the mouse, read its position, determine status of
	buttons, position mouse, etc.  Check out a system BIOS manual
	for details.  I wrote a few basic routines to do this stuff.  If you
	are using MSC and would like them, let me know & I'll email them
	to you.

	Another approach is to use a canned package that has mouse support
	built into its library.  All you have to do is include their library
	at compile time & use their ready-made mouse functions.  These
	functions use the same idea as above (int 0x33).  One such company
	is:
		Greenleaf Software Inc.
		16479 Dallas Parkway, Suite 570
		Bent Tree Tower Two
		Dallas, TX 75248
		(214) 248-2561

	They have a lot more than the basic functions I wrote, but they
	also cost more.

NOTE:	I am not associated with or endorsing Greenleaf Software Inc. or
	any of its products.

Reply 5: From: "Stuart R. Kemp" <kemp@umn-cs.cs.umn.edu>

The mouse stuff is all available via int 33h. The entire list
of options are available in some books; otherwise look
in the list of interrupts that appears here sometimes.
(As mainatined by Ralf Brown). Is available via anon ftp
from cs.cmu.edu (128.2.222.173). Look in directory
/afs/cs/user/ralf/pub (you must cd to that directory all at
once) File is interrup.zip.

Reply 6: From raymond@math.berkeley.edu  Wed Jan 17 12:17:21 1990

Grab the Interrupt List and read about Int 33h.  That's where all the
mouse information comes from.
--

		Marcell							BITNET : Batman@Watsci.uwaterloo.ca

I can't believe the news today, I can't close my eyes and make it go away!" -U2