827 lines
14 KiB
C
827 lines
14 KiB
C
#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 */
|
|
ulong counter; /* increments every update */
|
|
ulong msec; /* time of last event */
|
|
};
|
|
|
|
struct Mouseinfo
|
|
{
|
|
Lock;
|
|
Mousestate;
|
|
int inbuttons; /* buttons from /dev/mousein */
|
|
int redraw; /* update cursor on screen */
|
|
Rendez redrawr; /* wait for cursor screen updates */
|
|
ulong lastcounter; /* value when /dev/mouse read */
|
|
int resize; /* generate resize event */
|
|
Rendez r;
|
|
Ref;
|
|
int open;
|
|
int acceleration;
|
|
int maxacc;
|
|
Mousestate queue[16]; /* circular buffer of click events */
|
|
ulong ri; /* read index into queue */
|
|
ulong wi; /* write index into queue */
|
|
};
|
|
|
|
enum
|
|
{
|
|
CMbuttonmap,
|
|
CMscrollswap,
|
|
CMswap,
|
|
CMblank,
|
|
CMblanktime,
|
|
CMtwitch,
|
|
CMwildcard,
|
|
};
|
|
|
|
static Cmdtab mousectlmsg[] =
|
|
{
|
|
CMbuttonmap, "buttonmap", 0,
|
|
CMscrollswap, "scrollswap", 0,
|
|
CMswap, "swap", 1,
|
|
CMblank, "blank", 1,
|
|
CMblanktime, "blanktime", 2,
|
|
CMtwitch, "twitch", 1,
|
|
CMwildcard, "*", 0,
|
|
};
|
|
|
|
Mouseinfo mouse;
|
|
Cursorinfo cursor;
|
|
Cursor curs;
|
|
|
|
void Cursortocursor(Cursor*);
|
|
void mouseblankscreen(int);
|
|
int mousechanged(void*);
|
|
void mouseredraw(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 uchar buttonmap[8] = {
|
|
0, 1, 2, 3, 4, 5, 6, 7,
|
|
};
|
|
static int mouseswap;
|
|
static int scrollswap;
|
|
static ulong mousetime;
|
|
static ulong blanktime = 30; /* in minutes; a half hour */
|
|
|
|
extern Memimage* gscreen;
|
|
|
|
Cursor arrow = {
|
|
{ -1, -1 },
|
|
{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
|
|
0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
|
|
0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
|
|
0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
|
|
},
|
|
{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
|
|
0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
|
|
0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
|
|
0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
|
|
},
|
|
};
|
|
|
|
static void
|
|
mousereset(void)
|
|
{
|
|
if(!conf.monitor)
|
|
return;
|
|
|
|
curs = arrow;
|
|
Cursortocursor(&arrow);
|
|
}
|
|
|
|
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 mouseproc(void*);
|
|
|
|
static void
|
|
mouseinit(void)
|
|
{
|
|
if(!conf.monitor)
|
|
return;
|
|
|
|
curs = arrow;
|
|
Cursortocursor(&arrow);
|
|
cursoron();
|
|
mousetime = seconds();
|
|
|
|
kproc("mouse", mouseproc, 0);
|
|
}
|
|
|
|
static Chan*
|
|
mouseattach(char *spec)
|
|
{
|
|
if(!conf.monitor)
|
|
error(Egreg);
|
|
return devattach('m', spec);
|
|
}
|
|
|
|
static Walkqid*
|
|
mousewalk(Chan *c, Chan *nc, char **name, int nname)
|
|
{
|
|
/*
|
|
* We use devgen() and not mousedevgen() here
|
|
* see "Ugly problem" in dev.c/devwalk()
|
|
*/
|
|
return devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
|
|
}
|
|
|
|
static int
|
|
mousestat(Chan *c, uchar *db, int n)
|
|
{
|
|
return devstat(c, db, n, mousedir, nelem(mousedir), mousedevgen);
|
|
}
|
|
|
|
static Chan*
|
|
mouseopen(Chan *c, int omode)
|
|
{
|
|
int mode;
|
|
|
|
mode = openmode(omode);
|
|
switch((ulong)c->qid.path){
|
|
case Qdir:
|
|
if(omode != OREAD)
|
|
error(Eperm);
|
|
break;
|
|
case Qmousein:
|
|
if(!iseve())
|
|
error(Eperm);
|
|
c->aux = malloc(sizeof(Mousestate));
|
|
if(c->aux == nil)
|
|
error(Enomem);
|
|
break;
|
|
case Qmouse:
|
|
if(tas(&mouse.open) != 0)
|
|
error(Einuse);
|
|
mouse.lastcounter = mouse.counter;
|
|
mouse.resize = 0;
|
|
mousetime = seconds();
|
|
/* wet floor */
|
|
case Qcursor:
|
|
incref(&mouse);
|
|
}
|
|
c->mode = mode;
|
|
c->flag |= COPEN;
|
|
c->offset = 0;
|
|
return c;
|
|
}
|
|
|
|
static void
|
|
mouseclose(Chan *c)
|
|
{
|
|
if((c->qid.type&QTDIR)!=0 || (c->flag&COPEN)==0)
|
|
return;
|
|
switch((ulong)c->qid.path){
|
|
case Qmousein:
|
|
mouse.inbuttons &= ~((Mousestate*)c->aux)->buttons;
|
|
free(c->aux); /* Mousestate */
|
|
c->aux = nil;
|
|
return;
|
|
case Qmouse:
|
|
mouse.open = 0;
|
|
mouseblankscreen(0);
|
|
/* wet floor */
|
|
case Qcursor:
|
|
if(decref(&mouse) != 0)
|
|
return;
|
|
cursoroff();
|
|
curs = arrow;
|
|
Cursortocursor(&arrow);
|
|
cursoron();
|
|
}
|
|
}
|
|
|
|
|
|
static long
|
|
mouseread(Chan *c, void *va, long n, vlong off)
|
|
{
|
|
char buf[1+4*12+1];
|
|
uchar *p;
|
|
ulong offset = off;
|
|
Mousestate m;
|
|
int b;
|
|
|
|
p = va;
|
|
switch((ulong)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;
|
|
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);
|
|
return n;
|
|
|
|
case Qmouse:
|
|
while(!mousechanged(nil)){
|
|
tsleep(&mouse.r, mousechanged, nil, 30*1000);
|
|
if(blanktime && !mousechanged(nil) &&
|
|
(seconds() - mousetime) >= blanktime*60)
|
|
mouseblankscreen(1);
|
|
}
|
|
mousetime = seconds();
|
|
mouseblankscreen(0);
|
|
|
|
ilock(&mouse);
|
|
if(mouse.ri != mouse.wi)
|
|
m = mouse.queue[mouse.ri++ % nelem(mouse.queue)];
|
|
else
|
|
m = mouse.Mousestate;
|
|
iunlock(&mouse);
|
|
|
|
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;
|
|
sprint(buf, "m%11d %11d %11d %11ld ",
|
|
m.xy.x, m.xy.y, b, m.msec);
|
|
|
|
mouse.lastcounter = m.counter;
|
|
if(mouse.resize){
|
|
mouse.resize = 0;
|
|
buf[0] = 'r';
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
void scmousetrack(int, int, int, ulong);
|
|
|
|
static long
|
|
mousewrite(Chan *c, void *va, long n, vlong)
|
|
{
|
|
char *p;
|
|
Point pt;
|
|
Cmdbuf *cb;
|
|
Cmdtab *ct;
|
|
char buf[64];
|
|
int b, z, msec;
|
|
Mousestate *m;
|
|
|
|
p = va;
|
|
switch((ulong)c->qid.path){
|
|
case Qdir:
|
|
error(Eisdir);
|
|
|
|
case Qcursor:
|
|
cursoroff();
|
|
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);
|
|
}
|
|
cursoron();
|
|
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 CMblank:
|
|
mouseblankscreen(1);
|
|
break;
|
|
|
|
case CMblanktime:
|
|
blanktime = strtoul(cb->f[1], 0, 0);
|
|
/* wet floor */
|
|
case CMtwitch:
|
|
mousetime = seconds();
|
|
mouseblankscreen(0);
|
|
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;
|
|
|
|
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 = (ulong)strtoll(p, 0, 0);
|
|
if(msec == 0)
|
|
msec = TK2MS(MACHP(0)->ticks);
|
|
|
|
/* exclude wheel */
|
|
z = b & (8|16);
|
|
b ^= z;
|
|
|
|
m = (Mousestate*)c->aux;
|
|
m->xy = pt;
|
|
m->msec = msec;
|
|
b ^= m->buttons;
|
|
m->buttons ^= b;
|
|
mouse.inbuttons = (m->buttons & b) | (mouse.inbuttons & ~b);
|
|
b = mouse.buttons & ~b;
|
|
|
|
/* include wheel */
|
|
b &= ~(8|16);
|
|
b ^= z;
|
|
|
|
if(buf[0] == 'A')
|
|
absmousetrack(pt.x, pt.y, b, msec);
|
|
else if(buf[0] == 'a')
|
|
scmousetrack(pt.x, pt.y, b, msec);
|
|
else
|
|
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;
|
|
|
|
pt.x = strtol(buf+1, &p, 0);
|
|
if(*p == 0)
|
|
error(Eshort);
|
|
pt.y = strtol(p, 0, 0);
|
|
absmousetrack(pt.x, pt.y, mouse.buttons, TK2MS(MACHP(0)->ticks));
|
|
return n;
|
|
}
|
|
|
|
error(Egreg);
|
|
return -1;
|
|
}
|
|
|
|
Dev mousedevtab = {
|
|
'm',
|
|
"mouse",
|
|
|
|
mousereset,
|
|
mouseinit,
|
|
devshutdown,
|
|
mouseattach,
|
|
mousewalk,
|
|
mousestat,
|
|
mouseopen,
|
|
devcreate,
|
|
mouseclose,
|
|
mouseread,
|
|
devbread,
|
|
mousewrite,
|
|
devbwrite,
|
|
devremove,
|
|
devwstat,
|
|
};
|
|
|
|
void
|
|
Cursortocursor(Cursor *c)
|
|
{
|
|
qlock(&drawlock);
|
|
lock(&cursor);
|
|
memmove(&cursor.Cursor, c, sizeof(Cursor));
|
|
setcursor(c);
|
|
unlock(&cursor);
|
|
qunlock(&drawlock);
|
|
}
|
|
|
|
void
|
|
mouseblankscreen(int blank)
|
|
{
|
|
static int blanked;
|
|
|
|
if(blank == blanked)
|
|
return;
|
|
qlock(&drawlock);
|
|
if(blanked != blank){
|
|
blankscreen(blank);
|
|
blanked = blank;
|
|
}
|
|
qunlock(&drawlock);
|
|
}
|
|
|
|
static int
|
|
shouldredraw(void*)
|
|
{
|
|
return mouse.redraw != 0;
|
|
}
|
|
|
|
/*
|
|
* process that redraws the cursor
|
|
*/
|
|
static void
|
|
mouseproc(void*)
|
|
{
|
|
while(waserror())
|
|
;
|
|
for(;;){
|
|
sleep(&mouse.redrawr, shouldredraw, nil);
|
|
mouse.redraw = 0;
|
|
cursoroff();
|
|
cursoron();
|
|
}
|
|
}
|
|
|
|
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, ulong msec)
|
|
{
|
|
if(mouse.acceleration){
|
|
dx = scale(dx);
|
|
dy = scale(dy);
|
|
}
|
|
absmousetrack(mouse.xy.x + dx, mouse.xy.y + dy, b, msec);
|
|
}
|
|
|
|
void
|
|
absmousetrack(int x, int y, int b, ulong msec)
|
|
{
|
|
int lastb;
|
|
|
|
if(gscreen==nil)
|
|
return;
|
|
|
|
if(x < gscreen->clipr.min.x)
|
|
x = gscreen->clipr.min.x;
|
|
if(x >= gscreen->clipr.max.x)
|
|
x = gscreen->clipr.max.x-1;
|
|
if(y < gscreen->clipr.min.y)
|
|
y = gscreen->clipr.min.y;
|
|
if(y >= gscreen->clipr.max.y)
|
|
y = gscreen->clipr.max.y-1;
|
|
|
|
|
|
ilock(&mouse);
|
|
mouse.xy = Pt(x, y);
|
|
lastb = mouse.buttons;
|
|
b |= mouse.inbuttons;
|
|
mouse.buttons = b;
|
|
mouse.msec = msec;
|
|
mouse.counter++;
|
|
|
|
/*
|
|
* if the queue fills, don't queue any more events until a
|
|
* reader polls the mouse.
|
|
*/
|
|
if(b != lastb && (mouse.wi-mouse.ri) < nelem(mouse.queue))
|
|
mouse.queue[mouse.wi++ % nelem(mouse.queue)] = mouse.Mousestate;
|
|
iunlock(&mouse);
|
|
|
|
wakeup(&mouse.r);
|
|
|
|
mouseredraw();
|
|
}
|
|
|
|
void
|
|
scmousetrack(int x, int y, int b, ulong msec)
|
|
{
|
|
vlong vx, vy;
|
|
|
|
if(gscreen==nil)
|
|
return;
|
|
|
|
vx = (vlong)(uint)x * (gscreen->clipr.max.x - gscreen->clipr.min.x);
|
|
x = (vx + (1<<30) - (~vx>>31&1) >> 31) + gscreen->clipr.min.x;
|
|
vy = (vlong)(uint)y * (gscreen->clipr.max.y - gscreen->clipr.min.y);
|
|
y = (vy + (1<<30) - (~vy>>31&1) >> 31) + gscreen->clipr.min.y;
|
|
|
|
absmousetrack(x, y, b, msec);
|
|
}
|
|
|
|
static ulong
|
|
lastms(void)
|
|
{
|
|
static ulong lasttick;
|
|
ulong t, d;
|
|
|
|
t = MACHP(0)->ticks;
|
|
d = t - lasttick;
|
|
lasttick = t;
|
|
return TK2MS(d);
|
|
}
|
|
|
|
/*
|
|
* 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*, int c)
|
|
{
|
|
static uchar msg[3];
|
|
static int nb;
|
|
static int middle;
|
|
static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 3 };
|
|
short x;
|
|
int dx, dy, newbuttons;
|
|
|
|
if(lastms() > 500)
|
|
nb = 0;
|
|
if(nb == 3){
|
|
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(0)->ticks));
|
|
return 0;
|
|
}
|
|
}
|
|
msg[nb] = c;
|
|
if(++nb == 3){
|
|
newbuttons = middle | b[(msg[0]>>4)&3];
|
|
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(0)->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*, int c)
|
|
{
|
|
static uchar msg[4];
|
|
static int nb;
|
|
|
|
if(lastms() > 500)
|
|
nb = 0;
|
|
msg[nb] = c & 0x7f;
|
|
if(++nb == 4){
|
|
nb = 0;
|
|
schar dx,dy,newbuttons;
|
|
dx = msg[1] | (msg[0] & 0x3) << 6;
|
|
dy = msg[2] | (msg[0] & 0xc) << 4;
|
|
newbuttons =
|
|
(msg[0] & 0x10) >> 2
|
|
| (msg[0] & 0x20) >> 5
|
|
| ( msg[3] == 0x10 ? 0x02 :
|
|
msg[3] == 0x0f ? ScrollUp :
|
|
msg[3] == 0x01 ? ScrollDown : 0 );
|
|
mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks));
|
|
}
|
|
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*, int c)
|
|
{
|
|
static short msg[5];
|
|
static int nb;
|
|
static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 3, 3, 7};
|
|
int dx, dy, newbuttons;
|
|
|
|
if(lastms() > 500 || (c&0xF0) == 0x80)
|
|
nb = 0;
|
|
msg[nb] = c;
|
|
if(c & 0x80)
|
|
msg[nb] |= ~0xFF; /* sign extend */
|
|
if(++nb == 5){
|
|
nb = 0;
|
|
newbuttons = b[((msg[0]&7)^7)];
|
|
dx = msg[1]+msg[3];
|
|
dy = -(msg[2]+msg[4]);
|
|
mousetrack(dx, dy, newbuttons, TK2MS(MACHP(0)->ticks));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
mousechanged(void*)
|
|
{
|
|
return mouse.lastcounter != mouse.counter || mouse.resize != 0;
|
|
}
|
|
|
|
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 = 1;
|
|
wakeup(&mouse.r);
|
|
}
|
|
|
|
void
|
|
mouseredraw(void)
|
|
{
|
|
mouse.redraw = 1;
|
|
wakeup(&mouse.redrawr);
|
|
}
|