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,
75 void mouseblankscreen(int);
76 int mousechanged(void*);
77 void mouseredraw(void);
87 static Dirtab mousedir[]={
88 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
89 "cursor", {Qcursor}, 0, 0666,
90 "mouse", {Qmouse}, 0, 0666,
91 "mousein", {Qmousein}, 0, 0220,
92 "mousectl", {Qmousectl}, 0, 0220,
95 static uchar buttonmap[8] = {
96 0, 1, 2, 3, 4, 5, 6, 7,
99 static int scrollswap;
100 static ulong mousetime;
101 static ulong blanktime = 30; /* in minutes; a half hour */
103 extern Memimage* gscreen;
107 { 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
108 0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
109 0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
110 0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
112 { 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
113 0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
114 0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
115 0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
120 static void Cursortocursor(Cursor*);
123 mousedevgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
127 rc = devgen(c, name, tab, ntab, i, dp);
129 dp->atime = mousetime;
133 static void mouseproc(void*);
140 mousetime = seconds();
141 Cursortocursor(&arrow);
142 kproc("mouse", mouseproc, 0);
146 mouseattach(char *spec)
150 return devattach('m', spec);
154 mousewalk(Chan *c, Chan *nc, char **name, int nname)
157 * We use devgen() and not mousedevgen() here
158 * see "Ugly problem" in dev.c/devwalk()
160 return devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
164 mousestat(Chan *c, uchar *db, int n)
166 return devstat(c, db, n, mousedir, nelem(mousedir), mousedevgen);
170 mouseopen(Chan *c, int omode)
174 mode = openmode(omode);
175 switch((ulong)c->qid.path){
183 c->aux = malloc(sizeof(Mousestate));
188 if(tas(&mouse.open) != 0)
190 mouse.lastcounter = mouse.counter;
192 mousetime = seconds();
206 if((c->qid.type&QTDIR)!=0 || (c->flag&COPEN)==0)
208 switch((ulong)c->qid.path){
210 mouse.inbuttons &= ~((Mousestate*)c->aux)->buttons;
211 free(c->aux); /* Mousestate */
219 if(decref(&mouse) != 0)
221 Cursortocursor(&arrow);
227 mouseread(Chan *c, void *va, long n, vlong off)
237 switch((ulong)c->qid.path){
239 return devdirread(c, va, n, mousedir, nelem(mousedir), mousedevgen);
248 memmove(&curs, &cursor, sizeof(Cursor));
252 BPLONG(p+0, curs.offset.x);
253 BPLONG(p+4, curs.offset.y);
254 memmove(p+8, curs.clr, 2*16);
255 memmove(p+40, curs.set, 2*16);
259 while(!mousechanged(nil)){
260 tsleep(&mouse.r, mousechanged, nil, 30*1000);
261 if(blanktime && !mousechanged(nil) &&
262 (seconds() - mousetime) >= blanktime*60)
265 mousetime = seconds();
269 if(mouse.ri != mouse.wi)
270 m = mouse.queue[mouse.ri++ % nelem(mouse.queue)];
272 m = mouse.Mousestate;
275 b = buttonmap[m.buttons&7];
276 /* put buttons 4 and 5 back in */
277 b |= m.buttons & (3<<3);
283 sprint(buf, "m%11d %11d %11d %11ld ",
284 m.xy.x, m.xy.y, b, m.msec);
286 mouse.lastcounter = m.counter;
301 setbuttonmap(char* map)
303 int i, x, one, two, three;
305 one = two = three = 0;
306 for(i = 0; i < 3; i++){
312 else if(map[i] == '2'){
317 else if(map[i] == '3'){
328 memset(buttonmap, 0, 8);
329 for(i = 0; i < 8; i++){
341 void scmousetrack(int, int, int, ulong);
344 mousewrite(Chan *c, void *va, long n, vlong)
356 switch((ulong)c->qid.path){
362 Cursortocursor(&arrow);
366 curs.offset.x = BGLONG(p+0);
367 curs.offset.y = BGLONG(p+4);
368 memmove(curs.clr, p+8, 2*16);
369 memmove(curs.set, p+40, 2*16);
370 Cursortocursor(&curs);
374 cb = parsecmd(va, n);
380 ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
399 setbuttonmap(cb->f[1]);
407 blanktime = strtoul(cb->f[1], 0, 0);
410 mousetime = seconds();
429 pt.x = strtol(buf+1, &p, 0);
432 pt.y = strtol(p, &p, 0);
435 b = strtol(p, &p, 0);
436 msec = (ulong)strtoll(p, 0, 0);
438 msec = TK2MS(MACHP(0)->ticks);
444 m = (Mousestate*)c->aux;
449 mouse.inbuttons = (m->buttons & b) | (mouse.inbuttons & ~b);
450 b = mouse.buttons & ~b;
457 absmousetrack(pt.x, pt.y, b, msec);
458 else if(buf[0] == 'a')
459 scmousetrack(pt.x, pt.y, b, msec);
461 mousetrack(pt.x, pt.y, b, msec);
470 pt.x = strtol(buf+1, &p, 0);
473 pt.y = strtol(p, 0, 0);
474 absmousetrack(pt.x, pt.y, mouse.buttons, TK2MS(MACHP(0)->ticks));
504 Cursortocursor(Cursor *c)
508 memmove(&cursor, c, sizeof(Cursor));
515 mouseblankscreen(int blank)
522 if(blanked != blank){
532 return mouse.redraw != 0;
536 * process that redraws the cursor
544 sleep(&mouse.redrawr, shouldredraw, nil);
570 x = 6 + (mouse.acceleration>>2);
573 x = 9 + (mouse.acceleration>>1);
583 * called at interrupt level to update the structure and
584 * awaken any waiting procs.
587 mousetrack(int dx, int dy, int b, ulong msec)
589 if(mouse.acceleration){
593 absmousetrack(mouse.xy.x + dx, mouse.xy.y + dy, b, msec);
597 absmousetrack(int x, int y, int b, ulong msec)
604 if(x < gscreen->clipr.min.x)
605 x = gscreen->clipr.min.x;
606 if(x >= gscreen->clipr.max.x)
607 x = gscreen->clipr.max.x-1;
608 if(y < gscreen->clipr.min.y)
609 y = gscreen->clipr.min.y;
610 if(y >= gscreen->clipr.max.y)
611 y = gscreen->clipr.max.y-1;
616 lastb = mouse.buttons;
617 b |= mouse.inbuttons;
623 * if the queue fills, don't queue any more events until a
624 * reader polls the mouse.
626 if(b != lastb && (mouse.wi-mouse.ri) < nelem(mouse.queue))
627 mouse.queue[mouse.wi++ % nelem(mouse.queue)] = mouse.Mousestate;
636 scmousetrack(int x, int y, int b, ulong msec)
643 vx = (vlong)(uint)x * (gscreen->clipr.max.x - gscreen->clipr.min.x);
644 x = (vx + (1<<30) - (~vx>>31&1) >> 31) + gscreen->clipr.min.x;
645 vy = (vlong)(uint)y * (gscreen->clipr.max.y - gscreen->clipr.min.y);
646 y = (vy + (1<<30) - (~vy>>31&1) >> 31) + gscreen->clipr.min.y;
648 absmousetrack(x, y, b, msec);
654 static ulong lasttick;
664 * microsoft 3 button, 7 bit bytes
666 * byte 0 - 1 L R Y7 Y6 X7 X6
667 * byte 1 - 0 X5 X4 X3 X2 X1 X0
668 * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0
669 * byte 3 - 0 M x x x x x (optional)
671 * shift & right button is the same as middle button (for 2 button mice)
674 m3mouseputc(Queue*, int c)
679 static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 3 };
681 int dx, dy, newbuttons;
688 * an extra byte comes for middle button motion.
689 * only two possible values for the extra byte.
691 if(c == 0x00 || c == 0x20){
692 /* an extra byte gets sent for the middle button */
693 middle = (c&0x20) ? 2 : 0;
694 newbuttons = (mouse.buttons & ~2) | middle;
695 mousetrack(0, 0, newbuttons, TK2MS(MACHP(0)->ticks));
701 newbuttons = middle | b[(msg[0]>>4)&3];
702 x = (msg[0]&0x3)<<14;
703 dx = (x>>8) | msg[1];
704 x = (msg[0]&0xc)<<12;
705 dy = (x>>8) | msg[2];
706 mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks));
712 * microsoft intellimouse 3 buttons + scroll
713 * byte 0 - 1 L R Y7 Y6 X7 X6
714 * byte 1 - 0 X5 X4 X3 X2 X1 X0
715 * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0
716 * byte 3 - 0 0 M % % % %
718 * %: 0xf => U , 0x1 => D
726 m5mouseputc(Queue*, int c)
736 schar dx,dy,newbuttons;
737 dx = msg[1] | (msg[0] & 0x3) << 6;
738 dy = msg[2] | (msg[0] & 0xc) << 4;
741 | (msg[0] & 0x20) >> 5
742 | ( msg[3] == 0x10 ? 0x02 :
743 msg[3] == 0x0f ? ScrollUp :
744 msg[3] == 0x01 ? ScrollDown : 0 );
745 mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks));
751 * Logitech 5 byte packed binary mouse format, 8 bit bytes
753 * shift & right button is the same as middle button (for 2 button mice)
756 mouseputc(Queue*, int c)
760 static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 3, 3, 7};
761 int dx, dy, newbuttons;
763 if(lastms() > 500 || (c&0xF0) == 0x80)
767 msg[nb] |= ~0xFF; /* sign extend */
770 newbuttons = b[((msg[0]&7)^7)];
772 dy = -(msg[2]+msg[4]);
773 mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks));
781 return mouse.lastcounter != mouse.counter || mouse.resize != 0;
791 mouseaccelerate(int x)
793 mouse.acceleration = x;
794 if(mouse.acceleration < 3)
797 mouse.maxacc = mouse.acceleration;
801 * notify reader that screen has been resized
814 wakeup(&mouse.redrawr);