1 /* 2 * mouse or stylus 3 */ 4 5 #include "dat.h" 6 #include "fns.h" 7 #include "../port/error.h" 8 9 #include <draw.h> 10 #include <memdraw.h> 11 #include <cursor.h> 12 13 #define cursorenable() 14 #define cursordisable() 15 16 enum{ 17 Qdir, 18 Qpointer, 19 Qcursor 20 }; 21 22 typedef struct Pointer Pointer; 23 24 struct Pointer { 25 int x; 26 int y; 27 int b; 28 ulong msec; 29 }; 30 31 static struct 32 { 33 Pointer v; 34 int modify; 35 int lastb; 36 Rendez r; 37 Ref ref; 38 QLock q; 39 } mouse; 40 41 static 42 Dirtab pointertab[]={ 43 ".", {Qdir, 0, QTDIR}, 0, 0555, 44 "pointer", {Qpointer}, 0, 0666, 45 "cursor", {Qcursor}, 0, 0222, 46 }; 47 48 enum { 49 Nevent = 16 /* enough for some */ 50 }; 51 52 static struct { 53 int rd; 54 int wr; 55 Pointer clicks[Nevent]; 56 Rendez r; 57 int full; 58 int put; 59 int get; 60 } ptrq; 61 62 /* 63 * called by any source of pointer data 64 */ 65 void 66 mousetrack(int b, int x, int y, int isdelta) 67 { 68 int lastb; 69 ulong msec; 70 Pointer e; 71 72 if(isdelta){ 73 x += mouse.v.x; 74 y += mouse.v.y; 75 } 76 msec = osmillisec(); 77 if(0 && b && (mouse.v.b ^ b)&0x1f){ 78 if(msec - mouse.v.msec < 300 && mouse.lastb == b 79 && abs(mouse.v.x - x) < 12 && abs(mouse.v.y - y) < 12) 80 b |= 1<<8; 81 mouse.lastb = b & 0x1f; 82 mouse.v.msec = msec; 83 } 84 if((b&(1<<8))==0 && x == mouse.v.x && y == mouse.v.y && mouse.v.b == b) 85 return; 86 lastb = mouse.v.b; 87 mouse.v.x = x; 88 mouse.v.y = y; 89 mouse.v.b = b; 90 mouse.v.msec = msec; 91 if(!ptrq.full && lastb != b){ 92 e = mouse.v; 93 ptrq.clicks[ptrq.wr] = e; 94 if(++ptrq.wr >= Nevent) 95 ptrq.wr = 0; 96 if(ptrq.wr == ptrq.rd) 97 ptrq.full = 1; 98 } 99 mouse.modify = 1; 100 ptrq.put++; 101 Wakeup(&ptrq.r); 102 /* drawactive(1); */ 103 /* setpointer(x, y); */ 104 } 105 106 static int 107 ptrqnotempty(void *x) 108 { 109 USED(x); 110 return ptrq.full || ptrq.put != ptrq.get; 111 } 112 113 static Pointer 114 mouseconsume(void) 115 { 116 Pointer e; 117 118 Sleep(&ptrq.r, ptrqnotempty, 0); 119 ptrq.full = 0; 120 ptrq.get = ptrq.put; 121 if(ptrq.rd != ptrq.wr){ 122 e = ptrq.clicks[ptrq.rd]; 123 if(++ptrq.rd >= Nevent) 124 ptrq.rd = 0; 125 }else 126 e = mouse.v; 127 return e; 128 } 129 130 Point 131 mousexy(void) 132 { 133 return Pt(mouse.v.x, mouse.v.y); 134 } 135 136 137 static Chan* 138 pointerattach(char* spec) 139 { 140 return devattach('m', spec); 141 } 142 143 static Walkqid* 144 pointerwalk(Chan *c, Chan *nc, char **name, int nname) 145 { 146 Walkqid *wq; 147 148 wq = devwalk(c, nc, name, nname, pointertab, nelem(pointertab), devgen); 149 if(wq != nil && wq->clone != c && wq->clone != nil && (ulong)c->qid.path == Qpointer) 150 incref(&mouse.ref); /* can this happen? */ 151 return wq; 152 } 153 154 static int 155 pointerstat(Chan* c, uchar *db, int n) 156 { 157 return devstat(c, db, n, pointertab, nelem(pointertab), devgen); 158 } 159 160 static Chan* 161 pointeropen(Chan* c, int omode) 162 { 163 c = devopen(c, omode, pointertab, nelem(pointertab), devgen); 164 if((ulong)c->qid.path == Qpointer){ 165 if(waserror()){ 166 c->flag &= ~COPEN; 167 nexterror(); 168 } 169 if(!canqlock(&mouse.q)) 170 error(Einuse); 171 if(incref(&mouse.ref) != 1){ 172 qunlock(&mouse.q); 173 error(Einuse); 174 } 175 cursorenable(); 176 qunlock(&mouse.q); 177 poperror(); 178 } 179 return c; 180 } 181 182 static void 183 pointerclose(Chan* c) 184 { 185 if((c->flag & COPEN) == 0) 186 return; 187 switch((ulong)c->qid.path){ 188 case Qpointer: 189 qlock(&mouse.q); 190 if(decref(&mouse.ref) == 0){ 191 cursordisable(); 192 } 193 qunlock(&mouse.q); 194 break; 195 } 196 } 197 198 static long 199 pointerread(Chan* c, void* a, long n, vlong off) 200 { 201 Pointer mt; 202 char buf[1+4*12+1]; 203 int l; 204 205 USED(&off); 206 switch((ulong)c->qid.path){ 207 case Qdir: 208 return devdirread(c, a, n, pointertab, nelem(pointertab), devgen); 209 case Qpointer: 210 qlock(&mouse.q); 211 if(waserror()) { 212 qunlock(&mouse.q); 213 nexterror(); 214 } 215 mt = mouseconsume(); 216 poperror(); 217 qunlock(&mouse.q); 218 l = snprint(buf, sizeof(buf), "m%11d %11d %11d %11lud ", mt.x, mt.y, mt.b, mt.msec); 219 if(l < n) 220 n = l; 221 memmove(a, buf, n); 222 break; 223 default: 224 n=0; 225 break; 226 } 227 return n; 228 } 229 230 static long 231 pointerwrite(Chan* c, void* va, long n, vlong off) 232 { 233 char *a = va; 234 char buf[128]; 235 int b, x, y; 236 Drawcursor cur; 237 238 USED(&off); 239 switch((ulong)c->qid.path){ 240 case Qpointer: 241 if(n > sizeof buf-1) 242 n = sizeof buf -1; 243 memmove(buf, va, n); 244 buf[n] = 0; 245 x = strtoul(buf+1, &a, 0); 246 if(*a == 0) 247 error(Eshort); 248 y = strtoul(a, &a, 0); 249 if(*a != 0) 250 b = strtoul(a, 0, 0); 251 else 252 b = mouse.v.b; 253 /*mousetrack(b, x, y, msec);*/ 254 setpointer(x, y); 255 USED(b); 256 break; 257 case Qcursor: 258 /* TO DO: perhaps interpret data as an Image */ 259 /* 260 * hotx[4] hoty[4] dx[4] dy[4] clr[dx/8 * dy/2] set[dx/8 * dy/2] 261 * dx must be a multiple of 8; dy must be a multiple of 2. 262 */ 263 if(n == 0){ 264 cur.data = nil; 265 drawcursor(&cur); 266 break; 267 } 268 if(n < 8) 269 error(Eshort); 270 cur.hotx = BGLONG((uchar*)va+0*4); 271 cur.hoty = BGLONG((uchar*)va+1*4); 272 cur.minx = 0; 273 cur.miny = 0; 274 cur.maxx = BGLONG((uchar*)va+2*4); 275 cur.maxy = BGLONG((uchar*)va+3*4); 276 if(cur.maxx%8 != 0 || cur.maxy%2 != 0 || n-4*4 != (cur.maxx/8 * cur.maxy)) 277 error(Ebadarg); 278 cur.data = (uchar*)va + 4*4; 279 drawcursor(&cur); 280 break; 281 default: 282 error(Ebadusefd); 283 } 284 return n; 285 } 286 287 Dev pointerdevtab = { 288 'm', 289 "pointer", 290 291 devinit, 292 pointerattach, 293 pointerwalk, 294 pointerstat, 295 pointeropen, 296 devcreate, 297 pointerclose, 298 pointerread, 299 devbread, 300 pointerwrite, 301 devbwrite, 302 devremove, 303 devwstat, 304 }; 305