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.
This commit is contained in:
cinap_lenrek 2018-11-14 09:12:34 +01:00
parent 76812c9bb7
commit 06783edd7a

View file

@ -46,8 +46,16 @@ struct Hiddev
};
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,8 +63,14 @@ struct Hidreport
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 @@ repparse1(uchar *d, uchar *e, int g[], int l[], int c,
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 @@ static void
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)
return;
if(g[RepId] != 0){
if(p->p[0] != g[RepId]){
p->o = 0;
return;
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 */
}
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;
case CollectionEnd:
if(g[RepId] != 0 && p->p[0] != g[RepId])
return;
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 @@ hidparse(int t, int f, int g[], int l[], int, void *a)
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 @@ hidparse(int t, int f, int g[], int l[], int, void *a)
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 @@ readerproc(void* a)
{
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 @@ readerproc(void* a)
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 @@ readerproc(void* a)
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;
}
}
}