123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #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"
- enum {
- ScrollUp = 0x08,
- ScrollDown = 0x10,
- ScrollLeft = 0x20,
- ScrollRight = 0x40,
- };
- typedef struct Mouseinfo Mouseinfo;
- typedef struct Mousestate Mousestate;
- struct Mousestate
- {
- Point xy; /* mouse.xy */
- int buttons; /* mouse.buttons */
- uint32_t counter; /* increments every update */
- uint32_t msec; /* time of last event */
- };
- struct Mouseinfo
- {
- Lock _lock;
- Mousestate;
- int dx;
- int dy;
- int track; /* dx & dy updated */
- int redraw; /* update cursor on screen */
- uint32_t lastcounter; /* value when /dev/mouse read */
- uint32_t lastresize;
- uint32_t resize;
- Rendez rend;
- Ref r;
- QLock ql;
- int open;
- int acceleration;
- int maxacc;
- Mousestate queue[16]; /* circular buffer of click events */
- int ri; /* read index into queue */
- int wi; /* write index into queue */
- unsigned char qfull; /* queue is full */
- };
- enum
- {
- CMbuttonmap,
- CMscrollswap,
- CMswap,
- CMwildcard,
- };
- static Cmdtab mousectlmsg[] =
- {
- CMbuttonmap, "buttonmap", 0,
- CMscrollswap, "scrollswap", 0,
- CMswap, "swap", 1,
- CMwildcard, "*", 0,
- };
- Mouseinfo mouse;
- Cursorinfo cursor;
- int mouseshifted;
- int kbdbuttons;
- void (*kbdmouse)(int);
- Cursor curs;
- void Cursortocursor(Cursor*);
- int mousechanged(void*);
- static void mouseclock(void);
- enum{
- Qdir,
- Qcursor,
- Qmouse,
- Qmousein,
- Qmousectl,
- };
- static Dirtab mousedir[]={
- ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
- "cursor", {Qcursor}, 0, 0666,
- "mouse", {Qmouse}, 0, 0666,
- "mousein", {Qmousein}, 0, 0220,
- "mousectl", {Qmousectl}, 0, 0220,
- };
- static unsigned char buttonmap[8] = {
- 0, 1, 2, 3, 4, 5, 6, 7,
- };
- static int mouseswap;
- static int scrollswap;
- static uint32_t mousetime;
- extern Memimage* gscreen;
- extern uint32_t kerndate;
- static void
- mousereset(void)
- {
- curs = arrow;
- Cursortocursor(&arrow);
- /* redraw cursor about 30 times per second */
- addclock0link(mouseclock, 33);
- }
- static void
- mousefromkbd(int buttons)
- {
- kbdbuttons = buttons;
- mousetrack(0, 0, 0, TK2MS(machp()->ticks));
- }
- static int
- mousedevgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
- {
- int rc;
- rc = devgen(c, name, tab, ntab, i, dp);
- if(rc != -1)
- dp->atime = mousetime;
- return rc;
- }
- static void
- mouseinit(void)
- {
- curs = arrow;
- Cursortocursor(&arrow);
- cursoron(1);
- kbdmouse = mousefromkbd;
- mousetime = seconds();
- }
- static Chan*
- mouseattach(char *spec)
- {
- return devattach('m', spec);
- }
- static Walkqid*
- mousewalk(Chan *c, Chan *nc, char **name, int nname)
- {
- Walkqid *wq;
- /*
- * We use devgen() and not mousedevgen() here
- * see "Ugly problem" in dev.c/devwalk()
- */
- wq = devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
- if(wq != nil && wq->clone != c && wq->clone != nil && (wq->clone->qid.type&QTDIR)==0)
- incref(&mouse.r);
- return wq;
- }
- static int
- mousestat(Chan *c, unsigned char *db, int n)
- {
- return devstat(c, db, n, mousedir, nelem(mousedir), mousedevgen);
- }
- static Chan*
- mouseopen(Chan *c, int omode)
- {
- switch((uint32_t)c->qid.path){
- case Qdir:
- if(omode != OREAD)
- error(Eperm);
- break;
- case Qmouse:
- lock(&mouse.r.l);
- if(mouse.open){
- unlock(&mouse.r.l);
- error(Einuse);
- }
- mouse.open = 1;
- mouse.r.ref++;
- mouse.lastresize = mouse.resize;
- unlock(&mouse.r.l);
- break;
- case Qmousein:
- if(!iseve())
- error(Eperm);
- break;
- default:
- incref(&mouse.r);
- }
- c->mode = openmode(omode);
- c->flag |= COPEN;
- c->offset = 0;
- return c;
- }
- static void
- mousecreate(Chan *c, char *j, int i, int u)
- {
- error(Eperm);
- }
- static void
- mouseclose(Chan *c)
- {
- if((c->qid.type&QTDIR)==0 && (c->flag&COPEN)){
- if(c->qid.path == Qmousein)
- return;
- lock(&mouse.r.l);
- if(c->qid.path == Qmouse)
- mouse.open = 0;
- if(--mouse.r.ref == 0){
- cursoroff(1);
- curs = arrow;
- Cursortocursor(&arrow);
- cursoron(1);
- }
- unlock(&mouse.r.l);
- }
- }
- static int32_t
- mouseread(Chan *c, void *va, int32_t n, int64_t off)
- {
- Proc *up = externup();
- char buf[1+4*12+1];
- unsigned char *p;
- uint32_t offset = off;
- Mousestate m;
- int b;
- p = va;
- switch((uint32_t)c->qid.path){
- case Qdir:
- return devdirread(c, va, n, mousedir, nelem(mousedir), mousedevgen);
- case Qcursor:
- if(offset != 0)
- return 0;
- if(n < 2*4+2*2*16)
- error(Eshort);
- n = 2*4+2*2*16;
- lock(&cursor.l);
- BPLONG(p+0, curs.offset.x);
- BPLONG(p+4, curs.offset.y);
- memmove(p+8, curs.clr, 2*16);
- memmove(p+40, curs.set, 2*16);
- unlock(&cursor.l);
- return n;
- case Qmouse:
- while(mousechanged(0) == 0)
- sleep(&mouse.rend, mousechanged, 0);
- mouse.qfull = 0;
- mousetime = seconds();
- /*
- * 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 {
- while(!canlock(&cursor.l))
- tsleep(&up->sleep, return0, 0, TK2MS(1));
- m = mouse.Mousestate;
- unlock(&cursor.l);
- }
- b = buttonmap[m.buttons&7];
- /* put buttons 4 and 5 back in */
- b |= m.buttons & (3<<3);
- if (scrollswap)
- if (b == 8)
- b = 16;
- else if (b == 16)
- b = 8;
- snprint(buf, sizeof buf, "m%11d %11d %11d %11lud ",
- m.xy.x, m.xy.y,
- b,
- m.msec);
- mouse.lastcounter = m.counter;
- if(n > 1+4*12)
- n = 1+4*12;
- if(mouse.lastresize != mouse.resize){
- mouse.lastresize = mouse.resize;
- buf[0] = 'r';
- }
- 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 int32_t
- mousewrite(Chan *c, void *va, int32_t n, int64_t r)
- {
- Proc *up = externup();
- char *p;
- Point pt;
- Cmdbuf *cb;
- Cmdtab *ct;
- char buf[64];
- int b, msec;
- p = va;
- switch((uint32_t)c->qid.path){
- case Qdir:
- error(Eisdir);
- case Qcursor:
- cursoroff(1);
- if(n < 2*4+2*2*16){
- curs = arrow;
- Cursortocursor(&arrow);
- }else{
- n = 2*4+2*2*16;
- curs.offset.x = BGLONG(p+0);
- curs.offset.y = BGLONG(p+4);
- memmove(curs.clr, p+8, 2*16);
- memmove(curs.set, p+40, 2*16);
- Cursortocursor(&curs);
- }
- qlock(&mouse.ql);
- mouse.redraw = 1;
- mouseclock();
- qunlock(&mouse.ql);
- cursoron(1);
- return n;
- case Qmousectl:
- cb = parsecmd(va, n);
- if(waserror()){
- free(cb);
- nexterror();
- }
- ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
- switch(ct->index){
- case CMswap:
- if(mouseswap)
- setbuttonmap("123");
- else
- setbuttonmap("321");
- mouseswap ^= 1;
- break;
- case CMscrollswap:
- scrollswap ^= 1;
- break;
- case CMbuttonmap:
- if(cb->nf == 1)
- setbuttonmap("123");
- else
- setbuttonmap(cb->f[1]);
- break;
- case CMwildcard:
- mousectl(cb);
- 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);
- msec = strtol(p, &p, 0);
- if(msec == 0)
- msec = TK2MS(machp()->ticks);
- mousetrack(pt.x, pt.y, b, msec);
- 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.ql);
- if(ptinrect(pt, gscreen->r)){
- mouse.xy = pt;
- mouse.redraw = 1;
- mouse.track = 1;
- mouseclock();
- }
- qunlock(&mouse.ql);
- return n;
- }
- error(Egreg);
- return -1;
- }
- Dev mousedevtab = {
- 'm',
- "mouse",
- mousereset,
- mouseinit,
- devshutdown,
- mouseattach,
- mousewalk,
- mousestat,
- mouseopen,
- mousecreate,
- mouseclose,
- mouseread,
- devbread,
- mousewrite,
- devbwrite,
- devremove,
- devwstat,
- };
- void
- Cursortocursor(Cursor *c)
- {
- lock(&cursor.l);
- memmove(&cursor.c, c, sizeof(Cursor));
- setcursor(c);
- unlock(&cursor.l);
- }
- /*
- * called by the clock routine to redraw the cursor
- */
- static void
- mouseclock(void)
- {
- if(mouse.track){
- mousetrack(mouse.dx, mouse.dy, mouse.buttons, TK2MS(machp()->ticks));
- mouse.track = 0;
- mouse.dx = 0;
- mouse.dy = 0;
- }
- if(mouse.redraw && canlock(&cursor.l)){
- mouse.redraw = 0;
- cursoroff(0);
- mouse.redraw = cursoron(0);
- unlock(&cursor.l);
- }
- drawactive(0);
- }
- static int
- scale(int x)
- {
- int sign = 1;
- if(x < 0){
- sign = -1;
- x = -x;
- }
- switch(x){
- case 0:
- case 1:
- case 2:
- case 3:
- break;
- case 4:
- x = 6 + (mouse.acceleration>>2);
- break;
- case 5:
- x = 9 + (mouse.acceleration>>1);
- break;
- default:
- x *= mouse.maxacc;
- break;
- }
- return sign*x;
- }
- /*
- * called at interrupt level to update the structure and
- * awaken any waiting procs.
- */
- void
- mousetrack(int dx, int dy, int b, int msec)
- {
- int x, y, lastb;
- if(gscreen==nil)
- return;
- if(mouse.acceleration){
- dx = scale(dx);
- dy = scale(dy);
- }
- x = mouse.xy.x + dx;
- if(x < gscreen->clipr.min.x)
- x = gscreen->clipr.min.x;
- if(x >= gscreen->clipr.max.x)
- x = gscreen->clipr.max.x;
- y = mouse.xy.y + dy;
- if(y < gscreen->clipr.min.y)
- y = gscreen->clipr.min.y;
- if(y >= gscreen->clipr.max.y)
- y = gscreen->clipr.max.y;
- lastb = mouse.buttons;
- mouse.xy = Pt(x, y);
- mouse.buttons = b|kbdbuttons;
- mouse.redraw = 1;
- mouse.counter++;
- mouse.msec = msec;
- /*
- * 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.rend);
- drawactive(1);
- }
- /*
- * microsoft 3 button, 7 bit bytes
- *
- * byte 0 - 1 L R Y7 Y6 X7 X6
- * byte 1 - 0 X5 X4 X3 X2 X1 X0
- * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0
- * byte 3 - 0 M x x x x x (optional)
- *
- * shift & right button is the same as middle button (for 2 button mice)
- */
- int
- m3mouseputc(Queue *queue, int c)
- {
- static unsigned char msg[3];
- static int nb;
- static int middle;
- static unsigned char b[] = { 0, 4, 1, 5, 0, 2, 1, 3 };
- short x;
- int dx, dy, newbuttons;
- static uint32_t lasttick;
- uint32_t m;
- /* Resynchronize in stream with timing. */
- m = machp()->ticks;
- if(TK2SEC(m - lasttick) > 2)
- nb = 0;
- lasttick = m;
- if(nb==0){
- /*
- * an extra byte comes for middle button motion.
- * only two possible values for the extra byte.
- */
- if(c == 0x00 || c == 0x20){
- /* an extra byte gets sent for the middle button */
- middle = (c&0x20) ? 2 : 0;
- newbuttons = (mouse.buttons & ~2) | middle;
- mousetrack(0, 0, newbuttons, TK2MS(machp()->ticks));
- return 0;
- }
- }
- msg[nb] = c;
- if(++nb == 3){
- nb = 0;
- newbuttons = middle | b[(msg[0]>>4)&3 | (mouseshifted ? 4 : 0)];
- x = (msg[0]&0x3)<<14;
- dx = (x>>8) | msg[1];
- x = (msg[0]&0xc)<<12;
- dy = (x>>8) | msg[2];
- mousetrack(dx, dy, newbuttons, TK2MS(machp()->ticks));
- }
- return 0;
- }
- /*
- * microsoft intellimouse 3 buttons + scroll
- * byte 0 - 1 L R Y7 Y6 X7 X6
- * byte 1 - 0 X5 X4 X3 X2 X1 X0
- * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0
- * byte 3 - 0 0 M % % % %
- *
- * %: 0xf => U , 0x1 => D
- *
- * L: left
- * R: right
- * U: up
- * D: down
- */
- int
- m5mouseputc(Queue *queue, int c)
- {
- static unsigned char msg[3];
- static int nb;
- static uint32_t lasttick;
- uint32_t m;
- /* Resynchronize in stream with timing. */
- m = machp()->ticks;
- if(TK2SEC(m - lasttick) > 2)
- nb = 0;
- lasttick = m;
- msg[nb++] = c & 0x7f;
- if (nb == 4) {
- char dx,dy,newbuttons;
- dx = msg[1] | (msg[0] & 0x3) << 6;
- dy = msg[2] | (msg[0] & 0xc) << 4;
- newbuttons =
- (msg[0] & 0x10) >> (mouseshifted ? 3 : 2)
- | (msg[0] & 0x20) >> 5
- | ( msg[3] == 0x10 ? 0x02 :
- msg[3] == 0x0f ? ScrollUp :
- msg[3] == 0x01 ? ScrollDown : 0 );
- mousetrack(dx, dy, newbuttons, TK2MS(machp()->ticks));
- nb = 0;
- }
- return 0;
- }
- /*
- * Logitech 5 byte packed binary mouse format, 8 bit bytes
- *
- * shift & right button is the same as middle button (for 2 button mice)
- */
- int
- mouseputc(Queue *queue, int c)
- {
- static short msg[5];
- static int nb;
- static unsigned char b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 3, 3, 7};
- int dx, dy, newbuttons;
- static uint32_t lasttick;
- uint32_t m;
- /* Resynchronize in stream with timing. */
- m = machp()->ticks;
- if(TK2SEC(m - lasttick) > 2)
- nb = 0;
- lasttick = m;
- if((c&0xF0) == 0x80)
- nb=0;
- msg[nb] = c;
- if(c & 0x80)
- msg[nb] |= ~0xFF; /* sign extend */
- if(++nb == 5){
- newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)];
- dx = msg[1]+msg[3];
- dy = -(msg[2]+msg[4]);
- mousetrack(dx, dy, newbuttons, TK2MS(machp()->ticks));
- nb = 0;
- }
- return 0;
- }
- int
- mousechanged(void *v)
- {
- return mouse.lastcounter != mouse.counter ||
- mouse.lastresize != mouse.resize;
- }
- Point
- mousexy(void)
- {
- return mouse.xy;
- }
- void
- mouseaccelerate(int x)
- {
- mouse.acceleration = x;
- if(mouse.acceleration < 3)
- mouse.maxacc = 2;
- else
- mouse.maxacc = mouse.acceleration;
- }
- /*
- * notify reader that screen has been resized
- */
- void
- mouseresize(void)
- {
- mouse.resize++;
- wakeup(&mouse.rend);
- }
|