1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7
8 #define Image IMAGE
9 #include <draw.h>
10 #include <memdraw.h>
11 #include <cursor.h>
12 #include "screen.h"
13 #include <ctype.h>
14
15 typedef struct Mouseinfo Mouseinfo;
16 typedef struct Mousestate Mousestate;
17 typedef struct Calibration Calibration;
18
19 struct Calibration
20 {
21 long scalex;
22 long scaley;
23 long transx;
24 long transy;
25 } calibration = {
26 -16435,
27 23275,
28 253,
29 -23
30 };
31
32 /* The pen goes down, tracks some and goes up again. The pen alone can
33 * only simulate a one-button mouse.
34 * To simulate a more-button (five, in this case) mouse, we use the four
35 * keys along the the bottom of the iPaq as modifiers.
36 * When one (or more) of the modifier keys is (are) down, a pen-down event
37 * causes the corresponding bottons to go down. If no modifier key is
38 * depressed, a pen-down event is translated into a button-one down event.
39 * Releasing the modifier keys has no direct effect. The pen-up event is
40 * the one that triggers mouse-up events.
41 */
42 struct Mousestate
43 {
44 Point xy; /* mouse.xy */
45 int buttons; /* mouse.buttons */
46 int modifiers; /* state of physical buttons 2, 3, 4, 5 */
47 ulong counter; /* increments every update */
48 ulong msec; /* time of last event */
49 };
50
51 struct Mouseinfo
52 {
53 Lock;
54 Mousestate;
55 ulong lastcounter; /* value when /dev/mouse read */
56 ulong resize;
57 ulong lastresize;
58 Rendez r;
59 Ref;
60 QLock;
61 int open;
62 int inopen;
63 Mousestate queue[16]; /* circular buffer of click events */
64 int ri; /* read index into queue */
65 int wi; /* write index into queue */
66 uchar qfull; /* queue is full */
67 };
68
69 Mouseinfo mouse;
70 int mouseshifted;
71
72 int penmousechanged(void*);
73 static void penmousetrack(int b, int x, int y);
74
75 enum{
76 Qdir,
77 Qmouse,
78 Qmousein,
79 Qmousectl,
80 };
81
82 static Dirtab mousedir[]={
83 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
84 "mouse", {Qmouse}, 0, 0666,
85 "mousein", {Qmousein}, 0, 0220,
86 "mousectl", {Qmousectl}, 0, 0660,
87 };
88
89 enum
90 {
91 CMcalibrate,
92 CMswap,
93 };
94
95 static Cmdtab penmousecmd[] =
96 {
97 CMcalibrate, "calibrate", 0,
98 CMswap, "swap", 1,
99 };
100
101 static uchar buttonmap[8] = {
102 0, 1, 2, 3, 4, 5, 6, 7,
103 };
104 static int mouseswap;
105
106 extern Memimage* gscreen;
107
108 void
109 penbutton(int up, int b) {
110 // button 5 (side button) immediately causes an event
111 // when the pen is down (button 1), other buttons also
112 // cause events, allowing chording with button 1
113 if ((b & 0x20) || (mouse.buttons & 0x1)) {
114 if (up)
115 mouse.buttons &= ~b;
116 else
117 mouse.buttons |= b;
118 penmousetrack(mouse.buttons, -1, -1);
119 } else {
120 if (up)
121 mouse.modifiers &= ~b;
122 else
123 mouse.modifiers |= b;
124 }
125 }
126
127 void
128 pentrackxy(int x, int y) {
129
130 if (x == -1) {
131 /* pen up. associate with button 1 through 5 up */
132 mouse.buttons &= ~0x1f;
133 } else {
134 x = ((x*calibration.scalex)>>16) + calibration.transx;
135 y = ((y*calibration.scaley)>>16) + calibration.transy;
136 if ((mouse.buttons & 0x1f) == 0) {
137 if (mouse.modifiers)
138 mouse.buttons |= mouse.modifiers;
139 else
140 mouse.buttons |= 0x1;
141 }
142 }
143 penmousetrack(mouse.buttons, x, y);
144 }
145
146 static void
147 penmousereset(void)
148 {
149 if(!conf.monitor)
150 return;
151 }
152
153 static void
154 penmouseinit(void)
155 {
156 if(!conf.monitor)
157 return;
158 }
159
160 static Chan*
161 penmouseattach(char *spec)
162 {
163 if(!conf.monitor)
164 error(Egreg);
165 return devattach('m', spec);
166 }
167
168 static Walkqid*
169 penmousewalk(Chan *c, Chan *nc, char **name, int nname)
170 {
171 return devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
172 }
173
174 static int
175 penmousestat(Chan *c, uchar *db, int n)
176 {
177 return devstat(c, db, n, mousedir, nelem(mousedir), devgen);
178 }
179
180 static Chan*
181 penmouseopen(Chan *c, int omode)
182 {
183 switch((ulong)c->qid.path){
184 case Qdir:
185 if(omode != OREAD)
186 error(Eperm);
187 break;
188 case Qmouse:
189 lock(&mouse);
190 if(mouse.open){
191 unlock(&mouse);
192 error(Einuse);
193 }
194 mouse.open = 1;
195 mouse.ref++;
196 unlock(&mouse);
197 break;
198 case Qmousein:
199 /* error("disabled"); */
200 lock(&mouse);
201 if(mouse.inopen){
202 unlock(&mouse);
203 error(Einuse);
204 }
205 mouse.inopen = 1;
206 unlock(&mouse);
207 break;
208 default:
209 incref(&mouse);
210 }
211 c->mode = openmode(omode);
212 c->flag |= COPEN;
213 c->offset = 0;
214 return c;
215 }
216
217 static void
218 penmousecreate(Chan*, char*, int, ulong)
219 {
220 if(!conf.monitor)
221 error(Egreg);
222 error(Eperm);
223 }
224
225 static void
226 penmouseclose(Chan *c)
227 {
228 if(c->qid.path != Qdir && (c->flag&COPEN)){
229 lock(&mouse);
230 if(c->qid.path == Qmouse)
231 mouse.open = 0;
232 else if(c->qid.path == Qmousein){
233 mouse.inopen = 0;
234 unlock(&mouse);
235 return;
236 }
237 --mouse.ref;
238 unlock(&mouse);
239 }
240 }
241
242 static long
243 penmouseread(Chan *c, void *va, long n, vlong)
244 {
245 char buf[4*12+1];
246 static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
247 Mousestate m;
248
249 switch((ulong)c->qid.path){
250 case Qdir:
251 return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);
252
253 case Qmousectl:
254 sprint(buf, "c%11ld %11ld %11ld %11ld",
255 calibration.scalex, calibration.scaley,
256 calibration.transx, calibration.transy);
257 if(n > 1+4*12)
258 n = 1+4*12;
259 memmove(va, buf, n);
260 return n;
261
262 case Qmouse:
263 while(penmousechanged(0) == 0)
264 sleep(&mouse.r, penmousechanged, 0);
265
266 mouse.qfull = 0;
267
268 /*
269 * No lock of the indices is necessary here, because ri is only
270 * updated by us, and there is only one mouse reader
271 * at a time. I suppose that more than one process
272 * could try to read the fd at one time, but such behavior
273 * is degenerate and already violates the calling
274 * conventions for sleep above.
275 */
276 if(mouse.ri != mouse.wi) {
277 m = mouse.queue[mouse.ri];
278 if(++mouse.ri == nelem(mouse.queue))
279 mouse.ri = 0;
280 } else {
281 m = mouse.Mousestate;
282 }
283 sprint(buf, "m%11d %11d %11d %11lud",
284 m.xy.x, m.xy.y,
285 m.buttons,
286 m.msec);
287 mouse.lastcounter = m.counter;
288 if(n > 1+4*12)
289 n = 1+4*12;
290 if(mouse.lastresize != mouse.resize){
291 mouse.lastresize = mouse.resize;
292 buf[0] = 'r';
293 }
294 memmove(va, buf, n);
295 return n;
296 }
297 return 0;
298 }
299
300 static void
301 setbuttonmap(char* map)
302 {
303 int i, x, one, two, three;
304
305 one = two = three = 0;
306 for(i = 0; i < 3; i++){
307 if(map[i] == 0)
308 error(Ebadarg);
309 if(map[i] == '1'){
310 if(one)
311 error(Ebadarg);
312 one = 1<<i;
313 }
314 else if(map[i] == '2'){
315 if(two)
316 error(Ebadarg);
317 two = 1<<i;
318 }
319 else if(map[i] == '3'){
320 if(three)
321 error(Ebadarg);
322 three = 1<<i;
323 }
324 else
325 error(Ebadarg);
326 }
327 if(map[i])
328 error(Ebadarg);
329
330 memset(buttonmap, 0, 8);
331 for(i = 0; i < 8; i++){
332 x = 0;
333 if(i & 1)
334 x |= one;
335 if(i & 2)
336 x |= two;
337 if(i & 4)
338 x |= three;
339 buttonmap[x] = i;
340 }
341 }
342
343 static long
344 penmousewrite(Chan *c, void *va, long n, vlong)
345 {
346 char *p;
347 Point pt;
348 Cmdbuf *cb;
349 Cmdtab *ct;
350 char buf[64];
351 int b;
352
353 p = va;
354 switch((ulong)c->qid.path){
355 case Qdir:
356 error(Eisdir);
357
358 case Qmousectl:
359 cb = parsecmd(va, n);
360 if(waserror()){
361 free(cb);
362 nexterror();
363 }
364 ct = lookupcmd(cb, penmousecmd, nelem(penmousecmd));
365 switch(ct->index){
366 case CMswap:
367 if(mouseswap)
368 setbuttonmap("123");
369 else
370 setbuttonmap("321");
371 mouseswap ^= 1;
372 break;
373 case CMcalibrate:
374 if (cb->nf == 1) {
375 calibration.scalex = 1<<16;
376 calibration.scaley = 1<<16;
377 calibration.transx = 0;
378 calibration.transy = 0;
379 } else if (cb->nf == 5) {
380 if ((!isdigit(*cb->f[1]) && *cb->f[1] != '-')
381 || (!isdigit(*cb->f[2]) && *cb->f[2] != '-')
382 || (!isdigit(*cb->f[3]) && *cb->f[3] != '-')
383 || (!isdigit(*cb->f[4]) && *cb->f[4] != '-'))
384 error("bad syntax in control file message");
385 calibration.scalex = strtol(cb->f[1], nil, 0);
386 calibration.scaley = strtol(cb->f[2], nil, 0);
387 calibration.transx = strtol(cb->f[3], nil, 0);
388 calibration.transy = strtol(cb->f[4], nil, 0);
389 } else
390 cmderror(cb, Ecmdargs);
391 break;
392 }
393 free(cb);
394 poperror();
395 return n;
396
397 case Qmousein:
398 if(n > sizeof buf-1)
399 n = sizeof buf -1;
400 memmove(buf, va, n);
401 buf[n] = 0;
402 p = 0;
403 pt.x = strtol(buf+1, &p, 0);
404 if(p == 0)
405 error(Eshort);
406 pt.y = strtol(p, &p, 0);
407 if(p == 0)
408 error(Eshort);
409 b = strtol(p, &p, 0);
410 penmousetrack(b, pt.x, pt.y);
411 return n;
412
413 case Qmouse:
414 if(n > sizeof buf-1)
415 n = sizeof buf -1;
416 memmove(buf, va, n);
417 buf[n] = 0;
418 p = 0;
419 pt.x = strtoul(buf+1, &p, 0);
420 if(p == 0)
421 error(Eshort);
422 pt.y = strtoul(p, 0, 0);
423 qlock(&mouse);
424 if(ptinrect(pt, gscreen->r))
425 penmousetrack(mouse.buttons, pt.x, pt.y);
426 qunlock(&mouse);
427 return n;
428 }
429
430 error(Egreg);
431 return -1;
432 }
433
434 Dev penmousedevtab = {
435 'm',
436 "penmouse",
437
438 penmousereset,
439 penmouseinit,
440 devshutdown,
441 penmouseattach,
442 penmousewalk,
443 penmousestat,
444 penmouseopen,
445 penmousecreate,
446 penmouseclose,
447 penmouseread,
448 devbread,
449 penmousewrite,
450 devbwrite,
451 devremove,
452 devwstat,
453 };
454
455 /*
456 * called at interrupt level to update the structure and
457 * awaken any waiting procs.
458 */
459 static void
460 penmousetrack(int b, int x, int y)
461 {
462 int lastb;
463
464 if (x >= 0)
465 mouse.xy = Pt(x, y);
466 lastb = mouse.buttons;
467 mouse.buttons = b;
468 mouse.counter++;
469 mouse.msec = TK2MS(MACHP(0)->ticks);
470
471 /*
472 * if the queue fills, we discard the entire queue and don't
473 * queue any more events until a reader polls the mouse.
474 */
475 if(!mouse.qfull && lastb != b) { /* add to ring */
476 mouse.queue[mouse.wi] = mouse.Mousestate;
477 if(++mouse.wi == nelem(mouse.queue))
478 mouse.wi = 0;
479 if(mouse.wi == mouse.ri)
480 mouse.qfull = 1;
481 }
482 wakeup(&mouse.r);
483 drawactive(1);
484 resetsuspendtimer();
485 }
486
487 int
488 penmousechanged(void*)
489 {
490 return mouse.lastcounter != mouse.counter ||
491 mouse.lastresize != mouse.resize;
492 }
493
494 Point
495 penmousexy(void)
496 {
497 return mouse.xy;
498 }
499
500 /*
501 * notify reader that screen has been resized (ha!)
502 */
503 void
504 mouseresize(void)
505 {
506 mouse.resize++;
507 wakeup(&mouse.r);
508 }
509
Cache object: 8a2005c5ddebcbcc0d334a22af2b38bb
|