Date: Tue, 6 Mar 2007 18:46:33 +0100 (CET) From: Oliver Fromme <olli@secnetix.de> To: FreeBSD-gnats-submit@FreeBSD.org Cc: Oliver Fromme <olli@secnetix.de> Subject: bin/110003: [PATCH] Add dynamic acceleration to moused(8) Message-ID: <200703061746.l26HkXtK018814@lurza.secnetix.de> Resent-Message-ID: <200703061820.l26IK9d5086054@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>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:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200703061746.l26HkXtK018814>