bin/110003: [PATCH] Add dynamic acceleration to moused(8)

Oliver Fromme olli at secnetix.de
Tue Mar 6 18:20:09 UTC 2007


>Number:         110003
>Category:       bin
>Synopsis:       [PATCH] Add dynamic acceleration to moused(8)
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Tue Mar 06 18:20:08 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator:     Oliver Fromme
>Release:        FreeBSD 6.2-STABLE i386
>Organization:
secnetix GmbH & Co. KG
		http://www.secnetix.de/bsd
>Environment:

    The patch is for RELENG_6, but also applies to HEAD
    (there's one reject which can easily applied manually).

>Description:

    I'm finally submitting this patch so it doesn't get lost.  :-)

    Mice are stupid little animals.  It happens too often that
    my mouse hits the end of the mouse pad (or even the end
    of the desk), so I have to pick it up, re-center it and
    continue moving.  The mouse pad is always too small, or
    the screen is too large ...  I cannot move the pointer
    from one edge of the screen to the opposite one without
    leaving the mouse pad.  It's a PITA.

    There are two existing acceleration solutions:  The -a
    option in moused(8) and the ''xset m <m> <n>'' feature
    of the X server.  However, the former is only a linear
    acceleration, i.e. ''-a 2.0'' doubles all movements, so
    precision is lost (it skips every other pixel, so it is
    very bad for things like gimp).  The X server feature
    is a little better, because it uses a threshold value
    beyond which the acceleration is enabled, but it's
    still only a linear acceleration.

    This patch for moused(8) below introduces a new option
    -A to enable dynamic acceleration.  Let me quote from
    the manual page (patch is also included):

    -A exp[,offset]
            Apply exponential (dynamic) acceleration to mouse
            movements: the faster you move the mouse, the more it will
            be accelerated.  That means that small mouse movements are
            not accelerated, so they are still very accurate, while a
            faster movement will drive the pointer quickly across the
            screen.

            The exp value specifies the exponent, which is basically
            the amount of acceleration.  Useful values are in the
            range 1.1 to 2.0, but it depends on your mouse hardware
            and your personal preference.  A value of 1.0 means no
            exponential acceleration.  A value of 2.0 means squared
            acceleration (i.e. if you move the mouse twice as fast,
            the pointer will move four times as fast on the screen).
            Values beyond 2.0 are possible but not recommended.  A
            good value to start is probably 1.5.

            The optional offset value specifies the distance at which
            the acceleration begins.  The default is 1.0, which means
            that the acceleration is applied to movements larger
            than one unit.  If you specify a larger value, it takes
            more speed for the accelera- tion to kick in, i.e. the
            speed range for small and accurate movements is wider.
            Usually the default should be sufficient, but if you're
            not satisfied with the behaviour, try a value of 2.0.

            Note that the -A option interacts badly with the X
            server's own acceleration, which doesn't work very well
            anyway.  Therefore it is recommended to switch it off if
            necessary: ``xset m 1''.

            You can use the -a and -A options at the same time to
            have the combined effect of linear and exponential
            acceleration.

>How-To-Repeat:

    n/a

>Fix:

The fix is against RELENG_6.  It also applies to HEAD,
but there is one reject (however, it's easy to apply
manually).

--- src/usr.sbin/moused/moused.c.orig	Mon Jan 30 01:32:40 2006
+++ src/usr.sbin/moused/moused.c	Tue Mar  6 18:00:34 2007
@@ -72,6 +72,7 @@
 #include <syslog.h>
 #include <termios.h>
 #include <unistd.h>
+#include <math.h>
 
 #define MAX_CLICKTHRESHOLD	2000	/* 2 seconds */
 #define MAX_BUTTON2TIMEOUT	2000	/* 2 seconds */
@@ -101,6 +102,7 @@
 #define NoPnP		0x0010
 #define VirtualScroll	0x0020
 #define HVirtualScroll	0x0040
+#define ExponentialAcc	0x0080
 
 #define ID_NONE		0
 #define ID_PORT		1
@@ -396,6 +398,8 @@
     mousemode_t mode;		/* protocol information */
     float accelx;		/* Acceleration in the X axis */
     float accely;		/* Acceleration in the Y axis */
