[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference 7.286::atarist

Title:Atari ST, TT, & Falcon
Notice:Please read note 1.0 and its replies before posting!
Moderator:FUNYET::ANDERSON
Created:Mon Apr 04 1988
Last Modified:Tue May 06 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:1433
Total number of notes:10312

978.0. "evnt_multi (and GEM in general) programming" by ROYALT::ORSHAW (Associate FTSG membership pending.....) Tue Oct 09 1990 14:12

    I figured I would start a new topic on evnt_multi (and GEM in general)
    programming. Feel free to move this elsewhere.
    
    I'm writing a program where I want to use both mouse buttons. If I get
    a click on the left button, I want to do one thing. If I get a click on
    the right button, I want to do another. I call evnt_multi with:
    event_mask  = mouse buttons (and nothing else)
    number_of_clicks = 2
    button_mask = button1 and button2
    button_state = down
    
    When I do this, I get events continuously. I haven't even touched the
    mouse or its buttons. I just get a continuous swarm of events. Is there
    some trick to this??
    
    When I set button mask to button1 (only) it seems to work ok. I only
    get events when I press a button. But if I hold the button down, I get
    a continuous stream of events. It's as if the button is repeating like a
    key on the keyboard. Is that proper behavior??
    
    -Jim
    
    
T.RTitleUserPersonal
Name
DateLines
978.1other event_multi problems...AISG::MISKINISTue Oct 09 1990 14:3610
    Great idea for a topic...  I (and a friend) had problems with mouse
    button 2.  It seems that if we put 3 (1|2) in "which button to look for"
    we only get through the event_multi when BOTH buttons are pressed at
    the same time.  Putting a 1 in worked fine, putting a 2 in did
    nothing...
    
    Calling all event_multi gurus...
    
    _John_
    
978.2Just a thought...MINDER::GILBERTSystems Design & Eng Cntr @ MCOTue Oct 09 1990 15:5910
    re .0:
    
    Do you any chance have a joystick connected, with 'autofire' mode switched
    on?
    
    The 'fire' pin on Port 1 is also connected to the righthand mouse button
    pin of Port 0  (don't ask me why!) - that would shower your ST with right
    mouse button presses!
    
    Rgds, Brian
978.3Autofire joysticks TMCUK2::CMITCHELLMon Oct 15 1990 12:354
	Those things are fatal... I once spent an hour taking my mouse to bits
to find the "fault" only to discover that the autofire on my joystick had been
knocked on in the excitement of playing a game...I have disabled the autofire
switch...
978.4movin' on....ROYALT::ORSHAWAssociate FTSG membership pending.....Tue Oct 16 1990 13:5710
    Well, I only have the mouse connected. My joystick is packed away
    somewhere. I thought it might be the mouse accelerator program I had in
    my /auto folder but I took it out and I still get the flurry of
    buttonpress events.
    
    I've dropped the idea of using the other button and moved on with my
    application. But if anyone could shed some light on the subject, I may
    go back and re-visit it.
    
    Jim
978.5Another glitchROYALT::ORSHAWAssociate FTSG membership pending.....Wed Oct 17 1990 15:1021
    I've got another question/problem. I'm using form_alert() to put up an
    alert box. The problem is that when I send in my text such as:
    
    "[1] [This is my message] [Ok]"
    
    I get a box with the following text:
    
    [This is my message
    
    and my Ok button looks like:
    
    [Ok
    
    Is this a known problem or am I doing something wrong?? I'm getting the
    feeling that these are bugs in TOS 1.0 and have been addressed already.
    
    Any suggestions?
    
    Jim
    
    
978.6No extra whitespace pleasePRNSYS::LOMICKAJJeffrey A. LomickaWed Oct 17 1990 16:283
You're doing something wrong.

Take out the spaces between "]" and "[".
978.7Finally, a reply to .0PRNSYS::LOMICKAJJeffrey A. LomickaWed Oct 17 1990 16:4434
>    I'm writing a program where I want to use both mouse buttons. If I get
>    a click on the left button, I want to do one thing. If I get a click on
>    the right button, I want to do another.

This is nearly impossible.  I asked this question of the Atari ROM
developers at WAACE, and they confirmed this.  What you are telling
event_multi is "tell me when the mouse state is this".

The "button" parameter is a mask of buttons you are interested in, and the
"state" parameter is the state you are waiting for.  Therefore, the
possible conditions you can wait for are:

Button	Mask	Meaning
1	0	Trigger when left is up, right is a don't care
2	0	Trigger when right is up, left is a don't care
3	0	Trigger when both buttons are up
1	1	Trigger when left is down, right is a don't care
3	1	Trigger when left is down and right is up
2	2	Trigger when right is down, left is a don't care
3	2	Trigger when right is down and left is up
3	3	Trigger when both are down

Note that there is no event for "trigger when left or right is down".  The
best you can do is toggle between "left is down, right is don't care" and
"left is up, right is a don't care", and then check the value of the right
button at the time of the event.  The result is that you have left-button
clicks, and left-button clicks that use the right button as a "shift-key",
if you know what I mean.

>    When I do this, I get events continuously.

You start with button=1, state=1.  When the event is triggered, you reset
state = (state ^ 1);, and this toggles between waiting for button down and
waiting for button up.
978.8Atari's solution to getting two buttonsPRNSYS::LOMICKAJJeffrey A. LomickaWed Oct 17 1990 16:51115
Atari has an official, but inadequete, solution to this problem.  The
following program is their solution.  The general idea is to break into
the mouse event generator at interrupt level, and convert all mouse
events into left button events, leaving the actual button state around
in a global.  Note that this has some problems, most notably with it's
interaction with desk accessories and programs that use the left button
as a shift key for the right button.  I don't recommend it unless you
absolutely must have it.

#include <gemdefs.h>	/* include file for definitions */
#include <osbind.h>	/* include file for xbios calls */

/* Useful definitions for this program */
#define RETURN 0x1C0D	/* Return key code */

/*	This program prints different text at the mouse position 	    */
/*	determined by which mouse button (or combination) is pressed. 	    */
/* 	Link the assembled new button handler at the end of link statement: */
/*									    */
/* 	apstart,FILE,vdibind,aesbind,osbind,BUTTON_HNDLR.		    */
/*									    */
/*	To exit press the RETURN key. 					    */

/* Global arrays */

int contrl[12], intin[256], ptsin[256], intout[256], ptsout[256];
int dummy;
extern int BUT_STATE;			/* True button state */
extern NEW_BUT();			/* New button handler */
long BUT_ADDR;				/* Old button handler */
unsigned key;

main()
{
int handle, i;
int charw, charh, boxw, boxh;
int mgbuf[8];
int xres,yres;
int abort;
unsigned int which=(MU_KEYBD|MU_BUTTON);
int selection;
int xyarray[4];
int clicks, button, buttonstate;
int mousex,mousey,width,depth;

	/* Set the system up to do GEM calls*/
appl_init();

	/* Get the handle of the desktop */
handle=graf_handle(&charw,&charh,&boxw,&boxh);

	/* Open the workstation. */
intin[0] = Getrez()+2;
for (i=1; i<10; ++i) intin[i] = 1;
intin[10] = 2;

v_opnvwk(intin, &handle, intout);

	/* Keep track of the size of the screen */
xres=intout[0];
yres=intout[1];
xyarray[1]=xyarray[0]=1;xyarray[2]=xres-1;xyarray[3]=yres-1;
vs_clip(handle,1,xyarray);

graf_mouse(ARROW,&dummy);	/* Reset mouse form to arrow */

vex_butv(handle,&NEW_BUT,&BUT_ADDR);  /* new button handler,old button handler */

clicks=1;
button=1;
buttonstate=1;

for (;;)
	{
	selection=evnt_multi(which,
			clicks,button,buttonstate,
			0,0,0,0,0,
			0,0,0,0,0,
			&mgbuf,
			0,0,
			&mousex,&mousey,
			&dummy,
			&dummy,
			&key,
			&dummy);

	abort=0;		/* reset flag */

	
	if (selection|MU_KEYBD)
		if (key == RETURN)
			abort=1;
	
	if (selection == MU_BUTTON)	/* display text for button states */

		{
		if (BUT_STATE == 1)
			v_gtext(handle,mousex,mousey,"    left");
		else if (BUT_STATE == 2)
			v_gtext(handle,mousex,mousey,"  right");
		else if (BUT_STATE == 3)
			v_gtext(handle,mousex,mousey,"both");
		}
	if (abort) break;

	}	/* for */
	
	/* Cleanup -  return to the system button handler */
vex_butv(handle,BUT_ADDR,&dummy);

v_clsvwk(handle);			/* Close the workstation. */
 
appl_exit();				/* Release GEM calls */

}
978.9My version of Atari's fix, with additional fixesPRNSYS::LOMICKAJJeffrey A. LomickaWed Oct 17 1990 16:56289
I expanded on Atari's solution - converting the single state variable
into a queue, and fixing up a few other things.  The following methond
is what is used in Whack.  I'm still not happy about the interaction it
has with desk accessories, or as a desk accessory, but it does work
better than Atari's solution.  Personally, I'm going to migrate toward
the left-button-is-shift approach for all future applications, and might
even change Whack.  Apparently I wrote this around July of 1988:

What follows is instructions for how to get reliable mouse events from
either mouse button using evnt_multi().  When used as directed, this code
can be used to detect and process both the down and the up transitions of
either mouse button, including double-click detection.  (Only one down and
one up transition is reported when the double-click is detected.)

Problems to be solved:
---------------------

	1. Although the GEM routine "evnt_multi()" accepts a parameter which
	is a bit mask of mouse buttons to wait for and another parameter
	for which state to expect, in actuality, GEM will not respond
	until all of the buttons in the button mask are in the state
	requested.  This means that you can wait for left button do go
	down, right button to go down, or for both buttons to go down, but
	you can't tell GEM to wait for either the left button or the right
	button to go down.  This is, of course, what you usually want to
	do.

	2. Because of the double click timer, sometimes mouse button
	state reported by evnt_multi is not as useful as you might like.
	For example, if you wait for button 1 to go down, and the user
	presses and releases the button in one quick motion, GEM will
	report a single mouse event with a button state of "0" (all
	buttons up) instead of one for the downstroke, and a second event
	for the upstroke.

The solution:
-------------

	The code that I give below addresses both of these problems.  The
	general idea is this:

	1. Splice a routine into the mouse event interrupt handler that
	queues up mouse events, and turns all mouse button events into
	transitions of the left button.

	2. Always tell evnt_multi to wait for events on the left button.

	3. When an event comes in, look in the queue to see what really
	happened.

Complications:
--------------

	There are, of course, some things that complicate this technique,
	and otherwise make it less than perfect:

	1. The queue will fill up with events from ALL uses of the mouse.
	You must filter out events that go to desk accessories, form
	processing, and menu bar handling, or other localized uses of the
	mouse outside of primary evnt_multi().  The code I show here works
	for the cases I have tried.

	2. Because GEM is now seeing only two states for the mouse, you
	will only get events detected on the following two conditions:

	- Transition from all buttons up to any button down.

	- Transition from any button down to all buttons up.

	The sequence left-down, right-down, left-up, right-up only
	generates two events, one for the left-down, and one for the
	right-up.  This is not a problem so long as the user is only
	required to press one mouse button at a time.

The code:

STMOUSE.S contains the routine that is used as the new mouse event
interrupt handler.  All that this routine does is call two more mouse
event handlers, whose addresses are stored in the global symbols
"first_mhandler" and "second_mhandler".  Because the default mouse handler 
You need to assemble this routine and include it when you link your program.
----------------------------------------------------------------------
/	stmouse.s, a handler that preserves A0 across the call, and calls
/	two mouse routines.
/
/	31-Dec-1987	Jeff Lomicka
/
/	mymouse( a0) calls two handlers with A0 one long parameter that is
/	both on the stack in ordinary C fashion, and in A0 as is required
/	by the default mouse handler.
/
	.globl	mymouse_
	.globl	first_mhandler_
	.globl	second_mhandler_
	.shri
mymouse_:			/ Replacement mouse handler
	move.l	a0, -(a7)	/ Save value for second handler
	move.l	a0, -(a7)	/ Pass to first handler
	movea.l	first_mhandler_, a1	/ Pick up second handler
	jsr	(a1)		/ Call first handler
	addq	$4,a7		/ Recover stack
	movea.l	(a7), a0	/ Recover A0
	movea.l	second_mhandler_, a1	/ Pick up second handler
	jsr	(a1)
	addq	$4,a7		/ Recover stack
	rts
----------------------------------------------------------------------
The event handling module for your program will need to make the following
declarations:
----------------------------------------------------------------------
#include <osbind.h>
#include <xbios.h>
extern mymouse();		/* .s file for calling two mouse handlers */
int (*first_mhandler)();	/* Address of first handler */
int (*second_mhandler)();	/* Address of second handler */
struct kbdvbase *kv;		/* Keyboard vector table */
static int msevntsiz = 0;	/* Events in private mouse event queue */
static unsigned short msevntq[16];/* State of mouse keys at event */
static int msevntin = 0;	/* Queue input ptr */
static int msevntout = 0;	/* Queue output ptr */
static int mousekeys1 = 0;	/* Last mouse key event */
static int nextbstate;		/* Expect button state of next event */
/*
	me_mh - Mouse interrupt Handler.  This handler is called,
	in addition to the regular mouse handler, in order
	to have access to some more information about the mouse events.

	What it does is:

	- Queue a copy of the mouse button state at the actual moment of
	the event, rather than after GEM is finished playing with timers.

	- Convert all right-mouse-button events into left-mouse-button
	events BEFORE GEM's mouse interrupt handler, so that GEM will generate
	a left-mouse-button event.

	Note that we do NOT attempt to check for overflow in the mouse
	event queue.  We will always want to look at the most recent
	events in the mouse event queue, so we allow new events to wrap
	around the circular queue, and overwrite older events which we
	aren't going to be interested in anyway.
*/
me_mh( a)
char *a;
    {
    register unsigned mousekeys;
    
    mousekeys = ("\0\002\001\003")[ a[ 0] & 3];
    if( mousekeys != 0) a[ 0] = 0xFA; /* Any key down means button 1 down */
    else a[ 0] = 0xf8;			/* Otherwise button 1 up */
/*
	We intentionally allow the value of msevntsiz to grow beyond 15,
	because the event handler only actually looks at the most recent
	four events or so.
*/
	if( mousekeys != mousekeys1)
	    { /* A button change is detected, insert it in the queue */
	    msevntq[ msevntin++] = mousekeys;
	    msevntin &= 15;
	    msevntsiz++;
	    mousekeys1 = mousekeys;
	    }
    }
----------------------------------------------------------------------
The following routine is used to throw away mouse events down to the
last "n" most recent.  Other (non-evnt_multi) parts of the program that
respond to changes in mouse state may wish/need to call this routine.
----------------------------------------------------------------------
int dtemptymse( n)
int n;
    {
    register int qsiz;

    qsiz = msevntsiz;
    while( qsiz > n)
    	{ /* Slurp up events until there are only two left */
	qsiz--; msevntsiz--;
	msevntout = (msevntout + 1) & 15;
	}
    return( qsiz);
    }
----------------------------------------------------------------------
At initialization time, you will need to execute the following code in
order to initialize the mouse event queue handler:
----------------------------------------------------------------------
/*
	Set up an interrupt handler for the mouse that performs both
	me_mh() and the default mouse handling.  The .s file "stmouse.s"
	contains some special code for this purpose.
*/
    first_mhandler = me_mh;
    kv = Kbdvbase();
    second_mhandler = kv->kb_mousevec;
    kv->kb_mousevec = mymouse;
    nextbstate = 0;	/* Assume first event is button-down */
----------------------------------------------------------------------
It is absolutely essential that you execute the following code before your
program exits, or your system will crash shortly after the program exits.
This restore's the previous interrupt handling routine for the mouse.
----------------------------------------------------------------------
    kv->kb_mousevec = second_mhandler;	/* Restore original handler */
----------------------------------------------------------------------
The following code shows what is required for waiting on the mouse button
events in an event multi, and filtering out the events that are not for
this program.  (Note that I have deleted some code that is not specific
to the processing of mouse events.)
----------------------------------------------------------------------
dtprocess()
    {
    register int ev_which;	/* Event kind delivered */
    int bstate;		/* Current state of the mouse buttons */
    int mx, my;		/* Last known mouse location */
    int shiftkeys;	/* Last known state of the shift keys */
    int mc, key;	/* Click count, key code */
    short msg[ 8];	/* Messages from GEM */

    for(;;)
	{
	ev_which = evnt_multi(
	MU_KEYBD | MU_BUTTON | MU_MESAG,
	    2, 	/* Maximum clicks to wait for */
	    1,	/* Button mask of interesting buttons */
	    nextbstate,/* Button states that generate events */
	    0, 0, 0, 0, 0,/* enter/exit, x, y, w, h for rectangle 1 */
	    0, 0, 0, 0, 0,/* enter/exit, x, y, w, h for rectangle 2 */
	    msg,	/* Buffer to receive mesasge */
		/* Low and high order miliseconds of counter */
	    0, 0,	/* Timeout interval */
	    &mx, &my,	/* Mouse location */
	    &bstate,	/* State of the mouse buttons */
	    &shiftkeys,	/* State of the shift keys */
	    &key,	/* Actual number of clicks */
	    &mc);	/* Key pressed */
	if( ev_which & MU_KEYBD) process_keystroke( shiftkeys, key);
	if( ev_which & MU_BUTTON)
	    {
	    register int qsiz;
/*
	Each detected event will have, at MOST, two actual mouse events
	associated with it.  All others are noise from menu bars, desk
	accessories, or random forms, so throw away everything but the
	last two.
*/
	    qsiz = dtemptymse( 2); /* Sample mouse queue length only once */
	    if( bstate)
	    	{ /* If event was a down event, do not process spurious up
	    		events, they are from some windowing system event. */
	    	if( msevntq[ msevntout] == 0 && qsiz > 0)
	    	    { /* Eat spurious up event */
		    qsiz--; msevntsiz--;
		    msevntout = (msevntout + 1) & 15;
		    }
		}
/*
	nextbstate is set to the next button transition we expect to detect
*/
	    nextbstate = (~bstate)&1;	/* process_mouse() should change
					the value of nextbstate if it uses
					the mouse for anything */
	    while( qsiz > 0)
		{ /* Process each queued event */
/*
	Adjust mouse event queue before processing user's action routine,
	which is allowed to wait for and read additional entries from the
	queue.  "bstate" is re-used here as a temporary register for
	storing the dequeued mouse event.
*/
		bstate = msevntq[ msevntout];
		msevntout = (msevntout + 1) & 15;
		msevntsiz--;
		qsiz--;
		process_mouse( mx, my, bstate, mc, shiftkeys);
/*
	If the process_mouse() routine has accessed the mouse queue, we
	must be sure that we do not overflow that actual number of events
	that are remaining in the queue.  To do this, we reassure ourselves
	that the queue still holds enough events for the the remaining
	events we have to process.
*/
		if( msevntsiz < qsiz) break; /* Appl has cleared queue */
		}
	    }
	if( ev_which & MU_MESAG) dtgem_message( msg);
	}
    }
----------------------------------------------------------------------
I hope this information is helpful to somebody.

			- Jeff
978.10right-button-is-shiftREGENT::LOMICKARoy LomickaThu Oct 18 1990 05:3815
re: "left-button-is-shift" 

I presume you mean "right-button-is-shift", so what we do is either press 
the left button only, or hold right button down while pressing the left 
button. 

Also, when designing the human interface using this scheme, you must
consider the case where the state of the right button changes while 
the left button is down, assuming that the "up" transition of the 
left button is going to trigger a significant action. 

The usual way of using mouse clicks is that the "down" transition is 
used to select something and the "up" transition is used to cause an 
action involving the selected object.  With the right button as a shift 
key, it is possible to modify the selection, modify the action, or both.
978.11Sometimes I think I have two left handsPRNSYS::LOMICKAJJeffrey A. LomickaThu Oct 18 1990 15:452
Of course - right button is shift.

978.12Glue the buttons togetherBAGELS::FELDMANJerry Feldman DTN 227-3279Thu Oct 18 1990 16:562
    Sometines I think that the Apple's single button mouse concept makes
    sense.