xref: /inferno-os/os/port/devpointer.c (revision 556f8a312ed1b20f8ff25c104928646828e8b05c)
1 /*
2  * mouse or stylus
3  */
4 
5 #include	"u.h"
6 #include	"../port/lib.h"
7 #include	"mem.h"
8 #include	"dat.h"
9 #include	"fns.h"
10 #include	"../port/error.h"
11 
12 #include <draw.h>
13 #include <memdraw.h>
14 #include <cursor.h>
15 #include "screen.h"
16 
17 enum{
18 	Qdir,
19 	Qpointer,
20 	Qcursor,
21 };
22 
23 typedef struct Pointer Pointer;
24 
25 struct Pointer {
26 	int	x;
27 	int	y;
28 	int	b;
29 	ulong	msec;
30 };
31 
32 static struct
33 {
34 	Pointer;
35 	int	modify;
36 	int	lastb;
37 	Rendez	r;
38 	Ref	ref;
39 	QLock	q;
40 } mouse;
41 
42 static
43 Dirtab pointertab[]={
44 	".",			{Qdir, 0, QTDIR},	0,	0555,
45 	"pointer",		{Qpointer},	0,	0666,
46 	"cursor",		{Qcursor},		0,	0222,
47 };
48 
49 enum {
50 	Nevent = 16	/* enough for some */
51 };
52 
53 static struct {
54 	int	rd;
55 	int	wr;
56 	Pointer	clicks[Nevent];
57 	Rendez r;
58 	int	full;
59 	int	put;
60 	int	get;
61 } ptrq;
62 
63 /*
64  * called by any source of pointer data
65  */
66 void
67 mousetrack(int b, int x, int y, int isdelta)
68 {
69 	int lastb;
70 	ulong msec;
71 	Pointer e;
72 
73 	if(isdelta){
74 		x += mouse.x;
75 		y += mouse.y;
76 	}
77 	msec = TK2MS(MACHP(0)->ticks);
78 	if(b && (mouse.b ^ b)&0x1f){
79 		if(msec - mouse.msec < 300 && mouse.lastb == b
80 		   && abs(mouse.x - x) < 12 && abs(mouse.y - y) < 12)
81 			b |= 1<<8;
82 		mouse.lastb = b & 0x1f;
83 		mouse.msec = msec;
84 	}
85 	if(x == mouse.x && y == mouse.y && mouse.b == b)
86 		return;
87 	lastb = mouse.b;
88 	mouse.x = x;
89 	mouse.y = y;
90 	mouse.b = b;
91 	mouse.msec = msec;
92 	if(!ptrq.full && lastb != b){
93 		e = mouse.Pointer;
94 		ptrq.clicks[ptrq.wr] = e;
95 		if(++ptrq.wr >= Nevent)
96 			ptrq.wr = 0;
97 		if(ptrq.wr == ptrq.rd)
98 			ptrq.full = 1;
99 	}
100 	mouse.modify = 1;
101 	ptrq.put++;
102 	wakeup(&ptrq.r);
103 	drawactive(1);
104 	/* TO DO: cursor update */
105 }
106 
107 static int
108 ptrqnotempty(void*)
109 {
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.Pointer;
127 	return e;
128 }
129 
130 Point
131 mousexy(void)
132 {
133 	return Pt(mouse.x, mouse.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 		qunlock(&mouse.q);
193 		break;
194 	}
195 }
196 
197 static long
198 pointerread(Chan* c, void* a, long n, vlong)
199 {
200 	Pointer mt;
201 	char tmp[128];
202 	int l;
203 
204 	switch((ulong)c->qid.path){
205 	case Qdir:
206 		return devdirread(c, a, n, pointertab, nelem(pointertab), devgen);
207 	case Qpointer:
208 		qlock(&mouse.q);
209 		if(waserror()) {
210 			qunlock(&mouse.q);
211 			nexterror();
212 		}
213 		mt = mouseconsume();
214 		poperror();
215 		qunlock(&mouse.q);
216 		l = sprint(tmp, "m%11d %11d %11d %11lud ", mt.x, mt.y, mt.b, mt.msec);
217 		if(l < n)
218 			n = l;
219 		memmove(a, tmp, n);
220 		break;
221 	case Qcursor:
222 		/* TO DO: interpret data written as Image; give to drawcursor() */
223 		break;
224 	default:
225 		n=0;
226 		break;
227 	}
228 	return n;
229 }
230 
231 static long
232 pointerwrite(Chan* c, void* va, long n, vlong)
233 {
234 	char *a = va;
235 	char buf[128];
236 	int b, x, y;
237 
238 	switch((ulong)c->qid.path){
239 	case Qpointer:
240 		if(n > sizeof buf-1)
241 			n = sizeof buf -1;
242 		memmove(buf, va, n);
243 		buf[n] = 0;
244 		x = strtoul(buf+1, &a, 0);
245 		if(*a == 0)
246 			error(Eshort);
247 		y = strtoul(a, &a, 0);
248 		if(*a != 0)
249 			b = strtoul(a, 0, 0);
250 		else
251 			b = mouse.b;
252 		mousetrack(b, x, y, 0);
253 		break;
254 	default:
255 		error(Ebadusefd);
256 	}
257 	return n;
258 }
259 
260 Dev pointerdevtab = {
261 	'm',
262 	"pointer",
263 
264 	devreset,
265 	devinit,
266 	devshutdown,
267 	pointerattach,
268 	pointerwalk,
269 	pointerstat,
270 	pointeropen,
271 	devcreate,
272 	pointerclose,
273 	pointerread,
274 	devbread,
275 	pointerwrite,
276 	devbwrite,
277 	devremove,
278 	devwstat,
279 };
280