devmouse.c 12 KB

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