#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "../port/error.h" #define Image IMAGE#include <draw.h>#include <memdraw.h>#include <cursor.h>#include "screen.h"#include <ctype.h> typedef struct Mouseinfo Mouseinfo;typedef struct Mousestate Mousestate;typedef struct Calibration Calibration; struct Calibration{ long scalex; long scaley; long transx; long transy;} calibration = { -16435, 23275, 253, -23}; /* The pen goes down, tracks some and goes up again. The pen alone can * only simulate a one-button mouse. * To simulate a more-button (five, in this case) mouse, we use the four * keys along the the bottom of the iPaq as modifiers. * When one (or more) of the modifier keys is (are) down, a pen-down event * causes the corresponding bottons to go down. If no modifier key is * depressed, a pen-down event is translated into a button-one down event. * Releasing the modifier keys has no direct effect. The pen-up event is * the one that triggers mouse-up events. */struct Mousestate{ Point xy; /* mouse.xy */ int buttons; /* mouse.buttons */ int modifiers; /* state of physical buttons 2, 3, 4, 5 */ ulong counter; /* increments every update */ ulong msec; /* time of last event */}; struct Mouseinfo{ Mousestate; ulong lastcounter; /* value when /dev/mouse read */ Rendez r; Ref; QLock; int open; int inopen; Mousestate queue[16]; /* circular buffer of click events */ int ri; /* read index into queue */ int wi; /* write index into queue */ uchar qfull; /* queue is full */}; Mouseinfo mouse;int mouseshifted; int penmousechanged(void*);static void penmousetrack(int b, int x, int y); enum{ Qdir, Qmouse, Qmousein, Qmousectl,}; static Dirtab mousedir[]={ ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555, "mouse", {Qmouse}, 0, 0666, "mousein", {Qmousein}, 0, 0220, "mousectl", {Qmousectl}, 0, 0660,}; enum{ CMcalibrate, CMswap,}; static Cmdtab penmousecmd[] ={ CMcalibrate, "calibrate", 0, CMswap, "swap", 1,}; static uchar buttonmap[8] = { 0, 1, 2, 3, 4, 5, 6, 7,};static int mouseswap; extern Memimage* gscreen; voidpenbutton(int up, int b) { // button 5 (side button) immediately causes an event // when the pen is down (button 1), other buttons also // cause events, allowing chording with button 1 if ((b & 0x20) || (mouse.buttons & 0x1)) { if (up) mouse.buttons &= ~b; else mouse.buttons |= b; penmousetrack(mouse.buttons, -1, -1); } else { if (up) mouse.modifiers &= ~b; else mouse.modifiers |= b; }} voidpentrackxy(int x, int y) { if (x == -1) { /* pen up. associate with button 1 through 5 up */ mouse.buttons &= ~0x1f; } else { x = ((x*calibration.scalex)>>16) + calibration.transx; y = ((y*calibration.scaley)>>16) + calibration.transy; if ((mouse.buttons & 0x1f) == 0) { if (mouse.modifiers) mouse.buttons |= mouse.modifiers; else mouse.buttons |= 0x1; } } penmousetrack(mouse.buttons, x, y);} static voidpenmousereset(void){ if(!conf.monitor) return;} static voidpenmouseinit(void){ if(!conf.monitor) return;} static Chan*penmouseattach(char *spec){ if(!conf.monitor) error(Egreg); return devattach('m', spec);} static Walkqid*penmousewalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);} static intpenmousestat(Chan *c, uchar *db, int n){ return devstat(c, db, n, mousedir, nelem(mousedir), devgen);} static Chan*penmouseopen(Chan *c, int omode){ switch((ulong)c->qid.path){ case Qdir: if(omode != OREAD) error(Eperm); break; case Qmouse: lock(&mouse); if(mouse.open){ unlock(&mouse); error(Einuse); } mouse.open = 1; mouse.ref++; unlock(&mouse); break; case Qmousein: /* error("disabled"); */ lock(&mouse); if(mouse.inopen){ unlock(&mouse); error(Einuse); } mouse.inopen = 1; unlock(&mouse); break; default: incref(&mouse); } c->mode = openmode(omode); c->flag |= COPEN; c->offset = 0; return c;} static voidpenmousecreate(Chan*, char*, int, ulong){ if(!conf.monitor) error(Egreg); error(Eperm);} static voidpenmouseclose(Chan *c){ if(c->qid.path != Qdir && (c->flag&COPEN)){ lock(&mouse); if(c->qid.path == Qmouse) mouse.open = 0; else if(c->qid.path == Qmousein){ mouse.inopen = 0; unlock(&mouse); return; } --mouse.ref; unlock(&mouse); }} static longpenmouseread(Chan *c, void *va, long n, vlong){ char buf[4*12+1]; static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 }; Mousestate m; switch((ulong)c->qid.path){ case Qdir: return devdirread(c, va, n, mousedir, nelem(mousedir), devgen); case Qmousectl: sprint(buf, "c%11ld %11ld %11ld %11ld", calibration.scalex, calibration.scaley, calibration.transx, calibration.transy); if(n > 1+4*12) n = 1+4*12; memmove(va, buf, n); return n; case Qmouse: while(penmousechanged(0) == 0) sleep(&mouse.r, penmousechanged, 0); mouse.qfull = 0; /* * No lock of the indices is necessary here, because ri is only * updated by us, and there is only one mouse reader * at a time. I suppose that more than one process * could try to read the fd at one time, but such behavior * is degenerate and already violates the calling * conventions for sleep above. */ if(mouse.ri != mouse.wi) { m = mouse.queue[mouse.ri]; if(++mouse.ri == nelem(mouse.queue)) mouse.ri = 0; } else { m = mouse.Mousestate; } sprint(buf, "m%11d %11d %11d %11lud", m.xy.x, m.xy.y, m.buttons, m.msec); mouse.lastcounter = m.counter; if(n > 1+4*12) n = 1+4*12; memmove(va, buf, n); return n; } return 0;} static voidsetbuttonmap(char* map){ int i, x, one, two, three; one = two = three = 0; for(i = 0; i < 3; i++){ if(map[i] == 0) error(Ebadarg); if(map[i] == '1'){ if(one) error(Ebadarg); one = 1<<i; } else if(map[i] == '2'){ if(two) error(Ebadarg); two = 1<<i; } else if(map[i] == '3'){ if(three) error(Ebadarg); three = 1<<i; } else error(Ebadarg); } if(map[i]) error(Ebadarg); memset(buttonmap, 0, 8); for(i = 0; i < 8; i++){ x = 0; if(i & 1) x |= one; if(i & 2) x |= two; if(i & 4) x |= three; buttonmap[x] = i; }} static longpenmousewrite(Chan *c, void *va, long n, vlong){ char *p; Point pt; Cmdbuf *cb; Cmdtab *ct; char buf[64]; int b; p = va; switch((ulong)c->qid.path){ case Qdir: error(Eisdir); case Qmousectl: cb = parsecmd(va, n); if(waserror()){ free(cb); nexterror(); } ct = lookupcmd(cb, penmousecmd, nelem(penmousecmd)); switch(ct->index){ case CMswap: if(mouseswap) setbuttonmap("123"); else setbuttonmap("321"); mouseswap ^= 1; break; case CMcalibrate: if (cb->nf == 1) { calibration.scalex = 1<<16; calibration.scaley = 1<<16; calibration.transx = 0; calibration.transy = 0; } else if (cb->nf == 5) { if ((!isdigit(*cb->f[1]) && *cb->f[1] != '-') || (!isdigit(*cb->f[2]) && *cb->f[2] != '-') || (!isdigit(*cb->f[3]) && *cb->f[3] != '-') || (!isdigit(*cb->f[4]) && *cb->f[4] != '-')) error("bad syntax in control file message"); calibration.scalex = strtol(cb->f[1], nil, 0); calibration.scaley = strtol(cb->f[2], nil, 0); calibration.transx = strtol(cb->f[3], nil, 0); calibration.transy = strtol(cb->f[4], nil, 0); } else cmderror(cb, Ecmdargs); break; } free(cb); poperror(); return n; case Qmousein: if(n > sizeof buf-1) n = sizeof buf -1; memmove(buf, va, n); buf[n] = 0; p = 0; pt.x = strtol(buf+1, &p, 0); if(p == 0) error(Eshort); pt.y = strtol(p, &p, 0); if(p == 0) error(Eshort); b = strtol(p, &p, 0); penmousetrack(b, pt.x, pt.y); return n; case Qmouse: if(n > sizeof buf-1) n = sizeof buf -1; memmove(buf, va, n); buf[n] = 0; p = 0; pt.x = strtoul(buf+1, &p, 0); if(p == 0) error(Eshort); pt.y = strtoul(p, 0, 0); qlock(&mouse); if(ptinrect(pt, gscreen->r)) penmousetrack(mouse.buttons, pt.x, pt.y); qunlock(&mouse); return n; } error(Egreg); return -1;} Dev penmousedevtab = { 'm', "penmouse", penmousereset, penmouseinit, devshutdown, penmouseattach, penmousewalk, penmousestat, penmouseopen, penmousecreate, penmouseclose, penmouseread, devbread, penmousewrite, devbwrite, devremove, devwstat,}; /* * called at interrupt level to update the structure and * awaken any waiting procs. */static voidpenmousetrack(int b, int x, int y){ int lastb; if (x >= 0) mouse.xy = Pt(x, y); lastb = mouse.buttons; mouse.buttons = b; mouse.counter++; mouse.msec = TK2MS(MACHP(0)->ticks); /* * if the queue fills, we discard the entire queue and don't * queue any more events until a reader polls the mouse. */ if(!mouse.qfull && lastb != b) { /* add to ring */ mouse.queue[mouse.wi] = mouse.Mousestate; if(++mouse.wi == nelem(mouse.queue)) mouse.wi = 0; if(mouse.wi == mouse.ri) mouse.qfull = 1; } wakeup(&mouse.r); drawactive(1);} intpenmousechanged(void*){ return mouse.lastcounter != mouse.counter;} Pointpenmousexy(void){ return mouse.xy;}
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
#define Image IMAGE
#include <draw.h>
#include <memdraw.h>
#include <cursor.h>
#include "screen.h"
#include <ctype.h>
typedef struct Mouseinfo Mouseinfo;
typedef struct Mousestate Mousestate;
typedef struct Calibration Calibration;
struct Calibration
{
long scalex;
long scaley;
long transx;
long transy;
} calibration = {
-16435,
23275,
253,
-23
};
/* The pen goes down, tracks some and goes up again. The pen alone can
* only simulate a one-button mouse.
* To simulate a more-button (five, in this case) mouse, we use the four
* keys along the the bottom of the iPaq as modifiers.
* When one (or more) of the modifier keys is (are) down, a pen-down event
* causes the corresponding bottons to go down. If no modifier key is
* depressed, a pen-down event is translated into a button-one down event.
* Releasing the modifier keys has no direct effect. The pen-up event is
* the one that triggers mouse-up events.
*/
struct Mousestate
{
Point xy; /* mouse.xy */
int buttons; /* mouse.buttons */
int modifiers; /* state of physical buttons 2, 3, 4, 5 */
ulong counter; /* increments every update */
ulong msec; /* time of last event */
};
struct Mouseinfo
{
Mousestate;
ulong lastcounter; /* value when /dev/mouse read */
Rendez r;
Ref;
QLock;
int open;
int inopen;
Mousestate queue[16]; /* circular buffer of click events */
int ri; /* read index into queue */
int wi; /* write index into queue */
uchar qfull; /* queue is full */
};
Mouseinfo mouse;
int mouseshifted;
int penmousechanged(void*);
static void penmousetrack(int b, int x, int y);
enum{
Qdir,
Qmouse,
Qmousein,
Qmousectl,
};
static Dirtab mousedir[]={
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
"mouse", {Qmouse}, 0, 0666,
"mousein", {Qmousein}, 0, 0220,
"mousectl", {Qmousectl}, 0, 0660,
};
enum
{
CMcalibrate,
CMswap,
};
static Cmdtab penmousecmd[] =
{
CMcalibrate, "calibrate", 0,
CMswap, "swap", 1,
};
static uchar buttonmap[8] = {
0, 1, 2, 3, 4, 5, 6, 7,
};
static int mouseswap;
extern Memimage* gscreen;
void
penbutton(int up, int b) {
// button 5 (side button) immediately causes an event
// when the pen is down (button 1), other buttons also
// cause events, allowing chording with button 1
if ((b & 0x20) || (mouse.buttons & 0x1)) {
if (up)
mouse.buttons &= ~b;
else
mouse.buttons |= b;
penmousetrack(mouse.buttons, -1, -1);
} else {
if (up)
mouse.modifiers &= ~b;
else
mouse.modifiers |= b;
}
}
void
pentrackxy(int x, int y) {
if (x == -1) {
/* pen up. associate with button 1 through 5 up */
mouse.buttons &= ~0x1f;
} else {
x = ((x*calibration.scalex)>>16) + calibration.transx;
y = ((y*calibration.scaley)>>16) + calibration.transy;
if ((mouse.buttons & 0x1f) == 0) {
if (mouse.modifiers)
mouse.buttons |= mouse.modifiers;
else
mouse.buttons |= 0x1;
}
}
penmousetrack(mouse.buttons, x, y);
}
static void
penmousereset(void)
{
if(!conf.monitor)
return;
}
static void
penmouseinit(void)
{
if(!conf.monitor)
return;
}
static Chan*
penmouseattach(char *spec)
{
if(!conf.monitor)
error(Egreg);
return devattach('m', spec);
}
static Walkqid*
penmousewalk(Chan *c, Chan *nc, char **name, int nname)
{
return devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
}
static int
penmousestat(Chan *c, uchar *db, int n)
{
return devstat(c, db, n, mousedir, nelem(mousedir), devgen);
}
static Chan*
penmouseopen(Chan *c, int omode)
{
switch((ulong)c->qid.path){
case Qdir:
if(omode != OREAD)
error(Eperm);
break;
case Qmouse:
lock(&mouse);
if(mouse.open){
unlock(&mouse);
error(Einuse);
}
mouse.open = 1;
mouse.ref++;
unlock(&mouse);
break;
case Qmousein:
/* error("disabled"); */
lock(&mouse);
if(mouse.inopen){
unlock(&mouse);
error(Einuse);
}
mouse.inopen = 1;
unlock(&mouse);
break;
default:
incref(&mouse);
}
c->mode = openmode(omode);
c->flag |= COPEN;
c->offset = 0;
return c;
}
static void
penmousecreate(Chan*, char*, int, ulong)
{
if(!conf.monitor)
error(Egreg);
error(Eperm);
}
static void
penmouseclose(Chan *c)
{
if(c->qid.path != Qdir && (c->flag&COPEN)){
lock(&mouse);
if(c->qid.path == Qmouse)
mouse.open = 0;
else if(c->qid.path == Qmousein){
mouse.inopen = 0;
unlock(&mouse);
return;
}
--mouse.ref;
unlock(&mouse);
}
}
static long
penmouseread(Chan *c, void *va, long n, vlong)
{
char buf[4*12+1];
static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
Mousestate m;
switch((ulong)c->qid.path){
case Qdir:
return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);
case Qmousectl:
sprint(buf, "c%11ld %11ld %11ld %11ld",
calibration.scalex, calibration.scaley,
calibration.transx, calibration.transy);
if(n > 1+4*12)
n = 1+4*12;
memmove(va, buf, n);
return n;
case Qmouse:
while(penmousechanged(0) == 0)
sleep(&mouse.r, penmousechanged, 0);
mouse.qfull = 0;
/*
* No lock of the indices is necessary here, because ri is only
* updated by us, and there is only one mouse reader
* at a time. I suppose that more than one process
* could try to read the fd at one time, but such behavior
* is degenerate and already violates the calling
* conventions for sleep above.
*/
if(mouse.ri != mouse.wi) {
m = mouse.queue[mouse.ri];
if(++mouse.ri == nelem(mouse.queue))
mouse.ri = 0;
} else {
m = mouse.Mousestate;
}
sprint(buf, "m%11d %11d %11d %11lud",
m.xy.x, m.xy.y,
m.buttons,
m.msec);
mouse.lastcounter = m.counter;
if(n > 1+4*12)
n = 1+4*12;
memmove(va, buf, n);
return n;
}
return 0;
}
static void
setbuttonmap(char* map)
{
int i, x, one, two, three;
one = two = three = 0;
for(i = 0; i < 3; i++){
if(map[i] == 0)
error(Ebadarg);
if(map[i] == '1'){
if(one)
error(Ebadarg);
one = 1<<i;
}
else if(map[i] == '2'){
if(two)
error(Ebadarg);
two = 1<<i;
}
else if(map[i] == '3'){
if(three)
error(Ebadarg);
three = 1<<i;
}
else
error(Ebadarg);
}
if(map[i])
error(Ebadarg);
memset(buttonmap, 0, 8);
for(i = 0; i < 8; i++){
x = 0;
if(i & 1)
x |= one;
if(i & 2)
x |= two;
if(i & 4)
x |= three;
buttonmap[x] = i;
}
}
static long
penmousewrite(Chan *c, void *va, long n, vlong)
{
char *p;
Point pt;
Cmdbuf *cb;
Cmdtab *ct;
char buf[64];
int b;
p = va;
switch((ulong)c->qid.path){
case Qdir:
error(Eisdir);
case Qmousectl:
cb = parsecmd(va, n);
if(waserror()){
free(cb);
nexterror();
}
ct = lookupcmd(cb, penmousecmd, nelem(penmousecmd));
switch(ct->index){
case CMswap:
if(mouseswap)
setbuttonmap("123");
else
setbuttonmap("321");
mouseswap ^= 1;
break;
case CMcalibrate:
if (cb->nf == 1) {
calibration.scalex = 1<<16;
calibration.scaley = 1<<16;
calibration.transx = 0;
calibration.transy = 0;
} else if (cb->nf == 5) {
if ((!isdigit(*cb->f[1]) && *cb->f[1] != '-')
|| (!isdigit(*cb->f[2]) && *cb->f[2] != '-')
|| (!isdigit(*cb->f[3]) && *cb->f[3] != '-')
|| (!isdigit(*cb->f[4]) && *cb->f[4] != '-'))
error("bad syntax in control file message");
calibration.scalex = strtol(cb->f[1], nil, 0);
calibration.scaley = strtol(cb->f[2], nil, 0);
calibration.transx = strtol(cb->f[3], nil, 0);
calibration.transy = strtol(cb->f[4], nil, 0);
} else
cmderror(cb, Ecmdargs);
break;
}
free(cb);
poperror();
return n;
case Qmousein:
if(n > sizeof buf-1)
n = sizeof buf -1;
memmove(buf, va, n);
buf[n] = 0;
p = 0;
pt.x = strtol(buf+1, &p, 0);
if(p == 0)
error(Eshort);
pt.y = strtol(p, &p, 0);
if(p == 0)
error(Eshort);
b = strtol(p, &p, 0);
penmousetrack(b, pt.x, pt.y);
return n;
case Qmouse:
if(n > sizeof buf-1)
n = sizeof buf -1;
memmove(buf, va, n);
buf[n] = 0;
p = 0;
pt.x = strtoul(buf+1, &p, 0);
if(p == 0)
error(Eshort);
pt.y = strtoul(p, 0, 0);
qlock(&mouse);
if(ptinrect(pt, gscreen->r))
penmousetrack(mouse.buttons, pt.x, pt.y);
qunlock(&mouse);
return n;
}
error(Egreg);
return -1;
}
Dev penmousedevtab = {
'm',
"penmouse",
penmousereset,
penmouseinit,
devshutdown,
penmouseattach,
penmousewalk,
penmousestat,
penmouseopen,
penmousecreate,
penmouseclose,
penmouseread,
devbread,
penmousewrite,
devbwrite,
devremove,
devwstat,
};
/*
* called at interrupt level to update the structure and
* awaken any waiting procs.
*/
static void
penmousetrack(int b, int x, int y)
{
int lastb;
if (x >= 0)
mouse.xy = Pt(x, y);
lastb = mouse.buttons;
mouse.buttons = b;
mouse.counter++;
mouse.msec = TK2MS(MACHP(0)->ticks);
/*
* if the queue fills, we discard the entire queue and don't
* queue any more events until a reader polls the mouse.
*/
if(!mouse.qfull && lastb != b) { /* add to ring */
mouse.queue[mouse.wi] = mouse.Mousestate;
if(++mouse.wi == nelem(mouse.queue))
mouse.wi = 0;
if(mouse.wi == mouse.ri)
mouse.qfull = 1;
}
wakeup(&mouse.r);
drawactive(1);
}
int
penmousechanged(void*)
{
return mouse.lastcounter != mouse.counter;
}
Point
penmousexy(void)
{
return mouse.xy;
}