NetBSD Problem Report #46394
From www@NetBSD.org Tue May 1 14:43:41 2012
Return-Path: <www@NetBSD.org>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
by www.NetBSD.org (Postfix) with ESMTP id DDD2963C785
for <gnats-bugs@gnats.NetBSD.org>; Tue, 1 May 2012 14:43:40 +0000 (UTC)
Message-Id: <20120501144339.C5C2463BA4F@www.NetBSD.org>
Date: Tue, 1 May 2012 14:43:39 +0000 (UTC)
From: nathanialsloss@yahoo.com.au
Reply-To: nathanialsloss@yahoo.com.au
To: gnats-bugs@NetBSD.org
Subject: wsmouse - button remapping.
X-Send-Pr-Version: www-1.0
>Number: 46394
>Category: kern
>Synopsis: wsmouse - button remapping.
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: change-request
>Submitter-Id: net
>Arrival-Date: Tue May 01 14:45:00 +0000 2012
>Last-Modified: Sun Sep 15 07:25:00 +0000 2013
>Originator: Nat Sloss
>Release: NetBSD Current 6.99.5
>Organization:
>Environment:
NetBSD beast 6.99.5 NetBSD 6.99.5 (LOCKDEBUG) #41: Mon Apr 30 14:13:38 EST 2012 build@beast:/usr/src/sys/arch/i386/compile/obj/LOCKDEBUG i386
>Description:
Hi. Whilst playing around with button detection for my mouse and touchscreen I noticed there was no way to remap the button functions if button 0 was not the left most button and tip switch (for touchscreens and digitizers) was not mapped to the left most button.
There is no provision in ws(4) to remap buttons and that's what I use for my touchscreen. Luckily for me buttons are mapped properly, but if "tip" wasn't button 0 I'd be stuck.
>How-To-Repeat:
Try using a mouse where by button 0 is not the left most button or a touchscreen/digitizer where by the screen touch is not the tip switch but a tip switch is detected.
You'll find you will have no way to change the button mappings.
>Fix:
Originally I had modified the xf86-input-ws driver so I could remap buttons, but This only works in X. A system wide mechanism would be better.
So what I did was to add a button map array to the wsmouse struct and write a function to remap the buttons and finally to add sysctl setup and verify routines (Not the best way I believe, but the only way I knew how) to facilitate button mapping changes.
I believe that changing button mappings would be better in wsconsctl but I have no idea how to do it as yet, but I'm trying.
To use: sysctl -w hw.wsmouse.button0=-1 (to disable a button)
sysctl -w hw.wsmouse.button0=15 (To remap button 0 to 15)
I thought the ability to disable a button was important and its not even available with xf86-input-mouse.
Button remapping/disabling can be done with xinput but in my opinion a system wide one is better.
Note: This patch is my own work, which I make available under the NetBSD license.
--- wsmouse.c.orig 2011-12-04 01:13:29.000000000 +1100
+++ wsmouse.c 2012-05-01 00:34:17.000000000 +1000
@@ -117,6 +117,7 @@
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/proc.h>
+#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/tty.h>
@@ -144,6 +145,7 @@
#define INVALID_Y INT_MAX
#define INVALID_Z INT_MAX
#define INVALID_W INT_MAX
+#define NBUTTONS (int)(sizeof(u_int) * 8)
struct wsmouse_softc {
struct wsevsrc sc_base;
@@ -162,6 +164,10 @@
int sc_z; /* absolute-z */
int sc_w; /* absolute-w */
+ struct sysctllog *sc_log;
+ int sc_buttonMap[NBUTTONS]; /* button mappings */
+ int sc_buttonMib[NBUTTONS]; /* button sysctl nodes */
+
int sc_refcnt;
u_char sc_dying; /* device is being detached */
@@ -192,6 +198,8 @@
wsmouse_match, wsmouse_attach, wsmouse_detach, wsmouse_activate);
static void wsmouse_repeat(void *v);
+static void wsmouse_sysctl_setup(struct wsmouse_softc *);
+static int buttonRemap(struct wsmouse_softc *, int);
extern struct cfdriver wsmouse_cd;
@@ -237,6 +245,7 @@
{
struct wsmouse_softc *sc = device_private(self);
struct wsmousedev_attach_args *ap = aux;
+ int i;
#if NWSMUX > 0
int mux, error;
#endif
@@ -272,6 +281,12 @@
if (!pmf_device_register(self, NULL, NULL))
aprint_error_dev(self, "couldn't establish power handler\n");
+
+ /* Initialize button mappings 1:1 */
+ for (i = 0; i < NBUTTONS; i++)
+ sc->sc_buttonMap[i] = i;
+
+ wsmouse_sysctl_setup(sc);
}
int
@@ -336,9 +351,94 @@
mn = device_unit(self);
vdevgone(maj, mn, mn, VCHR);
+ if (sc->sc_log)
+ sysctl_teardown(&sc->sc_log);
+
return (0);
}
+static int
+button_sysctl_verify(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node;
+ struct wsmouse_softc *sc;
+ int err, tmp, i;
+
+ node = *rnode;
+ sc = rnode->sysctl_data;
+
+ for (i = 0; i < NBUTTONS; i++) {
+ if (node.sysctl_num == sc->sc_buttonMib[i]) {
+ tmp = sc->sc_buttonMap[i];
+ node.sysctl_data = &tmp;
+
+ err = sysctl_lookup(SYSCTLFN_CALL(&node));
+ if (err || newp == NULL)
+ return err;
+
+ if (tmp < -1 || tmp > NBUTTONS - 1)
+ return EINVAL;
+
+ sc->sc_buttonMap[i] = tmp;
+ }
+ }
+
+ return 0;
+}
+
+static void
+wsmouse_sysctl_setup(struct wsmouse_softc *sc)
+{
+ const struct sysctlnode *node_button[NBUTTONS], *node;
+ int err, i;
+ char buttonName[SYSCTL_NAMELEN];
+
+ err = sysctl_createv(&sc->sc_log, 0, NULL, NULL, 0,
+ CTLTYPE_NODE, "hw", NULL, NULL, 0, NULL, 0, CTL_HW, CTL_EOL);
+ if (err)
+ goto sysctl_err;
+
+ err = sysctl_createv(&sc->sc_log, 0, NULL, &node, 0,
+ CTLTYPE_NODE, device_xname(sc->sc_base.me_dv),
+ SYSCTL_DESCR("wsmouse controls"), NULL, 0,
+ NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
+ if (err)
+ goto sysctl_err;
+
+ for (i = 0; i < NBUTTONS; i++) {
+ snprintf(buttonName, sizeof(buttonName), "button%d", i);
+
+ err = sysctl_createv(&sc->sc_log, 0, &node,
+ &node_button[i], CTLFLAG_READWRITE|CTLFLAG_ANYWRITE,
+ CTLTYPE_INT, buttonName, SYSCTL_DESCR("button event mapping"),
+ button_sysctl_verify, 0, sc, 0, CTL_CREATE, CTL_EOL);
+ if (err)
+ goto sysctl_err;
+ sc->sc_buttonMib[i] = node_button[i]->sysctl_num;
+ }
+
+ return;
+sysctl_err:
+ aprint_error_dev(sc->sc_base.me_dv, "failed to add sysctl nodes. (%d)\n", err);
+}
+
+static int
+buttonRemap(struct wsmouse_softc *sc, int buttons)
+{
+ int buttonState, mappedButtons, i;
+
+ buttonState = buttons;
+ mappedButtons = 0;
+
+ for (i = 0; i < NBUTTONS; i++) {
+ if ((buttonState & 1) && (sc->sc_buttonMap[i] >= 0))
+ mappedButtons |= 1 << sc->sc_buttonMap[i];
+ buttonState >>= 1;
+ }
+
+ return mappedButtons;
+}
+
void
wsmouse_input(device_t wsmousedev, u_int btns /* 0 is up */,
int x, int y, int z, int w, u_int flags)
@@ -369,7 +469,7 @@
sc->sc_base.me_parent, evar));
#endif
- sc->sc_mb = btns;
+ sc->sc_mb = buttonRemap(sc, btns);
if (!(flags & WSMOUSE_INPUT_ABSOLUTE_X))
sc->sc_dx += x;
if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Y))
>Audit-Trail:
From: Nat Sloss <nathanialsloss@yahoo.com.au>
To: gnats-bugs@netbsd.org
Cc:
Subject: Re: kern/46394 wsmouse button remapping
Date: Sun, 15 Sep 2013 16:55:41 +1000
Hi I have a new set of patches for wsmouse button remapping.
These implement wsconsctl button remapping commands.
Usage:
wsconsctl -f /dev/wsmouse0 -m -w buttonmap=1,0
To reverse buttons for left handed people.
wsconctl -d /dev/wsmouse0 -m -w buttonmap=0,0,0
To make all buttons a left click.
wsconsctl -d /dev/wsmouse0 -m -w buttonmap=0,-1,-1
To disable right and middle buttons.
Index: sys/dev/wscons/wsconsio.h
===================================================================
RCS file: /cvsroot/src/sys/dev/wscons/wsconsio.h,v
retrieving revision 1.108
diff -u -r1.108 wsconsio.h
--- sys/dev/wscons/wsconsio.h 29 Apr 2013 13:39:47 -0000 1.108
+++ sys/dev/wscons/wsconsio.h 15 Sep 2013 07:11:51 -0000
@@ -268,6 +268,10 @@
#define WSMOUSEIO_SETVERSION _IOW('W', 41, int)
#define WSMOUSE_EVENT_VERSION WSEVENT_VERSION
+#define NBUTTONS (int)(sizeof(u_int) * 8)
+#define WSMOUSEIO_GETMAPBUTTONS _IOR('W', 43, int[NBUTTONS])
+#define WSMOUSEIO_SETMAPBUTTONS _IOW('W', 44, int[NBUTTONS])
+
/*
* Display ioctls (64 - 95)
*/
Index: sys/dev/wscons/wsmouse.c
===================================================================
RCS file: /cvsroot/src/sys/dev/wscons/wsmouse.c,v
retrieving revision 1.64
diff -u -r1.64 wsmouse.c
--- sys/dev/wscons/wsmouse.c 11 Sep 2011 22:28:21 -0000 1.64
+++ sys/dev/wscons/wsmouse.c 15 Sep 2013 07:13:39 -0000
@@ -162,6 +162,8 @@
int sc_z; /* absolute-z */
int sc_w; /* absolute-w */
+ int sc_buttonMap[NBUTTONS]; /* button mappings */
+
int sc_refcnt;
u_char sc_dying; /* device is being detached */
@@ -192,6 +194,7 @@
wsmouse_match, wsmouse_attach, wsmouse_detach, wsmouse_activate);
static void wsmouse_repeat(void *v);
+static int buttonRemap(struct wsmouse_softc *, int);
extern struct cfdriver wsmouse_cd;
@@ -237,6 +240,7 @@
{
struct wsmouse_softc *sc = device_private(self);
struct wsmousedev_attach_args *ap = aux;
+ int i;
#if NWSMUX > 0
int mux, error;
#endif
@@ -272,6 +276,11 @@
if (!pmf_device_register(self, NULL, NULL))
aprint_error_dev(self, "couldn't establish power handler\n");
+
+ /* Initialize button mappings 1:1 */
+ for (i = 0; i < NBUTTONS; i++)
+ sc->sc_buttonMap[i] = i;
+
}
int
@@ -339,6 +348,23 @@
return (0);
}
+static int
+buttonRemap(struct wsmouse_softc *sc, int buttons)
+{
+ int buttonState, mappedButtons, i;
+
+ buttonState = buttons;
+ mappedButtons = 0;
+
+ for (i = 0; i < NBUTTONS; i++) {
+ if ((buttonState & 1) && (sc->sc_buttonMap[i] >= 0))
+ mappedButtons |= 1 << sc->sc_buttonMap[i];
+ buttonState >>= 1;
+ }
+
+ return mappedButtons;
+}
+
void
wsmouse_input(device_t wsmousedev, u_int btns /* 0 is up */,
int x, int y, int z, int w, u_int flags)
@@ -369,7 +395,7 @@
sc->sc_base.me_parent, evar));
#endif
- sc->sc_mb = btns;
+ sc->sc_mb = buttonRemap(sc, btns);
if (!(flags & WSMOUSE_INPUT_ABSOLUTE_X))
sc->sc_dx += x;
if (!(flags & WSMOUSE_INPUT_ABSOLUTE_Y))
@@ -687,8 +713,9 @@
wsmouse_do_ioctl(struct wsmouse_softc *sc, u_long cmd, void *data,
int flag, struct lwp *l)
{
- int error;
+ int error, i;
struct wsmouse_repeat *wr;
+ int tmpButtonMap[NBUTTONS];
if (sc->sc_dying)
return (EIO);
@@ -751,6 +778,25 @@
return 0;
+ case WSMOUSEIO_GETMAPBUTTONS:
+ memcpy(data, &sc->sc_buttonMap, sizeof(sc->sc_buttonMap));
+ return 0;
+
+ case WSMOUSEIO_SETMAPBUTTONS:
+ if ((flag & FWRITE) == 0)
+ return EACCES;
+
+ /* Verify button mappings. */
+ memcpy(&tmpButtonMap, data, sizeof(tmpButtonMap));
+ for (i = 0; i < NBUTTONS; i++) {
+ if (tmpButtonMap[i] < -1 || tmpButtonMap[i] >= NBUTTONS)
+ return EINVAL;
+
+ }
+
+ memcpy(&sc->sc_buttonMap, data, sizeof(sc->sc_buttonMap));
+ return 0;
+
case WSMOUSEIO_SETVERSION:
return wsevent_setversion(sc->sc_base.me_evp, *(int *)data);
}
Index: sbin/wsconsctl/mouse.c
===================================================================
RCS file: /cvsroot/src/sbin/wsconsctl/mouse.c,v
retrieving revision 1.10
diff -u -r1.10 mouse.c
--- sbin/wsconsctl/mouse.c 24 Dec 2012 01:29:20 -0000 1.10
+++ sbin/wsconsctl/mouse.c 15 Sep 2013 07:13:58 -0000
@@ -47,6 +47,7 @@
static int samplerate;
static struct wsmouse_calibcoords calibration;
static char *calibration_samples;
+static char *buttonMapString;
static struct wsmouse_repeat repeat;
static void mouse_get_calibration(int);
@@ -55,6 +56,9 @@
static void mouse_get_repeat(int);
static void mouse_put_repeat(int);
+static void mouse_get_button_map(int);
+static void mouse_put_button_map(int);
+
struct field mouse_field_tab[] = {
{ "resolution", &resolution, FMT_UINT, FLG_WRONLY },
{ "samplerate", &samplerate, FMT_UINT, FLG_WRONLY },
@@ -77,6 +81,8 @@
FMT_UINT, FLG_MODIFY },
{ "repeat.delay.minimum", &repeat.wr_delay_minimum,
FMT_UINT, FLG_MODIFY },
+ { "buttonmap", &buttonMapString,
+ FMT_STRING, FLG_MODIFY },
};
int mouse_field_tab_len = sizeof(mouse_field_tab)/
@@ -102,6 +108,9 @@
field_by_value(&repeat.wr_delay_decrement)->flags & FLG_GET ||
field_by_value(&repeat.wr_delay_minimum)->flags & FLG_GET)
mouse_get_repeat(fd);
+
+ if (field_by_value(&buttonMapString)->flags & FLG_GET)
+ mouse_get_button_map(fd);
}
static void
@@ -157,6 +166,34 @@
}
static void
+mouse_get_button_map(int fd)
+{
+ int tmp[NBUTTONS];
+ char *tmpButtonMapString;
+ char buf[5];
+ int i;
+
+ tmpButtonMapString = malloc((4 * NBUTTONS) + 1);
+
+ if (tmpButtonMapString == NULL)
+ err(EXIT_FAILURE, "could not list button mappings");
+ tmpButtonMapString[0] = '\0';
+
+ if (ioctl(fd, WSMOUSEIO_GETMAPBUTTONS, &tmp) < 0) {
+ return;
+ }
+
+ for (i = 0; i < NBUTTONS; i++) {
+ if ( i == NBUTTONS - 1)
+ snprintf(buf, sizeof(buf), "%d", tmp[i]);
+ else
+ snprintf(buf, sizeof(buf), "%d,", tmp[i]);
+ strcat(tmpButtonMapString, buf);
+ }
+ buttonMapString = tmpButtonMapString;
+}
+
+static void
mouse_get_repeat(int fd)
{
struct wsmouse_repeat tmp;
@@ -205,6 +242,9 @@
field_by_value(&repeat.wr_delay_decrement)->flags & FLG_SET ||
field_by_value(&repeat.wr_delay_minimum)->flags & FLG_SET)
mouse_put_repeat(fd);
+
+ if (field_by_value(&buttonMapString)->flags & FLG_SET)
+ mouse_put_button_map(fd);
}
static void
@@ -272,6 +312,41 @@
}
static void
+mouse_put_button_map(int fd)
+{
+ int tmp[NBUTTONS];
+ int i;
+ const char *p;
+ char *q;
+
+ for (i = 0; i < NBUTTONS; i++)
+ tmp[i] = i;
+
+ if (field_by_value(&buttonMapString)->flags & FLG_SET) {
+ p = buttonMapString;
+ for (i = 0; p[0] != '\0' && i < NBUTTONS; i++) {
+ tmp[i] = strtol(p, &q, 0);
+ if (*q != ',') {
+ p = q;
+ break;
+ }
+ p = q + 1;
+ }
+ if (p[0] != '\0')
+ errx(EXIT_FAILURE, "%s: invalid button mappings",
+ buttonMapString);
+ }
+
+ /* Set new values for button mappings. */
+ if (ioctl(fd, WSMOUSEIO_SETMAPBUTTONS, &tmp) < 0)
+ err(EXIT_FAILURE, "WSMOUSEIO_SETMAPBUTTONS");
+
+ /* Now print what changed. */
+ if (field_by_value(&buttonMapString)->flags & FLG_SET)
+ pr_field(field_by_value(&buttonMapString), " -> ");
+}
+
+static void
mouse_put_repeat(int fd)
{
struct wsmouse_repeat tmp;
Regards,
Nat.
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.