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

1993/1006/port/devmouse.c (diff list | history)

1993/1006/sys/src/9/port/devmouse.c:1,5201993/1008/sys/src/9/port/devmouse.c:1,515 (short | long | prev | next)
1993/1006    
#include	"u.h" 
#include	"../port/lib.h" 
#include	<libg.h> 
#include	<gnot.h> 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
 
#include	"devtab.h" 
 
/* 
 * Some monochrome screens are reversed from what we like: 
 * We want 0's bright and 1's dark. 
 * Indexed by an Fcode, these compensate for the source bitmap being wrong 
 * (exchange S rows) and destination (exchange D columns and invert result) 
 */ 
int flipS[] = { 
	0x0, 0x4, 0x8, 0xC, 0x1, 0x5, 0x9, 0xD, 
	0x2, 0x6, 0xA, 0xE, 0x3, 0x7, 0xB, 0xF 
}; 
 
int flipD[] = { 
	0xF, 0xD, 0xE, 0xC, 0x7, 0x5, 0x6, 0x4, 
	0xB, 0x9, 0xA, 0x8, 0x3, 0x1, 0x2, 0x0,  
}; 
 
int flipping;	/* are flip tables being used to transform Fcodes? */ 
 
typedef struct Mouseinfo	Mouseinfo; 
typedef struct Cursorinfo	Cursorinfo; 
 
struct Mouseinfo 
{ 
	/* 
	 * First three fields are known in some l.s's 
	 */ 
	int	dx; 
	int	dy; 
	int	track;		/* l.s has updated dx & dy */ 
	Mouse; 
	int	redraw;		/* update cursor on screen */ 
	ulong	counter;	/* increments every update */ 
	ulong	lastcounter;	/* value when /dev/mouse read */ 
	Rendez	r; 
	Ref; 
	QLock; 
	int	open; 
}; 
 
struct Cursorinfo 
{ 
	Cursor; 
	Lock; 
	int	visible;	/* on screen */ 
	int	disable;	/* from being used */ 
	Rectangle r;		/* location */ 
}; 
 
Mouseinfo	mouse; 
Cursorinfo	cursor; 
int		mouseshifted; 
int		mousetype; 
int		hwcurs; 
 
Cursor	arrow = 
{ 
	{-1, -1}, 
	{0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xC0, 0xFF, 0x00, 
	 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0xC0, 0xFF, 0xE0, 
	 0xE7, 0xF0, 0xE3, 0xF8, 0xC1, 0xFC, 0x00, 0xFE, 
	 0x00, 0x7F, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 
	}, 
	{0x00, 0x00, 0x7F, 0xC0, 0x7F, 0x00, 0x7C, 0x00, 
	 0x7E, 0x00, 0x7F, 0x00, 0x6F, 0x80, 0x67, 0xC0, 
	 0x43, 0xE0, 0x41, 0xF0, 0x00, 0xF8, 0x00, 0x7C, 
	 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00, 
	} 
}; 
 
ulong setbits[16]; 
GBitmap	set = 
{ 
	setbits, 
	0, 
	1, 
	0, 
	{0, 0, 16, 16}, 
	{0, 0, 16, 16} 
}; 
 
ulong clrbits[16]; 
GBitmap	clr = 
{ 
	clrbits, 
	0, 
	1, 
	0, 
	{0, 0, 16, 16}, 
	{0, 0, 16, 16} 
}; 
 
ulong cursorbackbits[16*4]; 
GBitmap cursorback = 
{ 
	cursorbackbits, 
	0, 
	1, 
	0, 
	{0, 0, 16, 16}, 
	{0, 0, 16, 16} 
}; 
 
void	Cursortocursor(Cursor*); 
int	mousechanged(void*); 
 
enum{ 
	Qdir, 
	Qmouse, 
	Qmousectl, 
}; 
 
Dirtab mousedir[]={ 
	"mouse",	{Qmouse},	0,			0666, 
	"mousectl",	{Qmousectl},	0,			0220, 
}; 
 
#define	NMOUSE	(sizeof(mousedir)/sizeof(Dirtab)) 
 
extern	GBitmap	gscreen; 
 
