Tested on amd64-current, with a standard Logitech USB mouse and an
A4Tech serial mouse (detects as "microsoft type"), seems to work nicely.

Index: wsmoused.8
===================================================================
RCS file: /cvs/src/usr.sbin/wsmoused/wsmoused.8,v
retrieving revision 1.18
diff -u -r1.18 wsmoused.8
--- wsmoused.8  5 Jun 2009 06:50:52 -0000       1.18
+++ wsmoused.8  4 Sep 2010 19:22:17 -0000
@@ -40,6 +40,8 @@
 .Fl M
 .Ar N Ns = Ns Ar M
 .Oc
+.Op Fl a Ar accel
+.Op Fl r Ar resist
 .Op Fl p Ar device
 .Op Fl t Ar type
 .Sh DESCRIPTION
@@ -94,6 +96,17 @@
 .Ar file .
 .It Fl i
 Print the type and the protocol of the mouse and exit.
+.It Fl a Ar accel
+The acceleration that should be applied when the mouse is being moved
+with high speed.
+.Ar accel
+must be a floating point value greater than or equal to 1.0 and less than or 
equal to 10.0.
+If omitted, the default value of 2.0 is used.
+.It Fl r Ar resist
+Resistance to motion, the greater this value, the slower the mouse moves.
+.Ar resist
+must be a value greater than or equal to 0 and less than or equal to 80.
+If omitted, the default value of 15 is used.
 .It Fl M Ar N Ns = Ns Ar M
 Assign the physical button
 .Ar M
Index: wsmoused.c
===================================================================
RCS file: /cvs/src/usr.sbin/wsmoused/wsmoused.c,v
retrieving revision 1.25
diff -u -r1.25 wsmoused.c
--- wsmoused.c  21 Jun 2009 16:13:18 -0000      1.25
+++ wsmoused.c  4 Sep 2010 19:22:17 -0000
@@ -74,6 +74,8 @@
 
 #define        DEFAULT_TTY     "/dev/ttyCcfg"
 #define        DEFAULT_PIDFILE "/var/run/wsmoused.pid"
+#define        DEFAULT_RESISTANCE      15
+#define        DEFAULT_ACCELERATION    2.0
 
 extern char *__progname;
 extern char *mouse_names[];
@@ -83,6 +85,8 @@
 int nodaemon = FALSE;
 int identify = FALSE;
 char *pidfile = NULL;
+int resistance = -1;
+double acceleration = -1.0;
 
 mouse_t mouse = {
        .flags = 0,
@@ -303,45 +307,69 @@
        ioctl(mouse.cfd, WSDISPLAYIO_WSMOUSED, event);
 }
 
