diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-11-14 09:12:34 +0100 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2018-11-14 09:12:34 +0100 |
commit | 06783edd7a66eea0285c8a7ad2fd03e5577b80ef (patch) | |
tree | 0b6fe2eae3528c26443ac71b3b0a0df3f8ef1e09 /sys/src/cmd/nusb/kb | |
parent | 76812c9bb71193b7a9a4d059890915535ef49441 (diff) |
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.
Diffstat (limited to 'sys/src/cmd/nusb/kb')
-rw-r--r-- | sys/src/cmd/nusb/kb/kb.c | 211 |
1 files changed, 166 insertions, 45 deletions
diff --git a/sys/src/cmd/nusb/kb/kb.c b/sys/src/cmd/nusb/kb/kb.c index eb9a9bbed..a7de79507 100644 --- a/sys/src/cmd/nusb/kb/kb.c +++ b/sys/src/cmd/nusb/kb/kb.c @@ -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) + 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 @@ 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; - - 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); + /* handle mouse/touchpad */ + if(p.ns == 0) + continue; + + /* 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; } } } |