A PS/2 mouse in FreeBSD behaves very badly when it is configured to run
fast like can be done in any Windows NT operating system.

To compare XFree86 with Windows NT, the Windows Registry can have this
entered into it (with a reboot being done):

        [HKEY_CURRENT_USER\Control Panel\Mouse]

XFree86 has more than one problem with its mouse deceleration algorithm.
One problem is that it is too difficult to get the pointer positioned over
any particular pixel, provided that it is also configured to be as fast as
a sedately fast Windows NT mouse pointer.

A look at the algorithm below shows that it could be the cause of the
defects in the mouse's behaviour.

I note that Hewlett Packard has produced computers where users can write
their own program to control the mouse pointer. Xfree86 is different
because it provides poor control of a bad algorithm, and the control being
at the weakest in operating region where the algorithm is at its very
worst, which is when the mouse pointer is made to be fast.

In the algorithm below there is a 'raise to the power of' function. That
has a circular influence. But the presence of "abs(dx) + abs(dy)) >= ...",
is creating a region that has the shape of a diamond. That a power
function is used shows there was not a concern with speed which is
probably good enough. It is doubtful that a diamond shape is best. A thin
horizontal rectangle for nearly horizontal movements could be better (and
HP seems to have done that).

This is possibly not the best that can be done too:

if (device->ptrfeed->ctrl.threshold) {

It means that users can get a different behaviour if the mouse is speeded
from threshold 1 to threshold 0.

If the mouse is greatly slowed down a lot then the XFree86 mouse seems OK
to person familar with an excellent mouse algorithm, e.g. someone that has
use Windows NT, 2000, or 95, etc. However they may expect that XFree86
mouse not show amazing jerkiness after installing an 1.2GHz CPU and after
increasing the sample to at least 150 samples per second. Those changes
lead to just about no improvement in Windows NT, and also XFree86. I was
testing in FreeBSD and I did not perfectly rule out some FreeBSD problem,
but it looks like no one need search further than "xf86PostMotionEvent()"
to find the cause of why many Unix users have had a mouse that is difficult
to position over a given pixel.
In Windows, a mouse cursor can be rapidly moved over to a spot just as is

A major problem with the XFree86 pointer algorithm is this: the mouse
pointer decelerates in a bad way.  I described the problem with these
words in a bug report to KDE.org:

 >That is described again: there was a problem with a ring around
 >the point being stopped onto, having the speed of the mouse cursor
 >be too slow. Around that ring, another ring shaped region was
 >exhibiting a mouse speed of the decelerating mouse cursor that
 >seemed to be too fast.


So as the pointer nears the final point, the user has to slow the physical
mouse down too much. The XFree86 algorithm then slows the pointer even
more with unexpected strength and the pointer and then the operator has to
speed up the mouse. As that is happening, the XFree86 unexpectedly
somewhat suddenly cuts in and speeds up the mouse even more, and the extra
acceleration causes an overshoot. Added to that is a problem of huge jerky
movements for a nearly stationary slightly moving mouse. It can take quite
a while to get a fast mouse onto the final point it that user was trying
to get it onto.

In Windows NT, a rapid graceful straight line positioning of the
mouse pointer over the desired end point, can be done quickly and
efficiently. Even rewriting the offending XFree86 code inside of XFree86
would unpleasant and perhaps the top XFree86 developers would prefer to
drop into Vim in console mode [well I would].

I have been quite certain that the console windows of FreeBSD provide a
much more nicer more productive and friendly environment that is clearly
advanced over what KDE has to offer because it is running over XFree86.
Nevertheless the console windows with 60x132 characters seem inferior to
the graphical user interfaces of Microsoft's Windows 95. (Also X-term
defaults to having keys set wrongly). The FreeBSD console mouse is far too
slow and not adjustable too.

Users of XFree86 may need to pick the mouse off the pad a lot more often
they ought need to. There is an opportunity to make a noise when bringing
it down again but it is controversial to say that XFree86 ought bring such
a freedom upon users who would prefer instead a far better mouse feedback
pointer speed control algorithm.

