xref: /inferno-os/emu/port/devpointer.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1 /*
2  * mouse or stylus
3  */
4 
5 #include	"dat.h"
6 #include	"fns.h"
7 #include	"../port/error.h"
8 
9 #include <draw.h>
10 #include <memdraw.h>
11 #include <cursor.h>
12 
13 #define	cursorenable()
14 #define	cursordisable()
15 
16 enum{
17 	Qdir,
18 	Qpointer,
19 	Qcursor
20 };
21 
22 typedef struct Pointer Pointer;
23 
24 struct Pointer {
25 	int	x;
26 	int	y;
27 	int	b;
28 	ulong	msec;
29 };
30 
31 static struct
32 {
33 	Pointer	v;
34 	int	modify;
35 	int	lastb;
36 	Rendez	r;
37 	Ref	ref;
38 	QLock	q;
39 } mouse;
40 
41 static
42 Dirtab pointertab[]={
43 	".",			{Qdir, 0, QTDIR},	0,	0555,
44 	"pointer",		{Qpointer},	0,	0666,
45 	"cursor",		{Qcursor},		0,	0222,
46 };
47 
48 enum {
49 	Nevent = 16	/* enough for some */
50 };
51 
52 static struct {
53 	int	rd;
54 	int	wr;
55 	Pointer	clicks[Nevent];
56 	Rendez r;
57 	int	full;
58 	int	put;
59 	int	get;
60 } ptrq;
61 
62 /*
63  * called by any source of pointer data
64  */
65 void
66 mousetrack(int b, int x, int y, int isdelta)
67 {
68 	int lastb;
69 	ulong msec;
70 	Pointer e;
71 
72 	if(isdelta){
73 		x += mouse.v.x;
74 		y += mouse.v.y;
75 	}
76 	msec = osmillisec();
77 	if(0 && b && (mouse.v.b ^ b)&0x1f){
78 		if(msec - mouse.v.msec < 300 && mouse.lastb == b
79 		   && abs(mouse.v.x - x) < 12 && abs(mouse.v.y - y) < 12)
80 			b |= 1<<8;
81 		mouse.lastb = b & 0x1f;
82 		mouse.v.msec = msec;
83 	}
84 	if((b&(1<<8))==0 && x == mouse.v.x && y == mouse.v.y && mouse.v.b == b)
85 		return;
86 	lastb = mouse.v.b;
87 	mouse.v.x = x;
88 	mouse.v.y = y;
89 	mouse.v.b = b;
90 	mouse.v.msec = msec;
91 	if(!ptrq.full && lastb != b){
92 		e = mouse.v;
93 		ptrq.clicks[ptrq.wr] = e;
94 		if(++ptrq.wr >= Nevent)
95 			ptrq.wr = 0;
96 		if(ptrq.wr == ptrq.rd)
97 			ptrq.full = 1;
98 	}
99 	mouse.modify = 1;
100 	ptrq.put++;
101 	Wakeup(&ptrq.r);
102 /*	drawactive(1);	*/
103 /*	setpointer(x, y); */
104 }
105 
106 static int
107 ptrqnotempty(void *x)
108 {
109 	USED(x);
110 	return ptrq.full || ptrq.put != ptrq.get;
111 }
112 
113 static Pointer
114 mouseconsume(void)
115 {
116 	Pointer e;
117 
118 	Sleep(&ptrq.r, ptrqnotempty, 0);
119 	ptrq.full = 0;
120 	ptrq.get = ptrq.put;
121 	if(ptrq.rd != ptrq.wr){
122 		e = ptrq.clicks[ptrq.rd];
123 		if(++ptrq.rd >= Nevent)
124 			ptrq.rd = 0;
125 	}else
126 		e = mouse.v;
127 	return e;
128 }
129 
130 Point
131 mousexy(void)
132 {
133 	return Pt(mouse.v.x, mouse.v.y);
134 }
135 
136 
137 static Chan*
138 pointerattach(char* spec)
139 {
140 	return devattach('m', spec);
141 }
142 
143 static Walkqid*
144 pointerwalk(Chan *c, Chan *nc, char **name, int nname)
145 {
146 	Walkqid *wq;
147 
148 	wq = devwalk(c, nc, name, nname, pointertab, nelem(pointertab), devgen);
149 	if(wq != nil && wq->clone != c && wq->clone != nil && (ulong)c->qid.path == Qpointer)
150 		incref(&mouse.ref);	/* can this happen? */
151 	return wq;
152 }
153 
154 static int
155 pointerstat(Chan* c, uchar *db, int n)
156 {
157 	return devstat(c, db, n, pointertab, nelem(pointertab), devgen);
158 }
159 
160 static Chan*
161 pointeropen(Chan* c, int omode)
162 {
163 	c = devopen(c, omode, pointertab, nelem(pointertab), devgen);
164 	if((ulong)c->qid.path == Qpointer){
165 		if(waserror()){
166 			c->flag &= ~COPEN;
167 			nexterror();
168 		}
169 		if(!canqlock(&mouse.q))
170 			error(Einuse);
171 		if(incref(&mouse.ref) != 1){
172 			qunlock(&mouse.q);
173 			error(Einuse);
174 		}
175 		cursorenable();
176 		qunlock(&mouse.q);
177 		poperror();
178 	}
179 	return c;
180 }
181 
182 static void
183 pointerclose(Chan* c)
184 {
185 	if((c->flag & COPEN) == 0)
186 		return;
187 	switch((ulong)c->qid.path){
188 	case Qpointer:
189 		qlock(&mouse.q);
190 		if(decref(&mouse.ref) == 0){
191 			cursordisable();
192 		}
193 		qunlock(&mouse.q);
194 		break;
195 	}
196 }
197 
198 static long
199 pointerread(Chan* c, void* a, long n, vlong off)
200 {
201 	Pointer mt;
202 	char buf[1+4*12+1];
203 	int l;
204 
205 	USED(&off);
206 	switch((ulong)c->qid.path){
207 	case Qdir:
208 		return devdirread(c, a, n, pointertab, nelem(pointertab), devgen);
209 	case Qpointer:
210 		qlock(&mouse.q);
211 		if(waserror()) {
212 			qunlock(&mouse.q);
213 			nexterror();
214 		}
215 		mt = mouseconsume();
216 		poperror();
217 		qunlock(&mouse.q);
218 		l = snprint(buf, sizeof(buf), "m%11d %11d %11d %11lud ", mt.x, mt.y, mt.b, mt.msec);
219 		if(l < n)
220 			n = l;
221 		memmove(a, buf, n);
222 		break;
223 	default:
224 		n=0;
225 		break;
226 	}
227 	return n;
228 }
229 
230 static long
231 pointerwrite(Chan* c, void* va, long n, vlong off)
232 {
233 	char *a = va;
234 	char buf[128];
235 	int b, x, y;
236 	Drawcursor cur;
237 
238 	USED(&off);
239 	switch((ulong)c->qid.path){
240 	case Qpointer:
241 		if(n > sizeof buf-1)
242 			n = sizeof buf -1;
243 		memmove(buf, va, n);
244 		buf[n] = 0;
245 		x = strtoul(buf+1, &a, 0);
246 		if(*a == 0)
247 			error(Eshort);
248 		y = strtoul(a, &a, 0);
249 		if(*a != 0)
250 			b = strtoul(a, 0, 0);
251 		else
252 			b = mouse.v.b;
253 		/*mousetrack(b, x, y, msec);*/
254 		setpointer(x, y);
255 		USED(b);
256 		break;
257 	case Qcursor:
258 		/* TO DO: perhaps interpret data as an Image */
259 		/*
260 		 *  hotx[4] hoty[4] dx[4] dy[4] clr[dx/8 * dy/2] set[dx/8 * dy/2]
261 		 *  dx must be a multiple of 8; dy must be a multiple of 2.
262 		 */
263 		if(n == 0){
264 			cur.data = nil;
265 			drawcursor(&cur);
266 			break;
267 		}
268 		if(n < 8)
269 			error(Eshort);
270 		cur.hotx = BGLONG((uchar*)va+0*4);
271 		cur.hoty = BGLONG((uchar*)va+1*4);
272 		cur.minx = 0;
273 		cur.miny = 0;
274 		cur.maxx = BGLONG((uchar*)va+2*4);
275 		cur.maxy = BGLONG((uchar*)va+3*4);
276 		if(cur.maxx%8 != 0 || cur.maxy%2 != 0 || n-4*4 != (cur.maxx/8 * cur.maxy))
277 			error(Ebadarg);
278 		cur.data = (uchar*)va + 4*4;
279 		drawcursor(&cur);
280 		break;
281 	default:
282 		error(Ebadusefd);
283 	}
284 	return n;
285 }
286 
287 Dev pointerdevtab = {
288 	'm',
289 	"pointer",
290 
291 	devinit,
292 	pointerattach,
293 	pointerwalk,
294 	pointerstat,
295 	pointeropen,
296 	devcreate,
297 	pointerclose,
298 	pointerread,
299 	devbread,
300 	pointerwrite,
301 	devbwrite,
302 	devremove,
303 	devwstat,
304 };
305