devmouse.c 12 KB

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