2011-03-30 12:46:40 +00:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
|
|
|
#include "compat.h"
|
|
|
|
#include "error.h"
|
|
|
|
|
|
|
|
#define Image IMAGE
|
|
|
|
#include <draw.h>
|
|
|
|
#include <memdraw.h>
|
|
|
|
#include <cursor.h>
|
|
|
|
#include "screen.h"
|
|
|
|
|
|
|
|
typedef struct Mouseinfo Mouseinfo;
|
|
|
|
typedef struct Mousestate Mousestate;
|
|
|
|
|
|
|
|
struct Mousestate
|
|
|
|
{
|
2016-12-11 15:53:51 +00:00
|
|
|
Point xy; /* mouse.xy */
|
|
|
|
int buttons; /* mouse.buttons */
|
2011-03-30 12:46:40 +00:00
|
|
|
ulong counter; /* increments every update */
|
2016-12-11 15:53:51 +00:00
|
|
|
ulong msec; /* time of last event */
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Mouseinfo
|
|
|
|
{
|
2016-12-11 15:53:51 +00:00
|
|
|
Lock;
|
2011-03-30 12:46:40 +00:00
|
|
|
Mousestate;
|
|
|
|
ulong lastcounter; /* value when /dev/mouse read */
|
|
|
|
Rendez r;
|
|
|
|
Ref;
|
2018-08-20 17:23:42 +00:00
|
|
|
int resize;
|
2011-03-30 12:46:40 +00:00
|
|
|
int open;
|
2016-12-11 15:53:51 +00:00
|
|
|
Mousestate queue[16]; /* circular buffer of click events */
|
|
|
|
ulong ri; /* read index into queue */
|
|
|
|
ulong wi; /* write index into queue */
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
Mouseinfo mouse;
|
|
|
|
Cursorinfo cursor;
|
|
|
|
Cursor curs;
|
|
|
|
|
|
|
|
void Cursortocursor(Cursor*);
|
|
|
|
int mousechanged(void*);
|
|
|
|
|
|
|
|
enum{
|
|
|
|
Qdir,
|
|
|
|
Qcursor,
|
|
|
|
Qmouse,
|
2013-10-07 04:37:40 +00:00
|
|
|
Qmousein,
|
|
|
|
Qmousectl,
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static Dirtab mousedir[]={
|
|
|
|
".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
|
|
|
|
"cursor", {Qcursor}, 0, 0666,
|
|
|
|
"mouse", {Qmouse}, 0, 0666,
|
2013-10-07 04:37:40 +00:00
|
|
|
"mousein", {Qmousein}, 0, 0222,
|
|
|
|
"mousectl", {Qmousectl}, 0, 0222,
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
2016-12-11 15:53:51 +00:00
|
|
|
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,
|
|
|
|
},
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
2016-12-11 15:53:51 +00:00
|
|
|
extern Memimage* gscreen;
|
|
|
|
extern void mousewarpnote(Point);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
mousereset(void)
|
|
|
|
{
|
|
|
|
curs = arrow;
|
|
|
|
Cursortocursor(&arrow);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mouseinit(void)
|
|
|
|
{
|
2016-12-11 15:53:51 +00:00
|
|
|
curs = arrow;
|
|
|
|
Cursortocursor(&arrow);
|
|
|
|
cursoron();
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static Chan*
|
|
|
|
mouseattach(char *spec)
|
|
|
|
{
|
|
|
|
return devattach('m', spec);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Walkqid*
|
|
|
|
mousewalk(Chan *c, Chan *nc, char **name, int nname)
|
|
|
|
{
|
2016-12-11 15:53:51 +00:00
|
|
|
return devwalk(c, nc, name, nname, mousedir, nelem(mousedir), devgen);
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
mousestat(Chan *c, uchar *db, int n)
|
|
|
|
{
|
|
|
|
return devstat(c, db, n, mousedir, nelem(mousedir), devgen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Chan*
|
|
|
|
mouseopen(Chan *c, int omode)
|
|
|
|
{
|
2016-12-11 15:53:51 +00:00
|
|
|
int mode;
|
|
|
|
|
|
|
|
mode = openmode(omode);
|
2011-03-30 12:46:40 +00:00
|
|
|
switch((ulong)c->qid.path){
|
|
|
|
case Qdir:
|
|
|
|
if(omode != OREAD)
|
|
|
|
error(Eperm);
|
|
|
|
break;
|
2013-10-07 04:37:40 +00:00
|
|
|
case Qmousein:
|
|
|
|
case Qmousectl:
|
2016-12-11 15:53:51 +00:00
|
|
|
error(Egreg);
|
2013-10-07 04:37:40 +00:00
|
|
|
break;
|
2016-12-11 15:53:51 +00:00
|
|
|
case Qmouse:
|
|
|
|
if(_tas(&mouse.open) != 0)
|
|
|
|
error(Einuse);
|
|
|
|
mouse.lastcounter = mouse.counter;
|
|
|
|
/* wet floor */
|
|
|
|
case Qcursor:
|
2011-03-30 12:46:40 +00:00
|
|
|
incref(&mouse);
|
|
|
|
}
|
2016-12-11 15:53:51 +00:00
|
|
|
c->mode = mode;
|
2011-03-30 12:46:40 +00:00
|
|
|
c->flag |= COPEN;
|
|
|
|
c->offset = 0;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
mouseclose(Chan *c)
|
|
|
|
{
|
2016-12-11 15:53:51 +00:00
|
|
|
if((c->qid.type&QTDIR)!=0 || (c->flag&COPEN)==0)
|
|
|
|
return;
|
|
|
|
switch((ulong)c->qid.path){
|
|
|
|
case Qmouse:
|
|
|
|
mouse.open = 0;
|
|
|
|
/* wet floor */
|
|
|
|
case Qcursor:
|
|
|
|
if(decref(&mouse) != 0)
|
|
|
|
return;
|
|
|
|
cursoroff();
|
|
|
|
curs = arrow;
|
|
|
|
Cursortocursor(&arrow);
|
|
|
|
cursoron();
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static long
|
|
|
|
mouseread(Chan *c, void *va, long n, vlong off)
|
|
|
|
{
|
2016-12-11 15:53:51 +00:00
|
|
|
char buf[1+4*12+1];
|
2011-03-30 12:46:40 +00:00
|
|
|
uchar *p;
|
|
|
|
ulong offset = off;
|
|
|
|
Mousestate m;
|
|
|
|
|
|
|
|
p = va;
|
|
|
|
switch((ulong)c->qid.path){
|
|
|
|
case Qdir:
|
|
|
|
return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);
|
|
|
|
|
|
|
|
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(0) == 0)
|
|
|
|
rendsleep(&mouse.r, mousechanged, 0);
|
|
|
|
|
2016-12-11 15:53:51 +00:00
|
|
|
lock(&mouse);
|
|
|
|
if(mouse.ri != mouse.wi)
|
|
|
|
m = mouse.queue[mouse.ri++ % nelem(mouse.queue)];
|
|
|
|
else
|
2011-03-30 12:46:40 +00:00
|
|
|
m = mouse.Mousestate;
|
2016-12-11 15:53:51 +00:00
|
|
|
unlock(&mouse);
|
|
|
|
|
2018-07-23 17:29:15 +00:00
|
|
|
sprint(buf, "m%11d %11d %11d %11ld ",
|
2016-12-11 15:53:51 +00:00
|
|
|
m.xy.x, m.xy.y, m.buttons, m.msec);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
mouse.lastcounter = m.counter;
|
2018-08-20 17:23:42 +00:00
|
|
|
if(mouse.resize){
|
|
|
|
mouse.resize = 0;
|
|
|
|
buf[0] = 'r';
|
|
|
|
}
|
2016-12-11 15:53:51 +00:00
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
if(n > 1+4*12)
|
|
|
|
n = 1+4*12;
|
|
|
|
memmove(va, buf, n);
|
|
|
|
return n;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static long
|
|
|
|
mousewrite(Chan *c, void *va, long n, vlong)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
Point pt;
|
|
|
|
char buf[64];
|
|
|
|
|
|
|
|
p = va;
|
|
|
|
switch((ulong)c->qid.path){
|
|
|
|
case Qdir:
|
|
|
|
error(Eisdir);
|
|
|
|
|
|
|
|
case Qcursor:
|
2016-12-11 15:53:51 +00:00
|
|
|
cursoroff();
|
2011-03-30 12:46:40 +00:00
|
|
|
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);
|
|
|
|
}
|
2016-12-11 15:53:51 +00:00
|
|
|
cursoron();
|
2011-03-30 12:46:40 +00:00
|
|
|
return n;
|
|
|
|
|
|
|
|
case Qmouse:
|
|
|
|
if(n > sizeof buf-1)
|
|
|
|
n = sizeof buf -1;
|
|
|
|
memmove(buf, va, n);
|
|
|
|
buf[n] = 0;
|
2016-12-11 15:53:51 +00:00
|
|
|
|
|
|
|
pt.x = strtol(buf+1, &p, 0);
|
|
|
|
if(*p == 0)
|
2011-03-30 12:46:40 +00:00
|
|
|
error(Eshort);
|
2016-12-11 15:53:51 +00:00
|
|
|
pt.y = strtol(p, 0, 0);
|
|
|
|
absmousetrack(pt.x, pt.y, mouse.buttons, nsec()/(1000*1000LL));
|
|
|
|
mousewarpnote(pt);
|
2011-03-30 12:46:40 +00:00
|
|
|
return n;
|
|
|
|
}
|
|
|
|
|
|
|
|
error(Egreg);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Dev mousedevtab = {
|
|
|
|
'm',
|
|
|
|
"mouse",
|
|
|
|
|
|
|
|
mousereset,
|
|
|
|
mouseinit,
|
|
|
|
mouseattach,
|
|
|
|
mousewalk,
|
|
|
|
mousestat,
|
|
|
|
mouseopen,
|
2016-12-11 15:53:51 +00:00
|
|
|
devcreate,
|
2011-03-30 12:46:40 +00:00
|
|
|
mouseclose,
|
|
|
|
mouseread,
|
|
|
|
devbread,
|
|
|
|
mousewrite,
|
|
|
|
devbwrite,
|
|
|
|
devremove,
|
|
|
|
devwstat,
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
Cursortocursor(Cursor *c)
|
|
|
|
{
|
|
|
|
lock(&cursor);
|
|
|
|
memmove(&cursor.Cursor, c, sizeof(Cursor));
|
|
|
|
setcursor(c);
|
|
|
|
unlock(&cursor);
|
|
|
|
}
|
|
|
|
|
2016-12-11 15:53:51 +00:00
|
|
|
void
|
|
|
|
absmousetrack(int x, int y, int b, ulong msec)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2016-12-11 15:53:51 +00:00
|
|
|
int lastb;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2016-12-11 15:53:51 +00:00
|
|
|
if(gscreen==nil)
|
|
|
|
return;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2016-12-11 15:53:51 +00:00
|
|
|
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;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
|
2016-12-11 15:53:51 +00:00
|
|
|
lock(&mouse);
|
2011-03-30 12:46:40 +00:00
|
|
|
mouse.xy = Pt(x, y);
|
2016-12-11 15:53:51 +00:00
|
|
|
lastb = mouse.buttons;
|
2011-03-30 12:46:40 +00:00
|
|
|
mouse.buttons = b;
|
|
|
|
mouse.msec = msec;
|
2016-12-11 15:53:51 +00:00
|
|
|
mouse.counter++;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/*
|
2016-12-11 15:53:51 +00:00
|
|
|
* if the queue fills, don't queue any more events until a
|
|
|
|
* reader polls the mouse.
|
2011-03-30 12:46:40 +00:00
|
|
|
*/
|
2016-12-11 15:53:51 +00:00
|
|
|
if(b != lastb && (mouse.wi-mouse.ri) < nelem(mouse.queue))
|
|
|
|
mouse.queue[mouse.wi++ % nelem(mouse.queue)] = mouse.Mousestate;
|
|
|
|
unlock(&mouse);
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
rendwakeup(&mouse.r);
|
2016-12-11 15:53:51 +00:00
|
|
|
|
|
|
|
cursoron();
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
mousechanged(void*)
|
|
|
|
{
|
2018-08-20 17:23:42 +00:00
|
|
|
return mouse.lastcounter != mouse.counter || mouse.resize != 0;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Point
|
|
|
|
mousexy(void)
|
|
|
|
{
|
|
|
|
return mouse.xy;
|
|
|
|
}
|
2018-08-20 17:23:42 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* notify reader that screen has been resized
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
mouseresize(void)
|
|
|
|
{
|
|
|
|
mouse.resize = 1;
|
|
|
|
rendwakeup(&mouse.r);
|
|
|
|
}
|