devmouse.c 11 KB

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