Date: Sat, 16 Jun 2007 13:13:05 +0200 (CEST) From: Oliver Fromme <olli@secnetix.de> To: FreeBSD-gnats-submit@FreeBSD.org Cc: Oliver Fromme <olli@secnetix.de> Subject: bin/113749: [PATCH] moused(8) -a drops movements due to rounding errors Message-ID: <200706161113.l5GBD55D050973@lurza.secnetix.de> Resent-Message-ID: <200706161120.l5GBK3pr064378@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 113749 >Category: bin >Synopsis: [PATCH] moused(8) -a drops movements due to rounding errors >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Sat Jun 16 11:20:03 GMT 2007 >Closed-Date: >Last-Modified: >Originator: Oliver Fromme >Release: RELENG_6 and HEAD >Organization: secnetix GmbH & Co. KG http://www.secnetix.de/bsd >Environment: The problem described here exists for as long as moused(8) exists. It existed before the recent addition of the -A option and is unrelated to it, but the -A option inherited the problem and is also affected. The patch presented below applies to HEAD (moused.c 1.78) and RELENG_6 (moused.c 1.70.2.4). >Description: The problem was first reported by Harald Schmalzbauer in this thread on the -current ML, and I have been able to reproduce it: http://lists.freebsd.org/pipermail/freebsd-current/2007-June/073694.html When the -a option (linear acceleration) is used with an acceleration value less than one (i.e. to slow a mouse down because it has a very high resolution), rounding errors occur: Slow movements are not reported at all, movement information is dropped. You have to move the mouse at a certain minimum speed to get any movement of the pointer on the screen at all. The culprit is this code in moused.c: mouse.u.data.x = action2.dx * rodent.accelx; mouse.u.data.y = action2.dy * rodent.accely; mouse.u.data.* is the movement reported to the application (e.g. Xorg), action2.d* is the movement reported by the device, and rodent.accel* is the acceleration factor set by the -a option (e.g. 0.3 to reduce the speed to 30%). All those variables are ints, except for the accel* values which are floats. So if you move the mouse slowly so the device reports only 1, 2 or 3 units of movement, they will all be rounded down to zero: 3 * 0.3 = 0.9 = (int) 0. Therefore, with an acceleration value of 0.3, you have to move the mouse fast enough so it constantly reports at least four units of movement to get any movement of the pointer at all. Of course, the solution is to calculate and accumulate the rounding error and take it into account upon the next movement. That's what the following patch does, both for the -a option (linear acceleration) and for the new -A option (dynamic acceleration). >How-To-Repeat: Run moused(8) with some low -a value (less than 1), e.g. 0.3, and move the mouse slowly. >Fix: As mentioned above, this patch applies to both HEAD (moused.c 1.78) and RELENG_6 (moused.c 1.70.2.4). It should be applied in the directory src/usr.sbin/moused. Harald Schmalzbauer confirmed that this patch fixes the problem for him. If the patch got somehow mangled during transmission of the PR e-mail, it is also available from this URL: http://www.secnetix.de/~olli/tmp/moused.v2.patch --- moused.c.orig Sun Jun 3 15:36:04 2007 +++ moused.c Sat Jun 16 09:58:10 2007 @@ -400,6 +400,8 @@ float accely; /* Acceleration in the Y axis */ float expoaccel; /* Exponential acceleration */ float expoffset; /* Movement offset for exponential accel. */ + float remainx; /* Remainder on X and Y axis, respectively... */ + float remainy; /* ... to compensate for rounding errors. */ int scrollthreshold; /* Movement distance before virtual scrolling */ } rodent = { .flags = 0, @@ -421,6 +423,8 @@ .accely = 1.0, .expoaccel = 1.0, .expoffset = 1.0, + .remainx = 0.0, + .remainy = 0.0, .scrollthreshold = DFLT_SCROLLTHRESHOLD, }; @@ -500,6 +504,7 @@ /* function prototypes */ +static void linacc(int, int, int*, int*); static void expoacc(int, int, int*, int*); static void moused(void); static void hup(int sig); @@ -956,7 +961,33 @@ } /* + * Function to calculate linear acceleration. + * + * If there are any rounding errors, the remainder + * is stored in the remainx and remainy variables + * and taken into account upon the next movement. + */ + +static void +linacc(int dx, int dy, int *movex, int *movey) +{ + float fdx, fdy; + + if (dx == 0 && dy == 0) { + *movex = *movey = 0; + return; + } + fdx = dx * rodent.accelx + rodent.remainx; + fdy = dy * rodent.accely + rodent.remainy; + *movex = lround(fdx); + *movey = lround(fdy); + rodent.remainx = fdx - *movex; + rodent.remainy = fdy - *movey; +} + +/* * Function to calculate exponential acceleration. + * (Also includes linear acceleration if enabled.) * * In order to give a smoother behaviour, we record the four * most recent non-zero movements and use their average value @@ -979,8 +1010,12 @@ 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); + fdx = fdx * accel + rodent.remainx; + fdy = fdy * accel + rodent.remainy; + *movex = lroundf(fdx); + *movey = lroundf(fdy); + rodent.remainx = fdx - *movex; + rodent.remainy = fdy - *movey; lastlength[2] = lastlength[1]; lastlength[1] = lastlength[0]; lastlength[0] = length; /* Insert new average, not original length! */ @@ -1250,8 +1285,8 @@ &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; + linacc(action2.dx, action2.dy, + &mouse.u.data.x, &mouse.u.data.y); } mouse.u.data.z = action2.dz; if (debug < 2) @@ -1266,8 +1301,8 @@ &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; + linacc(action2.dx, action2.dy, + &mouse.u.data.x, &mouse.u.data.y); } mouse.u.data.z = action2.dz; if (debug < 2) >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200706161113.l5GBD55D050973>