-/* workaround for cursor speed on serial mice */
-static void
-normalize_event(struct wscons_event *event)
-{
-       int dx, dy;
-       int two_power = 1;
-
-/* 2: normal speed, 3: slower cursor, 1: faster cursor */
-#define NORMALIZE_DIVISOR 3
-
-       switch (event->type) {
-       case WSCONS_EVENT_MOUSE_DELTA_X:
-               dx = abs(event->value);
-               while (dx > 2) {
-                       two_power++;
-                       dx = dx / 2;
-               }
-               event->value = event->value / (NORMALIZE_DIVISOR * two_power);
-               break;
-       case WSCONS_EVENT_MOUSE_DELTA_Y:
-               two_power = 1;
-               dy = abs(event->value);
-               while (dy > 2) {
-                       two_power++;
-                       dy = dy / 2;
-               }
-               event->value = event->value / (NORMALIZE_DIVISOR * two_power);
-               break;
-       }
-}
-
 /* send a wscons_event to the kernel */
 static int
 treat_event(struct wscons_event *event)
 {
+       int i;
+       enum {
+               X_ACCUM,
+               Y_ACCUM,
+               N_ACCUMS
+       };
+       static int accums[N_ACCUMS];
+       /*
+        * Depending on the console's font dimensions, the "pixels" of the
+        * screen might be rectangular instead of being square. In fact, they
+        * are in default configuration, because a 8x16 font is used.
+        * Compensate for this fact by adding more resistance on Y axis.
+        * 4/3 is a compromise value, to compensate, but in turn not to make
+        * using say 8x8 font together with wsmoused too awkward.
+        * TODO (?)
+        *      make it so that wsmoused can detect when VT is switched and
+        *      so it could find out what the font dimensions on that
+        *      particular VT are (e.g. add VT switch event to wscons, add new
+        *      ioctl to request font dimensions?).
+        */
+       const double resist_mults[N_ACCUMS] = {
+               1.0,
+               4.0/3.0
+       };
+       static double max_speed = 1.0;
+       int resist;
        struct wscons_event mapped_event;
 
        if (IS_MOTION_EVENT(event->type)) {
-               ioctl(mouse.cfd, WSDISPLAYIO_WSMOUSED, event);
+               if (event->type == WSCONS_EVENT_MOUSE_DELTA_X)
+                       i = X_ACCUM;
+               else if (event->type == WSCONS_EVENT_MOUSE_DELTA_Y)
+                       i = Y_ACCUM;
+               else {
+                       /*
+                        * Delta_{w,z} aka scrollwheel events don't need any
+                        * additional processing such as scaling and/or
+                        * acceleration.
+                        */
+                       ioctl(mouse.cfd, WSDISPLAYIO_WSMOUSED, event);
+                       return 1;
+               }
+
+               if (max_speed < abs(event->value))
+                       max_speed = abs(event->value);
+
+               /*
+                * Maximum acceleration is applied when
+                * event->value tends to max_speed.
+                */
+               accums[i] += event->value + event->value *
+                   ((acceleration - 1.0) *
+                    (abs(event->value) / max_speed));
+
+               resist = resistance * resist_mults[i];
+               if ((event->value = accums[i] / resist) != 0) {
+                       accums[i] %= resist;
+                       ioctl(mouse.cfd, WSDISPLAYIO_WSMOUSED, event);
+               }
                return 1;
        } else if (IS_BUTTON_EVENT(event->type) &&
            (uint)event->value < MOUSE_MAXBUTTON) {
@@ -365,13 +393,11 @@
        if (act->dx != 0) {
                event.type = WSCONS_EVENT_MOUSE_DELTA_X;
                event.value = act->dx;
-               normalize_event(&event);
                treat_event(&event);
        }
        if (act->dy != 0) {
                event.type = WSCONS_EVENT_MOUSE_DELTA_Y;
                event.value = 0 - act->dy;
-               normalize_event(&event);
                treat_event(&event);
        }
        if (act->dz != 0) {
@@ -519,7 +545,8 @@
 usage(void)
 {
        fprintf(stderr, "usage: %s [-2dfi] [-C thresh] [-D device] [-I file]"
-           " [-M N=M]\n\t[-p device] [-t type]\n", __progname);
+           " [-M N=M]\n\t[-r resist] [-a accel] [-p device] [-t type]\n",
+           __progname);
        exit(1);
 }
 
@@ -530,14 +557,26 @@
        unsigned int type;
        int opt;
        int i;
+       const char *errstr;
 
-#define GETOPT_STRING "2dfhip:t:C:D:I:M:"
+#define GETOPT_STRING "2a:dfhip:r:t:C:D:I:M:"
        while ((opt = (getopt(argc, argv, GETOPT_STRING))) != -1) {
                switch (opt) {
                case '2':
                        /* on two button mice, right button pastes */
                        p2l[MOUSE_BUTTON3] = MOUSE_BUTTON2;
                        break;
+               case 'a':
+#define MAX_ACCELERATION 10.0
+                       acceleration = atof(optarg);
+                       if (acceleration < 1.0 ||
+                           acceleration > MAX_ACCELERATION) {
+                               warnx("invalid acceleration `%s': "
+                                   "max value is %.1f",
+                                   optarg, MAX_ACCELERATION);
+                               usage();
+                       }
+                       break;
                case 'd':
                        ++debug;
                        break;
@@ -555,6 +594,17 @@
                        if ((mouse.portname = strdup(optarg)) == NULL)
                                logerr(1, "out of memory");
                        break;
+               case 'r':
+#define MAX_RESISTANCE 80
+                       resistance =
+                           strtonum(optarg, 0, MAX_RESISTANCE, &errstr);
+                       if (errstr) {
+                               warnx("resistance `%s': %s",
+                                   optarg, errstr);
+                               usage();
+                       }
+                       resistance += 1;
+                       break;
                case 't':
                        if (strcmp(optarg, "auto") == 0) {
                                mouse.proto = P_UNKNOWN;
@@ -574,11 +624,11 @@
                        break;
                case 'C':
 #define MAX_CLICKTHRESHOLD 2000 /* max delay for double click */
-                       mouse.clickthreshold = atoi(optarg);
-                       if (mouse.clickthreshold < 0 ||
-                           mouse.clickthreshold > MAX_CLICKTHRESHOLD) {
-                               warnx("invalid threshold `%s': max value is %d",
-                                   optarg, MAX_CLICKTHRESHOLD);
+                       mouse.clickthreshold = 
+                           strtonum(optarg, 0, MAX_CLICKTHRESHOLD, &errstr);
+                       if (errstr) {
+                               warnx("threshold `%s': %s",
+                                   optarg, errstr);
                                usage();
                        }
                        break;
@@ -607,6 +657,11 @@
                mouse.portname = WSMOUSE_DEV;
        if (mouse.ttyname == NULL)
                mouse.ttyname = DEFAULT_TTY;
+
+       if (resistance == -1)
+               resistance = DEFAULT_RESISTANCE;
+       if (acceleration == -1.0)
+               acceleration = DEFAULT_ACCELERATION;
 
        if (!nodaemon) {
                openlog(__progname, LOG_PID, LOG_DAEMON);

Reply via email to