xref: /plan9-contrib/sys/src/9k/port/devmouse.c (revision 45e6af3b6d7025ef7184352bb3f6852edd8de07e)
1*45e6af3bSDavid du Colombier #include	"u.h"
2*45e6af3bSDavid du Colombier #include	"../port/lib.h"
3*45e6af3bSDavid du Colombier #include	"mem.h"
4*45e6af3bSDavid du Colombier #include	"dat.h"
5*45e6af3bSDavid du Colombier #include	"fns.h"
6*45e6af3bSDavid du Colombier #include	"../port/error.h"
7*45e6af3bSDavid du Colombier 
8*45e6af3bSDavid du Colombier #define	Image	IMAGE
9*45e6af3bSDavid du Colombier #include	<draw.h>
10*45e6af3bSDavid du Colombier #include	<memdraw.h>
11*45e6af3bSDavid du Colombier #include	<cursor.h>
12*45e6af3bSDavid du Colombier #include	"screen.h"
13*45e6af3bSDavid du Colombier 
14*45e6af3bSDavid du Colombier enum {
15*45e6af3bSDavid du Colombier 	ScrollUp = 0x08,
16*45e6af3bSDavid du Colombier 	ScrollDown = 0x10,
17*45e6af3bSDavid du Colombier 	ScrollLeft = 0x20,
18*45e6af3bSDavid du Colombier 	ScrollRight = 0x40,
19*45e6af3bSDavid du Colombier };
20*45e6af3bSDavid du Colombier 
21*45e6af3bSDavid du Colombier typedef struct Mouseinfo	Mouseinfo;
22*45e6af3bSDavid du Colombier typedef struct Mousestate	Mousestate;
23*45e6af3bSDavid du Colombier 
24*45e6af3bSDavid du Colombier struct Mousestate
25*45e6af3bSDavid du Colombier {
26*45e6af3bSDavid du Colombier 	Point	xy;		/* mouse.xy */
27*45e6af3bSDavid du Colombier 	int	buttons;	/* mouse.buttons */
28*45e6af3bSDavid du Colombier 	ulong	counter;	/* increments every update */
29*45e6af3bSDavid du Colombier 	ulong	msec;		/* time of last event */
30*45e6af3bSDavid du Colombier };
31*45e6af3bSDavid du Colombier 
32*45e6af3bSDavid du Colombier struct Mouseinfo
33*45e6af3bSDavid du Colombier {
34*45e6af3bSDavid du Colombier 	Lock;
35*45e6af3bSDavid du Colombier 	Mousestate;
36*45e6af3bSDavid du Colombier 	int	dx;
37*45e6af3bSDavid du Colombier 	int	dy;
38*45e6af3bSDavid du Colombier 	int	track;		/* dx & dy updated */
39*45e6af3bSDavid du Colombier 	int	redraw;		/* update cursor on screen */
40*45e6af3bSDavid du Colombier 	ulong	lastcounter;	/* value when /dev/mouse read */
41*45e6af3bSDavid du Colombier 	ulong	lastresize;
42*45e6af3bSDavid du Colombier 	ulong	resize;
43*45e6af3bSDavid du Colombier 	Rendez	r;
44*45e6af3bSDavid du Colombier 	Ref;
45*45e6af3bSDavid du Colombier 	QLock;
46*45e6af3bSDavid du Colombier 	int	open;
47*45e6af3bSDavid du Colombier 	int	acceleration;
48*45e6af3bSDavid du Colombier 	int	maxacc;
49*45e6af3bSDavid du Colombier 	Mousestate	queue[16];	/* circular buffer of click events */
50*45e6af3bSDavid du Colombier 	int	ri;		/* read index into queue */
51*45e6af3bSDavid du Colombier 	int	wi;		/* write index into queue */
52*45e6af3bSDavid du Colombier 	uchar	qfull;		/* queue is full */
53*45e6af3bSDavid du Colombier };
54*45e6af3bSDavid du Colombier 
55*45e6af3bSDavid du Colombier enum
56*45e6af3bSDavid du Colombier {
57*45e6af3bSDavid du Colombier 	CMbuttonmap,
58*45e6af3bSDavid du Colombier 	CMscrollswap,
59*45e6af3bSDavid du Colombier 	CMswap,
60*45e6af3bSDavid du Colombier 	CMwildcard,
61*45e6af3bSDavid du Colombier };
62*45e6af3bSDavid du Colombier 
63*45e6af3bSDavid du Colombier static Cmdtab mousectlmsg[] =
64*45e6af3bSDavid du Colombier {
65*45e6af3bSDavid du Colombier 	CMbuttonmap,	"buttonmap",	0,
66*45e6af3bSDavid du Colombier 	CMscrollswap,	"scrollswap",	0,
67*45e6af3bSDavid du Colombier 	CMswap,		"swap",		1,
68*45e6af3bSDavid du Colombier 	CMwildcard,	"*",		0,
69*45e6af3bSDavid du Colombier };
70*45e6af3bSDavid du Colombier 
71*45e6af3bSDavid du Colombier Mouseinfo	mouse;
72*45e6af3bSDavid du Colombier Cursorinfo	cursor;
73*45e6af3bSDavid du Colombier int		mouseshifted;
74*45e6af3bSDavid du Colombier int		kbdbuttons;
75*45e6af3bSDavid du Colombier void		(*kbdmouse)(int);
76*45e6af3bSDavid du Colombier Cursor		curs;
77*45e6af3bSDavid du Colombier 
78*45e6af3bSDavid du Colombier void	Cursortocursor(Cursor*);
79*45e6af3bSDavid du Colombier int	mousechanged(void*);
80*45e6af3bSDavid du Colombier 
81*45e6af3bSDavid du Colombier static void mouseclock(void);
82*45e6af3bSDavid du Colombier 
83*45e6af3bSDavid du Colombier enum{
84*45e6af3bSDavid du Colombier 	Qdir,
85*45e6af3bSDavid du Colombier 	Qcursor,
86*45e6af3bSDavid du Colombier 	Qmouse,
87*45e6af3bSDavid du Colombier 	Qmousein,
88*45e6af3bSDavid du Colombier 	Qmousectl,
89*45e6af3bSDavid du Colombier };
90*45e6af3bSDavid du Colombier 
91*45e6af3bSDavid du Colombier static Dirtab mousedir[]={
92*45e6af3bSDavid du Colombier 	".",	{Qdir, 0, QTDIR},	0,			DMDIR|0555,
93*45e6af3bSDavid du Colombier 	"cursor",	{Qcursor},	0,			0666,
94*45e6af3bSDavid du Colombier 	"mouse",	{Qmouse},	0,			0666,
95*45e6af3bSDavid du Colombier 	"mousein",	{Qmousein},	0,			0220,
96*45e6af3bSDavid du Colombier 	"mousectl",	{Qmousectl},	0,			0220,
97*45e6af3bSDavid du Colombier };
98*45e6af3bSDavid du Colombier 
99*45e6af3bSDavid du Colombier static uchar buttonmap[8] = {
100*45e6af3bSDavid du Colombier 	0, 1, 2, 3, 4, 5, 6, 7,
101*45e6af3bSDavid du Colombier };
102*45e6af3bSDavid du Colombier static int mouseswap;
103*45e6af3bSDavid du Colombier static int scrollswap;
104*45e6af3bSDavid du Colombier static ulong mousetime;
105*45e6af3bSDavid du Colombier 
106*45e6af3bSDavid du Colombier extern Memimage* gscreen;
107*45e6af3bSDavid du Colombier extern ulong kerndate;
108*45e6af3bSDavid du Colombier 
109*45e6af3bSDavid du Colombier static void
mousereset(void)110*45e6af3bSDavid du Colombier mousereset(void)
111*45e6af3bSDavid du Colombier {
112*45e6af3bSDavid du Colombier 	curs = arrow;
113*45e6af3bSDavid du Colombier 	Cursortocursor(&arrow);
114*45e6af3bSDavid du Colombier 	/* redraw cursor about 30 times per second */
115*45e6af3bSDavid du Colombier 	addclock0link(mouseclock, 33);
116*45e6af3bSDavid du Colombier }
117*45e6af3bSDavid du Colombier 
118*45e6af3bSDavid du Colombier static void
mousefromkbd(int buttons)119*45e6af3bSDavid du Colombier mousefromkbd(int buttons)
120*45e6af3bSDavid du Colombier {
121*45e6af3bSDavid du Colombier 	kbdbuttons = buttons;
122*45e6af3bSDavid du Colombier 	mousetrack(0, 0, 0, TK2MS(sys->ticks));
123*45e6af3bSDavid du Colombier }
124*45e6af3bSDavid du Colombier 
125*45e6af3bSDavid du Colombier static int
mousedevgen(Chan * c,char * name,Dirtab * tab,int ntab,int i,Dir * dp)126*45e6af3bSDavid du Colombier mousedevgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
127*45e6af3bSDavid du Colombier {
128*45e6af3bSDavid du Colombier 	int rc;
129*45e6af3bSDavid du Colombier 
130*45e6af3bSDavid du Colombier 	rc = devgen(c, name, tab, ntab, i, dp);
131*45e6af3bSDavid du Colombier 	if(rc != -1)
132*45e6af3bSDavid du Colombier 		dp->atime = mousetime;
133*45e6af3bSDavid du Colombier 	return rc;
134*45e6af3bSDavid du Colombier }
135*45e6af3bSDavid du Colombier 
136*45e6af3bSDavid du Colombier static void
mouseinit(void)137*45e6af3bSDavid du Colombier mouseinit(void)
138*45e6af3bSDavid du Colombier {
139*45e6af3bSDavid du Colombier 	curs = arrow;
140*45e6af3bSDavid du Colombier 	Cursortocursor(&arrow);
141*45e6af3bSDavid du Colombier 	cursoron(1);
142*45e6af3bSDavid du Colombier 	kbdmouse = mousefromkbd;
143*45e6af3bSDavid du Colombier 	mousetime = seconds();
144*45e6af3bSDavid du Colombier }
145*45e6af3bSDavid du Colombier 
146*45e6af3bSDavid du Colombier static Chan*
mouseattach(char * spec)147*45e6af3bSDavid du Colombier mouseattach(char *spec)
148*45e6af3bSDavid du Colombier {
149*45e6af3bSDavid du Colombier 	return devattach('m', spec);
150*45e6af3bSDavid du Colombier }
151*45e6af3bSDavid du Colombier 
152*45e6af3bSDavid du Colombier static Walkqid*
mousewalk(Chan * c,Chan * nc,char ** name,int nname)153*45e6af3bSDavid du Colombier mousewalk(Chan *c, Chan *nc, char **name, int nname)
154*45e6af3bSDavid du Colombier {
155*45e6af3bSDavid du Colombier 	Walkqid *wq;
156*45e6af3bSDavid du Colombier 
157*45e6af3bSDavid du Colombier 	/*
158*45e6af3bSDavid du Colombier 	 * We use devgen() and not mousedevgen() here
159*45e6af3bSDavid du Colombier 	 * see "Ugly problem" in dev.c/devwalk()
160*45e6af3bSDavid du Colombier 	 */
161*45e6af3bSDavid du Colombier 	wq = devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
162*45e6af3bSDavid du Colombier 	if(wq != nil && wq->clone != c && wq->clone != nil && (wq->clone->qid.type&QTDIR)==0)
163*45e6af3bSDavid du Colombier 		incref(&mouse);
164*45e6af3bSDavid du Colombier 	return wq;
165*45e6af3bSDavid du Colombier }
166*45e6af3bSDavid du Colombier 
167*45e6af3bSDavid du Colombier long int
mousestat(Chan * c,uchar * db,long n)168*45e6af3bSDavid du Colombier mousestat(Chan *c, uchar *db, long n)
169*45e6af3bSDavid du Colombier {
170*45e6af3bSDavid du Colombier 	return devstat(c, db, n, mousedir, nelem(mousedir), mousedevgen);
171*45e6af3bSDavid du Colombier }
172*45e6af3bSDavid du Colombier 
173*45e6af3bSDavid du Colombier static Chan*
mouseopen(Chan * c,int omode)174*45e6af3bSDavid du Colombier mouseopen(Chan *c, int omode)
175*45e6af3bSDavid du Colombier {
176*45e6af3bSDavid du Colombier 	switch((ulong)c->qid.path){
177*45e6af3bSDavid du Colombier 	case Qdir:
178*45e6af3bSDavid du Colombier 		if(omode != OREAD)
179*45e6af3bSDavid du Colombier 			error(Eperm);
180*45e6af3bSDavid du Colombier 		break;
181*45e6af3bSDavid du Colombier 	case Qmouse:
182*45e6af3bSDavid du Colombier 		lock(&mouse);
183*45e6af3bSDavid du Colombier 		if(mouse.open){
184*45e6af3bSDavid du Colombier 			unlock(&mouse);
185*45e6af3bSDavid du Colombier 			error(Einuse);
186*45e6af3bSDavid du Colombier 		}
187*45e6af3bSDavid du Colombier 		mouse.open = 1;
188*45e6af3bSDavid du Colombier 		mouse.ref++;
189*45e6af3bSDavid du Colombier 		mouse.lastresize = mouse.resize;
190*45e6af3bSDavid du Colombier 		unlock(&mouse);
191*45e6af3bSDavid du Colombier 		break;
192*45e6af3bSDavid du Colombier 	case Qmousein:
193*45e6af3bSDavid du Colombier 		if(!iseve())
194*45e6af3bSDavid du Colombier 			error(Eperm);
195*45e6af3bSDavid du Colombier 		break;
196*45e6af3bSDavid du Colombier 	default:
197*45e6af3bSDavid du Colombier 		incref(&mouse);
198*45e6af3bSDavid du Colombier 	}
199*45e6af3bSDavid du Colombier 	c->mode = openmode(omode);
200*45e6af3bSDavid du Colombier 	c->flag |= COPEN;
201*45e6af3bSDavid du Colombier 	c->offset = 0;
202*45e6af3bSDavid du Colombier 	return c;
203*45e6af3bSDavid du Colombier }
204*45e6af3bSDavid du Colombier 
205*45e6af3bSDavid du Colombier static void
mousecreate(Chan *,char *,int,int)206*45e6af3bSDavid du Colombier mousecreate(Chan*, char*, int, int)
207*45e6af3bSDavid du Colombier {
208*45e6af3bSDavid du Colombier 	error(Eperm);
209*45e6af3bSDavid du Colombier }
210*45e6af3bSDavid du Colombier 
211*45e6af3bSDavid du Colombier static void
mouseclose(Chan * c)212*45e6af3bSDavid du Colombier mouseclose(Chan *c)
213*45e6af3bSDavid du Colombier {
214*45e6af3bSDavid du Colombier 	if((c->qid.type&QTDIR)==0 && (c->flag&COPEN)){
215*45e6af3bSDavid du Colombier 		if(c->qid.path == Qmousein)
216*45e6af3bSDavid du Colombier 			return;
217*45e6af3bSDavid du Colombier 		lock(&mouse);
218*45e6af3bSDavid du Colombier 		if(c->qid.path == Qmouse)
219*45e6af3bSDavid du Colombier 			mouse.open = 0;
220*45e6af3bSDavid du Colombier 		if(--mouse.ref == 0){
221*45e6af3bSDavid du Colombier 			cursoroff(1);
222*45e6af3bSDavid du Colombier 			curs = arrow;
223*45e6af3bSDavid du Colombier 			Cursortocursor(&arrow);
224*45e6af3bSDavid du Colombier 			cursoron(1);
225*45e6af3bSDavid du Colombier 		}
226*45e6af3bSDavid du Colombier 		unlock(&mouse);
227*45e6af3bSDavid du Colombier 	}
228*45e6af3bSDavid du Colombier }
229*45e6af3bSDavid du Colombier 
230*45e6af3bSDavid du Colombier 
231*45e6af3bSDavid du Colombier static long
mouseread(Chan * c,void * va,long n,vlong off)232*45e6af3bSDavid du Colombier mouseread(Chan *c, void *va, long n, vlong off)
233*45e6af3bSDavid du Colombier {
234*45e6af3bSDavid du Colombier 	char buf[1+4*12+1];
235*45e6af3bSDavid du Colombier 	uchar *p;
236*45e6af3bSDavid du Colombier 	ulong offset = off;
237*45e6af3bSDavid du Colombier 	Mousestate m;
238*45e6af3bSDavid du Colombier 	int b;
239*45e6af3bSDavid du Colombier 
240*45e6af3bSDavid du Colombier 	p = va;
241*45e6af3bSDavid du Colombier 	switch((ulong)c->qid.path){
242*45e6af3bSDavid du Colombier 	case Qdir:
243*45e6af3bSDavid du Colombier 		return devdirread(c, va, n, mousedir, nelem(mousedir), mousedevgen);
244*45e6af3bSDavid du Colombier 
245*45e6af3bSDavid du Colombier 	case Qcursor:
246*45e6af3bSDavid du Colombier 		if(offset != 0)
247*45e6af3bSDavid du Colombier 			return 0;
248*45e6af3bSDavid du Colombier 		if(n < 2*4+2*2*16)
249*45e6af3bSDavid du Colombier 			error(Eshort);
250*45e6af3bSDavid du Colombier 		n = 2*4+2*2*16;
251*45e6af3bSDavid du Colombier 		lock(&cursor);
252*45e6af3bSDavid du Colombier 		BPLONG(p+0, curs.offset.x);
253*45e6af3bSDavid du Colombier 		BPLONG(p+4, curs.offset.y);
254*45e6af3bSDavid du Colombier 		memmove(p+8, curs.clr, 2*16);
255*45e6af3bSDavid du Colombier 		memmove(p+40, curs.set, 2*16);
256*45e6af3bSDavid du Colombier 		unlock(&cursor);
257*45e6af3bSDavid du Colombier 		return n;
258*45e6af3bSDavid du Colombier 
259*45e6af3bSDavid du Colombier 	case Qmouse:
260*45e6af3bSDavid du Colombier 		while(mousechanged(0) == 0)
261*45e6af3bSDavid du Colombier 			sleep(&mouse.r, mousechanged, 0);
262*45e6af3bSDavid du Colombier 
263*45e6af3bSDavid du Colombier 		mouse.qfull = 0;
264*45e6af3bSDavid du Colombier 		mousetime = seconds();
265*45e6af3bSDavid du Colombier 
266*45e6af3bSDavid du Colombier 		/*
267*45e6af3bSDavid du Colombier 		 * No lock of the indices is necessary here, because ri is only
268*45e6af3bSDavid du Colombier 		 * updated by us, and there is only one mouse reader
269*45e6af3bSDavid du Colombier 		 * at a time.  I suppose that more than one process
270*45e6af3bSDavid du Colombier 		 * could try to read the fd at one time, but such behavior
271*45e6af3bSDavid du Colombier 		 * is degenerate and already violates the calling
272*45e6af3bSDavid du Colombier 		 * conventions for sleep above.
273*45e6af3bSDavid du Colombier 		 */
274*45e6af3bSDavid du Colombier 		if(mouse.ri != mouse.wi) {
275*45e6af3bSDavid du Colombier 			m = mouse.queue[mouse.ri];
276*45e6af3bSDavid du Colombier 			if(++mouse.ri == nelem(mouse.queue))
277*45e6af3bSDavid du Colombier 				mouse.ri = 0;
278*45e6af3bSDavid du Colombier 		} else {
279*45e6af3bSDavid du Colombier 			while(!canlock(&cursor))
280*45e6af3bSDavid du Colombier 				tsleep(&up->sleep, return0, 0, TK2MS(1));
281*45e6af3bSDavid du Colombier 
282*45e6af3bSDavid du Colombier 			m = mouse.Mousestate;
283*45e6af3bSDavid du Colombier 			unlock(&cursor);
284*45e6af3bSDavid du Colombier 		}
285*45e6af3bSDavid du Colombier 
286*45e6af3bSDavid du Colombier 		b = buttonmap[m.buttons&7];
287*45e6af3bSDavid du Colombier 		/* put buttons 4 and 5 back in */
288*45e6af3bSDavid du Colombier 		b |= m.buttons & (3<<3);
289*45e6af3bSDavid du Colombier 		if (scrollswap)
290*45e6af3bSDavid du Colombier 			if (b == 8)
291*45e6af3bSDavid du Colombier 				b = 16;
292*45e6af3bSDavid du Colombier 			else if (b == 16)
293*45e6af3bSDavid du Colombier 				b = 8;
294*45e6af3bSDavid du Colombier 		snprint(buf, sizeof buf, "m%11d %11d %11d %11lud ",
295*45e6af3bSDavid du Colombier 			m.xy.x, m.xy.y,
296*45e6af3bSDavid du Colombier 			b,
297*45e6af3bSDavid du Colombier 			m.msec);
298*45e6af3bSDavid du Colombier 		mouse.lastcounter = m.counter;
299*45e6af3bSDavid du Colombier 		if(n > 1+4*12)
300*45e6af3bSDavid du Colombier 			n = 1+4*12;
301*45e6af3bSDavid du Colombier 		if(mouse.lastresize != mouse.resize){
302*45e6af3bSDavid du Colombier 			mouse.lastresize = mouse.resize;
303*45e6af3bSDavid du Colombier 			buf[0] = 'r';
304*45e6af3bSDavid du Colombier 		}
305*45e6af3bSDavid du Colombier 		memmove(va, buf, n);
306*45e6af3bSDavid du Colombier 		return n;
307*45e6af3bSDavid du Colombier 	}
308*45e6af3bSDavid du Colombier 	return 0;
309*45e6af3bSDavid du Colombier }
310*45e6af3bSDavid du Colombier 
311*45e6af3bSDavid du Colombier static void
setbuttonmap(char * map)312*45e6af3bSDavid du Colombier setbuttonmap(char* map)
313*45e6af3bSDavid du Colombier {
314*45e6af3bSDavid du Colombier 	int i, x, one, two, three;
315*45e6af3bSDavid du Colombier 
316*45e6af3bSDavid du Colombier 	one = two = three = 0;
317*45e6af3bSDavid du Colombier 	for(i = 0; i < 3; i++){
318*45e6af3bSDavid du Colombier 		if(map[i] == 0)
319*45e6af3bSDavid du Colombier 			error(Ebadarg);
320*45e6af3bSDavid du Colombier 		if(map[i] == '1'){
321*45e6af3bSDavid du Colombier 			if(one)
322*45e6af3bSDavid du Colombier 				error(Ebadarg);
323*45e6af3bSDavid du Colombier 			one = 1<<i;
324*45e6af3bSDavid du Colombier 		}
325*45e6af3bSDavid du Colombier 		else if(map[i] == '2'){
326*45e6af3bSDavid du Colombier 			if(two)
327*45e6af3bSDavid du Colombier 				error(Ebadarg);
328*45e6af3bSDavid du Colombier 			two = 1<<i;
329*45e6af3bSDavid du Colombier 		}
330*45e6af3bSDavid du Colombier 		else if(map[i] == '3'){
331*45e6af3bSDavid du Colombier 			if(three)
332*45e6af3bSDavid du Colombier 				error(Ebadarg);
333*45e6af3bSDavid du Colombier 			three = 1<<i;
334*45e6af3bSDavid du Colombier 		}
335*45e6af3bSDavid du Colombier 		else
336*45e6af3bSDavid du Colombier 			error(Ebadarg);
337*45e6af3bSDavid du Colombier 	}
338*45e6af3bSDavid du Colombier 	if(map[i])
339*45e6af3bSDavid du Colombier 		error(Ebadarg);
340*45e6af3bSDavid du Colombier 
341*45e6af3bSDavid du Colombier 	memset(buttonmap, 0, 8);
342*45e6af3bSDavid du Colombier 	for(i = 0; i < 8; i++){
343*45e6af3bSDavid du Colombier 		x = 0;
344*45e6af3bSDavid du Colombier 		if(i & 1)
345*45e6af3bSDavid du Colombier 			x |= one;
346*45e6af3bSDavid du Colombier 		if(i & 2)
347*45e6af3bSDavid du Colombier 			x |= two;
348*45e6af3bSDavid du Colombier 		if(i & 4)
349*45e6af3bSDavid du Colombier 			x |= three;
350*45e6af3bSDavid du Colombier 		buttonmap[x] = i;
351*45e6af3bSDavid du Colombier 	}
352*45e6af3bSDavid du Colombier }
353*45e6af3bSDavid du Colombier 
354*45e6af3bSDavid du Colombier static long
mousewrite(Chan * c,void * va,long n,vlong)355*45e6af3bSDavid du Colombier mousewrite(Chan *c, void *va, long n, vlong)
356*45e6af3bSDavid du Colombier {
357*45e6af3bSDavid du Colombier 	char *p;
358*45e6af3bSDavid du Colombier 	Point pt;
359*45e6af3bSDavid du Colombier 	Cmdbuf *cb;
360*45e6af3bSDavid du Colombier 	Cmdtab *ct;
361*45e6af3bSDavid du Colombier 	char buf[64];
362*45e6af3bSDavid du Colombier 	int b, msec;
363*45e6af3bSDavid du Colombier 
364*45e6af3bSDavid du Colombier 	p = va;
365*45e6af3bSDavid du Colombier 	switch((ulong)c->qid.path){
366*45e6af3bSDavid du Colombier 	case Qdir:
367*45e6af3bSDavid du Colombier 		error(Eisdir);
368*45e6af3bSDavid du Colombier 
369*45e6af3bSDavid du Colombier 	case Qcursor:
370*45e6af3bSDavid du Colombier 		cursoroff(1);
371*45e6af3bSDavid du Colombier 		if(n < 2*4+2*2*16){
372*45e6af3bSDavid du Colombier 			curs = arrow;
373*45e6af3bSDavid du Colombier 			Cursortocursor(&arrow);
374*45e6af3bSDavid du Colombier 		}else{
375*45e6af3bSDavid du Colombier 			n = 2*4+2*2*16;
376*45e6af3bSDavid du Colombier 			curs.offset.x = BGLONG(p+0);
377*45e6af3bSDavid du Colombier 			curs.offset.y = BGLONG(p+4);
378*45e6af3bSDavid du Colombier 			memmove(curs.clr, p+8, 2*16);
379*45e6af3bSDavid du Colombier 			memmove(curs.set, p+40, 2*16);
380*45e6af3bSDavid du Colombier 			Cursortocursor(&curs);
381*45e6af3bSDavid du Colombier 		}
382*45e6af3bSDavid du Colombier 		qlock(&mouse);
383*45e6af3bSDavid du Colombier 		mouse.redraw = 1;
384*45e6af3bSDavid du Colombier 		mouseclock();
385*45e6af3bSDavid du Colombier 		qunlock(&mouse);
386*45e6af3bSDavid du Colombier 		cursoron(1);
387*45e6af3bSDavid du Colombier 		return n;
388*45e6af3bSDavid du Colombier 
389*45e6af3bSDavid du Colombier 	case Qmousectl:
390*45e6af3bSDavid du Colombier 		cb = parsecmd(va, n);
391*45e6af3bSDavid du Colombier 		if(waserror()){
392*45e6af3bSDavid du Colombier 			free(cb);
393*45e6af3bSDavid du Colombier 			nexterror();
394*45e6af3bSDavid du Colombier 		}
395*45e6af3bSDavid du Colombier 
396*45e6af3bSDavid du Colombier 		ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
397*45e6af3bSDavid du Colombier 
398*45e6af3bSDavid du Colombier 		switch(ct->index){
399*45e6af3bSDavid du Colombier 		case CMswap:
400*45e6af3bSDavid du Colombier 			if(mouseswap)
401*45e6af3bSDavid du Colombier 				setbuttonmap("123");
402*45e6af3bSDavid du Colombier 			else
403*45e6af3bSDavid du Colombier 				setbuttonmap("321");
404*45e6af3bSDavid du Colombier 			mouseswap ^= 1;
405*45e6af3bSDavid du Colombier 			break;
406*45e6af3bSDavid du Colombier 
407*45e6af3bSDavid du Colombier 		case CMscrollswap:
408*45e6af3bSDavid du Colombier 			scrollswap ^= 1;
409*45e6af3bSDavid du Colombier 			break;
410*45e6af3bSDavid du Colombier 
411*45e6af3bSDavid du Colombier 		case CMbuttonmap:
412*45e6af3bSDavid du Colombier 			if(cb->nf == 1)
413*45e6af3bSDavid du Colombier 				setbuttonmap("123");
414*45e6af3bSDavid du Colombier 			else
415*45e6af3bSDavid du Colombier 				setbuttonmap(cb->f[1]);
416*45e6af3bSDavid du Colombier 			break;
417*45e6af3bSDavid du Colombier 
418*45e6af3bSDavid du Colombier 		case CMwildcard:
419*45e6af3bSDavid du Colombier 			mousectl(cb);
420*45e6af3bSDavid du Colombier 			break;
421*45e6af3bSDavid du Colombier 		}
422*45e6af3bSDavid du Colombier 
423*45e6af3bSDavid du Colombier 		free(cb);
424*45e6af3bSDavid du Colombier 		poperror();
425*45e6af3bSDavid du Colombier 		return n;
426*45e6af3bSDavid du Colombier 
427*45e6af3bSDavid du Colombier 	case Qmousein:
428*45e6af3bSDavid du Colombier 		if(n > sizeof buf-1)
429*45e6af3bSDavid du Colombier 			n = sizeof buf -1;
430*45e6af3bSDavid du Colombier 		memmove(buf, va, n);
431*45e6af3bSDavid du Colombier 		buf[n] = 0;
432*45e6af3bSDavid du Colombier 		p = 0;
433*45e6af3bSDavid du Colombier 		pt.x = strtol(buf+1, &p, 0);
434*45e6af3bSDavid du Colombier 		if(p == 0)
435*45e6af3bSDavid du Colombier 			error(Eshort);
436*45e6af3bSDavid du Colombier 		pt.y = strtol(p, &p, 0);
437*45e6af3bSDavid du Colombier 		if(p == 0)
438*45e6af3bSDavid du Colombier 			error(Eshort);
439*45e6af3bSDavid du Colombier 		b = strtol(p, &p, 0);
440*45e6af3bSDavid du Colombier 		msec = strtol(p, &p, 0);
441*45e6af3bSDavid du Colombier 		if(msec == 0)
442*45e6af3bSDavid du Colombier 			msec = TK2MS(sys->ticks);
443*45e6af3bSDavid du Colombier 		mousetrack(pt.x, pt.y, b, msec);
444*45e6af3bSDavid du Colombier 		return n;
445*45e6af3bSDavid du Colombier 
446*45e6af3bSDavid du Colombier 	case Qmouse:
447*45e6af3bSDavid du Colombier 		if(n > sizeof buf-1)
448*45e6af3bSDavid du Colombier 			n = sizeof buf -1;
449*45e6af3bSDavid du Colombier 		memmove(buf, va, n);
450*45e6af3bSDavid du Colombier 		buf[n] = 0;
451*45e6af3bSDavid du Colombier 		p = 0;
452*45e6af3bSDavid du Colombier 		pt.x = strtoul(buf+1, &p, 0);
453*45e6af3bSDavid du Colombier 		if(p == 0)
454*45e6af3bSDavid du Colombier 			error(Eshort);
455*45e6af3bSDavid du Colombier 		pt.y = strtoul(p, 0, 0);
456*45e6af3bSDavid du Colombier 		qlock(&mouse);
457*45e6af3bSDavid du Colombier 		if(ptinrect(pt, gscreen->r)){
458*45e6af3bSDavid du Colombier 			mouse.xy = pt;
459*45e6af3bSDavid du Colombier 			mouse.redraw = 1;
460*45e6af3bSDavid du Colombier 			mouse.track = 1;
461*45e6af3bSDavid du Colombier 			mouseclock();
462*45e6af3bSDavid du Colombier 		}
463*45e6af3bSDavid du Colombier 		qunlock(&mouse);
464*45e6af3bSDavid du Colombier 		return n;
465*45e6af3bSDavid du Colombier 	}
466*45e6af3bSDavid du Colombier 
467*45e6af3bSDavid du Colombier 	error(Egreg);
468*45e6af3bSDavid du Colombier 	return -1;
469*45e6af3bSDavid du Colombier }
470*45e6af3bSDavid du Colombier 
471*45e6af3bSDavid du Colombier Dev mousedevtab = {
472*45e6af3bSDavid du Colombier 	'm',
473*45e6af3bSDavid du Colombier 	"mouse",
474*45e6af3bSDavid du Colombier 
475*45e6af3bSDavid du Colombier 	mousereset,
476*45e6af3bSDavid du Colombier 	mouseinit,
477*45e6af3bSDavid du Colombier 	devshutdown,
478*45e6af3bSDavid du Colombier 	mouseattach,
479*45e6af3bSDavid du Colombier 	mousewalk,
480*45e6af3bSDavid du Colombier 	mousestat,
481*45e6af3bSDavid du Colombier 	mouseopen,
482*45e6af3bSDavid du Colombier 	mousecreate,
483*45e6af3bSDavid du Colombier 	mouseclose,
484*45e6af3bSDavid du Colombier 	mouseread,
485*45e6af3bSDavid du Colombier 	devbread,
486*45e6af3bSDavid du Colombier 	mousewrite,
487*45e6af3bSDavid du Colombier 	devbwrite,
488*45e6af3bSDavid du Colombier 	devremove,
489*45e6af3bSDavid du Colombier 	devwstat,
490*45e6af3bSDavid du Colombier };
491*45e6af3bSDavid du Colombier 
492*45e6af3bSDavid du Colombier void
Cursortocursor(Cursor * c)493*45e6af3bSDavid du Colombier Cursortocursor(Cursor *c)
494*45e6af3bSDavid du Colombier {
495*45e6af3bSDavid du Colombier 	lock(&cursor);
496*45e6af3bSDavid du Colombier 	memmove(&cursor.Cursor, c, sizeof(Cursor));
497*45e6af3bSDavid du Colombier 	setcursor(c);
498*45e6af3bSDavid du Colombier 	unlock(&cursor);
499*45e6af3bSDavid du Colombier }
500*45e6af3bSDavid du Colombier 
501*45e6af3bSDavid du Colombier 
502*45e6af3bSDavid du Colombier /*
503*45e6af3bSDavid du Colombier  *  called by the clock routine to redraw the cursor
504*45e6af3bSDavid du Colombier  */
505*45e6af3bSDavid du Colombier static void
mouseclock(void)506*45e6af3bSDavid du Colombier mouseclock(void)
507*45e6af3bSDavid du Colombier {
508*45e6af3bSDavid du Colombier 	if(mouse.track){
509*45e6af3bSDavid du Colombier 		mousetrack(mouse.dx, mouse.dy, mouse.buttons, TK2MS(sys->ticks));
510*45e6af3bSDavid du Colombier 		mouse.track = 0;
511*45e6af3bSDavid du Colombier 		mouse.dx = 0;
512*45e6af3bSDavid du Colombier 		mouse.dy = 0;
513*45e6af3bSDavid du Colombier 	}
514*45e6af3bSDavid du Colombier 	if(mouse.redraw && canlock(&cursor)){
515*45e6af3bSDavid du Colombier 		mouse.redraw = 0;
516*45e6af3bSDavid du Colombier 		cursoroff(0);
517*45e6af3bSDavid du Colombier 		mouse.redraw = cursoron(0);
518*45e6af3bSDavid du Colombier 		unlock(&cursor);
519*45e6af3bSDavid du Colombier 	}
520*45e6af3bSDavid du Colombier 	drawactive(0);
521*45e6af3bSDavid du Colombier }
522*45e6af3bSDavid du Colombier 
523*45e6af3bSDavid du Colombier static int
scale(int x)524*45e6af3bSDavid du Colombier scale(int x)
525*45e6af3bSDavid du Colombier {
526*45e6af3bSDavid du Colombier 	int sign = 1;
527*45e6af3bSDavid du Colombier 
528*45e6af3bSDavid du Colombier 	if(x < 0){
529*45e6af3bSDavid du Colombier 		sign = -1;
530*45e6af3bSDavid du Colombier 		x = -x;
531*45e6af3bSDavid du Colombier 	}
532*45e6af3bSDavid du Colombier 	switch(x){
533*45e6af3bSDavid du Colombier 	case 0:
534*45e6af3bSDavid du Colombier 	case 1:
535*45e6af3bSDavid du Colombier 	case 2:
536*45e6af3bSDavid du Colombier 	case 3:
537*45e6af3bSDavid du Colombier 		break;
538*45e6af3bSDavid du Colombier 	case 4:
539*45e6af3bSDavid du Colombier 		x = 6 + (mouse.acceleration>>2);
540*45e6af3bSDavid du Colombier 		break;
541*45e6af3bSDavid du Colombier 	case 5:
542*45e6af3bSDavid du Colombier 		x = 9 + (mouse.acceleration>>1);
543*45e6af3bSDavid du Colombier 		break;
544*45e6af3bSDavid du Colombier 	default:
545*45e6af3bSDavid du Colombier 		x *= mouse.maxacc;
546*45e6af3bSDavid du Colombier 		break;
547*45e6af3bSDavid du Colombier 	}
548*45e6af3bSDavid du Colombier 	return sign*x;
549*45e6af3bSDavid du Colombier }
550*45e6af3bSDavid du Colombier 
551*45e6af3bSDavid du Colombier /*
552*45e6af3bSDavid du Colombier  *  called at interrupt level to update the structure and
553*45e6af3bSDavid du Colombier  *  awaken any waiting procs.
554*45e6af3bSDavid du Colombier  */
555*45e6af3bSDavid du Colombier void
mousetrack(int dx,int dy,int b,int msec)556*45e6af3bSDavid du Colombier mousetrack(int dx, int dy, int b, int msec)
557*45e6af3bSDavid du Colombier {
558*45e6af3bSDavid du Colombier 	int x, y, lastb;
559*45e6af3bSDavid du Colombier 
560*45e6af3bSDavid du Colombier 	if(gscreen==nil)
561*45e6af3bSDavid du Colombier 		return;
562*45e6af3bSDavid du Colombier 
563*45e6af3bSDavid du Colombier 	if(mouse.acceleration){
564*45e6af3bSDavid du Colombier 		dx = scale(dx);
565*45e6af3bSDavid du Colombier 		dy = scale(dy);
566*45e6af3bSDavid du Colombier 	}
567*45e6af3bSDavid du Colombier 	x = mouse.xy.x + dx;
568*45e6af3bSDavid du Colombier 	if(x < gscreen->clipr.min.x)
569*45e6af3bSDavid du Colombier 		x = gscreen->clipr.min.x;
570*45e6af3bSDavid du Colombier 	if(x >= gscreen->clipr.max.x)
571*45e6af3bSDavid du Colombier 		x = gscreen->clipr.max.x;
572*45e6af3bSDavid du Colombier 	y = mouse.xy.y + dy;
573*45e6af3bSDavid du Colombier 	if(y < gscreen->clipr.min.y)
574*45e6af3bSDavid du Colombier 		y = gscreen->clipr.min.y;
575*45e6af3bSDavid du Colombier 	if(y >= gscreen->clipr.max.y)
576*45e6af3bSDavid du Colombier 		y = gscreen->clipr.max.y;
577*45e6af3bSDavid du Colombier 
578*45e6af3bSDavid du Colombier 	lastb = mouse.buttons;
579*45e6af3bSDavid du Colombier 	mouse.xy = Pt(x, y);
580*45e6af3bSDavid du Colombier 	mouse.buttons = b|kbdbuttons;
581*45e6af3bSDavid du Colombier 	mouse.redraw = 1;
582*45e6af3bSDavid du Colombier 	mouse.counter++;
583*45e6af3bSDavid du Colombier 	mouse.msec = msec;
584*45e6af3bSDavid du Colombier 
585*45e6af3bSDavid du Colombier 	/*
586*45e6af3bSDavid du Colombier 	 * if the queue fills, we discard the entire queue and don't
587*45e6af3bSDavid du Colombier 	 * queue any more events until a reader polls the mouse.
588*45e6af3bSDavid du Colombier 	 */
589*45e6af3bSDavid du Colombier 	if(!mouse.qfull && lastb != b) {	/* add to ring */
590*45e6af3bSDavid du Colombier 		mouse.queue[mouse.wi] = mouse.Mousestate;
591*45e6af3bSDavid du Colombier 		if(++mouse.wi == nelem(mouse.queue))
592*45e6af3bSDavid du Colombier 			mouse.wi = 0;
593*45e6af3bSDavid du Colombier 		if(mouse.wi == mouse.ri)
594*45e6af3bSDavid du Colombier 			mouse.qfull = 1;
595*45e6af3bSDavid du Colombier 	}
596*45e6af3bSDavid du Colombier 	wakeup(&mouse.r);
597*45e6af3bSDavid du Colombier 	drawactive(1);
598*45e6af3bSDavid du Colombier }
599*45e6af3bSDavid du Colombier 
600*45e6af3bSDavid du Colombier /*
601*45e6af3bSDavid du Colombier  *  microsoft 3 button, 7 bit bytes
602*45e6af3bSDavid du Colombier  *
603*45e6af3bSDavid du Colombier  *	byte 0 -	1  L  R Y7 Y6 X7 X6
604*45e6af3bSDavid du Colombier  *	byte 1 -	0 X5 X4 X3 X2 X1 X0
605*45e6af3bSDavid du Colombier  *	byte 2 -	0 Y5 Y4 Y3 Y2 Y1 Y0
606*45e6af3bSDavid du Colombier  *	byte 3 -	0  M  x  x  x  x  x	(optional)
607*45e6af3bSDavid du Colombier  *
608*45e6af3bSDavid du Colombier  *  shift & right button is the same as middle button (for 2 button mice)
609*45e6af3bSDavid du Colombier  */
610*45e6af3bSDavid du Colombier int
m3mouseputc(Queue *,int c)611*45e6af3bSDavid du Colombier m3mouseputc(Queue*, int c)
612*45e6af3bSDavid du Colombier {
613*45e6af3bSDavid du Colombier 	static uchar msg[3];
614*45e6af3bSDavid du Colombier 	static int nb;
615*45e6af3bSDavid du Colombier 	static int middle;
616*45e6af3bSDavid du Colombier 	static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 3 };
617*45e6af3bSDavid du Colombier 	short x;
618*45e6af3bSDavid du Colombier 	int dx, dy, newbuttons;
619*45e6af3bSDavid du Colombier 	static ulong lasttick;
620*45e6af3bSDavid du Colombier 	ulong m;
621*45e6af3bSDavid du Colombier 
622*45e6af3bSDavid du Colombier 	/* Resynchronize in stream with timing. */
623*45e6af3bSDavid du Colombier 	m = sys->ticks;
624*45e6af3bSDavid du Colombier 	if(TK2SEC(m - lasttick) > 2)
625*45e6af3bSDavid du Colombier 		nb = 0;
626*45e6af3bSDavid du Colombier 	lasttick = m;
627*45e6af3bSDavid du Colombier 
628*45e6af3bSDavid du Colombier 	if(nb==0){
629*45e6af3bSDavid du Colombier 		/*
630*45e6af3bSDavid du Colombier 		 * an extra byte comes for middle button motion.
631*45e6af3bSDavid du Colombier 		 * only two possible values for the extra byte.
632*45e6af3bSDavid du Colombier 		 */
633*45e6af3bSDavid du Colombier 		if(c == 0x00 || c == 0x20){
634*45e6af3bSDavid du Colombier 			/* an extra byte gets sent for the middle button */
635*45e6af3bSDavid du Colombier 			middle = (c&0x20) ? 2 : 0;
636*45e6af3bSDavid du Colombier 			newbuttons = (mouse.buttons & ~2) | middle;
637*45e6af3bSDavid du Colombier 			mousetrack(0, 0, newbuttons, TK2MS(sys->ticks));
638*45e6af3bSDavid du Colombier 			return 0;
639*45e6af3bSDavid du Colombier 		}
640*45e6af3bSDavid du Colombier 	}
641*45e6af3bSDavid du Colombier 	msg[nb] = c;
642*45e6af3bSDavid du Colombier 	if(++nb == 3){
643*45e6af3bSDavid du Colombier 		nb = 0;
644*45e6af3bSDavid du Colombier 		newbuttons = middle | b[(msg[0]>>4)&3 | (mouseshifted ? 4 : 0)];
645*45e6af3bSDavid du Colombier 		x = (msg[0]&0x3)<<14;
646*45e6af3bSDavid du Colombier 		dx = (x>>8) | msg[1];
647*45e6af3bSDavid du Colombier 		x = (msg[0]&0xc)<<12;
648*45e6af3bSDavid du Colombier 		dy = (x>>8) | msg[2];
649*45e6af3bSDavid du Colombier 		mousetrack(dx, dy, newbuttons, TK2MS(sys->ticks));
650*45e6af3bSDavid du Colombier 	}
651*45e6af3bSDavid du Colombier 	return 0;
652*45e6af3bSDavid du Colombier }
653*45e6af3bSDavid du Colombier 
654*45e6af3bSDavid du Colombier /*
655*45e6af3bSDavid du Colombier  * microsoft intellimouse 3 buttons + scroll
656*45e6af3bSDavid du Colombier  * 	byte 0 -	1  L  R Y7 Y6 X7 X6
657*45e6af3bSDavid du Colombier  *	byte 1 -	0 X5 X4 X3 X2 X1 X0
658*45e6af3bSDavid du Colombier  *	byte 2 -	0 Y5 Y4 Y3 Y2 Y1 Y0
659*45e6af3bSDavid du Colombier  *	byte 3 -	0  0  M  %  %  %  %
660*45e6af3bSDavid du Colombier  *
661*45e6af3bSDavid du Colombier  *	%: 0xf => U , 0x1 => D
662*45e6af3bSDavid du Colombier  *
663*45e6af3bSDavid du Colombier  *	L: left
664*45e6af3bSDavid du Colombier  *	R: right
665*45e6af3bSDavid du Colombier  *	U: up
666*45e6af3bSDavid du Colombier  *	D: down
667*45e6af3bSDavid du Colombier  */
668*45e6af3bSDavid du Colombier int
m5mouseputc(Queue *,int c)669*45e6af3bSDavid du Colombier m5mouseputc(Queue*, int c)
670*45e6af3bSDavid du Colombier {
671*45e6af3bSDavid du Colombier 	static uchar msg[3];
672*45e6af3bSDavid du Colombier 	static int nb;
673*45e6af3bSDavid du Colombier 	static ulong lasttick;
674*45e6af3bSDavid du Colombier 	ulong m;
675*45e6af3bSDavid du Colombier 
676*45e6af3bSDavid du Colombier 	/* Resynchronize in stream with timing. */
677*45e6af3bSDavid du Colombier 	m = sys->ticks;
678*45e6af3bSDavid du Colombier 	if(TK2SEC(m - lasttick) > 2)
679*45e6af3bSDavid du Colombier 		nb = 0;
680*45e6af3bSDavid du Colombier 	lasttick = m;
681*45e6af3bSDavid du Colombier 
682*45e6af3bSDavid du Colombier 	msg[nb++] = c & 0x7f;
683*45e6af3bSDavid du Colombier 	if (nb == 4) {
684*45e6af3bSDavid du Colombier 		schar dx,dy,newbuttons;
685*45e6af3bSDavid du Colombier 		dx = msg[1] | (msg[0] & 0x3) << 6;
686*45e6af3bSDavid du Colombier 		dy = msg[2] | (msg[0] & 0xc) << 4;
687*45e6af3bSDavid du Colombier 		newbuttons =
688*45e6af3bSDavid du Colombier 			(msg[0] & 0x10) >> (mouseshifted ? 3 : 2)
689*45e6af3bSDavid du Colombier 			| (msg[0] & 0x20) >> 5
690*45e6af3bSDavid du Colombier 			| ( msg[3] == 0x10 ? 0x02 :
691*45e6af3bSDavid du Colombier 			    msg[3] == 0x0f ? ScrollUp :
692*45e6af3bSDavid du Colombier 			    msg[3] == 0x01 ? ScrollDown : 0 );
693*45e6af3bSDavid du Colombier 		mousetrack(dx, dy, newbuttons, TK2MS(sys->ticks));
694*45e6af3bSDavid du Colombier 		nb = 0;
695*45e6af3bSDavid du Colombier 	}
696*45e6af3bSDavid du Colombier 	return 0;
697*45e6af3bSDavid du Colombier }
698*45e6af3bSDavid du Colombier 
699*45e6af3bSDavid du Colombier /*
700*45e6af3bSDavid du Colombier  *  Logitech 5 byte packed binary mouse format, 8 bit bytes
701*45e6af3bSDavid du Colombier  *
702*45e6af3bSDavid du Colombier  *  shift & right button is the same as middle button (for 2 button mice)
703*45e6af3bSDavid du Colombier  */
704*45e6af3bSDavid du Colombier int
mouseputc(Queue *,int c)705*45e6af3bSDavid du Colombier mouseputc(Queue*, int c)
706*45e6af3bSDavid du Colombier {
707*45e6af3bSDavid du Colombier 	static short msg[5];
708*45e6af3bSDavid du Colombier 	static int nb;
709*45e6af3bSDavid du Colombier 	static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 3, 3, 7};
710*45e6af3bSDavid du Colombier 	int dx, dy, newbuttons;
711*45e6af3bSDavid du Colombier 	static ulong lasttick;
712*45e6af3bSDavid du Colombier 	ulong m;
713*45e6af3bSDavid du Colombier 
714*45e6af3bSDavid du Colombier 	/* Resynchronize in stream with timing. */
715*45e6af3bSDavid du Colombier 	m = sys->ticks;
716*45e6af3bSDavid du Colombier 	if(TK2SEC(m - lasttick) > 2)
717*45e6af3bSDavid du Colombier 		nb = 0;
718*45e6af3bSDavid du Colombier 	lasttick = m;
719*45e6af3bSDavid du Colombier 
720*45e6af3bSDavid du Colombier 	if((c&0xF0) == 0x80)
721*45e6af3bSDavid du Colombier 		nb=0;
722*45e6af3bSDavid du Colombier 	msg[nb] = c;
723*45e6af3bSDavid du Colombier 	if(c & 0x80)
724*45e6af3bSDavid du Colombier 		msg[nb] |= ~0xFF;	/* sign extend */
725*45e6af3bSDavid du Colombier 	if(++nb == 5){
726*45e6af3bSDavid du Colombier 		newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)];
727*45e6af3bSDavid du Colombier 		dx = msg[1]+msg[3];
728*45e6af3bSDavid du Colombier 		dy = -(msg[2]+msg[4]);
729*45e6af3bSDavid du Colombier 		mousetrack(dx, dy, newbuttons, TK2MS(sys->ticks));
730*45e6af3bSDavid du Colombier 		nb = 0;
731*45e6af3bSDavid du Colombier 	}
732*45e6af3bSDavid du Colombier 	return 0;
733*45e6af3bSDavid du Colombier }
734*45e6af3bSDavid du Colombier 
735*45e6af3bSDavid du Colombier int
mousechanged(void *)736*45e6af3bSDavid du Colombier mousechanged(void*)
737*45e6af3bSDavid du Colombier {
738*45e6af3bSDavid du Colombier 	return mouse.lastcounter != mouse.counter ||
739*45e6af3bSDavid du Colombier 		mouse.lastresize != mouse.resize;
740*45e6af3bSDavid du Colombier }
741*45e6af3bSDavid du Colombier 
742*45e6af3bSDavid du Colombier Point
mousexy(void)743*45e6af3bSDavid du Colombier mousexy(void)
744*45e6af3bSDavid du Colombier {
745*45e6af3bSDavid du Colombier 	return mouse.xy;
746*45e6af3bSDavid du Colombier }
747*45e6af3bSDavid du Colombier 
748*45e6af3bSDavid du Colombier void
mouseaccelerate(int x)749*45e6af3bSDavid du Colombier mouseaccelerate(int x)
750*45e6af3bSDavid du Colombier {
751*45e6af3bSDavid du Colombier 	mouse.acceleration = x;
752*45e6af3bSDavid du Colombier 	if(mouse.acceleration < 3)
753*45e6af3bSDavid du Colombier 		mouse.maxacc = 2;
754*45e6af3bSDavid du Colombier 	else
755*45e6af3bSDavid du Colombier 		mouse.maxacc = mouse.acceleration;
756*45e6af3bSDavid du Colombier }
757*45e6af3bSDavid du Colombier 
758*45e6af3bSDavid du Colombier /*
759*45e6af3bSDavid du Colombier  * notify reader that screen has been resized
760*45e6af3bSDavid du Colombier  */
761*45e6af3bSDavid du Colombier void
mouseresize(void)762*45e6af3bSDavid du Colombier mouseresize(void)
763*45e6af3bSDavid du Colombier {
764*45e6af3bSDavid du Colombier 	mouse.resize++;
765*45e6af3bSDavid du Colombier 	wakeup(&mouse.r);
766*45e6af3bSDavid du Colombier }
767*45e6af3bSDavid du Colombier 
768