devmouse.c 13 KB

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