[comp.windows.x.motif] double clicks

carl@quad1.quad.com (Carl Priddy) (10/11/90)

Hey out there:
	I am having difficulty in coming up with a method of recognizing
	double clicks of mouse buttons. Currently, when I see one, I 
	then enter a timeout value (via select()) and use XCheckIfEvent()
	to see if the button of interest was pressed. This works, sometimes.
	I am very interested in how anyone else has accomplished this.

Thanks a heap,
carl.

kieron@root.co.uk (Kieron Drake) (10/11/90)

In <15395@gouda.quad.com> carl@quad1.quad.com (Carl Priddy) writes:

>Hey out there:
>	I am having difficulty in coming up with a method of recognizing
>	double clicks of mouse buttons. Currently, when I see one, I 
>	then enter a timeout value (via select()) and use XCheckIfEvent()
>	to see if the button of interest was pressed. This works, sometimes.
>	I am very interested in how anyone else has accomplished this.

>Thanks a heap,
>carl.

The normal Xt intrinsics provide an easy way to handle this via a
count field in translation table entries. You can always do your
own timing and stuff if you wish but why bother to reinvent the wheel?

DIGRESSION: In fact the X protocol makes it impossible to reliably
handle double clicks with arbitrary time envelopes. Basically the
problem is that events which are "close" in server time (and are
reliably time-stamped as such) may arrive at the client with arbitrary
temporal separation (but in order) due to the various latencies of
the intervening layers. One cannot, without an extension, make the server
recognise such sequences and return a special event for them, or a
ClientMessage event, or somesuch. Of course, in real life, the delays
that are likely are sufficiently small that waiting for a "suitable time"
for an event with a timestamp in the required range is OK. Some may be
missed, of course, but most dialogues use double-clicks to indicate
operations that are "more powerful" than those for single-clicks so
the late-arrivals can be dealt with. This does restrict the styles of
interaction available though, so that one could not have have single-click
meaning delete and double-click meaning execute, say, as a belatedly
recognised execute would find the object deleted already. This may or
may not be a good thing but it is worth recognising the restriction
even if it isn't onerous. END DIGRESSION

Meanwhile, back at the ranch.........in translation tables.....
The optional count field follows an event type and is enclosed in
parentheses. So double-click on Button 1 up would be:


	<Btn1Up>(2): something()\n

which is equivalent to:

	<Btn1Down>,<Btn1Up>,<Btn1Down>,<Btn1Up>: something()\n

with appropriate timers (default 200mS) retriggered by each event
if things are fast enough or expiring, and not matching, if too slow.
The timers can be set from resources or with XtSetMultiClickTime with
the values being integers and the default being 200, in units of mS.
Thus one could have:

	Xbozo.MultiClickTime:	619
	*multiClickTime:	450

as lines in a resource file, or use the following code:

	XtSetMultiClickTime( XtDisplay(toplevel), 619);

in xbozo.c, say. The names are important :-)
XtSetMultiClickTime is defined as:

	void XtSetMultiClickTime( dpy, time )
	    Display *dpy;
	    int time;

Once can specify "n or more" events to match, if they all have a
maximum separation within the multi-click-time bound, by following
the count with a plus ('+'), e.g.:

	<Btn1Up>(2+): clicketyclick()\n

in a translation entry means match two or more button 1 realeases,
each separated by no more than multi-click-time.

One final caveat: (a) motion events can occur between repeated
events and a match will still occur and, also, (b) sequences that match
two specifications will only be taken once if one specification is a
non-initial subset of the other and the matching events have occurred
in the context of the longer one. This means that:

	<Key>A,<Key>B:	ab()\n\
	<Key>B:		b()

works as expected, action b is only taken if a B-Key press is not immediately
preceeded by an A-Key press. If one had replaced "<Key>A" by "<Btn1Down>"
and "<Key>B" by "<Btn1Up>" then the equivalent would occur: b would only
be called if the button release is not immediately preceeded by a press.
This means, in the context of repeated button or key events, that motion
events will always be matched as a subset of them, between the button or key
events, so one cannot then have a separate translation for the pointer motion
events and expect a match. Pointer motion and double-clicks don't mix in
the same translation table.

Hope this helps.

	kieron


-- 
	Kieron Drake
MAIL:	kieron@root.co.uk
SNAIL:	UniSoft Ltd, Saunderson House, Hayne Street, London EC1A 9HH
PHONE:	+44 71 315 6637 (direct) +44 71 315 6600 (switchboard)