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.

NetBSD Home
NetBSD PR Database Search

(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.