+    float expoaccel;		/* Exponential acceleration */
+    float expoffset;		/* Movement offset for exponential accel. */
     int scrollthreshold;	/* Movement distance before virtual scrolling */
 } rodent = {
     .flags = 0,
@@ -415,6 +419,8 @@
     .button2timeout = DFLT_BUTTON2TIMEOUT,
     .accelx = 1.0,
     .accely = 1.0,
+    .expoaccel = 1.0,
+    .expoffset = 1.0,
     .scrollthreshold = DFLT_SCROLLTHRESHOLD,
 };
 
@@ -494,6 +500,7 @@
 
 /* function prototypes */
 
+static void	expoacc(int, int, int*, int*);
 static void	moused(void);
 static void	hup(int sig);
 static void	cleanup(int sig);
@@ -544,7 +551,7 @@
     for (i = 0; i < MOUSE_MAXBUTTON; ++i)
 	mstate[i] = &bstate[i];
 
-    while ((c = getopt(argc, argv, "3C:DE:F:HI:PRS:T:VU:a:cdfhi:l:m:p:r:st:w:z:")) != -1)
+    while ((c = getopt(argc, argv, "3A:C:DE:F:HI:PRS:T:VU:a:cdfhi:l:m:p:r:st:w:z:")) != -1)
 	switch(c) {
 
 	case '3':
@@ -563,7 +570,7 @@
 	case 'a':
 	    i = sscanf(optarg, "%f,%f", &rodent.accelx, &rodent.accely);
 	    if (i == 0) {
-		warnx("invalid acceleration argument '%s'", optarg);
+		warnx("invalid linear acceleration argument '%s'", optarg);
 		usage();
 	    }
 
@@ -572,6 +579,19 @@
 
 	    break;
 
+	case 'A':
+	    rodent.flags |= ExponentialAcc;
+	    i = sscanf(optarg, "%f,%f", &rodent.expoaccel, &rodent.expoffset);
+	    if (i == 0) {
+		warnx("invalid exponential acceleration argument '%s'", optarg);
+		usage();
+	    }
+
+	    if (i == 1)
+		rodent.expoffset = 1.0;
+
+	    break;
+
 	case 'c':
 	    rodent.flags |= ChordMiddle;
 	    break;
@@ -935,6 +955,37 @@
     return 0;
 }
 