void 
mousereset(void) 
{ 
	ulong r; 
 
	if(!conf.monitor) 
		return; 
 
	getcolor(0, &r, &r, &r); 
	if(r == 0) 
		flipping = 1; 
	flipping = 0;	/* howard, why is this necessary to get a black arrow on carrera? */ 
	Cursortocursor(&arrow); 
} 
 
void 
mouseinit(void) 
{ 
	if(!conf.monitor) 
		return; 
	if(gscreen.ldepth > 3) 
		cursorback.ldepth = 0; 
	else{ 
		cursorback.ldepth = gscreen.ldepth; 
		cursorback.width = ((16 << gscreen.ldepth) + 31) >> 5; 
	} 
	cursoron(1); 
} 
 
Chan* 
mouseattach(char *spec) 
{ 
	if(!conf.monitor) 
		error(Egreg); 
	return devattach('m', spec); 
} 
 
Chan* 
mouseclone(Chan *c, Chan *nc) 
{ 
	nc = devclone(c, nc); 
	if(c->qid.path != CHDIR) 
		incref(&mouse); 
	return nc; 
} 
 
int 
mousewalk(Chan *c, char *name) 
{ 
	return devwalk(c, name, mousedir, NMOUSE, devgen); 
} 
 
void 
mousestat(Chan *c, char *db) 
{ 
	devstat(c, db, mousedir, NMOUSE, devgen); 
} 
 
Chan* 
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; 
} 
 
void 
mousecreate(Chan *c, char *name, int omode, ulong perm) 
{ 
	if(!conf.monitor) 
		error(Egreg); 
	USED(c, name, omode, perm); 
	error(Eperm); 
} 
 
void 
mouseremove(Chan *c) 
{ 
	USED(c); 
	error(Eperm); 
} 
 
void 
mousewstat(Chan *c, char *db) 
{ 
	USED(c, db); 
	error(Eperm); 
} 
 
void 
mouseclose(Chan *c) 
{ 
	if(c->qid.path!=CHDIR && (c->flag&COPEN)){ 
		lock(&mouse); 
		if(c->qid.path == Qmouse) 
			mouse.open = 0; 
		unlock(&mouse); 
	} 
} 
 
long 
mouseread(Chan *c, void *va, long n, ulong offset) 
{ 
	uchar *p; 
1993/1008    
	char buf[4*12+1]; 
1993/1006    
 
	USED(offset); 
	if(c->qid.path & CHDIR) 
		return devdirread(c, va, n, mousedir, NMOUSE, devgen); 
 
	if(c->qid.path == Qmouse){ 
		/* 
		 * mouse: 
		 *	'm'		1 
		 *	buttons		1 
		 * 	point		8 
		 * 	msec		4 
		 */ 
		if(n < 14) 
			error(Eshort); 
		while(mousechanged(0) == 0) 
			sleep(&mouse.r, mousechanged, 0); 
		lock(&cursor); 
		p = va; 
		p[0] = 'm'; 
		p[1] = mouse.buttons; 
		BPLONG(p+2, mouse.xy.x); 
		BPLONG(p+6, mouse.xy.y); 
		BPLONG(p+10, TK2MS(MACHP(0)->ticks)); 
1993/1008    
		sprint(buf, "%11d %11d %11d %11d", 
			mouse.xy.x, mouse.xy.y, mouse.buttons, 
			TK2MS(MACHP(0)->ticks)); 
1993/1006    
		mouse.lastcounter = mouse.counter; 
		unlock(&cursor); 
		return 14; 
1993/1008    
		if(n > 4*12) 
			n = 4*12; 
		memmove(va, buf, n); 
		return n; 
1993/1006    
	} 
	return 0; 
} 
 
long 
mousewrite(Chan *c, void *va, long n, ulong offset) 
{ 
	uchar *p; 
1993/1008    
	char *p; 
1993/1006    
	Point pt; 
	char buf[64]; 
 
	USED(offset); 
 
	switch(c->qid.path){ 
	case CHDIR: 
		error(Eisdir); 
 
	case Qmousectl: 
		if(n >= sizeof(buf)) 
			n = sizeof(buf)-1; 
		strncpy(buf, va, n); 
		buf[n] = 0; 
		mousectl(buf); 
		return n; 
 
	case Qmouse: 
		if(n != 9) 
1993/1008    
		if(n > sizeof buf-1) 
			n = sizeof buf -1; 
		memmove(buf, va, n); 
		buf[n] = 0; 
		p = 0; 
		pt.x = strtoul(buf, &p, 0); 
		if(p == 0) 
1993/1006    
			error(Eshort); 
1993/1008    
		pt.y = strtoul(p, 0, 0); 
1993/1006    
		qlock(&mouse); 
		p = va; 
		pt.x = BGLONG(p+1); 
		pt.y = BGLONG(p+5); 
		if(ptinrect(pt, gscreen.r)){ 
			mouse.xy = pt; 
			mouse.redraw = 1; 
			mouse.track = 1; 
			mouseclock(); 
		} 
		qunlock(&mouse); 
		return n; 
	} 
 
	error(Egreg); 
	return -1; 
} 
 