Another problem is that when XFree86 mouse is configured to be as fast as
a good Windows NT mouse, then it can be found that extremely slow and
extremely small movements of the mouse result will produce very big jerky
jumpy movements that can be 1/2 cm or so, in length. That is a bug. The
XFree86 algorithm could do just that. Here it is (from

Either (1) or (2) is run:

If not (0 = threshold) then:

       valuator[0] = (dx * device->ptrfeed->ctrl.num) /

otherwise this:
   when not (0 = dx):
       local->dxremaind = mult * (float)dx + local->dxremaind;
       valuator[0] = (int)local->dxremaind;

The Hewlett Packard "find_deviceintrec()" routine (in
  "/xc/programs/Xserver/hw/hp/input/x_hil.c") has this:

       if ( (c[i] - threshold) > 0)
          c[i] = threshold + (c[i] - threshold) * acceleration;

The HP algorithm treats the x and y axis separately so we can expect
that for a constant diagonal motion of the physical mouse would produce
lines of different slope on the screen. That would be caused by one of
dx or dy being inside of the threshold and the other outside. That is
behaviour that the Microsoft mouse will show. Part of the problem with
the XFree86 algorithm could be partly due to the mixing up of the
axes with the dx*dx+dy*dy, in the code like this (from below):

       mult = pow((float)(dx*dx+dy*dy), ("accel" - 1.0)/2.0) / 2.0;


A message at Slashdot said that the mouse in Linux's X-Windows has always
been slower and it has always been like that. It is Unix and FreeBSD too,
They have a problem with KDE: it has a non-resizable tool bar and an
bad magnetic scheme for stopping windows from going over the edge. A
better faster method for GUI pros is the Shove-It system. It has windows
bounce back if they extend outside of the visible screen; code:
http://www.phord.com/shoveit.html [in NT boot start from Registry]

Some people could be wanting to run Windows NT/2000 inside of VMware
inside of Linux (or FreeBSD if it VMware runs OK which may not be the
But it could be too unsatisfactory when the mouse is controlled by XFree86
code. Until the problem is fixed somehow, the real Windows could be
preferred. A group of possible future users (and VMware customers, etc.)
would be avoiding the Unix operating systems.

Maybe users of XFree86 ought be able to hook in their own mouse pointer
feedback control algorithm. I am very sure that that is not currently the
way XFree86 is coded. Thus it can be implemented without harming the
functionality of existing software, i.e. it is solution that allows users
the best.

Increasing the sample rate of the mouse hardware seems to make about no
difference to the usability of the mouse in FreeBSD and Windows NT. It's
main effect is on smoothing up a fast moving mouse, which can be seen as
easy to do without. So the XFree86 problem can't be explained by the mouse
sampling rate.

The Hewlett Packard algorithm for decelerating the mouse has the
deceleration for each axis be calculated separately. In the XFree86
algorithm (in "xf86Xinput.c"), the multiplier is calculated from a radial
distance. Persons attempting a quick guess on which is better might
suppose that the HP algorithm is better, but it could be debatable. I
presume the HP algorithm allows much preciser vertical positioning when
the pointer is moving a lengthy distance but that path is nearly a
horizontal path. Maybe a hybrid might be best.

Users of KDE and GNOME get only 2 Real numbers with which they can
configure the algorithm. The way it is done is quite bad, although it
ought be possible to allow something far better with the 3 Integers.

To get the mouse very fast, the speed is 0 or 1. But persons can't
seriously consider that due to incorrect way in which deceleration is
implemented. To correct the deceleration algorithm would uncover the bug
of having a range of top speeds be selectable with the Integers, 0, 1 and
maybe 2. The numbers could be rescaled so that what currently is
reciprocal-speed "1" will later need to be selected using the number
"100". It must be possible to allows to actually select a fast speed with
a bit of precision. In Windows NT the ability to select the speed using
the Registry seems quite limited but an attempt to speed up the mouse does
not take effect until a reboot is done. It is possible to get a mouse
faster than would be desired with it seeming to decelerate optimally,
whereas in XFree86 world, the inadequacies in the deceleration algorithm
in practice limit the speed that can be selected.

A way to get XFree86 improved is to accurately copy the Microsoft
deceleration algorithm. XFree86 can get out of the problem trivially.
Once people can compile XFree86 and alter the algorithm, it would be hard
for them to be unable to much improve the deceleration algorithm. There
are sure to be programmers that can produce a far better algorithm and if
they could hook it in, a near optimal algorithm could appear. It is
presumably harming the popularity of KDE and GNOME to have a mouse that
can't easily positioned over pixels and that will remain too slow no
matter how fast the mouse and interrupts and CPU are.

Once change the XFree86 maintainers could do is alter the word
"acceleration" into "deceleration". A mouse need not be accurate when the
motion is started and a diamond shaped region for acceleration would not
be as significant as it is for the region where deceleration occurs.

There are no arguments in the XFree86 "xf86Xinput.c" code suggesting the
design should not be fixed.

xc\programs\Xserver\hw\xfree86\common\xf86Xinput.c :


xf86PostMotionEvent(DeviceIntPtr   device,
          int         is_absolute,
          int         first_valuator,
          int         num_valuators,
    va_list              var;
    int                  loop;
    LocalDevicePtr       local = (LocalDevicePtr)
    char                 *buff = 0;
    Time                 current;
    Bool                 is_core = xf86IsCorePointer(device);
    Bool                 is_shared = xf86ShareCorePointer(device);
    ValuatorClassPtr     val = device->valuator;
    int                  valuator[6];
    int                  *axisvals;
    AxisInfoPtr          axes;
    int                  dx = 0, dy = 0;
    float                mult;
    int                  loop_start;
    int                  num;

    DBG(5, ErrorF("xf86PostMotionEvent BEGIN 0x%x(%s) is_core=%s
                                              is_shared=%s is_absolute=%s\n",
          device, device->name,
          is_core ? "True" : "False",
          is_shared ? "True" : "False",
          is_absolute ? "True" : "False"));

    xf86Info.lastEventTime = xev->time = current = GetTimeInMillis();

    if (!is_core) {
       if (HAS_MOTION_HISTORY(local)) {
          buff = ((char *)local->motion_history +
                (sizeof(INT32) *
                local->dev->valuator->numAxes + sizeof(Time)) * local->last);

       if (num_valuators && (!val ||
                          (first_valuator + num_valuators > val->numAxes))) {
       ErrorF("Bad valuators reported for device \"%s\"\n", device->name);

    axisvals = val->axisVal;
    axes = val->axes;

    va_start(var, num_valuators);

    loop_start = first_valuator;
    for(loop=0; loop<num_valuators; loop++) {

    valuator[loop%6] = va_arg(var,int);

    if (loop % 6 == 5 || loop == num_valuators - 1) {
       num = loop % 6 + 1;
       * Adjust first two relative valuators
       if (!is_absolute && num_valuators >= 2 && loop_start == 0) {

          dx = valuator[0];
          dy = valuator[1];

          * Accelerate
          if (device->ptrfeed && device->ptrfeed->ctrl.num) {
             /* modeled from xf86Events.c */
             if (device->ptrfeed->ctrl.threshold) {
                if ((abs(dx) + abs(dy)) >= device->ptrfeed->ctrl.threshold) {
                   valuator[0] = (dx * device->ptrfeed->ctrl.num) /
                   valuator[1] = (dy * device->ptrfeed->ctrl.num) /
             else if (dx || dy) {
                mult = pow((float)(dx*dx+dy*dy),
                      ((float)(device->ptrfeed->ctrl.num) /
                         (float)(device->ptrfeed->ctrl.den) - 1.0) /
                      2.0) / 2.0;
                if (dx) {
                   local->dxremaind = mult * (float)dx + local->dxremaind;
                   valuator[0] = (int)local->dxremaind;
                   local->dxremaind = local->dxremaind - (float)valuator[0];
                if (dy) {
                   local->dyremaind = mult * (float)dy + local->dyremaind;
                   valuator[1] = (int)local->dyremaind;
                   local->dyremaind = local->dyremaind - (float)valuator[1];
             DBG(6, ErrorF("xf86PostMotionEvent acceleration v0=%d v1=%d\n",
                   valuator[0], valuator[1]));
          loop_start += 6;
    if (HAS_MOTION_HISTORY(local)) {
       local->last = (local->last + 1) % device->valuator->numMotionEvents;
       if (local->last == local->first)
          local->first = (local->first + 1) % device->valuator->numMotionEvents;
    DBG(5, ErrorF("xf86PostMotionEvent END   0x%x(%s) is_core=%s is_shared=%s\n",
          device, device->name,
          is_core ? "True" : "False",
          is_shared ? "True" : "False"));

Hewlett Packard's algorithm is very different and it creates a square
with a diameter that is twice the threshold that has a quite linear
behaviour inside an outside. [That can avoid a problem of a dead region
where the mouse does nothing, which is well able to be something that the
"raising to a power of" function in xf86PostMotionEvent() could produce.]

DeviceIntPtr find_deviceintrec (indevice) {
process_motion (dev, phys, log, c, timestamp)
    if (!playback_on) {
       if (!(phys->hpflags & ABSOLUTE_DATA) &&
          (acceleration != DEF_ACCELERATION))
          for (i=0; i < (u_char) log->d.ax_num; i++)
             if ( (c[i] - threshold) > 0)
                c[i] = threshold + (c[i] - threshold) * acceleration;
             else if ( (c[i] + threshold) < 0)
                c[i] = (c[i] + threshold) * acceleration - threshold;

None of the Kdrive Keith Packard "small Xserver" files have calls to
"xf86PostMotionEvent(...)" and it has a different deceleration algorithm.

KdMouseAccelerate (DeviceIntPtr device, int delta) {

Note: "xset.c" is an X-Windows program/feature allowing the deceleration
to be set. The xset program calls XChangePointerControl (...).


The Unix/Linux communities that were going to complain eventually can
instead produce a better mouse algorithm.

A 3 piece linear (with x and y independent) method might turn out to be
good enough under testing. If so then it could be found that the XFree86
"to the power of" function is not able to match that closely enough

Craig Carey
New Zealand

Xpert mailing list

Reply via email to