1 #include <u.h> 2 #include <libc.h> 3 #include "compat.h" 4 #include "error.h" 5 6 #define Image IMAGE 7 #include <draw.h> 8 #include <memdraw.h> 9 #include <cursor.h> 10 #include "screen.h" 11 12 typedef struct Mouseinfo Mouseinfo; 13 typedef struct Mousestate Mousestate; 14 15 struct Mousestate 16 { 17 Point xy; /* mouse.xy */ 18 int buttons; /* mouse.buttons */ 19 ulong counter; /* increments every update */ 20 ulong msec; /* time of last event */ 21 }; 22 23 struct Mouseinfo 24 { 25 Mousestate; 26 int dx; 27 int dy; 28 int track; /* dx & dy updated */ 29 int redraw; /* update cursor on screen */ 30 ulong lastcounter; /* value when /dev/mouse read */ 31 Rendez r; 32 Ref; 33 QLock; 34 int open; 35 int acceleration; 36 int maxacc; 37 Mousestate queue[16]; /* circular buffer of click events */ 38 int ri; /* read index into queue */ 39 int wi; /* write index into queue */ 40 uchar qfull; /* queue is full */ 41 }; 42 43 Mouseinfo mouse; 44 Cursorinfo cursor; 45 int mouseshifted; 46 Cursor curs; 47 48 void Cursortocursor(Cursor*); 49 int mousechanged(void*); 50 static void mouseclock(void); 51 52 enum{ 53 Qdir, 54 Qcursor, 55 Qmouse, 56 }; 57 58 static Dirtab mousedir[]={ 59 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, 60 "cursor", {Qcursor}, 0, 0666, 61 "mouse", {Qmouse}, 0, 0666, 62 }; 63 64 static uchar buttonmap[8] = { 65 0, 1, 2, 3, 4, 5, 6, 7, 66 }; 67 static int mouseswap; 68 69 extern Memimage* gscreen; 70 extern mousewarpnote(Point); 71 72 static void 73 mousereset(void) 74 { 75 curs = arrow; 76 Cursortocursor(&arrow); 77 } 78 79 static void 80 mouseinit(void) 81 { 82 cursoron(1); 83 } 84 85 static Chan* 86 mouseattach(char *spec) 87 { 88 return devattach('m', spec); 89 } 90 91 static Walkqid* 92 mousewalk(Chan *c, Chan *nc, char **name, int nname) 93 { 94 Walkqid *wq; 95 96 wq = devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen); 97 if(wq != nil && wq->clone != c && (wq->clone->qid.type&QTDIR)==0) 98 incref(&mouse); 99 return wq; 100 } 101 102 static int 103 mousestat(Chan *c, uchar *db, int n) 104 { 105 return devstat(c, db, n, mousedir, nelem(mousedir), devgen); 106 } 107 108 static Chan* 109 mouseopen(Chan *c, int omode) 110 { 111 switch((ulong)c->qid.path){ 112 case Qdir: 113 if(omode != OREAD) 114 error(Eperm); 115 break; 116 case Qmouse: 117 lock(&mouse); 118 if(mouse.open){ 119 unlock(&mouse); 120 error(Einuse); 121 } 122 mouse.open = 1; 123 mouse.ref++; 124 unlock(&mouse); 125 break; 126 default: 127 incref(&mouse); 128 } 129 c->mode = openmode(omode); 130 c->flag |= COPEN; 131 c->offset = 0; 132 return c; 133 } 134 135 static void 136 mousecreate(Chan*, char*, int, ulong) 137 { 138 error(Eperm); 139 } 140 141 static void 142 mouseclose(Chan *c) 143 { 144 if((c->qid.type&QTDIR)==0 && (c->flag&COPEN)){ 145 lock(&mouse); 146 if(c->qid.path == Qmouse) 147 mouse.open = 0; 148 if(--mouse.ref == 0){ 149 cursoroff(1); 150 curs = arrow; 151 Cursortocursor(&arrow); 152 cursoron(1); 153 } 154 unlock(&mouse); 155 } 156 } 157 158 159 static long 160 mouseread(Chan *c, void *va, long n, vlong off) 161 { 162 char buf[4*12+1]; 163 uchar *p; 164 static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 }; 165 ulong offset = off; 166 Mousestate m; 167 int b; 168 169 p = va; 170 switch((ulong)c->qid.path){ 171 case Qdir: 172 return devdirread(c, va, n, mousedir, nelem(mousedir), devgen); 173 174 case Qcursor: 175 if(offset != 0) 176 return 0; 177 if(n < 2*4+2*2*16) 178 error(Eshort); 179 n = 2*4+2*2*16; 180 lock(&cursor); 181 BPLONG(p+0, curs.offset.x); 182 BPLONG(p+4, curs.offset.y); 183 memmove(p+8, curs.clr, 2*16); 184 memmove(p+40, curs.set, 2*16); 185 unlock(&cursor); 186 return n; 187 188 case Qmouse: 189 while(mousechanged(0) == 0) 190 rendsleep(&mouse.r, mousechanged, 0); 191 192 mouse.qfull = 0; 193 194 /* 195 * No lock of the indicies is necessary here, because ri is only 196 * updated by us, and there is only one mouse reader 197 * at a time. I suppose that more than one process 198 * could try to read the fd at one time, but such behavior 199 * is degenerate and already violates the calling 200 * conventions for sleep above. 201 */ 202 if(mouse.ri != mouse.wi) { 203 m = mouse.queue[mouse.ri]; 204 if(++mouse.ri == nelem(mouse.queue)) 205 mouse.ri = 0; 206 } else { 207 lock(&cursor); 208 209 m = mouse.Mousestate; 210 unlock(&cursor); 211 } 212 213 b = buttonmap[m.buttons&7]; 214 /* put buttons 4 and 5 back in */ 215 b |= m.buttons & (3<<3); 216 sprint(buf, "m%11d %11d %11d %11lud", 217 m.xy.x, m.xy.y, 218 b, 219 m.msec); 220 mouse.lastcounter = m.counter; 221 if(n > 1+4*12) 222 n = 1+4*12; 223 memmove(va, buf, n); 224 return n; 225 } 226 return 0; 227 } 228 229 static void 230 setbuttonmap(char* map) 231 { 232 int i, x, one, two, three; 233 234 one = two = three = 0; 235 for(i = 0; i < 3; i++){ 236 if(map[i] == 0) 237 error(Ebadarg); 238 if(map[i] == '1'){ 239 if(one) 240 error(Ebadarg); 241 one = 1<<i; 242 } 243 else if(map[i] == '2'){ 244 if(two) 245 error(Ebadarg); 246 two = 1<<i; 247 } 248 else if(map[i] == '3'){ 249 if(three) 250 error(Ebadarg); 251 three = 1<<i; 252 } 253 else 254 error(Ebadarg); 255 } 256 if(map[i]) 257 error(Ebadarg); 258 259 memset(buttonmap, 0, 8); 260 for(i = 0; i < 8; i++){ 261 x = 0; 262 if(i & 1) 263 x |= one; 264 if(i & 2) 265 x |= two; 266 if(i & 4) 267 x |= three; 268 buttonmap[x] = i; 269 } 270 } 271 272 static long 273 mousewrite(Chan *c, void *va, long n, vlong) 274 { 275 char *p; 276 Point pt; 277 char buf[64]; 278 279 p = va; 280 switch((ulong)c->qid.path){ 281 case Qdir: 282 error(Eisdir); 283 284 case Qcursor: 285 cursoroff(1); 286 if(n < 2*4+2*2*16){ 287 curs = arrow; 288 Cursortocursor(&arrow); 289 }else{ 290 n = 2*4+2*2*16; 291 curs.offset.x = BGLONG(p+0); 292 curs.offset.y = BGLONG(p+4); 293 memmove(curs.clr, p+8, 2*16); 294 memmove(curs.set, p+40, 2*16); 295 Cursortocursor(&curs); 296 } 297 qlock(&mouse); 298 mouse.redraw = 1; 299 mouseclock(); 300 qunlock(&mouse); 301 cursoron(1); 302 return n; 303 304 case Qmouse: 305 if(n > sizeof buf-1) 306 n = sizeof buf -1; 307 memmove(buf, va, n); 308 buf[n] = 0; 309 p = 0; 310 pt.x = strtoul(buf+1, &p, 0); 311 if(p == 0) 312 error(Eshort); 313 pt.y = strtoul(p, 0, 0); 314 qlock(&mouse); 315 if(ptinrect(pt, gscreen->r)) { 316 mousetrack(pt.x, pt.y, mouse.buttons, nsec()/(1000*1000LL)); 317 mousewarpnote(pt); 318 } 319 qunlock(&mouse); 320 return n; 321 } 322 323 error(Egreg); 324 return -1; 325 } 326 327 Dev mousedevtab = { 328 'm', 329 "mouse", 330 331 mousereset, 332 mouseinit, 333 mouseattach, 334 mousewalk, 335 mousestat, 336 mouseopen, 337 mousecreate, 338 mouseclose, 339 mouseread, 340 devbread, 341 mousewrite, 342 devbwrite, 343 devremove, 344 devwstat, 345 }; 346 347 void 348 Cursortocursor(Cursor *c) 349 { 350 lock(&cursor); 351 memmove(&cursor.Cursor, c, sizeof(Cursor)); 352 setcursor(c); 353 unlock(&cursor); 354 } 355 356 static int 357 scale(int x) 358 { 359 int sign = 1; 360 361 if(x < 0){ 362 sign = -1; 363 x = -x; 364 } 365 switch(x){ 366 case 0: 367 case 1: 368 case 2: 369 case 3: 370 break; 371 case 4: 372 x = 6 + (mouse.acceleration>>2); 373 break; 374 case 5: 375 x = 9 + (mouse.acceleration>>1); 376 break; 377 default: 378 x *= mouse.maxacc; 379 break; 380 } 381 return sign*x; 382 } 383 384 static void 385 mouseclock(void) 386 { 387 lock(&cursor); 388 if(mouse.redraw){ 389 mouse.redraw = 0; 390 cursoroff(0); 391 mouse.redraw = cursoron(0); 392 } 393 unlock(&cursor); 394 } 395 396 /* 397 * called at interrupt level to update the structure and 398 * awaken any waiting procs. 399 */ 400 void 401 mousetrack(int x, int y, int b, int msec) 402 { 403 int lastb; 404 405 lastb = mouse.buttons; 406 mouse.xy = Pt(x, y); 407 mouse.buttons = b; 408 mouse.redraw = 1; 409 mouse.counter++; 410 mouse.msec = msec; 411 412 /* 413 * if the queue fills, we discard the entire queue and don't 414 * queue any more events until a reader polls the mouse. 415 */ 416 if(!mouse.qfull && lastb != b){ /* add to ring */ 417 mouse.queue[mouse.wi] = mouse.Mousestate; 418 if(++mouse.wi == nelem(mouse.queue)) 419 mouse.wi = 0; 420 if(mouse.wi == mouse.ri) 421 mouse.qfull = 1; 422 } 423 rendwakeup(&mouse.r); 424 mouseclock(); 425 } 426 427 int 428 mousechanged(void*) 429 { 430 return mouse.lastcounter != mouse.counter; 431 } 432 433 Point 434 mousexy(void) 435 { 436 return mouse.xy; 437 } 438 439 void 440 mouseaccelerate(int x) 441 { 442 mouse.acceleration = x; 443 if(mouse.acceleration < 3) 444 mouse.maxacc = 2; 445 else 446 mouse.maxacc = mouse.acceleration; 447 } 448