devmouse.c 12 KB

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