plan 9 kernel history: overview | file list | diff list

1999/1005/port/devmouse.c (diff list | history)

port/devmouse.c on 1993/1006
1993/1006    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
 
1997/1101    
#define	Image	IMAGE 
#include	<draw.h> 
#include	<memdraw.h> 
1999/0119    
#include	<cursor.h> 
1994/0210    
#include	"screen.h" 
1993/1006    
 
typedef struct Mouseinfo	Mouseinfo; 
 
struct Mouseinfo 
{ 
	int	dx; 
	int	dy; 
1997/1101    
	int	track;		/* dx & dy updated */ 
1999/0119    
	Point	xy;			/* mouse.xy */ 
	int	buttons;		/* mouse.buttons */ 
1993/1006    
	int	redraw;		/* update cursor on screen */ 
	ulong	counter;	/* increments every update */ 
	ulong	lastcounter;	/* value when /dev/mouse read */ 
	Rendez	r; 
	Ref; 
	QLock; 
	int	open; 
1995/1216    
	int	acceleration; 
	int	maxacc; 
1993/1006    
}; 
 
Mouseinfo	mouse; 
Cursorinfo	cursor; 
int		mouseshifted; 
1994/0414    
Cursor		curs; 
1993/1006    
 
void	Cursortocursor(Cursor*); 
int	mousechanged(void*); 
1997/0327    
static void mouseclock(void); 
1993/1006    
 
enum{ 
	Qdir, 
1993/1009    
	Qcursor, 
1993/1006    
	Qmouse, 
	Qmousectl, 
}; 
 
1998/0417    
static Dirtab mousedir[]={ 
1993/1009    
	"cursor",	{Qcursor},	0,			0666, 
1993/1006    
	"mouse",	{Qmouse},	0,			0666, 
	"mousectl",	{Qmousectl},	0,			0220, 
}; 
 
1998/0417    
static uchar buttonmap[8] = { 
	0, 1, 2, 3, 4, 5, 6, 7, 
}; 
static int mouseswap; 
 
1999/1005    
extern	Memimage*	gscreen; 
1993/1006    
 
1997/0327    
static void 
1993/1006    
mousereset(void) 
{ 
	if(!conf.monitor) 
		return; 
 
1993/1009    
	curs = arrow; 
1993/1006    
	Cursortocursor(&arrow); 
1997/0327    
	addclock0link(mouseclock); 
1993/1006    
} 
 
1997/0327    
static void 
1993/1006    
mouseinit(void) 
{ 
	if(!conf.monitor) 
		return; 
1994/0413    
 
1993/1006    
	cursoron(1); 
} 
 
1997/0327    
static Chan* 
1993/1006    
mouseattach(char *spec) 
{ 
	if(!conf.monitor) 
		error(Egreg); 
	return devattach('m', spec); 
} 
 
1997/0327    
static Chan* 
1993/1006    
mouseclone(Chan *c, Chan *nc) 
{ 
	nc = devclone(c, nc); 
	if(c->qid.path != CHDIR) 
		incref(&mouse); 
	return nc; 
} 
 
1997/0327    
static int 
1993/1006    
mousewalk(Chan *c, char *name) 
{ 
1997/0327    
	return devwalk(c, name, mousedir, nelem(mousedir), devgen); 
1993/1006    
} 
 
1997/0327    
static void 
1993/1006    
mousestat(Chan *c, char *db) 
{ 
1997/0327    
	devstat(c, db, mousedir, nelem(mousedir), devgen); 
1993/1006    
} 
 
1997/0327    
static Chan* 
1993/1006    
mouseopen(Chan *c, int omode) 
{ 
	switch(c->qid.path){ 
	case CHDIR: 
		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; 
	default: 
		incref(&mouse); 
	} 
	c->mode = openmode(omode); 
	c->flag |= COPEN; 
	c->offset = 0; 
	return c; 
} 
 
1997/0327    
static void 
1995/0804    
mousecreate(Chan*, char*, int, ulong) 
1993/1006    
{ 
	if(!conf.monitor) 
		error(Egreg); 
	error(Eperm); 
} 
 
1997/0327    
static void 
1993/1006    
mouseclose(Chan *c) 
{ 
	if(c->qid.path!=CHDIR && (c->flag&COPEN)){ 
		lock(&mouse); 
		if(c->qid.path == Qmouse) 
			mouse.open = 0; 
1993/1009    
		if(--mouse.ref == 0){ 
			cursoroff(1); 
			curs = arrow; 
			Cursortocursor(&arrow); 
			cursoron(1); 
		} 
1993/1006    
		unlock(&mouse); 
	} 
} 
 
