devmouse.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include "compat.h"
  12. #include "error.h"
  13. #define Image IMAGE
  14. #include <draw.h>
  15. #include <memdraw.h>
  16. #include <cursor.h>
  17. #include "screen.h"
  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. uint32_t counter; /* increments every update */
  25. uint32_t msec; /* time of last event */
  26. };
  27. struct Mouseinfo
  28. {
  29. Mousestate mst;
  30. int dx;
  31. int dy;
  32. int track; /* dx & dy updated */
  33. int redraw; /* update cursor on screen */
  34. uint32_t lastcounter; /* value when /dev/mouse read */
  35. Rendez r;
  36. Ref ref;
  37. QLock qlock;
  38. int open;
  39. int acceleration;
  40. int maxacc;
  41. Mousestate queue[16]; /* circular buffer of click events */
  42. int ri; /* read index into queue */
  43. int wi; /* write index into queue */
  44. uint8_t qfull; /* queue is full */
  45. };
  46. Mouseinfo mouse;
  47. Cursorinfo cursor;
  48. int mouseshifted;
  49. Cursor curs;
  50. void Cursortocursor(Cursor*);
  51. int mousechanged(void*);
  52. static void mouseclock(void);
  53. enum{
  54. Qdir,
  55. Qcursor,
  56. Qmouse,
  57. };
  58. static Dirtab mousedir[]={
  59. {".", {Qdir, 0, QTDIR}, 0, DMDIR|0555},
  60. {"cursor", {Qcursor}, 0, 0666},
  61. {"mouse", {Qmouse}, 0, 0666},
  62. };
  63. static uint8_t buttonmap[8] = {
  64. 0, 1, 2, 3, 4, 5, 6, 7,
  65. };
  66. extern Memimage* gscreen;
  67. extern void mousewarpnote(Point);
  68. static void
  69. mousereset(void)
  70. {
  71. curs = arrow;
  72. Cursortocursor(&arrow);
  73. }
  74. static void
  75. mouseinit(void)
  76. {
  77. cursoron(1);
  78. }
  79. static Chan*
  80. mouseattach(char *spec)
  81. {
  82. return devattach('m', spec);
  83. }
  84. static Walkqid*
  85. mousewalk(Chan *c, Chan *nc, char **name, int nname)
  86. {
  87. Walkqid *wq;
  88. wq = devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
  89. if(wq != nil && wq->clone != c && (wq->clone->qid.type&QTDIR)==0)
  90. incref(&mouse.ref);
  91. return wq;
  92. }
  93. static int
  94. mousestat(Chan *c, uint8_t *db, int n)
  95. {
  96. return devstat(c, db, n, mousedir, nelem(mousedir), devgen);
  97. }
  98. static Chan*
  99. mouseopen(Chan *c, int omode)
  100. {
  101. switch((uint32_t)c->qid.path){
  102. case Qdir:
  103. if(omode != OREAD)
  104. error(Eperm);
  105. break;
  106. case Qmouse:
  107. lock(&mouse.ref.lock);
  108. if(mouse.open){
  109. unlock(&mouse.ref.lock);
  110. error(Einuse);
  111. }
  112. mouse.open = 1;
  113. mouse.ref.ref++;
  114. unlock(&mouse.ref.lock);
  115. break;
  116. default:
  117. incref(&mouse.ref);
  118. }
  119. c->mode = openmode(omode);
  120. c->flag |= COPEN;
  121. c->offset = 0;
  122. return c;
  123. }
  124. static void
  125. mousecreate(Chan *c, char *a, int i, uint32_t u)
  126. {
  127. error(Eperm);
  128. }
  129. static void
  130. mouseclose(Chan *c)
  131. {
  132. if((c->qid.type&QTDIR)==0 && (c->flag&COPEN)){
  133. lock(&mouse.ref.lock);
  134. if(c->qid.path == Qmouse)
  135. mouse.open = 0;
  136. if(--mouse.ref.ref == 0){
  137. cursoroff(1);
  138. curs = arrow;
  139. Cursortocursor(&arrow);
  140. cursoron(1);
  141. }
  142. unlock(&mouse.ref.lock);
  143. }
  144. }
  145. static int32_t
  146. mouseread(Chan *c, void *va, int32_t n, int64_t off)
  147. {
  148. char buf[4*12+1];
  149. uint8_t *p;
  150. uint32_t offset = off;
  151. Mousestate m;
  152. int b;
  153. p = va;
  154. switch((uint32_t)c->qid.path){
  155. case Qdir:
  156. return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);
  157. case Qcursor:
  158. if(offset != 0)
  159. return 0;
  160. if(n < 2*4+2*2*16)
  161. error(Eshort);
  162. n = 2*4+2*2*16;
  163. lock(&cursor.lock);
  164. BPLONG(p+0, curs.offset.x);
  165. BPLONG(p+4, curs.offset.y);
  166. memmove(p+8, curs.clr, 2*16);
  167. memmove(p+40, curs.set, 2*16);
  168. unlock(&cursor.lock);
  169. return n;
  170. case Qmouse:
  171. while(mousechanged(0) == 0)
  172. rendsleep(&mouse.r, mousechanged, 0);
  173. mouse.qfull = 0;
  174. /*
  175. * No lock of the indicies is necessary here, because ri is only
  176. * updated by us, and there is only one mouse reader
  177. * at a time. I suppose that more than one process
  178. * could try to read the fd at one time, but such behavior
  179. * is degenerate and already violates the calling
  180. * conventions for sleep above.
  181. */
  182. if(mouse.ri != mouse.wi){
  183. m = mouse.queue[mouse.ri];
  184. if(++mouse.ri == nelem(mouse.queue))
  185. mouse.ri = 0;
  186. } else {
  187. lock(&cursor.lock);
  188. m = mouse.mst;
  189. unlock(&cursor.lock);
  190. }
  191. b = buttonmap[m.buttons&7];
  192. /* put buttons 4 and 5 back in */
  193. b |= m.buttons & (3<<3);
  194. sprint(buf, "m%11d %11d %11d %11lu",
  195. m.xy.x, m.xy.y,
  196. b,
  197. m.msec);
  198. mouse.lastcounter = m.counter;
  199. if(n > 1+4*12)
  200. n = 1+4*12;
  201. memmove(va, buf, n);
  202. return n;
  203. }
  204. return 0;
  205. }
  206. static int32_t
  207. mousewrite(Chan *c, void *va, int32_t n, int64_t m)
  208. {
  209. char *p;
  210. Point pt;
  211. char buf[64];
  212. p = va;
  213. switch((uint32_t)c->qid.path){
  214. case Qdir:
  215. error(Eisdir);
  216. case Qcursor:
  217. cursoroff(1);
  218. if(n < 2*4+2*2*16){
  219. curs = arrow;
  220. Cursortocursor(&arrow);
  221. }else{
  222. n = 2*4+2*2*16;
  223. curs.offset.x = BGLONG(p+0);
  224. curs.offset.y = BGLONG(p+4);
  225. memmove(curs.clr, p+8, 2*16);
  226. memmove(curs.set, p+40, 2*16);
  227. Cursortocursor(&curs);
  228. }
  229. qlock(&mouse.qlock);
  230. mouse.redraw = 1;
  231. mouseclock();
  232. qunlock(&mouse.qlock);
  233. cursoron(1);
  234. return n;
  235. case Qmouse:
  236. if(n > sizeof buf-1)
  237. n = sizeof buf -1;
  238. memmove(buf, va, n);
  239. buf[n] = 0;
  240. p = 0;
  241. pt.x = strtoul(buf+1, &p, 0);
  242. if(p == 0)
  243. error(Eshort);
  244. pt.y = strtoul(p, 0, 0);
  245. qlock(&mouse.qlock);
  246. if(ptinrect(pt, gscreen->r)){
  247. mousetrack(pt.x, pt.y, mouse.mst.buttons, nsec()/(1000*1000LL));
  248. mousewarpnote(pt);
  249. }
  250. qunlock(&mouse.qlock);
  251. return n;
  252. }
  253. error(Egreg);
  254. return -1;
  255. }
  256. Dev mousedevtab = {
  257. 'm',
  258. "mouse",
  259. mousereset,
  260. mouseinit,
  261. mouseattach,
  262. mousewalk,
  263. mousestat,
  264. mouseopen,
  265. mousecreate,
  266. mouseclose,
  267. mouseread,
  268. devbread,
  269. mousewrite,
  270. devbwrite,
  271. devremove,
  272. devwstat,
  273. };
  274. void
  275. Cursortocursor(Cursor *c)
  276. {
  277. lock(&cursor.lock);
  278. memmove(&cursor.cursor, c, sizeof(Cursor));
  279. setcursor(c);
  280. unlock(&cursor.lock);
  281. }
  282. static void
  283. mouseclock(void)
  284. {
  285. lock(&cursor.lock);
  286. if(mouse.redraw){
  287. mouse.redraw = 0;
  288. cursoroff(0);
  289. mouse.redraw = cursoron(0);
  290. }
  291. unlock(&cursor.lock);
  292. }
  293. /*
  294. * called at interrupt level to update the structure and
  295. * awaken any waiting procs.
  296. */
  297. void
  298. mousetrack(int x, int y, int b, int msec)
  299. {
  300. int lastb;
  301. lastb = mouse.mst.buttons;
  302. mouse.mst.xy = Pt(x, y);
  303. mouse.mst.buttons = b;
  304. mouse.redraw = 1;
  305. mouse.mst.counter++;
  306. mouse.mst.msec = msec;
  307. /*
  308. * if the queue fills, we discard the entire queue and don't
  309. * queue any more events until a reader polls the mouse.
  310. */
  311. if(!mouse.qfull && lastb != b){ /* add to ring */
  312. mouse.queue[mouse.wi] = mouse.mst;
  313. if(++mouse.wi == nelem(mouse.queue))
  314. mouse.wi = 0;
  315. if(mouse.wi == mouse.ri)
  316. mouse.qfull = 1;
  317. }
  318. rendwakeup(&mouse.r);
  319. mouseclock();
  320. }
  321. int
  322. mousechanged(void *v)
  323. {
  324. return mouse.lastcounter != mouse.mst.counter;
  325. }
  326. Point
  327. mousexy(void)
  328. {
  329. return mouse.mst.xy;
  330. }
  331. void
  332. mouseaccelerate(int x)
  333. {
  334. mouse.acceleration = x;
  335. if(mouse.acceleration < 3)
  336. mouse.maxacc = 2;
  337. else
  338. mouse.maxacc = mouse.acceleration;
  339. }