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);