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