changelog shortlog tags branches files raw gz bz2 help

Mercurial > hg > plan9front / changeset: nusb/kb: multitouch support (touchscreens, stylus)

changeset 6887: f1e9a71d650a
parent 6886: b3f02338356b
child 6888: 4136602b93e9
author: cinap_lenrek@felloff.net
date: Wed, 14 Nov 2018 09:12:34 +0100
files: sys/src/cmd/nusb/kb/kb.c
description: nusb/kb: multitouch support (touchscreens, stylus)

touchscreens signal multiple contact points (X/Y) in
the hid descriptor separated by being nested in separate
collections. the contact point is identified by a
optional contact id. if omited, we use the collection
index and report id.

so we collect all the items (X/Y, buttons, wheel) from
separate collections in Hidslot structures and in the
end combine all the slots together.

buttons are or'ed together while absolute X/Y is applied
when it changed. relative X/Y deltas get added together.

thanks to kivik and Glats for testing.
     1.1--- a/sys/src/cmd/nusb/kb/kb.c
     1.2+++ b/sys/src/cmd/nusb/kb/kb.c
     1.3@@ -46,8 +46,16 @@ struct Hiddev
     1.4 };
     1.5 
     1.6 typedef struct Hidreport Hidreport;
     1.7-struct Hidreport
     1.8+typedef struct Hidslot Hidslot;
     1.9+struct Hidslot
    1.10 {
    1.11+	int	valid;
    1.12+	int	usage;
    1.13+	int	id;
    1.14+	int	oor;
    1.15+
    1.16+	int	abs;	/* for xyz */
    1.17+
    1.18 	int	x;
    1.19 	int	y;
    1.20 	int	z;
    1.21@@ -55,8 +63,14 @@ struct Hidreport
    1.22 	int	b;
    1.23 	int	m;
    1.24 
    1.25-	int	absz;
    1.26-	u8int	abs;
    1.27+	int	w;
    1.28+	int	h;
    1.29+};
    1.30+
    1.31+struct Hidreport
    1.32+{
    1.33+	int	ns;
    1.34+	Hidslot	s[16];
    1.35 
    1.36 	int	nk;
    1.37 	uchar	k[64];
    1.38@@ -222,7 +236,14 @@ repparse1(uchar *d, uchar *e, int g[], i
    1.39 			switch(t){
    1.40 			case Collection:
    1.41 				memset(l, 0, Nl*sizeof(l[0]));
    1.42+				i = l[Nu] | g[UsagPg]<<16;
    1.43+				l[Usage] = i;
    1.44+				(*f)(t, v, g, l, c, a);
    1.45+
    1.46 				d = repparse1(d, e, g, l, v, f, a);
    1.47+
    1.48+				l[Usage] = i;
    1.49+				(*f)(CollectionEnd, v, g, l, c, a);
    1.50 				continue;
    1.51 			case CollectionEnd:
    1.52 				return d;
    1.53@@ -495,17 +516,40 @@ static void
    1.54 hidparse(int t, int f, int g[], int l[], int, void *a)
    1.55 {
    1.56 	Hidreport *p = a;
    1.57+	Hidslot *s = &p->s[p->ns];
    1.58 	int v, m;
    1.59 
    1.60-	if(t != Input)
    1.61+	switch(t){
    1.62+	case Input:
    1.63+		if(g[RepId] != 0){
    1.64+			if(p->p[0] != g[RepId]){
    1.65+				p->o = 0;
    1.66+				return;
    1.67+			}
    1.68+			if(p->o < 8)
    1.69+				p->o = 8;	/* skip report id byte */
    1.70+		}
    1.71+		break;
    1.72+	case Collection:
    1.73+		if(g[RepId] != 0 && p->p[0] != g[RepId])
    1.74+			return;
    1.75+		if(s->valid && p->ns < nelem(p->s)-1)
    1.76+			s = &p->s[++p->ns];
    1.77+		memset(s, 0, sizeof(*s));
    1.78+		s->usage = l[Usage];
    1.79+		s->id = (p->ns+1)<<8 | g[RepId];
    1.80 		return;
    1.81-	if(g[RepId] != 0){
    1.82-		if(p->p[0] != g[RepId]){
    1.83-			p->o = 0;
    1.84+	case CollectionEnd:
    1.85+		if(g[RepId] != 0 && p->p[0] != g[RepId])
    1.86+			return;
    1.87+		if(!s->valid || s->usage != l[Usage])
    1.88 			return;
    1.89-		}
    1.90-		if(p->o < 8)
    1.91-			p->o = 8;	/* skip report id byte */
    1.92+		/* if out of range or touchscreen finger not touching, ignore the slot */
    1.93+		if(s->oor || s->usage == 0x0D0022 && s->b == 0)
    1.94+			s->valid = 0;
    1.95+		return;
    1.96+	default:
    1.97+		return;
    1.98 	}
    1.99 	v = getbits(p->p, p->e, g[RepSize], p->o);
   1.100 	p->o += g[RepSize];
   1.101@@ -540,6 +584,9 @@ hidparse(int t, int f, int g[], int l[],
   1.102 			v -= (g[PhysMax] * (g[LogiMax] - g[LogiMin])) / (g[PhysMax] - g[PhysMin]);
   1.103 
   1.104 		switch(l[Usage]){
   1.105+		default:
   1.106+			return;
   1.107+
   1.108 		case 0x090001:
   1.109 		case 0x090002:
   1.110 		case 0x090003:
   1.111@@ -549,35 +596,59 @@ hidparse(int t, int f, int g[], int l[],
   1.112 		case 0x090007:
   1.113 		case 0x090008:
   1.114 			m = 1<<(l[Usage] - 0x090001);
   1.115-			p->m |= m;
   1.116-			p->b &= ~m;
   1.117+		Button:
   1.118+			s->m |= m;
   1.119+			s->b &= ~m;
   1.120 			if(v != 0)
   1.121-				p->b |= m;
   1.122+				s->b |= m;
   1.123+			break;
   1.124+
   1.125+		case 0x0D0032:	/* In Range */
   1.126+			s->oor = !v;
   1.127 			break;
   1.128+
   1.129+		case 0x0D0042:	/* Tip Switch */
   1.130+			m = 1;
   1.131+			goto Button;
   1.132+		case 0x0D0044:	/* Barrel Switch */
   1.133+			m = 2;
   1.134+			goto Button;
   1.135+		case 0x0D0045:	/* Eraser */
   1.136+			m = 4;
   1.137+			goto Button;
   1.138+
   1.139+		case 0x0D0048:	/* Contact width */
   1.140+			s->w = v;
   1.141+			break;
   1.142+		case 0x0D0049:	/* Contact height */
   1.143+			s->h = v;
   1.144+			break;
   1.145+
   1.146+		case 0x0D0051:	/* Conteact identifier */
   1.147+			s->id = v;
   1.148+			break;
   1.149+
   1.150 		case 0x010030:
   1.151 			if((f & (Fabs|Frel)) == Fabs){
   1.152 				v = ((vlong)(v - g[LogiMin]) << 31) / (g[LogiMax] - g[LogiMin]);
   1.153-				p->abs = 1;
   1.154+				s->abs |= 1;
   1.155 			}
   1.156-			p->x = v;
   1.157+			s->x = v;
   1.158 			break;
   1.159 		case 0x010031:
   1.160 			if((f & (Fabs|Frel)) == Fabs){
   1.161 				v = ((vlong)(v - g[LogiMin]) << 31) / (g[LogiMax] - g[LogiMin]);
   1.162-				p->abs = 1;
   1.163+				s->abs |= 2;
   1.164 			}
   1.165-			p->y = v;
   1.166+			s->y = v;
   1.167 			break;
   1.168 		case 0x010038:
   1.169-			if((f & (Fabs|Frel)) == Fabs){
   1.170-				p->z = v - p->absz;
   1.171-				p->absz = v;
   1.172-			} else {
   1.173-				p->z = v;
   1.174-				p->absz += v;
   1.175-			}
   1.176+			if((f & (Fabs|Frel)) == Fabs)
   1.177+				s->abs |= 4;
   1.178+			s->z = v;
   1.179 			break;
   1.180 		}
   1.181+		s->valid = 1;
   1.182 	}
   1.183 }
   1.184 
   1.185@@ -600,14 +671,17 @@ readerproc(void* a)
   1.186 {
   1.187 	char	err[ERRMAX], mbuf[80];
   1.188 	uchar	lastk[64], uk, dk;
   1.189-	int	i, c, b, nerrs, lastb, nlastk;
   1.190+	int	i, c, nerrs, lastb, nlastk;
   1.191+	int	abs, x, y, z, b;
   1.192 	Hidreport p;
   1.193-	Hiddev*	f = a;
   1.194+	Hidslot lasts[nelem(p.s)], *s, *l;
   1.195+	Hiddev *f = a;
   1.196 
   1.197 	threadsetname("readerproc %s", f->ep->dir);
   1.198 	sethipri();
   1.199 
   1.200 	memset(&p, 0, sizeof(p));
   1.201+	memset(lasts, 0, sizeof(lasts));
   1.202 	lastb = nlastk = nerrs = 0;
   1.203 
   1.204 	for(;;){
   1.205@@ -634,9 +708,13 @@ readerproc(void* a)
   1.206 
   1.207 		p.o = 0;
   1.208 		p.e = p.p + c;
   1.209-		p.abs = 0;
   1.210+		p.ns = 0;
   1.211+		memset(p.s, 0, sizeof(p.s[0]));
   1.212 		repparse(f->rep, f->rep+f->nrep, hidparse, &p);
   1.213+		if(p.s[p.ns].valid)
   1.214+			p.ns++;
   1.215 
   1.216+		/* handle keyboard report */
   1.217 		if(p.nk != 0 || nlastk != 0){
   1.218 			if(debug){
   1.219 				fprint(2, "kbd: ");
   1.220@@ -678,32 +756,75 @@ readerproc(void* a)
   1.221 			p.nk = 0;
   1.222 		}
   1.223 
   1.224-		/* map mouse buttons */
   1.225-		b = p.b & 1;
   1.226-		if(p.b & (4|8))
   1.227-			b |= 2;
   1.228-		if(p.b & 2)
   1.229-			b |= 4;
   1.230-		if(p.z != 0)
   1.231-			b |= (p.z > 0) ? 8 : 16;
   1.232+		/* handle mouse/touchpad */
   1.233+		if(p.ns == 0)
   1.234+			continue;
   1.235+
   1.236+		/* combine all the slots */
   1.237+		abs = x = y = b = 0;
   1.238+		for(i=0; i<p.ns; *l = *s, i++){
   1.239+			s = &p.s[i];
   1.240+
   1.241+			/* find the last slot of the same id */
   1.242+			for(l = lasts; l->valid && l < &lasts[nelem(lasts)-1]; l++)
   1.243+				if(l->usage == s->usage && l->id == s->id)
   1.244+					break;
   1.245+			if(l == &lasts[nelem(lasts)-1] || !l->valid)
   1.246+				*l = *s;
   1.247+
   1.248+			/* convet absolute z to relative */
   1.249+			z = s->z;
   1.250+			if(s->abs & 4)
   1.251+				z -= l->z;
   1.252 
   1.253-		if(p.abs || p.x != 0 || p.y != 0 || p.z != 0 || b != lastb){
   1.254-			if(debug)
   1.255-				if(p.abs)
   1.256-					fprint(2, "ptr: b=%x m=%x x=%f y=%f z=%d\n", p.b, p.m, (uint)p.x / 2147483648.0, (uint)p.y / 2147483648.0, p.z);
   1.257+			if(debug) {
   1.258+				if((s->abs & 3) == 3)
   1.259+					fprint(2, "ptr[%d]: id=%x b=%x m=%x x=%f y=%f z=%d\n",
   1.260+						i, s->id, s->b, s->m,
   1.261+						(uint)s->x / 2147483648.0,
   1.262+						(uint)s->y / 2147483648.0,
   1.263+						z);
   1.264 				else
   1.265-					fprint(2, "ptr: b=%x m=%x x=%d y=%d z=%d\n", p.b, p.m, p.x, p.y, p.z);
   1.266+					fprint(2, "ptr[%d]: id=%x b=%x m=%x x=%d y=%d z=%d\n",
   1.267+						i, s->id, s->b, s->m, s->x, s->y, z);
   1.268+			}
   1.269+
   1.270+			/* map to mouse buttons */
   1.271+			b |= s->b & 1;
   1.272+			if(s->b & (4|8))
   1.273+				b |= 2;
   1.274+			if(s->b & 2)
   1.275+				b |= 4;
   1.276+			if(z != 0)
   1.277+				b |= z > 0 ? 8 : 16;
   1.278+
   1.279+			/* X/Y are absolute? */
   1.280+			if((s->abs & 3) == 3){
   1.281+				/* ignore absolute position when nothing changed */
   1.282+				if(s->abs == l->abs && s->x == l->x && s->y == l->y && s->b == l->b)
   1.283+					continue;
   1.284+				abs = 1;
   1.285+				x = s->x;
   1.286+				y = s->y;
   1.287+			} else {
   1.288+				/* everything needs to be relative */
   1.289+				if((s->abs & 3) != 0 || abs)
   1.290+					continue;
   1.291+				x += s->x;
   1.292+				y += s->y;
   1.293+			}
   1.294+		}
   1.295+
   1.296+		if(abs || x != 0 || y != 0 || b != lastb){
   1.297+			lastb = b;
   1.298 
   1.299 			if(f->minfd < 0){
   1.300 				f->minfd = open("/dev/mousein", OWRITE);
   1.301 				if(f->minfd < 0)
   1.302 					hdfatal(f, "open /dev/mousein");
   1.303 			}
   1.304-
   1.305-			seprint(mbuf, mbuf+sizeof(mbuf), "%c%11d %11d %11d", "ma"[p.abs], p.x, p.y, b);
   1.306+			seprint(mbuf, mbuf+sizeof(mbuf), "%c%11d %11d %11d", "ma"[abs], x, y, b);
   1.307 			write(f->minfd, mbuf, strlen(mbuf));
   1.308-
   1.309-			lastb = b;
   1.310 		}
   1.311 	}
   1.312 }