NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/46394: wsmouse - button remapping.



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



Home | Main Index | Thread Index | Old Index