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 lastb = mouse.v.b; 78 mouse.v.x = x; 79 mouse.v.y = y; 80 mouse.v.b = b; 81 mouse.v.msec = msec; 82 if(!ptrq.full && lastb != b){ 83 e = mouse.v; 84 ptrq.clicks[ptrq.wr] = e; 85 if(++ptrq.wr >= Nevent) 86 ptrq.wr = 0; 87 if(ptrq.wr == ptrq.rd) 88 ptrq.full = 1; 89 } 90 mouse.modify = 1; 91 ptrq.put++; 92 Wakeup(&ptrq.r); 93 /* drawactive(1); */ 94 /* setpointer(x, y); */ 95 } 96 97 static int 98 ptrqnotempty(void *x) 99 { 100 USED(x); 101 return ptrq.full || ptrq.put != ptrq.get; 102 } 103 104 static Pointer 105 mouseconsume(void) 106 { 107 Pointer e; 108 109 Sleep(&ptrq.r, ptrqnotempty, 0); 110 ptrq.full = 0; 111 ptrq.get = ptrq.put; 112 if(ptrq.rd != ptrq.wr){ 113 e = ptrq.clicks[ptrq.rd]; 114 if(++ptrq.rd >= Nevent) 115 ptrq.rd = 0; 116 }else 117 e = mouse.v; 118 return e; 119 } 120 121 Point 122 mousexy(void) 123 { 124 return Pt(mouse.v.x, mouse.v.y); 125 } 126 127 128 static Chan* 129 pointerattach(char* spec) 130 { 131 return devattach('m', spec); 132 } 133 134 static Walkqid* 135 pointerwalk(Chan *c, Chan *nc, char **name, int nname) 136 { 137 Walkqid *wq; 138 139 wq = devwalk(c, nc, name, nname, pointertab, nelem(pointertab), devgen); 140 if(wq != nil && wq->clone != c && wq->clone != nil && (ulong)c->qid.path == Qpointer) 141 incref(&mouse.ref); /* can this happen? */ 142 return wq; 143 } 144 145 static int 146 pointerstat(Chan* c, uchar *db, int n) 147 { 148 return devstat(c, db, n, pointertab, nelem(pointertab), devgen); 149 } 150 151 static Chan* 152 pointeropen(Chan* c, int omode) 153 { 154 c = devopen(c, omode, pointertab, nelem(pointertab), devgen); 155 if((ulong)c->qid.path == Qpointer){ 156 if(waserror()){ 157 c->flag &= ~COPEN; 158 nexterror(); 159 } 160 if(!canqlock(&mouse.q)) 161 error(Einuse); 162 if(incref(&mouse.ref) != 1){ 163 qunlock(&mouse.q); 164 error(Einuse); 165 } 166 cursorenable(); 167 qunlock(&mouse.q); 168 poperror(); 169 } 170 return c; 171 } 172 173 static void 174 pointerclose(Chan* c) 175 { 176 if((c->flag & COPEN) == 0) 177 return; 178 switch((ulong)c->qid.path){ 179 case Qpointer: 180 qlock(&mouse.q); 181 if(decref(&mouse.ref) == 0){ 182 cursordisable(); 183 } 184 qunlock(&mouse.q); 185 break; 186 } 187 } 188 189 static long 190 pointerread(Chan* c, void* a, long n, vlong off) 191 { 192 Pointer mt; 193 char buf[1+4*12+1]; 194 int l; 195 196 USED(&off); 197 switch((ulong)c->qid.path){ 198 case Qdir: 199 return devdirread(c, a, n, pointertab, nelem(pointertab), devgen); 200 case Qpointer: 201 qlock(&mouse.q); 202 if(waserror()) { 203 qunlock(&mouse.q); 204 nexterror(); 205 } 206 mt = mouseconsume(); 207 poperror(); 208 qunlock(&mouse.q); 209 l = snprint(buf, sizeof(buf), "m%11d %11d %11d %11lud ", mt.x, mt.y, mt.b, mt.msec); 210 if(l < n) 211 n = l; 212 memmove(a, buf, n); 213 break; 214 default: 215 n=0; 216 break; 217 } 218 return n; 219 } 220 221 static long 222 pointerwrite(Chan* c, void* va, long n, vlong off) 223 { 224 char *a = va; 225 char buf[128]; 226 int b, x, y; 227 Drawcursor cur; 228 229 USED(&off); 230 switch((ulong)c->qid.path){ 231 case Qpointer: 232 if(n > sizeof buf-1) 233 n = sizeof buf -1; 234 memmove(buf, va, n); 235 buf[n] = 0; 236 x = strtoul(buf+1, &a, 0); 237 if(*a == 0) 238 error(Eshort); 239 y = strtoul(a, &a, 0); 240 if(*a != 0) 241 b = strtoul(a, 0, 0); 242 else 243 b = mouse.v.b; 244 /*mousetrack(b, x, y, msec);*/ 245 setpointer(x, y); 246 USED(b); 247 break; 248 case Qcursor: 249 /* TO DO: perhaps interpret data as an Image */ 250 /* 251 * hotx[4] hoty[4] dx[4] dy[4] clr[dx/8 * dy/2] set[dx/8 * dy/2] 252 * dx must be a multiple of 8; dy must be a multiple of 2. 253 */ 254 if(n == 0){ 255 cur.data = nil; 256 drawcursor(&cur); 257 break; 258 } 259 if(n < 8) 260 error(Eshort); 261 cur.hotx = BGLONG((uchar*)va+0*4); 262 cur.hoty = BGLONG((uchar*)va+1*4); 263 cur.minx = 0; 264 cur.miny = 0; 265 cur.maxx = BGLONG((uchar*)va+2*4); 266 cur.maxy = BGLONG((uchar*)va+3*4); 267 if(cur.maxx%8 != 0 || cur.maxy%2 != 0 || n-4*4 != (cur.maxx/8 * cur.maxy)) 268 error(Ebadarg); 269 cur.data = (uchar*)va + 4*4; 270 drawcursor(&cur); 271 break; 272 default: 273 error(Ebadusefd); 274 } 275 return n; 276 } 277 278 Dev pointerdevtab = { 279 'm', 280 "pointer", 281 282 devinit, 283 pointerattach, 284 pointerwalk, 285 pointerstat, 286 pointeropen, 287 devcreate, 288 pointerclose, 289 pointerread, 290 devbread, 291 pointerwrite, 292 devbwrite, 293 devremove, 294 devwstat, 295 }; 296