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 14 enum { 15 ScrollUp = 0x08, 16 ScrollDown = 0x10, 17 ScrollLeft = 0x20, 18 ScrollRight = 0x40, 19 }; 20 21 typedef struct Mouseinfo Mouseinfo; 22 typedef struct Mousestate Mousestate; 23 24 struct Mousestate 25 { 26 Point xy; /* mouse.xy */ 27 int buttons; /* mouse.buttons */ 28 ulong counter; /* increments every update */ 29 ulong msec; /* time of last event */ 30 }; 31 32 struct Mouseinfo 33 { 34 Lock; 35 Mousestate; 36 int dx; 37 int dy; 38 int track; /* dx & dy updated */ 39 int redraw; /* update cursor on screen */ 40 ulong lastcounter; /* value when /dev/mouse read */ 41 Rendez r; 42 Ref; 43 QLock; 44 int open; 45 int inopen; 46 int acceleration; 47 int maxacc; 48 Mousestate queue[16]; /* circular buffer of click events */ 49 int ri; /* read index into queue */ 50 int wi; /* write index into queue */ 51 uchar qfull; /* queue is full */ 52 }; 53 54 enum 55 { 56 CMbuttonmap, 57 CMscrollswap, 58 CMswap, 59 CMwildcard, 60 }; 61 62 static Cmdtab mousectlmsg[] = 63 { 64 CMbuttonmap, "buttonmap", 0, 65 CMscrollswap, "scrollswap", 0, 66 CMswap, "swap", 1, 67 CMwildcard, "*", 0, 68 }; 69 70 Mouseinfo mouse; 71 Cursorinfo cursor; 72 int mouseshifted; 73 Cursor curs; 74 75 void Cursortocursor(Cursor*); 76 int mousechanged(void*); 77 static void mouseclock(void); 78 79 enum{ 80 Qdir, 81 Qcursor, 82 Qmouse, 83 Qmousein, 84 Qmousectl, 85 }; 86 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, 93 }; 94 95 static uchar buttonmap[8] = { 96 0, 1, 2, 3, 4, 5, 6, 7, 97 }; 98 static int mouseswap; 99 static int scrollswap; 100 extern Memimage* gscreen; 101 102 static void 103 mousereset(void) 104 { 105 if(!conf.monitor) 106 return; 107 108 curs = arrow; 109 Cursortocursor(&arrow); 110 /* redraw cursor about 30 times per second */ 111 addclock0link(mouseclock, 33); 112 } 113 114 static void 115 mouseinit(void) 116 { 117 if(!conf.monitor) 118 return; 119 120 curs = arrow; 121 Cursortocursor(&arrow); 122 cursoron(1); 123 } 124 125 static Chan* 126 mouseattach(char *spec) 127 { 128 if(!conf.monitor) 129 error(Egreg); 130 return devattach('m', spec); 131 } 132 133 static Walkqid* 134 mousewalk(Chan *c, Chan *nc, char **name, int nname) 135 { 136 Walkqid *wq; 137 138 wq = devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen); 139 if(wq != nil && wq->clone != c && wq->clone != nil && (wq->clone->qid.type&QTDIR)==0) 140 incref(&mouse); 141 return wq; 142 } 143 144 static int 145 mousestat(Chan *c, uchar *db, int n) 146 { 147 return devstat(c, db, n, mousedir, nelem(mousedir), devgen); 148 } 149 150 static Chan* 151 mouseopen(Chan *c, int omode) 152 { 153 switch((ulong)c->qid.path){ 154 case Qdir: 155 if(omode != OREAD) 156 error(Eperm); 157 break; 158 case Qmouse: 159 lock(&mouse); 160 if(mouse.open){ 161 unlock(&mouse); 162 error(Einuse); 163 } 164 mouse.open = 1; 165 mouse.ref++; 166 unlock(&mouse); 167 break; 168 case Qmousein: 169 if(!iseve()) 170 error(Eperm); 171 lock(&mouse); 172 if(mouse.inopen){ 173 unlock(&mouse); 174 error(Einuse); 175 } 176 mouse.inopen = 1; 177 unlock(&mouse); 178 break; 179 default: 180 incref(&mouse); 181 } 182 c->mode = openmode(omode); 183 c->flag |= COPEN; 184 c->offset = 0; 185 return c; 186 } 187 188 static void 189 mousecreate(Chan*, char*, int, ulong) 190 { 191 if(!conf.monitor) 192 error(Egreg); 193 error(Eperm); 194 } 195 196 static void 197 mouseclose(Chan *c) 198 { 199 if((c->qid.type&QTDIR)==0 && (c->flag&COPEN)){ 200 lock(&mouse); 201 if(c->qid.path == Qmouse) 202 mouse.open = 0; 203 else if(c->qid.path == Qmousein){ 204 mouse.inopen = 0; 205 unlock(&mouse); 206 return; 207 } 208 if(--mouse.ref == 0){ 209 cursoroff(1); 210 curs = arrow; 211 Cursortocursor(&arrow); 212 cursoron(1); 213 } 214 unlock(&mouse); 215 } 216 } 217 218 219 static long 220 mouseread(Chan *c, void *va, long n, vlong off) 221 { 222 char buf[1+4*12+1]; 223 uchar *p; 224 static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 }; 225 ulong offset = off; 226 Mousestate m; 227 int b; 228 229 p = va; 230 switch((ulong)c->qid.path){ 231 case Qdir: 232 return devdirread(c, va, n, mousedir, nelem(mousedir), devgen); 233 234 case Qcursor: 235 if(offset != 0) 236 return 0; 237 if(n < 2*4+2*2*16) 238 error(Eshort); 239 n = 2*4+2*2*16; 240 lock(&cursor); 241 BPLONG(p+0, curs.offset.x); 242 BPLONG(p+4, curs.offset.y); 243 memmove(p+8, curs.clr, 2*16); 244 memmove(p+40, curs.set, 2*16); 245 unlock(&cursor); 246 return n; 247 248 case Qmouse: 249 while(mousechanged(0) == 0) 250 sleep(&mouse.r, mousechanged, 0); 251 252 mouse.qfull = 0; 253 254 /* 255 * No lock of the indicies is necessary here, because ri is only 256 * updated by us, and there is only one mouse reader 257 * at a time. I suppose that more than one process 258 * could try to read the fd at one time, but such behavior 259 * is degenerate and already violates the calling 260 * conventions for sleep above. 261 */ 262 if(mouse.ri != mouse.wi) { 263 m = mouse.queue[mouse.ri]; 264 if(++mouse.ri == nelem(mouse.queue)) 265 mouse.ri = 0; 266 } else { 267 while(!canlock(&cursor)) 268 tsleep(&up->sleep, return0, 0, TK2MS(1)); 269 270 m = mouse.Mousestate; 271 unlock(&cursor); 272 } 273 274 b = buttonmap[m.buttons&7]; 275 /* put buttons 4 and 5 back in */ 276 b |= m.buttons & (3<<3); 277 if (scrollswap) 278 if (b == 8) 279 b = 16; 280 else if (b == 16) 281 b = 8; 282 sprint(buf, "m%11d %11d %11d %11lud ", 283 m.xy.x, m.xy.y, 284 b, 285 m.msec); 286 mouse.lastcounter = m.counter; 287 if(n > 1+4*12) 288 n = 1+4*12; 289 memmove(va, buf, n); 290 return n; 291 } 292 return 0; 293 } 294 295 static void 296 setbuttonmap(char* map) 297 { 298 int i, x, one, two, three; 299 300 one = two = three = 0; 301 for(i = 0; i < 3; i++){ 302 if(map[i] == 0) 303 error(Ebadarg); 304 if(map[i] == '1'){ 305 if(one) 306 error(Ebadarg); 307 one = 1<<i; 308 } 309 else if(map[i] == '2'){ 310 if(two) 311 error(Ebadarg); 312 two = 1<<i; 313 } 314 else if(map[i] == '3'){ 315 if(three) 316 error(Ebadarg); 317 three = 1<<i; 318 } 319 else 320 error(Ebadarg); 321 } 322 if(map[i]) 323 error(Ebadarg); 324 325 memset(buttonmap, 0, 8); 326 for(i = 0; i < 8; i++){ 327 x = 0; 328 if(i & 1) 329 x |= one; 330 if(i & 2) 331 x |= two; 332 if(i & 4) 333 x |= three; 334 buttonmap[x] = i; 335 } 336 } 337 338 static long 339 mousewrite(Chan *c, void *va, long n, vlong) 340 { 341 char *p; 342 Point pt; 343 Cmdbuf *cb; 344 Cmdtab *ct; 345 char buf[64]; 346 int b, msec; 347 348 p = va; 349 switch((ulong)c->qid.path){ 350 case Qdir: 351 error(Eisdir); 352 353 case Qcursor: 354 cursoroff(1); 355 if(n < 2*4+2*2*16){ 356 curs = arrow; 357 Cursortocursor(&arrow); 358 }else{ 359 n = 2*4+2*2*16; 360 curs.offset.x = BGLONG(p+0); 361 curs.offset.y = BGLONG(p+4); 362 memmove(curs.clr, p+8, 2*16); 363 memmove(curs.set, p+40, 2*16); 364 Cursortocursor(&curs); 365 } 366 qlock(&mouse); 367 mouse.redraw = 1; 368 mouseclock(); 369 qunlock(&mouse); 370 cursoron(1); 371 return n; 372 373 case Qmousectl: 374 cb = parsecmd(va, n); 375 if(waserror()){ 376 free(cb); 377 nexterror(); 378 } 379 380 ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg)); 381 382 switch(ct->index){ 383 case CMswap: 384 if(mouseswap) 385 setbuttonmap("123"); 386 else 387 setbuttonmap("321"); 388 mouseswap ^= 1; 389 break; 390 391 case CMscrollswap: 392 scrollswap ^= 1; 393 break; 394 395 case CMbuttonmap: 396 if(cb->nf == 1) 397 setbuttonmap("123"); 398 else 399 setbuttonmap(cb->f[1]); 400 break; 401 402 case CMwildcard: 403 mousectl(cb); 404 break; 405 } 406 407 free(cb); 408 poperror(); 409 return n; 410 411 case Qmousein: 412 if(n > sizeof buf-1) 413 n = sizeof buf -1; 414 memmove(buf, va, n); 415 buf[n] = 0; 416 p = 0; 417 pt.x = strtol(buf+1, &p, 0); 418 if(p == 0) 419 error(Eshort); 420 pt.y = strtol(p, &p, 0); 421 if(p == 0) 422 error(Eshort); 423 b = strtol(p, &p, 0); 424 msec = strtol(p, &p, 0); 425 if(msec == 0) 426 msec = TK2MS(MACHP(0)->ticks); 427 mousetrack(pt.x, pt.y, b, msec); 428 return n; 429 430 case Qmouse: 431 if(n > sizeof buf-1) 432 n = sizeof buf -1; 433 memmove(buf, va, n); 434 buf[n] = 0; 435 p = 0; 436 pt.x = strtoul(buf+1, &p, 0); 437 if(p == 0) 438 error(Eshort); 439 pt.y = strtoul(p, 0, 0); 440 qlock(&mouse); 441 if(ptinrect(pt, gscreen->r)){ 442 mouse.xy = pt; 443 mouse.redraw = 1; 444 mouse.track = 1; 445 mouseclock(); 446 } 447 qunlock(&mouse); 448 return n; 449 } 450 451 error(Egreg); 452 return -1; 453 } 454 455 Dev mousedevtab = { 456 'm', 457 "mouse", 458 459 mousereset, 460 mouseinit, 461 devshutdown, 462 mouseattach, 463 mousewalk, 464 mousestat, 465 mouseopen, 466 mousecreate, 467 mouseclose, 468 mouseread, 469 devbread, 470 mousewrite, 471 devbwrite, 472 devremove, 473 devwstat, 474 }; 475 476 void 477 Cursortocursor(Cursor *c) 478 { 479 lock(&cursor); 480 memmove(&cursor.Cursor, c, sizeof(Cursor)); 481 setcursor(c); 482 unlock(&cursor); 483 } 484 485 486 /* 487 * called by the clock routine to redraw the cursor 488 */ 489 static void 490 mouseclock(void) 491 { 492 if(mouse.track){ 493 mousetrack(mouse.dx, mouse.dy, mouse.buttons, TK2MS(MACHP(0)->ticks)); 494 mouse.track = 0; 495 mouse.dx = 0; 496 mouse.dy = 0; 497 } 498 if(mouse.redraw && canlock(&cursor)){ 499 mouse.redraw = 0; 500 cursoroff(0); 501 mouse.redraw = cursoron(0); 502 unlock(&cursor); 503 } 504 drawactive(0); 505 } 506 507 static int 508 scale(int x) 509 { 510 int sign = 1; 511 512 if(x < 0){ 513 sign = -1; 514 x = -x; 515 } 516 switch(x){ 517 case 0: 518 case 1: 519 case 2: 520 case 3: 521 break; 522 case 4: 523 x = 6 + (mouse.acceleration>>2); 524 break; 525 case 5: 526 x = 9 + (mouse.acceleration>>1); 527 break; 528 default: 529 x *= mouse.maxacc; 530 break; 531 } 532 return sign*x; 533 } 534 535 /* 536 * called at interrupt level to update the structure and 537 * awaken any waiting procs. 538 */ 539 void 540 mousetrack(int dx, int dy, int b, int msec) 541 { 542 int x, y, lastb; 543 544 if(gscreen==nil) 545 return; 546 547 if(mouse.acceleration){ 548 dx = scale(dx); 549 dy = scale(dy); 550 } 551 x = mouse.xy.x + dx; 552 if(x < gscreen->clipr.min.x) 553 x = gscreen->clipr.min.x; 554 if(x >= gscreen->clipr.max.x) 555 x = gscreen->clipr.max.x; 556 y = mouse.xy.y + dy; 557 if(y < gscreen->clipr.min.y) 558 y = gscreen->clipr.min.y; 559 if(y >= gscreen->clipr.max.y) 560 y = gscreen->clipr.max.y; 561 562 lastb = mouse.buttons; 563 mouse.xy = Pt(x, y); 564 mouse.buttons = b; 565 mouse.redraw = 1; 566 mouse.counter++; 567 mouse.msec = msec; 568 569 /* 570 * if the queue fills, we discard the entire queue and don't 571 * queue any more events until a reader polls the mouse. 572 */ 573 if(!mouse.qfull && lastb != b) { /* add to ring */ 574 mouse.queue[mouse.wi] = mouse.Mousestate; 575 if(++mouse.wi == nelem(mouse.queue)) 576 mouse.wi = 0; 577 if(mouse.wi == mouse.ri) 578 mouse.qfull = 1; 579 } 580 wakeup(&mouse.r); 581 drawactive(1); 582 } 583 584 /* 585 * microsoft 3 button, 7 bit bytes 586 * 587 * byte 0 - 1 L R Y7 Y6 X7 X6 588 * byte 1 - 0 X5 X4 X3 X2 X1 X0 589 * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0 590 * byte 3 - 0 M x x x x x (optional) 591 * 592 * shift & right button is the same as middle button (for 2 button mice) 593 */ 594 int 595 m3mouseputc(Queue*, int c) 596 { 597 static uchar msg[3]; 598 static int nb; 599 static int middle; 600 static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 3 }; 601 short x; 602 int dx, dy, newbuttons; 603 604 if(nb==0){ 605 /* 606 * an extra byte comes for middle button motion. 607 * only two possible values for the extra byte. 608 */ 609 if(c == 0x00 || c == 0x20){ 610 /* an extra byte gets sent for the middle button */ 611 middle = (c&0x20) ? 2 : 0; 612 newbuttons = (mouse.buttons & ~2) | middle; 613 mousetrack(0, 0, newbuttons, TK2MS(MACHP(0)->ticks)); 614 return 0; 615 } 616 } 617 msg[nb] = c; 618 if(++nb == 3){ 619 nb = 0; 620 newbuttons = middle | b[(msg[0]>>4)&3 | (mouseshifted ? 4 : 0)]; 621 x = (msg[0]&0x3)<<14; 622 dx = (x>>8) | msg[1]; 623 x = (msg[0]&0xc)<<12; 624 dy = (x>>8) | msg[2]; 625 mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks)); 626 } 627 return 0; 628 } 629 630 /* 631 * microsoft intellimouse 3 buttons + scroll 632 * byte 0 - 1 L R Y7 Y6 X7 X6 633 * byte 1 - 0 X5 X4 X3 X2 X1 X0 634 * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0 635 * byte 3 - 0 0 M % % % % 636 * 637 * %: 0xf => U , 0x1 => D 638 * 639 * L: left 640 * R: right 641 * U: up 642 * D: down 643 */ 644 int 645 m5mouseputc(Queue*, int c) 646 { 647 static uchar msg[3]; 648 static int nb; 649 msg[nb++] = c & 0x7f; 650 if (nb == 4) { 651 schar dx,dy,newbuttons; 652 dx = msg[1] | (msg[0] & 0x3) << 6; 653 dy = msg[2] | (msg[0] & 0xc) << 4; 654 newbuttons = 655 (msg[0] & 0x10) >> (mouseshifted ? 3 : 2) 656 | (msg[0] & 0x20) >> 5 657 | ( msg[3] == 0x10 ? 0x02 : 658 msg[3] == 0x0f ? ScrollUp : 659 msg[3] == 0x01 ? ScrollDown : 0 ); 660 mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks)); 661 nb = 0; 662 } 663 return 0; 664 } 665 666 /* 667 * Logitech 5 byte packed binary mouse format, 8 bit bytes 668 * 669 * shift & right button is the same as middle button (for 2 button mice) 670 */ 671 int 672 mouseputc(Queue*, int c) 673 { 674 static short msg[5]; 675 static int nb; 676 static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 3, 3, 7}; 677 int dx, dy, newbuttons; 678 679 if((c&0xF0) == 0x80) 680 nb=0; 681 msg[nb] = c; 682 if(c & 0x80) 683 msg[nb] |= ~0xFF; /* sign extend */ 684 if(++nb == 5){ 685 newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)]; 686 dx = msg[1]+msg[3]; 687 dy = -(msg[2]+msg[4]); 688 mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks)); 689 nb = 0; 690 } 691 return 0; 692 } 693 694 int 695 mousechanged(void*) 696 { 697 return mouse.lastcounter != mouse.counter; 698 } 699 700 Point 701 mousexy(void) 702 { 703 return mouse.xy; 704 } 705 706 void 707 mouseaccelerate(int x) 708 { 709 mouse.acceleration = x; 710 if(mouse.acceleration < 3) 711 mouse.maxacc = 2; 712 else 713 mouse.maxacc = mouse.acceleration; 714 } 715