devpenmouse.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  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. #include <ctype.h>
  13. typedef struct Mouseinfo Mouseinfo;
  14. typedef struct Mousestate Mousestate;
  15. typedef struct Calibration Calibration;
  16. struct Calibration
  17. {
  18. long scalex;
  19. long scaley;
  20. long transx;
  21. long transy;
  22. } calibration = {
  23. -16435,
  24. 23275,
  25. 253,
  26. -23
  27. };
  28. /* The pen goes down, tracks some and goes up again. The pen alone can
  29. * only simulate a one-button mouse.
  30. * To simulate a more-button (five, in this case) mouse, we use the four
  31. * keys along the the bottom of the iPaq as modifiers.
  32. * When one (or more) of the modifier keys is (are) down, a pen-down event
  33. * causes the corresponding bottons to go down. If no modifier key is
  34. * depressed, a pen-down event is translated into a button-one down event.
  35. * Releasing the modifier keys has no direct effect. The pen-up event is
  36. * the one that triggers mouse-up events.
  37. */
  38. struct Mousestate
  39. {
  40. Point xy; /* mouse.xy */
  41. int buttons; /* mouse.buttons */
  42. int modifiers; /* state of physical buttons 2, 3, 4, 5 */
  43. ulong counter; /* increments every update */
  44. ulong msec; /* time of last event */
  45. };
  46. struct Mouseinfo
  47. {
  48. Lock;
  49. Mousestate;
  50. ulong lastcounter; /* value when /dev/mouse read */
  51. ulong resize;
  52. ulong lastresize;
  53. Rendez r;
  54. Ref;
  55. QLock;
  56. int open;
  57. int inopen;
  58. Mousestate queue[16]; /* circular buffer of click events */
  59. int ri; /* read index into queue */
  60. int wi; /* write index into queue */
  61. uchar qfull; /* queue is full */
  62. };
  63. Mouseinfo mouse;
  64. int mouseshifted;
  65. int penmousechanged(void*);
  66. static void penmousetrack(int b, int x, int y);
  67. enum{
  68. Qdir,
  69. Qmouse,
  70. Qmousein,
  71. Qmousectl,
  72. };
  73. static Dirtab mousedir[]={
  74. ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
  75. "mouse", {Qmouse}, 0, 0666,
  76. "mousein", {Qmousein}, 0, 0220,
  77. "mousectl", {Qmousectl}, 0, 0660,
  78. };
  79. enum
  80. {
  81. CMcalibrate,
  82. CMswap,
  83. };
  84. static Cmdtab penmousecmd[] =
  85. {
  86. CMcalibrate, "calibrate", 0,
  87. CMswap, "swap", 1,
  88. };
  89. static uchar buttonmap[8] = {
  90. 0, 1, 2, 3, 4, 5, 6, 7,
  91. };
  92. static int mouseswap;
  93. extern Memimage* gscreen;
  94. void
  95. penbutton(int up, int b) {
  96. // button 5 (side button) immediately causes an event
  97. // when the pen is down (button 1), other buttons also
  98. // cause events, allowing chording with button 1
  99. if ((b & 0x20) || (mouse.buttons & 0x1)) {
  100. if (up)
  101. mouse.buttons &= ~b;
  102. else
  103. mouse.buttons |= b;
  104. penmousetrack(mouse.buttons, -1, -1);
  105. } else {
  106. if (up)
  107. mouse.modifiers &= ~b;
  108. else
  109. mouse.modifiers |= b;
  110. }
  111. }
  112. void
  113. pentrackxy(int x, int y) {
  114. if (x == -1) {
  115. /* pen up. associate with button 1 through 5 up */
  116. mouse.buttons &= ~0x1f;
  117. } else {
  118. x = ((x*calibration.scalex)>>16) + calibration.transx;
  119. y = ((y*calibration.scaley)>>16) + calibration.transy;
  120. if ((mouse.buttons & 0x1f) == 0) {
  121. if (mouse.modifiers)
  122. mouse.buttons |= mouse.modifiers;
  123. else
  124. mouse.buttons |= 0x1;
  125. }
  126. }
  127. penmousetrack(mouse.buttons, x, y);
  128. }
  129. static void
  130. penmousereset(void)
  131. {
  132. if(!conf.monitor)
  133. return;
  134. }
  135. static void
  136. penmouseinit(void)
  137. {
  138. if(!conf.monitor)
  139. return;
  140. }
  141. static Chan*
  142. penmouseattach(char *spec)
  143. {
  144. if(!conf.monitor)
  145. error(Egreg);
  146. return devattach('m', spec);
  147. }
  148. static Walkqid*
  149. penmousewalk(Chan *c, Chan *nc, char **name, int nname)
  150. {
  151. return devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
  152. }
  153. static int
  154. penmousestat(Chan *c, uchar *db, int n)
  155. {
  156. return devstat(c, db, n, mousedir, nelem(mousedir), devgen);
  157. }
  158. static Chan*
  159. penmouseopen(Chan *c, int omode)
  160. {
  161. switch((ulong)c->qid.path){
  162. case Qdir:
  163. if(omode != OREAD)
  164. error(Eperm);
  165. break;
  166. case Qmouse:
  167. lock(&mouse);
  168. if(mouse.open){
  169. unlock(&mouse);
  170. error(Einuse);
  171. }
  172. mouse.open = 1;
  173. mouse.ref++;
  174. unlock(&mouse);
  175. break;
  176. case Qmousein:
  177. /* error("disabled"); */
  178. lock(&mouse);
  179. if(mouse.inopen){
  180. unlock(&mouse);
  181. error(Einuse);
  182. }
  183. mouse.inopen = 1;
  184. unlock(&mouse);
  185. break;
  186. default:
  187. incref(&mouse);
  188. }
  189. c->mode = openmode(omode);
  190. c->flag |= COPEN;
  191. c->offset = 0;
  192. return c;
  193. }
  194. static void
  195. penmousecreate(Chan*, char*, int, ulong)
  196. {
  197. if(!conf.monitor)
  198. error(Egreg);
  199. error(Eperm);
  200. }
  201. static void
  202. penmouseclose(Chan *c)
  203. {
  204. if(c->qid.path != Qdir && (c->flag&COPEN)){
  205. lock(&mouse);
  206. if(c->qid.path == Qmouse)
  207. mouse.open = 0;
  208. else if(c->qid.path == Qmousein){
  209. mouse.inopen = 0;
  210. unlock(&mouse);
  211. return;
  212. }
  213. --mouse.ref;
  214. unlock(&mouse);
  215. }
  216. }
  217. static long
  218. penmouseread(Chan *c, void *va, long n, vlong)
  219. {
  220. char buf[4*12+1];
  221. static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
  222. Mousestate m;
  223. switch((ulong)c->qid.path){
  224. case Qdir:
  225. return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);
  226. case Qmousectl:
  227. sprint(buf, "c%11ld %11ld %11ld %11ld",
  228. calibration.scalex, calibration.scaley,
  229. calibration.transx, calibration.transy);
  230. if(n > 1+4*12)
  231. n = 1+4*12;
  232. memmove(va, buf, n);
  233. return n;
  234. case Qmouse:
  235. while(penmousechanged(0) == 0)
  236. sleep(&mouse.r, penmousechanged, 0);
  237. mouse.qfull = 0;
  238. /*
  239. * No lock of the indices is necessary here, because ri is only
  240. * updated by us, and there is only one mouse reader
  241. * at a time. I suppose that more than one process
  242. * could try to read the fd at one time, but such behavior
  243. * is degenerate and already violates the calling
  244. * conventions for sleep above.
  245. */
  246. if(mouse.ri != mouse.wi) {
  247. m = mouse.queue[mouse.ri];
  248. if(++mouse.ri == nelem(mouse.queue))
  249. mouse.ri = 0;
  250. } else {
  251. m = mouse.Mousestate;
  252. }
  253. sprint(buf, "m%11d %11d %11d %11lud",
  254. m.xy.x, m.xy.y,
  255. m.buttons,
  256. m.msec);
  257. mouse.lastcounter = m.counter;
  258. if(n > 1+4*12)
  259. n = 1+4*12;
  260. if(mouse.lastresize != mouse.resize){
  261. mouse.lastresize = mouse.resize;
  262. buf[0] = 'r';
  263. }
  264. memmove(va, buf, n);
  265. return n;
  266. }
  267. return 0;
  268. }
  269. static void
  270. setbuttonmap(char* map)
  271. {
  272. int i, x, one, two, three;
  273. one = two = three = 0;
  274. for(i = 0; i < 3; i++){
  275. if(map[i] == 0)
  276. error(Ebadarg);
  277. if(map[i] == '1'){
  278. if(one)
  279. error(Ebadarg);
  280. one = 1<<i;
  281. }
  282. else if(map[i] == '2'){
  283. if(two)
  284. error(Ebadarg);
  285. two = 1<<i;
  286. }
  287. else if(map[i] == '3'){
  288. if(three)
  289. error(Ebadarg);
  290. three = 1<<i;
  291. }
  292. else
  293. error(Ebadarg);
  294. }
  295. if(map[i])
  296. error(Ebadarg);
  297. memset(buttonmap, 0, 8);
  298. for(i = 0; i < 8; i++){
  299. x = 0;
  300. if(i & 1)
  301. x |= one;
  302. if(i & 2)
  303. x |= two;
  304. if(i & 4)
  305. x |= three;
  306. buttonmap[x] = i;
  307. }
  308. }
  309. static long
  310. penmousewrite(Chan *c, void *va, long n, vlong)
  311. {
  312. char *p;
  313. Point pt;
  314. Cmdbuf *cb;
  315. Cmdtab *ct;
  316. char buf[64];
  317. int b;
  318. p = va;
  319. switch((ulong)c->qid.path){
  320. case Qdir:
  321. error(Eisdir);
  322. case Qmousectl:
  323. cb = parsecmd(va, n);
  324. if(waserror()){
  325. free(cb);
  326. nexterror();
  327. }
  328. ct = lookupcmd(cb, penmousecmd, nelem(penmousecmd));
  329. switch(ct->index){
  330. case CMswap:
  331. if(mouseswap)
  332. setbuttonmap("123");
  333. else
  334. setbuttonmap("321");
  335. mouseswap ^= 1;
  336. break;
  337. case CMcalibrate:
  338. if (cb->nf == 1) {
  339. calibration.scalex = 1<<16;
  340. calibration.scaley = 1<<16;
  341. calibration.transx = 0;
  342. calibration.transy = 0;
  343. } else if (cb->nf == 5) {
  344. if ((!isdigit(*cb->f[1]) && *cb->f[1] != '-')
  345. || (!isdigit(*cb->f[2]) && *cb->f[2] != '-')
  346. || (!isdigit(*cb->f[3]) && *cb->f[3] != '-')
  347. || (!isdigit(*cb->f[4]) && *cb->f[4] != '-'))
  348. error("bad syntax in control file message");
  349. calibration.scalex = strtol(cb->f[1], nil, 0);
  350. calibration.scaley = strtol(cb->f[2], nil, 0);
  351. calibration.transx = strtol(cb->f[3], nil, 0);
  352. calibration.transy = strtol(cb->f[4], nil, 0);
  353. } else
  354. cmderror(cb, Ecmdargs);
  355. break;
  356. }
  357. free(cb);
  358. poperror();
  359. return n;
  360. case Qmousein:
  361. if(n > sizeof buf-1)
  362. n = sizeof buf -1;
  363. memmove(buf, va, n);
  364. buf[n] = 0;
  365. p = 0;
  366. pt.x = strtol(buf+1, &p, 0);
  367. if(p == 0)
  368. error(Eshort);
  369. pt.y = strtol(p, &p, 0);
  370. if(p == 0)
  371. error(Eshort);
  372. b = strtol(p, &p, 0);
  373. penmousetrack(b, pt.x, pt.y);
  374. return n;
  375. case Qmouse:
  376. if(n > sizeof buf-1)
  377. n = sizeof buf -1;
  378. memmove(buf, va, n);
  379. buf[n] = 0;
  380. p = 0;
  381. pt.x = strtoul(buf+1, &p, 0);
  382. if(p == 0)
  383. error(Eshort);
  384. pt.y = strtoul(p, 0, 0);
  385. qlock(&mouse);
  386. if(ptinrect(pt, gscreen->r))
  387. penmousetrack(mouse.buttons, pt.x, pt.y);
  388. qunlock(&mouse);
  389. return n;
  390. }
  391. error(Egreg);
  392. return -1;
  393. }
  394. Dev penmousedevtab = {
  395. 'm',
  396. "penmouse",
  397. penmousereset,
  398. penmouseinit,
  399. devshutdown,
  400. penmouseattach,
  401. penmousewalk,
  402. penmousestat,
  403. penmouseopen,
  404. penmousecreate,
  405. penmouseclose,
  406. penmouseread,
  407. devbread,
  408. penmousewrite,
  409. devbwrite,
  410. devremove,
  411. devwstat,
  412. };
  413. /*
  414. * called at interrupt level to update the structure and
  415. * awaken any waiting procs.
  416. */
  417. static void
  418. penmousetrack(int b, int x, int y)
  419. {
  420. int lastb;
  421. if (x >= 0)
  422. mouse.xy = Pt(x, y);
  423. lastb = mouse.buttons;
  424. mouse.buttons = b;
  425. mouse.counter++;
  426. mouse.msec = TK2MS(MACHP(0)->ticks);
  427. /*
  428. * if the queue fills, we discard the entire queue and don't
  429. * queue any more events until a reader polls the mouse.
  430. */
  431. if(!mouse.qfull && lastb != b) { /* add to ring */
  432. mouse.queue[mouse.wi] = mouse.Mousestate;
  433. if(++mouse.wi == nelem(mouse.queue))
  434. mouse.wi = 0;
  435. if(mouse.wi == mouse.ri)
  436. mouse.qfull = 1;
  437. }
  438. wakeup(&mouse.r);
  439. drawactive(1);
  440. resetsuspendtimer();
  441. }
  442. int
  443. penmousechanged(void*)
  444. {
  445. return mouse.lastcounter != mouse.counter ||
  446. mouse.lastresize != mouse.resize;
  447. }
  448. Point
  449. penmousexy(void)
  450. {
  451. return mouse.xy;
  452. }
  453. /*
  454. * notify reader that screen has been resized (ha!)
  455. */
  456. void
  457. mouseresize(void)
  458. {
  459. mouse.resize++;
  460. wakeup(&mouse.r);
  461. }