ref: 06783edd7a66eea0285c8a7ad2fd03e5577b80ef
parent: 76812c9bb71193b7a9a4d059890915535ef49441
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Wed Nov 14 04:12:34 EST 2018
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.
--- a/sys/src/cmd/nusb/kb/kb.c
+++ b/sys/src/cmd/nusb/kb/kb.c
@@ -46,8 +46,16 @@
};
typedef struct Hidreport Hidreport;
-struct Hidreport
+typedef struct Hidslot Hidslot;
+struct Hidslot
{
+ int valid;
+ int usage;
+ int id;
+ int oor;
+
+ int abs; /* for xyz */
+
int x;
int y;
int z;
@@ -55,9 +63,15 @@
int b;
int m;
- int absz;
- u8int abs;
+ int w;
+ int h;
+};
+struct Hidreport
+{
+ int ns;
+ Hidslot s[16];
+
int nk;
uchar k[64];
@@ -222,7 +236,14 @@
switch(t){
case Collection:
memset(l, 0, Nl*sizeof(l[0]));
+ i = l[Nu] | g[UsagPg]<<16;
+ l[Usage] = i;
+ (*f)(t, v, g, l, c, a);
+
d = repparse1(d, e, g, l, v, f, a);
+
+ l[Usage] = i;
+ (*f)(CollectionEnd, v, g, l, c, a);
continue;
case CollectionEnd:
return d;
@@ -495,17 +516,40 @@
hidparse(int t, int f, int g[], int l[], int, void *a)
{
Hidreport *p = a;
+ Hidslot *s = &p->s[p->ns];
int v, m;
- if(t != Input)
+ switch(t){
+ case Input:
+ if(g[RepId] != 0){
+ if(p->p[0] != g[RepId]){
+ p->o = 0;
+ return;
+ }
+ if(p->o < 8)
+ p->o = 8; /* skip report id byte */
+ }
+ break;
+ case Collection:
+ if(g[RepId] != 0 && p->p[0] != g[RepId])
+ return;
+ if(s->valid && p->ns < nelem(p->s)-1)
+ s = &p->s[++p->ns];
+ memset(s, 0, sizeof(*s));
+ s->usage = l[Usage];
+ s->id = (p->ns+1)<<8 | g[RepId];
return;
- if(g[RepId] != 0){
- if(p->p[0] != g[RepId]){
- p->o = 0;
+ case CollectionEnd:
+ if(g[RepId] != 0 && p->p[0] != g[RepId])
return;
- }
- if(p->o < 8)
- p->o = 8; /* skip report id byte */
+ if(!s->valid || s->usage != l[Usage])
+ return;
+ /* if out of range or touchscreen finger not touching, ignore the slot */
+ if(s->oor || s->usage == 0x0D0022 && s->b == 0)
+ s->valid = 0;
+ return;
+ default:
+ return;
}
v = getbits(p->p, p->e, g[RepSize], p->o);
p->o += g[RepSize];
@@ -540,6 +584,9 @@
v -= (g[PhysMax] * (g[LogiMax] - g[LogiMin])) / (g[PhysMax] - g[PhysMin]);
switch(l[Usage]){
+ default:
+ return;
+
case 0x090001:
case 0x090002:
case 0x090003:
@@ -549,35 +596,59 @@
case 0x090007:
case 0x090008:
m = 1<<(l[Usage] - 0x090001);
- p->m |= m;
- p->b &= ~m;
+ Button:
+ s->m |= m;
+ s->b &= ~m;
if(v != 0)
- p->b |= m;
+ s->b |= m;
break;
+
+ case 0x0D0032: /* In Range */
+ s->oor = !v;
+ break;
+
+ case 0x0D0042: /* Tip Switch */
+ m = 1;
+ goto Button;
+ case 0x0D0044: /* Barrel Switch */
+ m = 2;
+ goto Button;
+ case 0x0D0045: /* Eraser */
+ m = 4;
+ goto Button;
+
+ case 0x0D0048: /* Contact width */
+ s->w = v;
+ break;
+ case 0x0D0049: /* Contact height */
+ s->h = v;
+ break;
+
+ case 0x0D0051: /* Conteact identifier */
+ s->id = v;
+ break;
+
case 0x010030:
if((f & (Fabs|Frel)) == Fabs){
v = ((vlong)(v - g[LogiMin]) << 31) / (g[LogiMax] - g[LogiMin]);
- p->abs = 1;
+ s->abs |= 1;
}
- p->x = v;
+ s->x = v;
break;
case 0x010031:
if((f & (Fabs|Frel)) == Fabs){
v = ((vlong)(v - g[LogiMin]) << 31) / (g[LogiMax] - g[LogiMin]);
- p->abs = 1;
+ s->abs |= 2;
}
- p->y = v;
+ s->y = v;
break;
case 0x010038:
- if((f & (Fabs|Frel)) == Fabs){
- p->z = v - p->absz;
- p->absz = v;
- } else {
- p->z = v;
- p->absz += v;
- }
+ if((f & (Fabs|Frel)) == Fabs)
+ s->abs |= 4;
+ s->z = v;
break;
}
+ s->valid = 1;
}
}
@@ -600,14 +671,17 @@
{
char err[ERRMAX], mbuf[80];
uchar lastk[64], uk, dk;
- int i, c, b, nerrs, lastb, nlastk;
+ int i, c, nerrs, lastb, nlastk;
+ int abs, x, y, z, b;
Hidreport p;
- Hiddev* f = a;
+ Hidslot lasts[nelem(p.s)], *s, *l;
+ Hiddev *f = a;
threadsetname("readerproc %s", f->ep->dir);
sethipri();
memset(&p, 0, sizeof(p));
+ memset(lasts, 0, sizeof(lasts));
lastb = nlastk = nerrs = 0;
for(;;){
@@ -634,9 +708,13 @@
p.o = 0;
p.e = p.p + c;
- p.abs = 0;
+ p.ns = 0;
+ memset(p.s, 0, sizeof(p.s[0]));
repparse(f->rep, f->rep+f->nrep, hidparse, &p);
+ if(p.s[p.ns].valid)
+ p.ns++;
+ /* handle keyboard report */
if(p.nk != 0 || nlastk != 0){
if(debug){
fprint(2, "kbd: ");
@@ -678,32 +756,75 @@
p.nk = 0;
}
- /* map mouse buttons */
- b = p.b & 1;
- if(p.b & (4|8))
- b |= 2;
- if(p.b & 2)
- b |= 4;
- if(p.z != 0)
- b |= (p.z > 0) ? 8 : 16;
+ /* handle mouse/touchpad */
+ if(p.ns == 0)
+ continue;
- if(p.abs || p.x != 0 || p.y != 0 || p.z != 0 || b != lastb){
- if(debug)
- if(p.abs)
- 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);
+ /* combine all the slots */
+ abs = x = y = b = 0;
+ for(i=0; i<p.ns; *l = *s, i++){
+ s = &p.s[i];
+
+ /* find the last slot of the same id */
+ for(l = lasts; l->valid && l < &lasts[nelem(lasts)-1]; l++)
+ if(l->usage == s->usage && l->id == s->id)
+ break;
+ if(l == &lasts[nelem(lasts)-1] || !l->valid)
+ *l = *s;
+
+ /* convet absolute z to relative */
+ z = s->z;
+ if(s->abs & 4)
+ z -= l->z;
+
+ if(debug) {
+ if((s->abs & 3) == 3)
+ fprint(2, "ptr[%d]: id=%x b=%x m=%x x=%f y=%f z=%d\n",
+ i, s->id, s->b, s->m,
+ (uint)s->x / 2147483648.0,
+ (uint)s->y / 2147483648.0,
+ z);
else
- fprint(2, "ptr: b=%x m=%x x=%d y=%d z=%d\n", p.b, p.m, p.x, p.y, p.z);
+ fprint(2, "ptr[%d]: id=%x b=%x m=%x x=%d y=%d z=%d\n",
+ i, s->id, s->b, s->m, s->x, s->y, z);
+ }
+ /* map to mouse buttons */
+ b |= s->b & 1;
+ if(s->b & (4|8))
+ b |= 2;
+ if(s->b & 2)
+ b |= 4;
+ if(z != 0)
+ b |= z > 0 ? 8 : 16;
+
+ /* X/Y are absolute? */
+ if((s->abs & 3) == 3){
+ /* ignore absolute position when nothing changed */
+ if(s->abs == l->abs && s->x == l->x && s->y == l->y && s->b == l->b)
+ continue;
+ abs = 1;
+ x = s->x;
+ y = s->y;
+ } else {
+ /* everything needs to be relative */
+ if((s->abs & 3) != 0 || abs)
+ continue;
+ x += s->x;
+ y += s->y;
+ }
+ }
+
+ if(abs || x != 0 || y != 0 || b != lastb){
+ lastb = b;
+
if(f->minfd < 0){
f->minfd = open("/dev/mousein", OWRITE);
if(f->minfd < 0)
hdfatal(f, "open /dev/mousein");
}
-
- seprint(mbuf, mbuf+sizeof(mbuf), "%c%11d %11d %11d", "ma"[p.abs], p.x, p.y, b);
+ seprint(mbuf, mbuf+sizeof(mbuf), "%c%11d %11d %11d", "ma"[abs], x, y, b);
write(f->minfd, mbuf, strlen(mbuf));
-
- lastb = b;
}
}
}