1994/0216    
 
1997/0327    
static long 
1998/0319    
mouseread(Chan *c, void *va, long n, vlong off) 
1993/1006    
{ 
1993/1008    
	char buf[4*12+1]; 
1993/1009    
	uchar *p; 
1994/0216    
	static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 }; 
1998/0319    
	ulong offset = off; 
1993/1006    
 
1993/1009    
	p = va; 
	switch(c->qid.path){ 
	case CHDIR: 
1997/0327    
		return devdirread(c, va, n, mousedir, nelem(mousedir), devgen); 
1993/1006    
 
1993/1009    
	case Qcursor: 
		if(offset != 0) 
			return 0; 
		if(n < 2*4+2*2*16) 
			error(Eshort); 
		n = 2*4+2*2*16; 
		lock(&cursor); 
		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); 
		return n; 
 
	case Qmouse: 
1993/1006    
		while(mousechanged(0) == 0) 
			sleep(&mouse.r, mousechanged, 0); 
1995/0812    
 
		while(!canlock(&cursor)) 
			tsleep(&up->sleep, return0, 0, TK2MS(1)); 
 
1998/0825    
		sprint(buf, "m%11d %11d %11d %11lud", 
1994/0216    
			mouse.xy.x, mouse.xy.y, 
1998/0417    
			buttonmap[mouse.buttons&7], 
1993/1008    
			TK2MS(MACHP(0)->ticks)); 
1993/1006    
		mouse.lastcounter = mouse.counter; 
		unlock(&cursor); 
1994/1013    
		if(n > 1+4*12) 
			n = 1+4*12; 
1993/1008    
		memmove(va, buf, n); 
		return n; 
1993/1006    
	} 
	return 0; 
} 
 
1998/0417    
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; 
	} 
} 
 
1997/0327    
static long 
1998/0319    
mousewrite(Chan *c, void *va, long n, vlong) 
1993/1006    
{ 
1993/1008    
	char *p; 
1993/1006    
	Point pt; 
1998/0417    
	char buf[64], *field[3]; 
	int nf; 
1993/1006    
 
1993/1009    
	p = va; 
1993/1006    
	switch(c->qid.path){ 
	case CHDIR: 
		error(Eisdir); 
1993/1009    
 
	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); 
		} 
1993/1108    
		qlock(&mouse); 
		mouse.redraw = 1; 
		mouseclock(); 
		qunlock(&mouse); 
1993/1009    
		cursoron(1); 
		return n; 
1993/1006    
 
	case Qmousectl: 
		if(n >= sizeof(buf)) 
			n = sizeof(buf)-1; 
		strncpy(buf, va, n); 
1995/1216    
		if(buf[n - 1] == '\n') 
			buf[n-1] = 0; 
		else 
			buf[n] = 0; 
1998/0417    
		nf = parsefields(buf, field, 3, " "); 
		if(strcmp(field[0], "swap") == 0){ 
			if(mouseswap) 
				setbuttonmap("123"); 
			else 
				setbuttonmap("321"); 
			mouseswap ^= 1; 
		} 
		else if(strcmp(field[0], "buttonmap") == 0){ 
			if(nf == 1) 
				setbuttonmap("123"); 
			else 
				setbuttonmap(field[1]); 
		} 
		else 
			mousectl(field, nf); 
1993/1006    
		return n; 
 
	case Qmouse: 
1993/1008    
		if(n > sizeof buf-1) 
			n = sizeof buf -1; 
		memmove(buf, va, n); 
		buf[n] = 0; 
		p = 0; 
1994/1013    
		pt.x = strtoul(buf+1, &p, 0); 
1993/1008    
		if(p == 0) 
1993/1006    
			error(Eshort); 
1993/1008    
		pt.y = strtoul(p, 0, 0); 
1993/1006    
		qlock(&mouse); 
1999/1005    
		if(ptinrect(pt, gscreen->r)){ 
1993/1006    
			mouse.xy = pt; 
			mouse.redraw = 1; 
			mouse.track = 1; 
			mouseclock(); 
		} 
		qunlock(&mouse); 
		return n; 
	} 
 
	error(Egreg); 
	return -1; 
1995/0108    
} 
 
