On Thu, 2002-03-14 at 21:15, Michael Toomim wrote:
> Does anyone know of any programs, patches, drivers, etc. that allow for 
> a better mouse cursor acceleration than what X does?
> 
> The current method of multiplying the mouse's velocity by a constant 
> whenever the motion exceeds a certain threshold isn't as nice and usable 
> as the extremely smooth polynomial, exponential, etc. acceleration 
> mechanisms that have been the standard in all the other modern windowing 
> systems (windows, macos, etc.).
> 
> Alternatively, does anyone know why the X mouse acceleration system 
> sucks so much? :)
> 
> Michael
> 
> _______________________________________________
> Xpert mailing list
> [EMAIL PROTECTED]
> http://XFree86.Org/mailman/listinfo/xpert

Hi,.

this is what i hacked together a year ago; it works for me,.

have a go with it

I ripped pieces of X / gpm and other sources
can't quite remember which anymore.

I fixed it up nicely once, with runtime configurablity and such
but lost the sources ;-(, and never got motivated enough to do it
again.

for the X pplz out there, this thing supports a 'dragmouse' feature
which turns the mouse movement into wheel/scroller movements when a
sertain button is pressed, trouble with this is that X doesn't support
the 2nd axis.

regards,

Peter Zijlstra
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
#include <string.h>

#include "sensmouse.h"

inline void event_set_button( mouse_event_t * event_, int button_, bool state_) {
	if ( state_)
		event_->buttons |= 1 << button_;
	else
		event_->buttons &= ~(1 << button_);
}

inline bool event_get_button( const mouse_event_t * event_, int button_) { 
	return !!(event_->buttons & (1 << button_));
}

static u8 * mouse_read( mouse_dev_t * dev_, int fd_ ) {

	size_t	read_len = dev_->read_len;
	size_t	packet_pos = 0;
	int 	rlen;
	u8 		* packet = dev_->packet_in ?: calloc( 2, dev_->packet_len);
	
	while (packet) {
		do {
			rlen = read( fd_, packet + packet_pos, read_len);
		} while ( rlen && (packet_pos += rlen) < dev_->packet_len);

		if ( !rlen) {
			if ( !dev_->packet_in) free( packet);
			return NULL;
		}	

		if ( (packet[0] & dev_->id[0]) == dev_->id[1] && 
			 (packet[1] & dev_->id[2]) == dev_->id[3])
			return packet;
		else {
			memmove( packet, packet+1, dev_->packet_len - 1);
			read_len = 1;
			packet_pos--;
		}
	}
	return NULL;
}

static bool mouse_write( mouse_dev_t * dev_, int fd_) {
	return write( fd_, dev_->packet_out, dev_->packet_len) == dev_->packet_len;
}

static bool mouse_null_init( mouse_dev_t * dev_, int fd_) {
	return 1;
}

static bool ps2_init( mouse_dev_t * dev_, int fd_) {

	unsigned char * param = NULL;
	size_t paramlen = 0;
	static unsigned char s2[] = { 
		230, 		// 1:1 scaling
		244, 		// enable mouse
		243, 200, 	// set sampling rate, 200
		232, 3, 	// set device resolution [0,..,3]
	};
	
	switch( dev_->proto) {
		case MOUSE_PROTO_IMPS2:
		{
			static unsigned char s[] = { 243, 200, 243, 100, 243, 80, 242 };
			
			param = s;
			paramlen = sizeof( s);
		} 
		break;

		case MOUSE_PROTO_EXPPS2:
		{
			static unsigned char s[] = { 243, 200, 243, 200, 243, 80, 242 };

			param = s;
			paramlen = sizeof(s);
		}
		break;

		case MOUSE_PROTO_NETPS2:
		case MOUSE_PROTO_NETSCPS2:
		{
			static unsigned char s[] = { 232, 3, 230, 230, 230 };

			param = s;
			paramlen = sizeof( s);
		}
		break;
		
		case MOUSE_PROTO_MMPS2:
		{
			static unsigned char s[] = { 230, 232, 0, 232, 3, 232, 2, 232, 1, 
										 230, 232, 3, 232, 1, 232, 2, 232, 3 };

			param = s;
			paramlen = sizeof( s);
		}
		break;

		case MOUSE_PROTO_THINKPS2:
		{
			static unsigned char s[] = { 243, 10, 232,  0, 243, 20, 243, 60,
										 243, 40, 243, 20, 243, 20, 243, 60,
										 243, 40, 243, 20, 243, 20 };

			param = s;
			paramlen = sizeof( s);
		}
		break;

		case MOUSE_PROTO_PS2:
		case MOUSE_PROTO_GLIDEPS2:
		default:
			break;
	}
	
	if ( param) {
		write (fd_, param, paramlen);
		usleep (30000);
	}
	
	write (fd_, s2, sizeof (s2));
	usleep (30000);

	tcflush (fd_, TCIFLUSH);

	return 1;
}

#define RANGE( x, min, max) (((x) > (min)) && ((x) < (max)))

#define CLIP( x, min, max)				\
	if ( (x) < (min)) (x) = (min);		\
	if ( (x) > (max)) (x) = (max);

#define PS2_DECODE_MOVE( dx, dy, packet)										\
	dx =   ((packet)[0] & 0x10) ? (int)(packet)[1] - 256 : (int)(packet)[1];	\
	dy = -(((packet)[0] & 0x20) ? (int)(packet)[2] - 256 : (int)(packet)[2]);

#define PS2_ENCODE_MOVE( packet, dx, dy)								\
	{																	\
		register int _dx = dx, _dy = -dy;								\
		CLIP( _dx, -255, 255);											\
		CLIP( _dy, -255, 255);											\
		(packet)[0] |= (_dx < 0 ? 0x10 : 0) | (_dy < 0 ? 0x20 : 0);		\
		(packet)[1] = _dx;												\
		(packet)[2] = _dy;												\
	}

	
static mouse_event_t ps2_decode( mouse_dev_t * dev_, u8 * packet_) {

	mouse_event_t event;

	event.buttons = 0;
	event.dz = event.dw = 0;
		
	switch( dev_->proto) {

		case MOUSE_PROTO_PS2:
		{
			int i;
			for ( i = 0; i < 3; i++)
				event_set_button( &event, i, packet_[0] & (1 << i));
		
			PS2_DECODE_MOVE( event.dx, event.dy, packet_);
		}
		break;
		
		case MOUSE_PROTO_IMPS2:
		case MOUSE_PROTO_NETPS2:
		{
			int i;
			for ( i = 0; i < 3; i++)
				event_set_button( &event, i, packet_[0] & (1 << i));
			for ( ; i < 5; i++)
				event_set_button( &event, i, packet_[0] & (1 << i+3));

			PS2_DECODE_MOVE( event.dx, event.dy, packet_);
			event.dz = (signed char)packet_[3];
			if (!RANGE( event.dz, -6, 6))
				event.dz = 0;
		}
		break;
		
		case MOUSE_PROTO_EXPPS2:
		{
			int i;
			for ( i = 0; i < 3; i++)
				event_set_button( &event, i, packet_[0] & (1 << i));
			for ( ; i < 5; i++)
				event_set_button( &event, i, packet_[3] & (1 << i+1));

			PS2_DECODE_MOVE( event.dx, event.dy, packet_);
			event.dz = (packet_[3] & 0x08) ? (packet_[3] & 0x0f) - 16 : (packet_[3] & 0x0f);
		}
		break;
		
		case MOUSE_PROTO_MMPS2:
		break;
		
		case MOUSE_PROTO_GLIDEPS2:
		{
			int i;
			for ( i = 0; i < 3; i++)
				event_set_button( &event, i, packet_[0] & (1 << i));
			event_set_button( &event, i, !(packet_[0] & 0x08));

			PS2_DECODE_MOVE( event.dx, event.dy, packet_);
		}
		break;
		
		case MOUSE_PROTO_NETSCPS2:
		{
			int i;
			for ( i = 0; i < 3; i++)
				event_set_button( &event, i, packet_[0] & (1 << i));
			event_set_button( &event, i++, packet_[3] & 0x02);
			event_set_button( &event, i++, packet_[3] & 0x01);

			PS2_DECODE_MOVE( event.dx, event.dy, packet_);
			PS2_DECODE_MOVE( event.dz, event.dw, packet_+3);
		}
		break;
		
		case MOUSE_PROTO_THINKPS2:
		{
			int i;
			for ( i = 0; i < 3; i++)
				event_set_button( &event, i, packet_[0] & (1 << i));
			event_set_button( &event, i, packet_[0] & 0x08);
			packet_[1] |= (packet_[0] & 0x40) << 1;
			PS2_DECODE_MOVE( event.dx, event.dy, packet_);
		}
		break;

		default:
		break;
	}

	return event;
}

static u8 * ps2_encode( mouse_dev_t * dev_, mouse_event_t event_) {

	u8 * packet = dev_->packet_out ?: calloc( 1, dev_->packet_len);

	switch( dev_->proto) {
		
		case MOUSE_PROTO_PS2:
		{
			int i;
			
			packet[0] = 0;
			for ( i = 0; i < 3; i++)
				packet[0] |= event_get_button( &event_, i) << i;

			PS2_ENCODE_MOVE( packet, event_.dx, event_.dy);
		}
		break;
		
		case MOUSE_PROTO_IMPS2:
		case MOUSE_PROTO_NETPS2:
		{
			int i;
			
			packet[0] = 0x08;
			for ( i = 0; i < 3; i++)
				packet[0] |= event_get_button( &event_, i) << i;
			for ( ; i < 5; i++)
				packet[0] |= event_get_button( &event_, i) << i+3;

			PS2_ENCODE_MOVE( packet, event_.dx, event_.dy);

			CLIP( event_.dz, -6, 6);
			packet[3] = event_.dz;
		}
		break;
		
		case MOUSE_PROTO_EXPPS2:
		{
			int i;

			packet[0] = 0x08;
			CLIP( event_.dz, -15, 15);
			packet[3] = event_.dz;
			packet[3] &= 0x0f;
			
			for ( i = 0; i < 3; i++)
				packet[0] |= event_get_button( &event_, i) << i;
			for ( ; i < 5; i++)
				packet[3] |= event_get_button( &event_, i) << i+1;

			PS2_ENCODE_MOVE( packet, event_.dx, event_.dy);
		}
		break;
			
		case MOUSE_PROTO_MMPS2:
		break;
		
		case MOUSE_PROTO_GLIDEPS2:
		{
			int i;

			packet[0] = 0;
			for ( i = 0; i < 3; i++)
				packet[0] |= event_get_button( &event_, i) << i;
			packet[0] |= !event_get_button( &event_, i) << i;

			PS2_ENCODE_MOVE( packet, event_.dx, event_.dy);
		}
		break;
		
		case MOUSE_PROTO_NETSCPS2:
		{
			int i;
			
			packet[0] = packet[3] = 0;
			PS2_ENCODE_MOVE( packet  , event_.dx, event_.dy);
			PS2_ENCODE_MOVE( packet+3, event_.dz, event_.dw);

			for ( i = 0; i < 3; i++)
				packet[0] |= event_get_button( &event_, i) << i;
			packet[3] |= event_get_button( &event_, i++) << 1;
			packet[3] |= event_get_button( &event_, i++);
		}
		break;
		
		case MOUSE_PROTO_THINKPS2:
		{
			int i;

			packet[0] = 0x80;
			PS2_ENCODE_MOVE( packet, event_.dx, event_.dy);
			packet[0] |= (packet[1] & 0x80) >> 1;
			packet[1] &= ~0x80;

			for ( i = 0; i < 3; i++)
				packet[0] |= event_get_button( &event_, i) << i;
		}
		break;
		
		default:
		break;
	}

	
	return packet;
}

static mouse_dev_t mice[] = {
	{ 
		"ps2",
		MOUSE_PROTO_PS2,
		ps2_init,
		mouse_read,
		mouse_write,
		ps2_decode,
		ps2_encode,
		3, 1, 
		{ 0xc0, 0x00, 0x00, 0x00 },
		NULL, NULL
	},
	{ 
		"imps2",
		MOUSE_PROTO_IMPS2,
		ps2_init,
		mouse_read,
		mouse_write,
		ps2_decode,
		ps2_encode,
		4, 1, 
		{ 0x08, 0x08, 0x00, 0x00 },
		NULL, NULL
	},
	{ 
		"netps2",
		MOUSE_PROTO_NETPS2,
		ps2_init,
		mouse_read,
		mouse_write,
		ps2_decode,
		ps2_encode,
		4, 1, 
		{ 0x08, 0x08, 0x00, 0x00 },
		NULL, NULL
	},
	{ 
		"expps2",
		MOUSE_PROTO_EXPPS2,
		ps2_init,
		mouse_read,
		mouse_write,
		ps2_decode,
		ps2_encode,
		4, 1, 
		{ 0x08, 0x08, 0x00, 0x00 },
		NULL, NULL
	},
	/*
	{ 
		"mmps2",
		MOUSE_PROTO_MMPS2,
		ps2_init,
		mouse_read,
		mouse_write,
		ps2_decode,
		ps2_encode,
		3, 1, 
		{ 0x08, 0x08, 0x00, 0x00 },
		NULL, NULL
	},
	*/
	{ 
		"glideps2",
		MOUSE_PROTO_GLIDEPS2,
		ps2_init,
		mouse_read,
		mouse_write,
		ps2_decode,
		ps2_encode,
		3, 1, 
		{ 0xc0, 0x00, 0x00, 0x00 },
		NULL, NULL
	},
	{ 
		"netscps2",
		MOUSE_PROTO_NETSCPS2,
		ps2_init,
		mouse_read,
		mouse_write,
		ps2_decode,
		ps2_encode,
		6, 1, 
		{ 0xc0, 0x00, 0x00, 0x00 },
		NULL, NULL
	},
	{ 
		"thinkps2",
		MOUSE_PROTO_THINKPS2,
		ps2_init,
		mouse_read,
		mouse_write,
		ps2_decode,
		ps2_encode,
		3, 1, 
		{ 0x80, 0x80, 0x00, 0x00 },
		NULL, NULL
	},
	{
		NULL,			// name
		0,				// proto
		NULL,			// init
		NULL,			// read
		NULL,			// write
		NULL,			// decode
		NULL,			// encode
		0, 0, 			// packet_len, read_len
		{ 0, 0, 0, 0 },	// id
		NULL, NULL 		// packet_in, packet_out
	}
};

mouse_dev_t * mouse_get( const char * name_) {

	mouse_dev_t * mouse = mice;
	for ( ; mouse->name != NULL; mouse++)
		if ( strcmp( name_, mouse->name) == 0) return mouse;

	return NULL;

}
#ifndef __MICE_INCLUDED
#define __MICE_INCLUDED

#include "sensmouse.h"

mouse_dev_t * mouse_get( const char *);

#endif // __MICE_INLCUDED
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sysexits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <sys/resource.h>
#include <math.h>
#include <sys/file.h>
#include <string.h>
#include <sched.h>

#include "sensmouse.h"
#include "mice.h"

static char * input_device = "/dev/misc/psaux";
static char * output_device = "/dev/sensmouse";
static char * input_proto = "imps2", * output_proto = NULL;
static int drag_map = 0;

void usage( const char * prog_) {
	printf( "usage: %s [-i proto:device] [-o proto:device] [-d]\n", prog_);
	printf( "\n");
	printf( "proto: ps2 imps2 netps2 expps2 glideps2 netscps2 thinkps2\n");
	printf( "\n");

	exit( EX_USAGE);
}

// XXX: button maps
static double a = 3.5;

void parse_args( int argc, char ** argv) {

	extern char	* optarg;
	extern int	optind;
	extern int	opterr;
	extern int	optopt;

	int ch, error = 0;

	while ( (ch = getopt( argc, argv, "i:o:hw:a:")) != EOF) {
		switch ( ch) {
			case 'i':
			{
				char * sep = strchr( optarg, ':');
				if ( sep) {
					*sep++ = '\0';
					if ( strlen( optarg)) input_proto = optarg;
					if ( strlen( sep)) input_device = sep;
				} else
					input_proto = optarg;
			}
			break;

			case 'o':
			{
				char * sep = strchr( optarg, ':');
				if ( sep) {
					*sep++ = '\0';
					if ( strlen( optarg)) output_proto = optarg;
					if ( strlen( sep)) output_device = sep;
				} else
					output_proto = optarg;
			}
			break;

			case 'd':
				drag_map = atoi( optarg);
				break;

			case 'a':
			{
				double accel;
				if ( sscanf( optarg, "%lf", &accel) == 1)
					a = accel;
			}
			break;

			default:
				usage( argv[0]);
				break;
		}
	}

	if ( !output_proto) output_proto = input_proto;
}

#define LIN( x) ((1-a) + a*(x))

inline void accel( volatile mouse_event_t * event_) {
	register int x = event_->dx, y = event_->dy;
	double l = sqrt( x*x + y*y);

	l = LIN( l);

	event_->dx = x*l;
	event_->dy = y*l;
}

static volatile mouse_event_t cum_event = { 0, 0, 0, 0 };
static mouse_dev_t * i_dev, * o_dev;
static int in_fd, out_fd;

void sig_timer( int sig) {

	signal( SIGALRM, sig_timer);

	if ( cum_event.dx || cum_event.dy || cum_event.dz || cum_event.dw) {
		accel( &cum_event);
		o_dev->encode( o_dev, cum_event);
		cum_event.dx = cum_event.dy = cum_event.dz = cum_event.dw = 0;
		o_dev->write( o_dev, out_fd);
	}
}

int main ( int argc, char ** argv) {

	u8 p_in[10], p_out[10];
	int old_buttons = ~0;

	struct itimerval ival = {
		{ 0, 10000 },	// it_interval; 100Hz
		{ 0, 1 }		// it_value; 0
	};

	struct sched_param sparam;
	mouse_event_t event;

	parse_args( argc, argv);

	in_fd = open( input_device, O_RDWR);
	if ( in_fd < 0) {
		printf( "failed to open input device: %s\n", input_device);
		exit( EX_IOERR);
	}
	if ( flock( in_fd, LOCK_EX | LOCK_NB) == -1) {
		printf( "failed to lock input device: %s\n", input_device);
		exit( EX_IOERR);
	}

	i_dev = mouse_get( input_proto);
	o_dev = mouse_get( output_proto);
	if ( i_dev == NULL) {
		printf( "no such mouse proto: %s\n", input_proto ?: "NULL");
		exit( EX_CONFIG);
	}
	if ( o_dev == NULL) {
		printf( "no such mouse proto: %s\n", output_proto ?: "NULL");
		exit( EX_CONFIG);
	}

	if ( !i_dev->init( i_dev, in_fd)) {
		printf( "error initializing device: %s\n", i_dev->name);
		exit( EX_SOFTWARE);
	}

	unlink( output_device);
	if( mkfifo( output_device, 0666) && errno != EEXIST) {
		printf( "failed to create fifo: %s\n", output_device);
		exit( EX_IOERR);
	}
	out_fd = open( output_device, O_RDWR | O_NONBLOCK);
	if ( out_fd < 0) {
		unlink( output_device);
		printf( "failed to open fifo: %s\n", output_device);
		exit( EX_IOERR);
	}

	i_dev->packet_in = p_in;
	o_dev->packet_out = p_out;

	if ( fork()) exit(0);

#if 0
	// XXX: get ourselves RT, instead of this:
	setpriority( PRIO_PROCESS, getpid(), -20);
#else
	sparam.sched_priority = sched_get_priority_max(SCHED_FIFO);
	sched_setscheduler(0, SCHED_FIFO, &sparam);
#endif
	
	signal( SIGALRM, sig_timer);
	setitimer( ITIMER_REAL, &ival, NULL);

	while ( 1) {
		i_dev->read( i_dev, in_fd);
		event = i_dev->decode( i_dev, i_dev->packet_in);

		if ( drag_map && event.buttons & 0x08) {
			event.buttons &= ~0x08;
			event.dw = event.dx/drag_map;
			event.dz = event.dy/drag_map;
			event.dx = event.dy = 0;
		}

		cum_event.buttons = event.buttons;
		cum_event.dx += event.dx;
		cum_event.dy += event.dy;
		cum_event.dz += event.dz;
		cum_event.dw += event.dw;
		event.dx = event.dy = event.dz = event.dw = 0;
		
		if ( event.buttons != old_buttons) {
			old_buttons = event.buttons;
			o_dev->encode( o_dev, event);
			o_dev->write( o_dev, out_fd);
		}
	}

	return EX_OK;
}
#ifndef __SENSMOUSE_INCLUDED
#define __SENSMOUSE_INCLUDED

typedef int bool;

typedef struct {

	unsigned int	buttons;
	int				dx, dy;
	int				dz, dw;

} mouse_event_t;

typedef unsigned char u8;

typedef struct __mouse_dev {

	char * name;

	unsigned int proto;

	bool (*init)( struct __mouse_dev *, int);
	u8 * (*read)( struct __mouse_dev *, int);
	bool (*write)( struct __mouse_dev *, int);

	mouse_event_t (*decode)( struct __mouse_dev *, u8 *);
	u8 * (*encode)( struct __mouse_dev *, mouse_event_t);
	
	size_t			packet_len;
	size_t			read_len;
	char			id[4];

	u8				* packet_in;
	u8				* packet_out;

} mouse_dev_t;

#define MOUSE_PROTO_PS2			0x0001
#define MOUSE_PROTO_IMPS2		0x0002
#define MOUSE_PROTO_NETPS2		0x0003
#define MOUSE_PROTO_EXPPS2		0x0004
#define MOUSE_PROTO_MMPS2		0x0005
#define MOUSE_PROTO_GLIDEPS2	0x0006
#define MOUSE_PROTO_NETSCPS2	0x0007
#define MOUSE_PROTO_THINKPS2	0x0008

#endif // __SENSMOUSE_INCLUDED

Reply via email to