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 */
38 int track; /* dx & dy updated */
39 int redraw; /* update cursor on screen */
40 ulong lastcounter; /* value when /dev/mouse read */
49 Mousestate queue[16]; /* circular buffer of click events */
50 int ri; /* read index into queue */
51 int wi; /* write index into queue */
52 uchar qfull; /* queue is full */
64 static Cmdtab mousectlmsg[] =
66 CMbuttonmap, "buttonmap", 0,
67 CMscrollswap, "scrollswap", 0,
69 CMtwitch, "twitch", 0,
78 void Cursortocursor(Cursor*);
79 int mousechanged(void*);
81 static void mouseclock(void);
91 static Dirtab mousedir[]={
92 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
93 "cursor", {Qcursor}, 0, 0666,
94 "mouse", {Qmouse}, 0, 0666,
95 "mousein", {Qmousein}, 0, 0220,
96 "mousectl", {Qmousectl}, 0, 0220,
99 static uchar buttonmap[8] = {
100 0, 1, 2, 3, 4, 5, 6, 7,
102 static int mouseswap;
103 static int scrollswap;
104 static ulong mousetime;
106 extern Memimage* gscreen;
107 extern ulong kerndate;
116 Cursortocursor(&arrow);
117 /* redraw cursor about 30 times per second */
118 addclock0link(mouseclock, 33);
122 mousedevgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
126 rc = devgen(c, name, tab, ntab, i, dp);
128 dp->atime = mousetime;
139 Cursortocursor(&arrow);
141 mousetime = seconds();
145 mouseattach(char *spec)
149 return devattach('m', spec);
153 mousewalk(Chan *c, Chan *nc, char **name, int nname)
158 * We use devgen() and not mousedevgen() here
159 * see "Ugly problem" in dev.c/devwalk()
161 wq = devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
162 if(wq != nil && wq->clone != c && wq->clone != nil && (wq->clone->qid.type&QTDIR)==0)
168 mousestat(Chan *c, uchar *db, int n)
170 return devstat(c, db, n, mousedir, nelem(mousedir), mousedevgen);
174 mouseopen(Chan *c, int omode)
176 switch((ulong)c->qid.path){
189 mouse.lastresize = mouse.resize;
199 c->mode = openmode(omode);
206 mousecreate(Chan*, char*, int, ulong)
217 if((c->qid.type&QTDIR)==0 && (c->flag&COPEN)){
219 if(c->qid.path == Qmouse)
221 else if(c->qid.path == Qmousein){
225 if(--mouse.ref == 0){
228 Cursortocursor(&arrow);
237 mouseread(Chan *c, void *va, long n, vlong off)
241 static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
247 switch((ulong)c->qid.path){
249 return devdirread(c, va, n, mousedir, nelem(mousedir), mousedevgen);
258 BPLONG(p+0, curs.offset.x);
259 BPLONG(p+4, curs.offset.y);
260 memmove(p+8, curs.clr, 2*16);
261 memmove(p+40, curs.set, 2*16);
266 while(mousechanged(0) == 0)
267 sleep(&mouse.r, mousechanged, 0);
270 mousetime = seconds();
273 * No lock of the indices is necessary here, because ri is only
274 * updated by us, and there is only one mouse reader
275 * at a time. I suppose that more than one process
276 * could try to read the fd at one time, but such behavior
277 * is degenerate and already violates the calling
278 * conventions for sleep above.
280 if(mouse.ri != mouse.wi) {
281 m = mouse.queue[mouse.ri];
282 if(++mouse.ri == nelem(mouse.queue))
285 while(!canlock(&cursor))
286 tsleep(&up->sleep, return0, 0, TK2MS(1));
288 m = mouse.Mousestate;
292 b = buttonmap[m.buttons&7];
293 /* put buttons 4 and 5 back in */
294 b |= m.buttons & (3<<3);
300 sprint(buf, "m%11d %11d %11d %11lud ",
304 mouse.lastcounter = m.counter;
307 if(mouse.lastresize != mouse.resize){
308 mouse.lastresize = mouse.resize;
318 setbuttonmap(char* map)
320 int i, x, one, two, three;
322 one = two = three = 0;
323 for(i = 0; i < 3; i++){
331 else if(map[i] == '2'){
336 else if(map[i] == '3'){
347 memset(buttonmap, 0, 8);
348 for(i = 0; i < 8; i++){
361 mousewrite(Chan *c, void *va, long n, vlong)
371 switch((ulong)c->qid.path){
379 Cursortocursor(&arrow);
382 curs.offset.x = BGLONG(p+0);
383 curs.offset.y = BGLONG(p+4);
384 memmove(curs.clr, p+8, 2*16);
385 memmove(curs.set, p+40, 2*16);
386 Cursortocursor(&curs);
396 cb = parsecmd(va, n);
402 ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
421 setbuttonmap(cb->f[1]);
443 pt.x = strtol(buf+1, &p, 0);
446 pt.y = strtol(p, &p, 0);
449 b = strtol(p, &p, 0);
450 msec = strtol(p, &p, 0);
452 msec = TK2MS(MACHP(0)->ticks);
454 absmousetrack(pt.x, pt.y, b, msec);
456 mousetrack(pt.x, pt.y, b, msec);
465 pt.x = strtoul(buf+1, &p, 0);
468 pt.y = strtoul(p, 0, 0);
470 if(ptinrect(pt, gscreen->r)){
506 Cursortocursor(Cursor *c)
509 memmove(&cursor.Cursor, c, sizeof(Cursor));
516 * called by the clock routine to redraw the cursor
522 mousetrack(mouse.dx, mouse.dy, mouse.buttons, TK2MS(MACHP(0)->ticks));
527 if(mouse.redraw && canlock(&cursor)){
530 mouse.redraw = cursoron(0);
552 x = 6 + (mouse.acceleration>>2);
555 x = 9 + (mouse.acceleration>>1);
565 * called at interrupt level to update the structure and
566 * awaken any waiting procs.
569 mousetrack(int dx, int dy, int b, int msec)
576 if(mouse.acceleration){
581 if(x < gscreen->clipr.min.x)
582 x = gscreen->clipr.min.x;
583 if(x >= gscreen->clipr.max.x)
584 x = gscreen->clipr.max.x;
586 if(y < gscreen->clipr.min.y)
587 y = gscreen->clipr.min.y;
588 if(y >= gscreen->clipr.max.y)
589 y = gscreen->clipr.max.y;
591 lastb = mouse.buttons;
599 * if the queue fills, we discard the entire queue and don't
600 * queue any more events until a reader polls the mouse.
602 if(!mouse.qfull && lastb != b) { /* add to ring */
603 mouse.queue[mouse.wi] = mouse.Mousestate;
604 if(++mouse.wi == nelem(mouse.queue))
606 if(mouse.wi == mouse.ri)
614 absmousetrack(int x, int y, int b, int msec)
621 if(x < gscreen->clipr.min.x)
622 x = gscreen->clipr.min.x;
623 if(x >= gscreen->clipr.max.x)
624 x = gscreen->clipr.max.x;
625 if(y < gscreen->clipr.min.y)
626 y = gscreen->clipr.min.y;
627 if(y >= gscreen->clipr.max.y)
628 y = gscreen->clipr.max.y;
630 lastb = mouse.buttons;
638 * if the queue fills, we discard the entire queue and don't
639 * queue any more events until a reader polls the mouse.
641 if(!mouse.qfull && lastb != b) { /* add to ring */
642 mouse.queue[mouse.wi] = mouse.Mousestate;
643 if(++mouse.wi == nelem(mouse.queue))
645 if(mouse.wi == mouse.ri)
653 * microsoft 3 button, 7 bit bytes
655 * byte 0 - 1 L R Y7 Y6 X7 X6
656 * byte 1 - 0 X5 X4 X3 X2 X1 X0
657 * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0
658 * byte 3 - 0 M x x x x x (optional)
660 * shift & right button is the same as middle button (for 2 button mice)
663 m3mouseputc(Queue*, int c)
668 static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 3 };
670 int dx, dy, newbuttons;
671 static ulong lasttick;
674 /* Resynchronize in stream with timing. */
676 if(TK2SEC(m - lasttick) > 2)
682 * an extra byte comes for middle button motion.
683 * only two possible values for the extra byte.
685 if(c == 0x00 || c == 0x20){
686 /* an extra byte gets sent for the middle button */
687 middle = (c&0x20) ? 2 : 0;
688 newbuttons = (mouse.buttons & ~2) | middle;
689 mousetrack(0, 0, newbuttons, TK2MS(MACHP(0)->ticks));
696 newbuttons = middle | b[(msg[0]>>4)&3 | (mouseshifted ? 4 : 0)];
697 x = (msg[0]&0x3)<<14;
698 dx = (x>>8) | msg[1];
699 x = (msg[0]&0xc)<<12;
700 dy = (x>>8) | msg[2];
701 mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks));
707 * microsoft intellimouse 3 buttons + scroll
708 * byte 0 - 1 L R Y7 Y6 X7 X6
709 * byte 1 - 0 X5 X4 X3 X2 X1 X0
710 * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0
711 * byte 3 - 0 0 M % % % %
713 * %: 0xf => U , 0x1 => D
721 m5mouseputc(Queue*, int c)
725 static ulong lasttick;
728 /* Resynchronize in stream with timing. */
730 if(TK2SEC(m - lasttick) > 2)
734 msg[nb++] = c & 0x7f;
736 schar dx,dy,newbuttons;
737 dx = msg[1] | (msg[0] & 0x3) << 6;
738 dy = msg[2] | (msg[0] & 0xc) << 4;
740 (msg[0] & 0x10) >> (mouseshifted ? 3 : 2)
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));
752 * Logitech 5 byte packed binary mouse format, 8 bit bytes
754 * shift & right button is the same as middle button (for 2 button mice)
757 mouseputc(Queue*, int c)
761 static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 3, 3, 7};
762 int dx, dy, newbuttons;
763 static ulong lasttick;
766 /* Resynchronize in stream with timing. */
768 if(TK2SEC(m - lasttick) > 2)
776 msg[nb] |= ~0xFF; /* sign extend */
778 newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)];
780 dy = -(msg[2]+msg[4]);
781 mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks));
790 return mouse.lastcounter != mouse.counter ||
791 mouse.lastresize != mouse.resize;
801 mouseaccelerate(int x)
803 mouse.acceleration = x;
804 if(mouse.acceleration < 3)
807 mouse.maxacc = mouse.acceleration;
811 * notify reader that screen has been resized