[comp.sys.atari.st] resetting mouse position on screen

rosenkra@hall.cray.com (Bill Rosenkranz) (06/17/89)

a while back i had this question as well, called up atari, and got this
suggestion which works fine for my application. someone has asked me to
post it so here goes...

-bill
rosenkra@boston.cray.com


/*
 *	this is the code i use to reset the mouse position. the application
 *	involves sort of a "mouse drag window scroller" which works pretty
 *	well. the new position is set as soon as the mouse moves again,
 *	NOT (unfortunately) RIGHT NOW! this is ok for me but may not be for
 *	you. this is, however, 100% legal and does not rely on any version-
 *	specific code. there may be better ways of doing this but this is
 *	what atari suggested. i am not a wiz at assembler so the .s file
 *	could be optimized possibly. the regs d0 and d1 store the current
 *	mous position (before the normal AES/VDI handler gets them so you
 *	can stuff anything there you want.
 *
 *	there is an assembler file at the bottom. this works with alcyon
 *	4.14 but should be readily portable to other compilers... (int is
 *	16 bit)
 */

#define BEG_MCTRL		2
#define END_MCTRL		3

/*------------------------------*/
/*	track_it		*/
/*------------------------------*/
track_it ()
{

/*
 *	this is just a skeleton of my routine. what i do is wait for the
 *	x coord to exceed a certain value (move out of a box) then redraw
 *	the window and finally move the mouse to the other (left) side of
 *	the box. it works like sort of a "mouse scroll" 
 */

	extern		_NEW_MOT ();		/* our new handler */
	extern int	new_mouse_position ();
	extern int	wind_update ();
	extern int	vex_motv ();
	extern int	graf_mkstate ();

	extern long	_AES_MOT;		/* "normal" handler */
	extern int	vdi_handle_G;		/* device handle */

	long		dummy;
	int		but,
			key;
	int		mx,
			my,
			new_x,
			new_y;

	/*
	 *   capture mouse
	 */
	wind_update (BEG_MCTRL);


	/*
	 *   setup new motion vector
	 */
	vex_motv (vdi_handle_G, &_NEW_MOT, &_AES_MOT);
	new_mouse_position (-1, -1, -1);


	/*
	 *   track mouse. when button comes up, stop and use last mx, my
	 *   to calc new position
	 */
	while (graf_mkstate (&mx, &my, &but, &key), !(but & 0x0001))
	{
		/*
		 *   if some condition is met, reset the mouse position...
		 */
		if (!new_mouse_position (-1, -1, 0)
		&& some_condition_met (mx, my))
		{
			new_x = mx, new_y = my;
			calc_new_xy (&new_x, &new_y);	/* your routine... */
			new_mouse_position (new_x, new_y, 1);
		}
	}


	/*
	 *   reset normal AES/VDI mouse movement vector
	 */
	vex_motv (vdi_handle_G, _AES_MOT, &dummy);

	/*
	 *   release mouse to GEM
	 */
	wind_update (END_MCTRL);
}



/*------------------------------*/
/*	new_mouse_position	*/
/*------------------------------*/
new_mouse_position (newx, newy, opt)
int	newx,
	newy;
int	opt;
{

/*
 *	this works with the new mouse movement vector, _NEW_MOT. we set the
 *	globals here to the new (desired) mouse position and then flag the
 *	routine to reset (via _mot_flg). the new mouse vector reads these
 *	values and clears _mot_flg. if _mot_flg is 1, it resets the mouse
 *	coord to _mot_x,_mot_y before calling the VDI handler (which will
 *	redraw the cursor, if !hidden).
 *
 *	opt=1	do it			ret=1
 *	opt=0	inquire status		ret=_mot_flg
 *	opt=-1	reset _mot_flg to 0	ret=0
 *
 *	ret=-1 if error
 *
 *	note: the new mouse routine is called only after there is mouse
 *	movement, not continuously.
 */

	extern int	_mot_flg;	/* these are in the .s file */
	extern int	_mot_x;
	extern int	_mot_y;

	switch (opt)
	{
	case 1:				/* new coord */	
		if (newx >= 0 && newy >= 0)
		{
			_mot_x   = newx;
			_mot_y   = newy;
			_mot_flg = 1;	/* tell it to change on next ms move */
			return (1);
		}
		break;

	case 0:				/* inquire status */
		return ((_mot_flg == 1) ? 1 : 0);

	case -1:			/* reset */
		_mot_flg = 0;
		return (0);

	default:			/* error */
		break;
	}

	/*
	 *   error...
	 */
	return (-1);
}





* NAME
*	_NEW_MOT - new mouse motion detector handler (passes on to normal one)
*
* SYNOPSIS
*	extern		_NEW_MOT ();
*	extern int	_mot_flg;
*	extern int	_mot_x;
*	extern int	_mot_y;
*	extern long	_AES_MOT;
*	long		dummy;
*
*	vex_motv (handle, &_NEW_MOT, &_AES_MOT);	(set new handler)
*
*	(loop here looking for events, say evnt_multi())
*
*	_mot_x   = new_x;				(set new coord)
*	_mot_y   = new_y;
*	_mot_flg = 1;					(tell hndlr to change
*							 on next mouse move)
*	vex_motv (handle, _AES_MOT, &dummy);		(reset AES handler)
*
* DESCRIPTION
*	The routine looks for _mot_flg set. If it is, it moves the new
*	coords (_mot_x -> d0.w, _mot_y -> d1.w), unsets _mot_flg, then
*	jumps to the normal AES/VDI routine. If unset, it just jumps to
*	the normal routine (which redraws the mouse cursor).
*
*	the vex_motv () calls set/get pointers to the routines.
*
*	_AES_MOT contains the address of the AES interrupt routine
*	that deals with mouse motion. It is saved during the first vex_butv
*	and restored with the last
*
*	_mot_flg contains 1 if the program wants to change coordinates.
*	This routine then resets it to 0.
*


	.globl	__NEW_MOT
	.globl	__AES_MOT
	.globl	__mot_flg
	.globl	__mot_x
	.globl	__mot_y

	.text

__NEW_MOT:
	move.l	d2,-(a7)		* save reg (just in case)
	move.w	__mot_flg,d2		* test semaphore flag
	tst	d2
	beq	bypass			* if not set, bypass
	move.w	__mot_x,d0		* set new position
	move.w	__mot_y,d1
	clr.w	__mot_flg		* clear the flag
bypass:
	move.l	(a7)+,d2		* restore reg
	move.l	__AES_MOT,-(sp)
	rts				* jmp to AES subroutine

	.even
	.bss

__AES_MOT:	ds.l	1		* place to store normal AES routine
__mot_flg:	ds.w	1		* semaphore
__mot_x:	ds.w	1		* new coords
__mot_y:	ds.w	1

	.end

rosenkra@hall.cray.com (Bill Rosenkranz) (06/17/89)

oops... just notices a bug in the posting i just made. here is the correction:

	while (graf_mkstate (&mx, &my, &but, &key), !(but & 0x0001))

_SHOULD_ be:

	while (graf_mkstate (&mx, &my, &but, &key), (but & 0x0001))

or (the way i actually wrote it):

	while (1)
	{
		graf_mkstate (&mx, &my, &but, &key);
		if (!(but & 0x0001))
			break;


sorry...(so much for ignoring KISS, temporary insanity)

-bill