1 #include <u.h>
2 #include <libc.h>
3 #include "compat.h"
4 #include "error.h"
5
6 #define Image IMAGE
7 #include <draw.h>
8 #include <memdraw.h>
9 #include <cursor.h>
10 #include "screen.h"
11
12 typedef struct Mouseinfo Mouseinfo;
13 typedef struct Mousestate Mousestate;
14
15 struct Mousestate
16 {
17 Point xy; /* mouse.xy */
18 int buttons; /* mouse.buttons */
19 ulong counter; /* increments every update */
20 ulong msec; /* time of last event */
21 };
22
23 struct Mouseinfo
24 {
25 Mousestate;
26 int dx;
27 int dy;
28 int track; /* dx & dy updated */
29 int redraw; /* update cursor on screen */
30 ulong lastcounter; /* value when /dev/mouse read */
31 Rendez r;
32 Ref;
33 QLock;
34 int open;
35 int acceleration;
36 int maxacc;
37 Mousestate queue[16]; /* circular buffer of click events */
38 int ri; /* read index into queue */
39 int wi; /* write index into queue */
40 uchar qfull; /* queue is full */
41 };
42
43 Mouseinfo mouse;
44 Cursorinfo cursor;
45 int mouseshifted;
46 Cursor curs;
47
48 void Cursortocursor(Cursor*);
49 int mousechanged(void*);
50 static void mouseclock(void);
51
52 enum{
53 Qdir,
54 Qcursor,
55 Qmouse,
56 };
57
58 static Dirtab mousedir[]={
59 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
60 "cursor", {Qcursor}, 0, 0666,
61 "mouse", {Qmouse}, 0, 0666,
62 };
63
64 static uchar buttonmap[8] = {
65 0, 1, 2, 3, 4, 5, 6, 7,
66 };
67 static int mouseswap;
68
69 extern Memimage* gscreen;
70 extern void mousewarpnote(Point);
71
72 static void
mousereset(void)73 mousereset(void)
74 {
75 curs = arrow;
76 Cursortocursor(&arrow);
77 }
78
79 static void
mouseinit(void)80 mouseinit(void)
81 {
82 cursoron(1);
83 }
84
85 static Chan*
mouseattach(char * spec)86 mouseattach(char *spec)
87 {
88 return devattach('m', spec);
89 }
90
91 static Walkqid*
mousewalk(Chan * c,Chan * nc,char ** name,int nname)92 mousewalk(Chan *c, Chan *nc, char **name, int nname)
93 {
94 Walkqid *wq;
95
96 wq = devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
97 if(wq != nil && wq->clone != c && (wq->clone->qid.type&QTDIR)==0)
98 incref(&mouse);
99 return wq;
100 }
101
102 static int
mousestat(Chan * c,uchar * db,int n)103 mousestat(Chan *c, uchar *db, int n)
104 {
105 return devstat(c, db, n, mousedir, nelem(mousedir), devgen);
106 }
107
108 static Chan*
mouseopen(Chan * c,int omode)109 mouseopen(Chan *c, int omode)
110 {
111 switch((ulong)c->qid.path){
112 case Qdir:
113 if(omode != OREAD)
114 error(Eperm);
115 break;
116 case Qmouse:
117 lock(&mouse);
118 if(mouse.open){
119 unlock(&mouse);
120 error(Einuse);
121 }
122 mouse.open = 1;
123 mouse.ref++;
124 unlock(&mouse);
125 break;
126 default:
127 incref(&mouse);
128 }
129 c->mode = openmode(omode);
130 c->flag |= COPEN;
131 c->offset = 0;
132 return c;
133 }
134
135 static void
mousecreate(Chan *,char *,int,ulong)136 mousecreate(Chan*, char*, int, ulong)
137 {
138 error(Eperm);
139 }
140
141 static void
mouseclose(Chan * c)142 mouseclose(Chan *c)
143 {
144 if((c->qid.type&QTDIR)==0 && (c->flag&COPEN)){
145 lock(&mouse);
146 if(c->qid.path == Qmouse)
147 mouse.open = 0;
148 if(--mouse.ref == 0){
149 cursoroff(1);
150 curs = arrow;
151 Cursortocursor(&arrow);
152 cursoron(1);
153 }
154 unlock(&mouse);
155 }
156 }
157
158
159 static long
mouseread(Chan * c,void * va,long n,vlong off)160 mouseread(Chan *c, void *va, long n, vlong off)
161 {
162 char buf[4*12+1];
163 uchar *p;
164 static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
165 ulong offset = off;
166 Mousestate m;
167 int b;
168
169 p = va;
170 switch((ulong)c->qid.path){
171 case Qdir:
172 return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);
173
174 case Qcursor:
175 if(offset != 0)
176 return 0;
177 if(n < 2*4+2*2*16)
178 error(Eshort);
179 n = 2*4+2*2*16;
180 lock(&cursor);
181 BPLONG(p+0, curs.offset.x);
182 BPLONG(p+4, curs.offset.y);
183 memmove(p+8, curs.clr, 2*16);
184 memmove(p+40, curs.set, 2*16);
185 unlock(&cursor);
186 return n;
187
188 case Qmouse:
189 while(mousechanged(0) == 0)
190 rendsleep(&mouse.r, mousechanged, 0);
191
192 mouse.qfull = 0;
193
194 /*
195 * No lock of the indicies is necessary here, because ri is only
196 * updated by us, and there is only one mouse reader
197 * at a time. I suppose that more than one process
198 * could try to read the fd at one time, but such behavior
199 * is degenerate and already violates the calling
200 * conventions for sleep above.
201 */
202 if(mouse.ri != mouse.wi){
203 m = mouse.queue[mouse.ri];
204 if(++mouse.ri == nelem(mouse.queue))
205 mouse.ri = 0;
206 } else {
207 lock(&cursor);
208
209 m = mouse.Mousestate;
210 unlock(&cursor);
211 }
212
213 b = buttonmap[m.buttons&7];
214 /* put buttons 4 and 5 back in */
215 b |= m.buttons & (3<<3);
216 sprint(buf, "m%11d %11d %11d %11lud",
217 m.xy.x, m.xy.y,
218 b,
219 m.msec);
220 mouse.lastcounter = m.counter;
221 if(n > 1+4*12)
222 n = 1+4*12;
223 memmove(va, buf, n);
224 return n;
225 }
226 return 0;
227 }
228
229 static void
setbuttonmap(char * map)230 setbuttonmap(char* map)
231 {
232 int i, x, one, two, three;
233
234 one = two = three = 0;
235 for(i = 0; i < 3; i++){
236 if(map[i] == 0)
237 error(Ebadarg);
238 if(map[i] == '1'){
239 if(one)
240 error(Ebadarg);
241 one = 1<<i;
242 }
243 else if(map[i] == '2'){
244 if(two)
245 error(Ebadarg);
246 two = 1<<i;
247 }
248 else if(map[i] == '3'){
249 if(three)
250 error(Ebadarg);
251 three = 1<<i;
252 }
253 else
254 error(Ebadarg);
255 }
256 if(map[i])
257 error(Ebadarg);
258
259 memset(buttonmap, 0, 8);
260 for(i = 0; i < 8; i++){
261 x = 0;
262 if(i & 1)
263 x |= one;
264 if(i & 2)
265 x |= two;
266 if(i & 4)
267 x |= three;
268 buttonmap[x] = i;
269 }
270 }
271
272 static long
mousewrite(Chan * c,void * va,long n,vlong)273 mousewrite(Chan *c, void *va, long n, vlong)
274 {
275 char *p;
276 Point pt;
277 char buf[64];
278
279 p = va;
280 switch((ulong)c->qid.path){
281 case Qdir:
282 error(Eisdir);
283
284 case Qcursor:
285 cursoroff(1);
286 if(n < 2*4+2*2*16){
287 curs = arrow;
288 Cursortocursor(&arrow);
289 }else{
290 n = 2*4+2*2*16;
291 curs.offset.x = BGLONG(p+0);
292 curs.offset.y = BGLONG(p+4);
293 memmove(curs.clr, p+8, 2*16);
294 memmove(curs.set, p+40, 2*16);
295 Cursortocursor(&curs);
296 }
297 qlock(&mouse);
298 mouse.redraw = 1;
299 mouseclock();
300 qunlock(&mouse);
301 cursoron(1);
302 return n;
303
304 case Qmouse:
305 if(n > sizeof buf-1)
306 n = sizeof buf -1;
307 memmove(buf, va, n);
308 buf[n] = 0;
309 p = 0;
310 pt.x = strtoul(buf+1, &p, 0);
311 if(p == 0)
312 error(Eshort);
313 pt.y = strtoul(p, 0, 0);
314 qlock(&mouse);
315 if(ptinrect(pt, gscreen->r)){
316 mousetrack(pt.x, pt.y, mouse.buttons, nsec()/(1000*1000LL));
317 mousewarpnote(pt);
318 }
319 qunlock(&mouse);
320 return n;
321 }
322
323 error(Egreg);
324 return -1;
325 }
326
327 Dev mousedevtab = {
328 'm',
329 "mouse",
330
331 mousereset,
332 mouseinit,
333 mouseattach,
334 mousewalk,
335 mousestat,
336 mouseopen,
337 mousecreate,
338 mouseclose,
339 mouseread,
340 devbread,
341 mousewrite,
342 devbwrite,
343 devremove,
344 devwstat,
345 };
346
347 void
Cursortocursor(Cursor * c)348 Cursortocursor(Cursor *c)
349 {
350 lock(&cursor);
351 memmove(&cursor.Cursor, c, sizeof(Cursor));
352 setcursor(c);
353 unlock(&cursor);
354 }
355
356 static int
scale(int x)357 scale(int x)
358 {
359 int sign = 1;
360
361 if(x < 0){
362 sign = -1;
363 x = -x;
364 }
365 switch(x){
366 case 0:
367 case 1:
368 case 2:
369 case 3:
370 break;
371 case 4:
372 x = 6 + (mouse.acceleration>>2);
373 break;
374 case 5:
375 x = 9 + (mouse.acceleration>>1);
376 break;
377 default:
378 x *= mouse.maxacc;
379 break;
380 }
381 return sign*x;
382 }
383
384 static void
mouseclock(void)385 mouseclock(void)
386 {
387 lock(&cursor);
388 if(mouse.redraw){
389 mouse.redraw = 0;
390 cursoroff(0);
391 mouse.redraw = cursoron(0);
392 }
393 unlock(&cursor);
394 }
395
396 /*
397 * called at interrupt level to update the structure and
398 * awaken any waiting procs.
399 */
400 void
mousetrack(int x,int y,int b,int msec)401 mousetrack(int x, int y, int b, int msec)
402 {
403 int lastb;
404
405 lastb = mouse.buttons;
406 mouse.xy = Pt(x, y);
407 mouse.buttons = b;
408 mouse.redraw = 1;
409 mouse.counter++;
410 mouse.msec = msec;
411
412 /*
413 * if the queue fills, we discard the entire queue and don't
414 * queue any more events until a reader polls the mouse.
415 */
416 if(!mouse.qfull && lastb != b){ /* add to ring */
417 mouse.queue[mouse.wi] = mouse.Mousestate;
418 if(++mouse.wi == nelem(mouse.queue))
419 mouse.wi = 0;
420 if(mouse.wi == mouse.ri)
421 mouse.qfull = 1;
422 }
423 rendwakeup(&mouse.r);
424 mouseclock();
425 }
426
427 int
mousechanged(void *)428 mousechanged(void*)
429 {
430 return mouse.lastcounter != mouse.counter;
431 }
432
433 Point
mousexy(void)434 mousexy(void)
435 {
436 return mouse.xy;
437 }
438
439 void
mouseaccelerate(int x)440 mouseaccelerate(int x)
441 {
442 mouse.acceleration = x;
443 if(mouse.acceleration < 3)
444 mouse.maxacc = 2;
445 else
446 mouse.maxacc = mouse.acceleration;
447 }
448