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
mousetrack(int b,int x,int y,int isdelta)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 lastb = mouse.v.b;
78 mouse.v.x = x;
79 mouse.v.y = y;
80 mouse.v.b = b;
81 mouse.v.msec = msec;
82 if(!ptrq.full && lastb != b){
83 e = mouse.v;
84 ptrq.clicks[ptrq.wr] = e;
85 if(++ptrq.wr >= Nevent)
86 ptrq.wr = 0;
87 if(ptrq.wr == ptrq.rd)
88 ptrq.full = 1;
89 }
90 mouse.modify = 1;
91 ptrq.put++;
92 Wakeup(&ptrq.r);
93 /* drawactive(1); */
94 /* setpointer(x, y); */
95 }
96
97 static int
ptrqnotempty(void * x)98 ptrqnotempty(void *x)
99 {
100 USED(x);
101 return ptrq.full || ptrq.put != ptrq.get;
102 }
103
104 static Pointer
mouseconsume(void)105 mouseconsume(void)
106 {
107 Pointer e;
108
109 Sleep(&ptrq.r, ptrqnotempty, 0);
110 ptrq.full = 0;
111 ptrq.get = ptrq.put;
112 if(ptrq.rd != ptrq.wr){
113 e = ptrq.clicks[ptrq.rd];
114 if(++ptrq.rd >= Nevent)
115 ptrq.rd = 0;
116 }else
117 e = mouse.v;
118 return e;
119 }
120
121 Point
mousexy(void)122 mousexy(void)
123 {
124 return Pt(mouse.v.x, mouse.v.y);
125 }
126
127
128 static Chan*
pointerattach(char * spec)129 pointerattach(char* spec)
130 {
131 return devattach('m', spec);
132 }
133
134 static Walkqid*
pointerwalk(Chan * c,Chan * nc,char ** name,int nname)135 pointerwalk(Chan *c, Chan *nc, char **name, int nname)
136 {
137 Walkqid *wq;
138
139 wq = devwalk(c, nc, name, nname, pointertab, nelem(pointertab), devgen);
140 if(wq != nil && wq->clone != c && wq->clone != nil && (ulong)c->qid.path == Qpointer)
141 incref(&mouse.ref); /* can this happen? */
142 return wq;
143 }
144
145 static int
pointerstat(Chan * c,uchar * db,int n)146 pointerstat(Chan* c, uchar *db, int n)
147 {
148 return devstat(c, db, n, pointertab, nelem(pointertab), devgen);
149 }
150
151 static Chan*
pointeropen(Chan * c,int omode)152 pointeropen(Chan* c, int omode)
153 {
154 c = devopen(c, omode, pointertab, nelem(pointertab), devgen);
155 if((ulong)c->qid.path == Qpointer){
156 if(waserror()){
157 c->flag &= ~COPEN;
158 nexterror();
159 }
160 if(!canqlock(&mouse.q))
161 error(Einuse);
162 if(incref(&mouse.ref) != 1){
163 qunlock(&mouse.q);
164 error(Einuse);
165 }
166 cursorenable();
167 qunlock(&mouse.q);
168 poperror();
169 }
170 return c;
171 }
172
173 static void
pointerclose(Chan * c)174 pointerclose(Chan* c)
175 {
176 if((c->flag & COPEN) == 0)
177 return;
178 switch((ulong)c->qid.path){
179 case Qpointer:
180 qlock(&mouse.q);
181 if(decref(&mouse.ref) == 0){
182 cursordisable();
183 }
184 qunlock(&mouse.q);
185 break;
186 }
187 }
188
189 static long
pointerread(Chan * c,void * a,long n,vlong off)190 pointerread(Chan* c, void* a, long n, vlong off)
191 {
192 Pointer mt;
193 char buf[1+4*12+1];
194 int l;
195
196 USED(&off);
197 switch((ulong)c->qid.path){
198 case Qdir:
199 return devdirread(c, a, n, pointertab, nelem(pointertab), devgen);
200 case Qpointer:
201 qlock(&mouse.q);
202 if(waserror()) {
203 qunlock(&mouse.q);
204 nexterror();
205 }
206 mt = mouseconsume();
207 poperror();
208 qunlock(&mouse.q);
209 l = snprint(buf, sizeof(buf), "m%11d %11d %11d %11lud ", mt.x, mt.y, mt.b, mt.msec);
210 if(l < n)
211 n = l;
212 memmove(a, buf, n);
213 break;
214 default:
215 n=0;
216 break;
217 }
218 return n;
219 }
220
221 static long
pointerwrite(Chan * c,void * va,long n,vlong off)222 pointerwrite(Chan* c, void* va, long n, vlong off)
223 {
224 char *a = va;
225 char buf[128];
226 int b, x, y;
227 Drawcursor cur;
228
229 USED(&off);
230 switch((ulong)c->qid.path){
231 case Qpointer:
232 if(n > sizeof buf-1)
233 n = sizeof buf -1;
234 memmove(buf, va, n);
235 buf[n] = 0;
236 x = strtoul(buf+1, &a, 0);
237 if(*a == 0)
238 error(Eshort);
239 y = strtoul(a, &a, 0);
240 if(*a != 0)
241 b = strtoul(a, 0, 0);
242 else
243 b = mouse.v.b;
244 /*mousetrack(b, x, y, msec);*/
245 setpointer(x, y);
246 USED(b);
247 break;
248 case Qcursor:
249 /* TO DO: perhaps interpret data as an Image */
250 /*
251 * hotx[4] hoty[4] dx[4] dy[4] clr[dx/8 * dy/2] set[dx/8 * dy/2]
252 * dx must be a multiple of 8; dy must be a multiple of 2.
253 */
254 if(n == 0){
255 cur.data = nil;
256 drawcursor(&cur);
257 break;
258 }
259 if(n < 8)
260 error(Eshort);
261 cur.hotx = BGLONG((uchar*)va+0*4);
262 cur.hoty = BGLONG((uchar*)va+1*4);
263 cur.minx = 0;
264 cur.miny = 0;
265 cur.maxx = BGLONG((uchar*)va+2*4);
266 cur.maxy = BGLONG((uchar*)va+3*4);
267 if(cur.maxx%8 != 0 || cur.maxy%2 != 0 || n-4*4 != (cur.maxx/8 * cur.maxy))
268 error(Ebadarg);
269 cur.data = (uchar*)va + 4*4;
270 drawcursor(&cur);
271 break;
272 default:
273 error(Ebadusefd);
274 }
275 return n;
276 }
277
278 Dev pointerdevtab = {
279 'm',
280 "pointer",
281
282 devinit,
283 pointerattach,
284 pointerwalk,
285 pointerstat,
286 pointeropen,
287 devcreate,
288 pointerclose,
289 pointerread,
290 devbread,
291 pointerwrite,
292 devbwrite,
293 devremove,
294 devwstat,
295 };
296