void 
Cursortocursor(Cursor *c) 
{ 
	int i; 
	uchar *p; 
 
	lock(&cursor); 
	memmove(&cursor, c, sizeof(Cursor)); 
	for(i=0; i<16; i++){ 
		p = (uchar*)&setbits[i]; 
		*p = c->set[2*i]; 
		*(p+1) = c->set[2*i+1]; 
		p = (uchar*)&clrbits[i]; 
		*p = c->clr[2*i]; 
		*(p+1) = c->clr[2*i+1]; 
	} 
	if(hwcurs) 
		hwcursset(set.base, clr.base, cursor.offset.x, cursor.offset.y); 
	unlock(&cursor); 
} 
 
void 
cursoron(int dolock) 
{ 
	if(cursor.disable) 
		return; 
	if(dolock) 
		lock(&cursor); 
	if(cursor.visible++ == 0){ 
		if(hwcurs) 
			hwcursmove(mouse.xy.x, mouse.xy.y); 
		else { 
			cursor.r.min = mouse.xy; 
			cursor.r.max = add(mouse.xy, Pt(16, 16)); 
			cursor.r = raddp(cursor.r, cursor.offset); 
			gbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S); 
			gbitblt(&gscreen, cursor.r.min, 
				&clr, Rect(0, 0, 16, 16), flipping? flipD[D&~S] : D&~S); 
			gbitblt(&gscreen, cursor.r.min, 
				&set, Rect(0, 0, 16, 16), flipping? flipD[S|D] : S|D); 
			mbbrect(cursor.r); 
		} 
	} 
	if(dolock) 
		unlock(&cursor); 
} 
 
void 
cursoroff(int dolock) 
{ 
	if(cursor.disable) 
		return; 
	if(dolock) 
		lock(&cursor); 
	if(--cursor.visible == 0) { 
		if(!hwcurs) { 
			gbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S); 
			mbbrect(cursor.r); 
			mousescreenupdate(); 
		} 
	} 
	if(dolock) 
		unlock(&cursor); 
} 
 
/* 
 *  called by the clock routine to redraw the cursor 
 */ 
void 
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); 
		cursoron(0); 
		mousescreenupdate(); 
		unlock(&cursor); 
	} 
} 
 
/* 
 *  called at interrupt level to update the structure and 
 *  awaken any waiting procs. 
 */ 
void 
mousetrack(int b, int dx, int dy) 
{ 
	int x, y; 
 
	x = mouse.xy.x + dx; 
	if(x < gscreen.r.min.x) 
		x = gscreen.r.min.x; 
	if(x >= gscreen.r.max.x) 
		x = gscreen.r.max.x; 
	y = mouse.xy.y + dy; 
	if(y < gscreen.r.min.y) 
		y = gscreen.r.min.y; 
	if(y >= gscreen.r.max.y) 
		y = gscreen.r.max.y; 
	mouse.counter++; 
	mouse.xy = Pt(x, y); 
	mouse.buttons = b; 
	mouse.redraw = 1; 
	wakeup(&mouse.r); 
} 
 
/* 
 *  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(IOQ *q, int c) 
{ 
	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; 
 
	USED(q); 
	/*  
	 *  check bit 6 for consistency 
	 */ 
	if(nb==0){ 
		if((c&0x40) == 0){ 
			/* 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 
mouseputc(IOQ *q, 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, 5, 3, 7}; 
	int dx, dy, newbuttons; 
 
	USED(q); 
	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 
mousechanged(void *m) 
{ 
	USED(m); 
	return mouse.lastcounter - mouse.counter; 
} 


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