1997/0327    
Dev mousedevtab = { 
1997/0408    
	'm', 
	"mouse", 
 
1997/0327    
	mousereset, 
	mouseinit, 
	mouseattach, 
	mouseclone, 
	mousewalk, 
	mousestat, 
	mouseopen, 
	mousecreate, 
	mouseclose, 
	mouseread, 
	devbread, 
	mousewrite, 
	devbwrite, 
	devremove, 
	devwstat, 
}; 
1993/1006    
 
void 
Cursortocursor(Cursor *c) 
{ 
	lock(&cursor); 
1994/0414    
	memmove(&cursor.Cursor, c, sizeof(Cursor)); 
1994/0520    
	setcursor(c); 
1993/1026    
	unlock(&cursor); 
} 
 
 
1993/1006    
/* 
 *  called by the clock routine to redraw the cursor 
 */ 
1997/0327    
static void 
1993/1006    
mouseclock(void) 
{ 
	if(mouse.track){ 
		mousetrack(mouse.buttons, mouse.dx, mouse.dy); 
		mouse.track = 0; 
		mouse.dx = 0; 
		mouse.dy = 0; 
	} 
	if(mouse.redraw && canlock(&cursor)){ 
		mouse.redraw = 0; 
		cursoroff(0); 
1994/0624    
		mouse.redraw = cursoron(0); 
1993/1006    
		unlock(&cursor); 
	} 
1997/1101    
	drawactive(0); 
1993/1006    
} 
 
1995/1216    
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; 
} 
 
1993/1006    
/* 
 *  called at interrupt level to update the structure and 
 *  awaken any waiting procs. 
 */ 
void 
mousetrack(int b, int dx, int dy) 
{ 
	int x, y; 
 
1999/1005    
	if(gscreen==nil) 
		return; 
 
1995/1216    
	if(mouse.acceleration){ 
		dx = scale(dx); 
		dy = scale(dy); 
	} 
1993/1006    
	x = mouse.xy.x + dx; 
1999/1005    
	if(x < gscreen->r.min.x) 
		x = gscreen->r.min.x; 
	if(x >= gscreen->r.max.x) 
		x = gscreen->r.max.x; 
1993/1006    
	y = mouse.xy.y + dy; 
1999/1005    
	if(y < gscreen->r.min.y) 
		y = gscreen->r.min.y; 
	if(y >= gscreen->r.max.y) 
		y = gscreen->r.max.y; 
1993/1006    
	mouse.counter++; 
	mouse.xy = Pt(x, y); 
	mouse.buttons = b; 
	mouse.redraw = 1; 
	wakeup(&mouse.r); 
1997/1101    
	drawactive(1); 
1993/1006    
} 
 
/* 
 *  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 
1999/0320    
m3mouseputc(Queue*, int c) 
1993/1006    
{ 
	static uchar msg[3]; 
	static int nb; 
	static int middle; 
	static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 5 }; 
	short x; 
	int dx, dy, newbuttons; 
 
	if(nb==0){ 
1997/1112    
		/* 
		 * an extra byte comes for middle button motion. 
		 * only two possible values for the extra byte. 
		 */ 
		if(c == 0x00 || c == 0x20){ 
1993/1006    
			/* an extra byte gets sent for the middle button */ 
			middle = (c&0x20) ? 2 : 0; 
			newbuttons = (mouse.buttons & ~2) | middle; 
			mousetrack(newbuttons, 0, 0); 
			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(newbuttons, dx, dy); 
	} 
	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 
1999/0320    
mouseputc(Queue*, int c) 
1993/1006    
{ 
	static short msg[5]; 
	static int nb; 
	static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 5, 3, 7}; 
	int dx, dy, newbuttons; 
 
	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(newbuttons, dx, dy); 
		nb = 0; 
	} 
	return 0; 
} 
 
int 
1995/0804    
mousechanged(void*) 
1993/1006    
{ 
	return mouse.lastcounter - mouse.counter; 
1994/0414    
} 
 
Point 
mousexy(void) 
{ 
	return mouse.xy; 
1995/1216    
} 
 
void 
1999/0225    
mouseaccelerate(int x) 
1995/1216    
{ 
1999/0225    
	mouse.acceleration = x; 
1995/1216    
	if(mouse.acceleration < 3) 
		mouse.maxacc = 2; 
	else 
		mouse.maxacc = mouse.acceleration; 
1993/1006    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)