2 #include "../port/lib.h"
6 #include "../port/error.h"
21 typedef struct Mouseinfo Mouseinfo;
22 typedef struct Mousestate Mousestate;
26 Point xy; /* mouse.xy */
27 int buttons; /* mouse.buttons */
28 ulong counter; /* increments every update */
29 ulong msec; /* time of last event */
36 int inbuttons; /* buttons from /dev/mousein */
37 int redraw; /* update cursor on screen */
38 Rendez redrawr; /* wait for cursor screen updates */
39 ulong lastcounter; /* value when /dev/mouse read */
40 int resize; /* generate resize event */
46 Mousestate queue[16]; /* circular buffer of click events */
47 ulong ri; /* read index into queue */
48 ulong wi; /* write index into queue */
62 static Cmdtab mousectlmsg[] =
64 CMbuttonmap, "buttonmap", 0,
65 CMscrollswap, "scrollswap", 0,
68 CMblanktime, "blanktime", 2,
69 CMtwitch, "twitch", 1,
77 void Cursortocursor(Cursor*);
78 void mouseblankscreen(int);
79 int mousechanged(void*);
80 void mouseredraw(void);
90 static Dirtab mousedir[]={
91 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
92 "cursor", {Qcursor}, 0, 0666,
93 "mouse", {Qmouse}, 0, 0666,
94 "mousein", {Qmousein}, 0, 0220,
95 "mousectl", {Qmousectl}, 0, 0220,
98 static uchar buttonmap[8] = {
99 0, 1, 2, 3, 4, 5, 6, 7,
101 static int mouseswap;
102 static int scrollswap;
103 static ulong mousetime;
104 static ulong blanktime = 30; /* in minutes; a half hour */
106 extern Memimage* gscreen;
110 { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
111 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
112 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
113 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
115 { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
116 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
117 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
118 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
129 Cursortocursor(&arrow);
133 mousedevgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
137 rc = devgen(c, name, tab, ntab, i, dp);
139 dp->atime = mousetime;
143 static void mouseproc(void*);
152 Cursortocursor(&arrow);
154 mousetime = seconds();
156 kproc("mouse", mouseproc, 0);
160 mouseattach(char *spec)
164 return devattach('m', spec);
168 mousewalk(Chan *c, Chan *nc, char **name, int nname)
171 * We use devgen() and not mousedevgen() here
172 * see "Ugly problem" in dev.c/devwalk()
174 return devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
178 mousestat(Chan *c, uchar *db, int n)
180 return devstat(c, db, n, mousedir, nelem(mousedir), mousedevgen);
184 mouseopen(Chan *c, int omode)
188 mode = openmode(omode);
189 switch((ulong)c->qid.path){
197 c->aux = malloc(sizeof(Mousestate));
202 if(tas(&mouse.open) != 0)
204 mouse.lastcounter = mouse.counter;
206 mousetime = seconds();
220 if((c->qid.type&QTDIR)!=0 || (c->flag&COPEN)==0)
222 switch((ulong)c->qid.path){
224 mouse.inbuttons &= ~((Mousestate*)c->aux)->buttons;
225 free(c->aux); /* Mousestate */
233 if(decref(&mouse) != 0)
237 Cursortocursor(&arrow);
244 mouseread(Chan *c, void *va, long n, vlong off)
253 switch((ulong)c->qid.path){
255 return devdirread(c, va, n, mousedir, nelem(mousedir), mousedevgen);
263 BPLONG(p+0, curs.offset.x);
264 BPLONG(p+4, curs.offset.y);
265 memmove(p+8, curs.clr, 2*16);
266 memmove(p+40, curs.set, 2*16);
270 while(!mousechanged(nil)){
271 tsleep(&mouse.r, mousechanged, nil, 30*1000);
272 if(blanktime && !mousechanged(nil) &&
273 (seconds() - mousetime) >= blanktime*60)
276 mousetime = seconds();
280 if(mouse.ri != mouse.wi)
281 m = mouse.queue[mouse.ri++ % nelem(mouse.queue)];
283 m = mouse.Mousestate;
286 b = buttonmap[m.buttons&7];
287 /* put buttons 4 and 5 back in */
288 b |= m.buttons & (3<<3);
294 sprint(buf, "m%11d %11d %11d %11lud ",
295 m.xy.x, m.xy.y, b, m.msec);
297 mouse.lastcounter = m.counter;
312 setbuttonmap(char* map)
314 int i, x, one, two, three;
316 one = two = three = 0;
317 for(i = 0; i < 3; i++){
325 else if(map[i] == '2'){
330 else if(map[i] == '3'){
341 memset(buttonmap, 0, 8);
342 for(i = 0; i < 8; i++){
355 mousewrite(Chan *c, void *va, long n, vlong)
366 switch((ulong)c->qid.path){
374 Cursortocursor(&arrow);
377 curs.offset.x = BGLONG(p+0);
378 curs.offset.y = BGLONG(p+4);
379 memmove(curs.clr, p+8, 2*16);
380 memmove(curs.set, p+40, 2*16);
381 Cursortocursor(&curs);
387 cb = parsecmd(va, n);
393 ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
412 setbuttonmap(cb->f[1]);
420 blanktime = strtoul(cb->f[1], 0, 0);
423 mousetime = seconds();
442 pt.x = strtol(buf+1, &p, 0);
445 pt.y = strtol(p, &p, 0);
448 b = strtol(p, &p, 0);
449 msec = strtol(p, 0, 0);
451 msec = TK2MS(MACHP(0)->ticks);
457 m = (Mousestate*)c->aux;
462 mouse.inbuttons = (m->buttons & b) | (mouse.inbuttons & ~b);
463 b = mouse.buttons & ~b;
470 absmousetrack(pt.x, pt.y, b, msec);
472 mousetrack(pt.x, pt.y, b, msec);
481 pt.x = strtol(buf+1, &p, 0);
484 pt.y = strtol(p, 0, 0);
485 absmousetrack(pt.x, pt.y, mouse.buttons, TK2MS(MACHP(0)->ticks));
515 Cursortocursor(Cursor *c)
519 memmove(&cursor.Cursor, c, sizeof(Cursor));
526 mouseblankscreen(int blank)
533 if(blanked != blank){
543 return mouse.redraw != 0;
547 * process that redraws the cursor
555 sleep(&mouse.redrawr, shouldredraw, nil);
578 x = 6 + (mouse.acceleration>>2);
581 x = 9 + (mouse.acceleration>>1);
591 * called at interrupt level to update the structure and
592 * awaken any waiting procs.
595 mousetrack(int dx, int dy, int b, ulong msec)
597 if(mouse.acceleration){
601 absmousetrack(mouse.xy.x + dx, mouse.xy.y + dy, b, msec);
605 absmousetrack(int x, int y, int b, ulong msec)
612 if(x < gscreen->clipr.min.x)
613 x = gscreen->clipr.min.x;
614 if(x >= gscreen->clipr.max.x)
615 x = gscreen->clipr.max.x-1;
616 if(y < gscreen->clipr.min.y)
617 y = gscreen->clipr.min.y;
618 if(y >= gscreen->clipr.max.y)
619 y = gscreen->clipr.max.y-1;
624 lastb = mouse.buttons;
625 b |= mouse.inbuttons;
631 * if the queue fills, don't queue any more events until a
632 * reader polls the mouse.
634 if(b != lastb && (mouse.wi-mouse.ri) < nelem(mouse.queue))
635 mouse.queue[mouse.wi++ % nelem(mouse.queue)] = mouse.Mousestate;
646 static ulong lasttick;
656 * microsoft 3 button, 7 bit bytes
658 * byte 0 - 1 L R Y7 Y6 X7 X6
659 * byte 1 - 0 X5 X4 X3 X2 X1 X0
660 * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0
661 * byte 3 - 0 M x x x x x (optional)
663 * shift & right button is the same as middle button (for 2 button mice)
666 m3mouseputc(Queue*, int c)
671 static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 3 };
673 int dx, dy, newbuttons;
680 * an extra byte comes for middle button motion.
681 * only two possible values for the extra byte.
683 if(c == 0x00 || c == 0x20){
684 /* an extra byte gets sent for the middle button */
685 middle = (c&0x20) ? 2 : 0;
686 newbuttons = (mouse.buttons & ~2) | middle;
687 mousetrack(0, 0, newbuttons, TK2MS(MACHP(0)->ticks));
693 newbuttons = middle | b[(msg[0]>>4)&3];
694 x = (msg[0]&0x3)<<14;
695 dx = (x>>8) | msg[1];
696 x = (msg[0]&0xc)<<12;
697 dy = (x>>8) | msg[2];
698 mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks));
704 * microsoft intellimouse 3 buttons + scroll
705 * byte 0 - 1 L R Y7 Y6 X7 X6
706 * byte 1 - 0 X5 X4 X3 X2 X1 X0
707 * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0
708 * byte 3 - 0 0 M % % % %
710 * %: 0xf => U , 0x1 => D
718 m5mouseputc(Queue*, int c)
728 schar dx,dy,newbuttons;
729 dx = msg[1] | (msg[0] & 0x3) << 6;
730 dy = msg[2] | (msg[0] & 0xc) << 4;
733 | (msg[0] & 0x20) >> 5
734 | ( msg[3] == 0x10 ? 0x02 :
735 msg[3] == 0x0f ? ScrollUp :
736 msg[3] == 0x01 ? ScrollDown : 0 );
737 mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks));
743 * Logitech 5 byte packed binary mouse format, 8 bit bytes
745 * shift & right button is the same as middle button (for 2 button mice)
748 mouseputc(Queue*, int c)
752 static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 3, 3, 7};
753 int dx, dy, newbuttons;
755 if(lastms() > 500 || (c&0xF0) == 0x80)
759 msg[nb] |= ~0xFF; /* sign extend */
762 newbuttons = b[((msg[0]&7)^7)];
764 dy = -(msg[2]+msg[4]);
765 mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks));
773 return mouse.lastcounter != mouse.counter || mouse.resize != 0;
783 mouseaccelerate(int x)
785 mouse.acceleration = x;
786 if(mouse.acceleration < 3)
789 mouse.maxacc = mouse.acceleration;
793 * notify reader that screen has been resized
806 wakeup(&mouse.redrawr);