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