+/*
+ * Function to calculate exponential acceleration.
+ *
+ * In order to give a smoother behaviour, we record the four
+ * most recent non-zero movements and use their average value
+ * to calculate the acceleration.
+ */
+
+static void
+expoacc(int dx, int dy, int *movex, int *movey)
+{
+    static float lastlength[3] = {0.0, 0.0, 0.0};
+    float fdx, fdy, length, lbase, accel;
+
+    if (dx == 0 && dy == 0) {
+	*movex = *movey = 0;
+	return;
+    }
+    fdx = dx * rodent.accelx;
+    fdy = dy * rodent.accely;
+    length = sqrtf((fdx * fdx) + (fdy * fdy));		/* Pythagoras */
+    length = (length + lastlength[0] + lastlength[1] + lastlength[2]) / 4;
+    lbase = length / rodent.expoffset;
+    accel = powf(lbase, rodent.expoaccel) / lbase;
+    *movex = lroundf(fdx * accel);
+    *movey = lroundf(fdy * accel);
+    lastlength[2] = lastlength[1];
+    lastlength[1] = lastlength[0];
+    lastlength[0] = length;	/* Insert new average, not original length! */
+}
+
 static void
 moused(void)
 {
@@ -1194,8 +1245,14 @@
 		if (action2.flags & MOUSE_POSCHANGED) {
 		    mouse.operation = MOUSE_MOTION_EVENT;
 		    mouse.u.data.buttons = action2.button;
-		    mouse.u.data.x = action2.dx * rodent.accelx;
-		    mouse.u.data.y = action2.dy * rodent.accely;
+		    if (rodent.flags & ExponentialAcc) {
+			expoacc(action2.dx, action2.dy,
+			    &mouse.u.data.x, &mouse.u.data.y);
+		    }
+		    else {
+			mouse.u.data.x = action2.dx * rodent.accelx;
+			mouse.u.data.y = action2.dy * rodent.accely;
+		    }
 		    mouse.u.data.z = action2.dz;
 		    if (debug < 2)
 			if (!paused)
@@ -1204,8 +1261,14 @@
 	    } else {
 		mouse.operation = MOUSE_ACTION;
 		mouse.u.data.buttons = action2.button;
-		mouse.u.data.x = action2.dx * rodent.accelx;
-		mouse.u.data.y = action2.dy * rodent.accely;
+		if (rodent.flags & ExponentialAcc) {
+		    expoacc(action2.dx, action2.dy,
+			&mouse.u.data.x, &mouse.u.data.y);
+		}
+		else {
+		    mouse.u.data.x = action2.dx * rodent.accelx;
+		    mouse.u.data.y = action2.dy * rodent.accely;
+		}
 		mouse.u.data.z = action2.dz;
 		if (debug < 2)
 		    if (!paused)
--- src/usr.sbin/moused/Makefile.orig	Sun Jan 15 18:50:37 2006
+++ src/usr.sbin/moused/Makefile	Tue Mar  6 12:03:52 2007
@@ -3,8 +3,8 @@
 PROG=	moused
 MAN=	moused.8
 
-DPADD=	${LIBUTIL}
-LDADD=	-lutil
+DPADD=	${LIBUTIL}  ${LIBM}
+LDADD=	-lutil -lm
 
 #BINMODE=4555
 #PRECIOUSPROG=
--- src/usr.sbin/moused/moused.8.orig	Mon Jan 30 01:32:39 2006
+++ src/usr.sbin/moused/moused.8	Tue Mar  6 18:03:06 2007
@@ -44,6 +44,7 @@
 .Op Fl r Ar resolution
 .Op Fl S Ar baudrate
 .Op Fl VH Op Fl U Ar distance
+.Op Fl A Ar exp Ns Op , Ns Ar offset
 .Op Fl a Ar X Ns Op , Ns Ar Y
 .Op Fl C Ar threshold
 .Op Fl m Ar N=M
@@ -210,12 +211,55 @@
 The default
 .Ar distance
 is 3 pixels.
+.It Fl A Ar exp Ns Op , Ns Ar offset
+Apply exponential (dynamic) acceleration to mouse movements:
+the faster you move the mouse, the more it will be accelerated.
+That means that small mouse movements are not accelerated,
+so they are still very accurate, while a faster movement will
+drive the pointer quickly across the screen.
+.Pp
+The
+.Ar exp
+value specifies the exponent, which is basically
+the amount of acceleration.  Useful values are in the
+range 1.1 to 2.0, but it depends on your mouse hardware
+and your personal preference.  A value of 1.0 means no
+exponential acceleration.  A value of 2.0 means squared
+acceleration (i.e. if you move the mouse twice as fast,
+the pointer will move four times as fast on the screen).
+Values beyond 2.0 are possible but not recommended.
+A good value to start is probably 1.5.
+.Pp
+The optional
+.Ar offset
+value specifies the distance at which the acceleration
+begins.  The default is 1.0, which means that the
+acceleration is applied to movements larger than one unit.
+If you specify a larger value, it takes more speed for
+the acceleration to kick in, i.e. the speed range for
+small and accurate movements is wider.
+Usually the default should be sufficient, but if you're
+not satisfied with the behaviour, try a value of 2.0.
+.Pp
+Note that the
+.Fl A
+option interacts badly with the X server's own acceleration,
+which doesn't work very well anyway.  Therefore it is
+recommended to switch it off if necessary:
+.Dq xset m 1 .
 .It Fl a Ar X Ns Op , Ns Ar Y
 Accelerate or decelerate the mouse input.
 This is a linear acceleration only.
 Values less than 1.0 slow down movement, values greater than 1.0 speed it
 up.
 Specifying only one value sets the acceleration for both axes.
+.Pp
+You can use the
+.Fl a
+and
+.Fl A
+options at the same time to have the combined effect
+of linear and exponential acceleration.
 .It Fl c
 Some mice report middle button down events
 as if the left and right buttons are being pressed.
@@ -758,6 +802,7 @@
 .Sh SEE ALSO
 .Xr kill 1 ,
 .Xr vidcontrol 1 ,
+.Xr xset 1 ,
 .Xr keyboard 4 ,
 .Xr mse 4 ,
 .Xr pcvt 4 ,
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list