1 /* 2 * mouse or stylus 3 */ 4 5 #include "u.h" 6 #include "../port/lib.h" 7 #include "mem.h" 8 #include "dat.h" 9 #include "fns.h" 10 #include "../port/error.h" 11 12 #include <draw.h> 13 #include <memdraw.h> 14 #include <cursor.h> 15 #include "screen.h" 16 17 enum{ 18 Qdir, 19 Qpointer, 20 Qcursor, 21 }; 22 23 typedef struct Pointer Pointer; 24 25 struct Pointer { 26 int x; 27 int y; 28 int b; 29 ulong msec; 30 }; 31 32 static struct 33 { 34 Pointer; 35 int modify; 36 int lastb; 37 Rendez r; 38 Ref ref; 39 QLock q; 40 } mouse; 41 42 static 43 Dirtab pointertab[]={ 44 ".", {Qdir, 0, QTDIR}, 0, 0555, 45 "pointer", {Qpointer}, 0, 0666, 46 "cursor", {Qcursor}, 0, 0222, 47 }; 48 49 enum { 50 Nevent = 16 /* enough for some */ 51 }; 52 53 static struct { 54 int rd; 55 int wr; 56 Pointer clicks[Nevent]; 57 Rendez r; 58 int full; 59 int put; 60 int get; 61 } ptrq; 62 63 /* 64 * called by any source of pointer data 65 */ 66 void 67 mousetrack(int b, int x, int y, int isdelta) 68 { 69 int lastb; 70 ulong msec; 71 Pointer e; 72 73 if(isdelta){ 74 x += mouse.x; 75 y += mouse.y; 76 } 77 msec = TK2MS(MACHP(0)->ticks); 78 if(b && (mouse.b ^ b)&0x1f){ 79 if(msec - mouse.msec < 300 && mouse.lastb == b 80 && abs(mouse.x - x) < 12 && abs(mouse.y - y) < 12) 81 b |= 1<<8; 82 mouse.lastb = b & 0x1f; 83 mouse.msec = msec; 84 } 85 if(x == mouse.x && y == mouse.y && mouse.b == b) 86 return; 87 lastb = mouse.b; 88 mouse.x = x; 89 mouse.y = y; 90 mouse.b = b; 91 mouse.msec = msec; 92 if(!ptrq.full && lastb != b){ 93 e = mouse.Pointer; 94 ptrq.clicks[ptrq.wr] = e; 95 if(++ptrq.wr >= Nevent) 96 ptrq.wr = 0; 97 if(ptrq.wr == ptrq.rd) 98 ptrq.full = 1; 99 } 100 mouse.modify = 1; 101 ptrq.put++; 102 wakeup(&ptrq.r); 103 drawactive(1); 104 /* TO DO: cursor update */ 105 } 106 107 static int 108 ptrqnotempty(void*) 109 { 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.Pointer; 127 return e; 128 } 129 130 Point 131 mousexy(void) 132 { 133 return Pt(mouse.x, mouse.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 qunlock(&mouse.q); 193 break; 194 } 195 } 196 197 static long 198 pointerread(Chan* c, void* a, long n, vlong) 199 { 200 Pointer mt; 201 char tmp[128]; 202 int l; 203 204 switch((ulong)c->qid.path){ 205 case Qdir: 206 return devdirread(c, a, n, pointertab, nelem(pointertab), devgen); 207 case Qpointer: 208 qlock(&mouse.q); 209 if(waserror()) { 210 qunlock(&mouse.q); 211 nexterror(); 212 } 213 mt = mouseconsume(); 214 poperror(); 215 qunlock(&mouse.q); 216 l = sprint(tmp, "m%11d %11d %11d %11lud ", mt.x, mt.y, mt.b, mt.msec); 217 if(l < n) 218 n = l; 219 memmove(a, tmp, n); 220 break; 221 case Qcursor: 222 /* TO DO: interpret data written as Image; give to drawcursor() */ 223 break; 224 default: 225 n=0; 226 break; 227 } 228 return n; 229 } 230 231 static long 232 pointerwrite(Chan* c, void* va, long n, vlong) 233 { 234 char *a = va; 235 char buf[128]; 236 int b, x, y; 237 238 switch((ulong)c->qid.path){ 239 case Qpointer: 240 if(n > sizeof buf-1) 241 n = sizeof buf -1; 242 memmove(buf, va, n); 243 buf[n] = 0; 244 x = strtoul(buf+1, &a, 0); 245 if(*a == 0) 246 error(Eshort); 247 y = strtoul(a, &a, 0); 248 if(*a != 0) 249 b = strtoul(a, 0, 0); 250 else 251 b = mouse.b; 252 mousetrack(b, x, y, 0); 253 break; 254 default: 255 error(Ebadusefd); 256 } 257 return n; 258 } 259 260 Dev pointerdevtab = { 261 'm', 262 "pointer", 263 264 devreset, 265 devinit, 266 devshutdown, 267 pointerattach, 268 pointerwalk, 269 pointerstat, 270 pointeropen, 271 devcreate, 272 pointerclose, 273 pointerread, 274 devbread, 275 pointerwrite, 276 devbwrite, 277 devremove, 278 devwstat, 279 }; 280