On Tue, Jul 20, 2010 at 8:48 PM, Peter Hutterer
<[email protected]> wrote:
> This addresses a hang in the driver when buttons are configured to send
> keystrokes. The current code calls XkbGetCoreMap() which allocates during
> the signal handler, causing server hangs.
>
> This patch changes the driver to use keycodes instead of keysyms. There are
> a number of reasons for this:
> - XkbCoreMap() only hands us a core keymap, not the XKB one that everyone
>  uses these days. There are some differences between the core and the XKB
>  map (mainly the use of modifiers), hence we should be focusing on the XKB
>  map anyway.
> - Parsing the XKB map manually in the driver is complicated and not
>  something we want to do, especially when trying to maintain ABI compat
>  with multiple X server versions. On the other hand, the client-side API
>  for XKB is frozen like all of Xlib.
> - The driver is not notified of XKB layout changes, thus a cached map would
>  potentially be out of date. Moving keysym to keycode conversion to the
>  client avoids this.
> - The server does not communicate through keysyms to any client, keycodes
>  are the only information. It is up to the client to pick the keysym (and
>  glyph) based on the keycode.
>
> Note that this changes the property API. Clients that would write straight
> to a button mapping property will need to change. AFAICT, only xsetwacom
> does this at this point and xsetwacom is updated with this patch.
>
> Note that the current xsetwacom implementation will only focus on level 0
> keys. It will not automatically fill in the modifier states. Thus, to get
> e.g. a string of "aBc", the following configuration is required:
>    xsetwacom set "device" "Button1" "key a +shift B -shift c"
>
> xsetwacom releases modifiers at the end of the configuration, thus to get a
> single uppercase letter (or multiple letters), the following is enough:
>    xsetwacom set "device" "Button1" "key shift A"
>
> Note: this breaks Ctrl+/- zoom support for keyboard layouts that have +/- on
> a different key than the 'us' keyboard layout. Did I mention that hacking up
> gestures in the driver is a bad idea?
>
> Signed-off-by: Peter Hutterer <[email protected]>

Acked-by: Ping Cheng <[email protected]>

> ---
>  src/wcmCommon.c      |  103 ++++---------------------------------------------
>  src/wcmTouchFilter.c |   18 ++++++---
>  src/xf86Wacom.h      |    2 +-
>  tools/xsetwacom.c    |   67 +++++++++++++++++++++++++-------
>  4 files changed, 74 insertions(+), 116 deletions(-)
>
> diff --git a/src/wcmCommon.c b/src/wcmCommon.c
> index 2185725..4516cc6 100644
> --- a/src/wcmCommon.c
> +++ b/src/wcmCommon.c
> @@ -318,94 +318,9 @@ static void wcmSendButtons(LocalDevicePtr local, int 
> buttons, int rx, int ry,
>        }
>  }
>
> -/*****************************************************************************
> - * wcmEmitKeysym --
> - *   Emit a keydown/keyup event
> - 
> ****************************************************************************/
> -static int ODDKEYSYM [][2] =
> +void wcmEmitKeycode (DeviceIntPtr keydev, int keycode, int state)
>  {
> -       { XK_asciitilde, XK_grave },
> -       { XK_exclam, XK_1 },
> -       { XK_at, XK_2 },
> -       { XK_numbersign, XK_3 },
> -       { XK_dollar, XK_4 },
> -       { XK_percent, XK_5 },
> -       { XK_asciicircum, XK_6 },
> -       { XK_ampersand, XK_7 },
> -       { XK_asterisk, XK_8 },
> -       { XK_parenleft, XK_9 },
> -       { XK_parenright, XK_0 },
> -       { XK_underscore, XK_minus },
> -       { XK_plus, XK_equal },
> -       { XK_braceleft, XK_bracketleft },
> -       { XK_braceright, XK_bracketright },
> -       { XK_colon, XK_semicolon },
> -       { XK_quotedbl, XK_quoteright },
> -       { XK_less, XK_comma },
> -       { XK_greater, XK_period },
> -       { XK_question, XK_slash },
> -       { XK_bar, XK_backslash },
> -       { 0, 0}
> -};
> -
> -void wcmEmitKeysym (DeviceIntPtr keydev, int keysym, int state)
> -{
> -       int i, j, alt_keysym = 0;
> -
> -       /* Now that we have the keycode look for key index */
> -#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
> -       KeySymsRec *ksr = XkbGetCoreMap(keydev);
> -#else
> -       KeySymsRec *ksr = &keydev->key->curKeySyms;
> -#endif
> -
> -       for (i = ksr->minKeyCode; i <= ksr->maxKeyCode; i++)
> -               if (ksr->map [(i - ksr->minKeyCode) * ksr->mapWidth] == 
> keysym)
> -                       break;
> -
> -       if (i > ksr->maxKeyCode)
> -       {
> -               if (isupper(keysym))
> -                       alt_keysym = tolower(keysym);
> -               else
> -               {
> -                       j = 0;
> -                       while (ODDKEYSYM [j][0])
> -                       {
> -                               if (ODDKEYSYM [j][0] == keysym)
> -                               {
> -                                       alt_keysym = ODDKEYSYM [j][1];
> -                                       break;
> -                               }
> -                               j++;
> -                       }
> -               }
> -               if ( alt_keysym )
> -               {
> -                       for (j = ksr->minKeyCode; j <= ksr->maxKeyCode; j++)
> -                               if (ksr->map [(j - ksr->minKeyCode) * 
> ksr->mapWidth] == XK_Shift_L)
> -                                       break;
> -                       if (state)
> -                               xf86PostKeyboardEvent (keydev, j, 1);
> -                       for (i = ksr->minKeyCode; i <= ksr->maxKeyCode; i++)
> -                               if (ksr->map [(i - ksr->minKeyCode) * 
> ksr->mapWidth] == alt_keysym)
> -                                       break;
> -                       xf86PostKeyboardEvent (keydev, i, state);
> -                       if (!state)
> -                               xf86PostKeyboardEvent (keydev, j, 0);
> -               }
> -               else
> -                       xf86Msg (X_WARNING, "%s: Couldn't find key with code 
> %08x on keyboard device %s\n",
> -                                       keydev->name, keysym, keydev->name);
> -#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
> -               free(ksr);
> -#endif
> -               return;
> -       }
> -       xf86PostKeyboardEvent (keydev, i, state);
> -#if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 7
> -       free(ksr);
> -#endif
> +       xf86PostKeyboardEvent (keydev, keycode, state);
>  }
>
>  static void toggleDisplay(LocalDevicePtr local)
> @@ -512,9 +427,9 @@ static void sendAButton(LocalDevicePtr local, int button, 
> int mask,
>                                break;
>                        case AC_KEY:
>                                {
> -                                       int key_sym = (action & AC_CODE);
> +                                       int key_code = (action & AC_CODE);
>                                        int is_press = (action & 
> AC_KEYBTNPRESS);
> -                                       wcmEmitKeysym(local->dev, key_sym, 
> is_press);
> +                                       wcmEmitKeycode(local->dev, key_code, 
> is_press);
>                                }
>                                break;
>                        case AC_MODETOGGLE:
> @@ -565,15 +480,15 @@ static void sendAButton(LocalDevicePtr local, int 
> button, int mask,
>                                break;
>                        case AC_KEY:
>                                {
> -                                       int key_sym = (action & AC_CODE);
> +                                       int key_code = (action & AC_CODE);
>
>                                        /* don't care about releases here */
>                                        if (!(action & AC_KEYBTNPRESS))
>                                                break;
>
> -                                       if (countPresses(key_sym, 
> &priv->keys[button][i],
> +                                       if (countPresses(key_code, 
> &priv->keys[button][i],
>                                                        
> ARRAY_SIZE(priv->keys[button]) - i))
> -                                               wcmEmitKeysym(local->dev, 
> key_sym, 0);
> +                                               wcmEmitKeycode(local->dev, 
> key_code, 0);
>                                }
>                }
>
> @@ -688,8 +603,8 @@ static void sendWheelStripEvents(LocalDevicePtr local, 
> const WacomDeviceState* d
>            break;
>
>            case AC_KEY:
> -                   wcmEmitKeysym(local->dev, (fakeButton & AC_CODE), 1);
> -                   wcmEmitKeysym(local->dev, (fakeButton & AC_CODE), 0);
> +                   wcmEmitKeycode(local->dev, (fakeButton & AC_CODE), 1);
> +                   wcmEmitKeycode(local->dev, (fakeButton & AC_CODE), 0);
>            break;
>
>            default:
> diff --git a/src/wcmTouchFilter.c b/src/wcmTouchFilter.c
> index 246b33c..7d3f860 100644
> --- a/src/wcmTouchFilter.c
> +++ b/src/wcmTouchFilter.c
> @@ -467,17 +467,23 @@ static void wcmFingerZoom(WacomDevicePtr priv)
>                return;
>        }
>
> -       /* zooming? */
> -       key = (dist > 0) ? XK_plus : XK_minus;
> +       /* zooming?
> +       FIXME: this hardcodes the positions of ctrl, + and - to the ones on
> +       the us keyboard layout. Tough luck. The alternative is to run
> +       through the XKB table and figure out where +/- are hiding. Good
> +       luck.
> +       Gesture support is not supposed to be in the driver...
> +        */
> +       key = (dist > 0) ? 21 /*XK_plus*/ : 20 /*XK_minus*/;

I have a solution for this one :). I'll make a patch soon.

Ping

>        count -= common->wcmGestureParameters.wcmGestureUsed;
>        common->wcmGestureParameters.wcmGestureUsed += count;
>        while (count--)
>        {
> -               wcmEmitKeysym (priv->local->dev, XK_Control_L, 1);
> -               wcmEmitKeysym (priv->local->dev, key, 1);
> -               wcmEmitKeysym (priv->local->dev, key, 0);
> -               wcmEmitKeysym (priv->local->dev, XK_Control_L, 0);
> +               wcmEmitKeycode (priv->local->dev, 37 /*XK_Control_L*/, 1);
> +               wcmEmitKeycode (priv->local->dev, key, 1);
> +               wcmEmitKeycode (priv->local->dev, key, 0);
> +               wcmEmitKeycode (priv->local->dev, 37 /*XK_Control_L*/, 0);
>        }
>  }
>
> diff --git a/src/xf86Wacom.h b/src/xf86Wacom.h
> index 2ec55b6..2067790 100644
> --- a/src/xf86Wacom.h
> +++ b/src/xf86Wacom.h
> @@ -161,7 +161,7 @@ extern int wcmDevSwitchMode(ClientPtr client, 
> DeviceIntPtr dev, int mode);
>  extern void wcmChangeScreen(LocalDevicePtr local, int value);
>  extern void wcmTilt2R(WacomDeviceStatePtr ds);
>  extern void wcmGestureFilter(WacomDevicePtr priv, int channel);
> -extern void wcmEmitKeysym(DeviceIntPtr keydev, int keysym, int state);
> +extern void wcmEmitKeycode(DeviceIntPtr keydev, int keycode, int state);
>  extern void wcmSoftOutEvent(LocalDevicePtr local);
>
>  extern void wcmRotateTablet(LocalDevicePtr local, int value);
> diff --git a/tools/xsetwacom.c b/tools/xsetwacom.c
> index 59f1270..23136af 100644
> --- a/tools/xsetwacom.c
> +++ b/tools/xsetwacom.c
> @@ -34,6 +34,7 @@
>  #include <X11/Xlib.h>
>  #include <X11/Xatom.h>
>  #include <X11/extensions/XInput.h>
> +#include <X11/XKBlib.h>
>
>  #define TRACE(...) \
>        if (verbose) fprintf(stderr, "... " __VA_ARGS__)
> @@ -1197,16 +1198,16 @@ static int is_modifier(const char* modifier)
>        return 0;
>  }
>
> -static int special_map_keystrokes(int argc, char **argv, unsigned long 
> *ndata, unsigned long* data);
> -static int special_map_button(int argc, char **argv, unsigned long *ndata, 
> unsigned long* data);
> -static int special_map_core(int argc, char **argv, unsigned long *ndata, 
> unsigned long *data);
> -static int special_map_modetoggle(int argc, char **argv, unsigned long 
> *ndata, unsigned long *data);
> -static int special_map_displaytoggle(int argc, char **argv, unsigned long 
> *ndata, unsigned long *data);
> +static int special_map_keystrokes(Display *dpy, int argc, char **argv, 
> unsigned long *ndata, unsigned long* data);
> +static int special_map_button(Display *dpy, int argc, char **argv, unsigned 
> long *ndata, unsigned long* data);
> +static int special_map_core(Display *dpy, int argc, char **argv, unsigned 
> long *ndata, unsigned long *data);
> +static int special_map_modetoggle(Display *dpy, int argc, char **argv, 
> unsigned long *ndata, unsigned long *data);
> +static int special_map_displaytoggle(Display *dpy, int argc, char **argv, 
> unsigned long *ndata, unsigned long *data);
>
>  /* Valid keywords for the --set ButtonX options */
>  struct keywords {
>        const char *keyword;
> -       int (*func)(int, char **, unsigned long*, unsigned long *);
> +       int (*func)(Display*, int, char **, unsigned long*, unsigned long *);
>  } keywords[] = {
>        {"key", special_map_keystrokes},
>        {"button", special_map_button},
> @@ -1218,7 +1219,7 @@ struct keywords {
>
>  /* the "core" keyword isn't supported anymore, we just have this here to
>    tell people that. */
> -static int special_map_core(int argc, char **argv, unsigned long *ndata, 
> unsigned long *data)
> +static int special_map_core(Display *dpy, int argc, char **argv, unsigned 
> long *ndata, unsigned long *data)
>  {
>        static int once_only = 1;
>        if (once_only)
> @@ -1230,7 +1231,7 @@ static int special_map_core(int argc, char **argv, 
> unsigned long *ndata, unsigne
>        return 0;
>  }
>
> -static int special_map_modetoggle(int argc, char **argv, unsigned long 
> *ndata, unsigned long *data)
> +static int special_map_modetoggle(Display *dpy, int argc, char **argv, 
> unsigned long *ndata, unsigned long *data)
>  {
>        data[*ndata] = AC_MODETOGGLE;
>
> @@ -1239,7 +1240,7 @@ static int special_map_modetoggle(int argc, char 
> **argv, unsigned long *ndata, u
>        return 0;
>  }
>
> -static int special_map_displaytoggle(int argc, char **argv, unsigned long 
> *ndata, unsigned long *data)
> +static int special_map_displaytoggle(Display *dpy, int argc, char **argv, 
> unsigned long *ndata, unsigned long *data)
>  {
>        data[*ndata] = AC_DISPLAYTOGGLE;
>
> @@ -1261,7 +1262,7 @@ static inline int is_valid_keyword(const char *keyword)
>        return 0;
>  }
>
> -static int special_map_button(int argc, char **argv, unsigned long *ndata, 
> unsigned long *data)
> +static int special_map_button(Display *dpy, int argc, char **argv, unsigned 
> long *ndata, unsigned long *data)
>  {
>        int nitems = 0;
>        int i;
> @@ -1306,11 +1307,44 @@ static int special_map_button(int argc, char **argv, 
> unsigned long *ndata, unsig
>        return nitems;
>  }
>
> +/* Return the first keycode to have the required keysym in the current group.
> +   TODOs:
> +   - parse other groups as well (do we need this?)
> +   - for keysyms not on level 0, return the keycodes for the modifiers as
> +     well
> +*/
> +static int keysym_to_keycode(Display *dpy, KeySym sym)
> +{
> +       static XkbDescPtr xkb = NULL;
> +       XkbStateRec state;
> +       int group;
> +       int kc = 0;
> +
> +
> +       if (!xkb)
> +               xkb = XkbGetKeyboard(dpy, XkbAllComponentsMask, 
> XkbUseCoreKbd);
> +       XkbGetState(dpy, XkbUseCoreKbd, &state);
> +       group = state.group;
> +
> +       for (kc = xkb->min_key_code; kc <= xkb->max_key_code; kc++)
> +       {
> +               KeySym* ks;
> +               int i;
> +
> +               ks = XkbKeySymsPtr(xkb, kc);
> +               for (i = 0; i < XkbKeyGroupWidth(xkb, kc, state.group); i++)
> +                       if (ks[i] == sym)
> +                               goto out;
> +       }
> +
> +out:
> +       return kc;
> +}
>  /*
>    Map gibberish like "ctrl alt f2" into the matching AC_KEY values.
>    Returns 1 on success or 0 otherwise.
>  */
> -static int special_map_keystrokes(int argc, char **argv, unsigned long 
> *ndata, unsigned long* data)
> +static int special_map_keystrokes(Display *dpy, int argc, char **argv, 
> unsigned long *ndata, unsigned long* data)
>  {
>        int i;
>        int nitems = 0;
> @@ -1318,6 +1352,7 @@ static int special_map_keystrokes(int argc, char 
> **argv, unsigned long *ndata, u
>        for (i = 0; i < argc; i++)
>        {
>                KeySym ks;
> +               KeyCode kc;
>                int need_press = 0, need_release = 0;
>                char *key = argv[i];
>
> @@ -1358,12 +1393,14 @@ static int special_map_keystrokes(int argc, char 
> **argv, unsigned long *ndata, u
>                        need_press = need_release = 1;
>
>                ks = XStringToKeysym(key);
> +               kc = keysym_to_keycode(dpy, ks);
> +
>                if (need_press)
> -                       data[*ndata + nitems++] = AC_KEY | AC_KEYBTNPRESS | 
> ks;
> +                       data[*ndata + nitems++] = AC_KEY | AC_KEYBTNPRESS | 
> kc;
>                if (need_release)
> -                       data[*ndata + nitems++] = AC_KEY | ks;
> +                       data[*ndata + nitems++] = AC_KEY | kc;
>
> -               TRACE("Key map %ld ('%s') [%s,%s]\n", ks,
> +               TRACE("Key map %ld (%d, '%s') [%s,%s]\n", ks, kc,
>                                XKeysymToString(ks),
>                                need_press ?  "press" : "",
>                                need_release ?  "release" : "");
> @@ -1481,7 +1518,7 @@ static void special_map_buttons(Display *dpy, XDevice 
> *dev, param_t* param, int
>                        int parsed = 0;
>                        if (strcasecmp(words[i], keywords[j].keyword) == 0)
>                        {
> -                               parsed = keywords[j].func(nwords - i - 1,
> +                               parsed = keywords[j].func(dpy, nwords - i - 1,
>                                                          &words[i + 1],
>                                                          &nitems, data);
>                                i += parsed;
> --
> 1.7.1
>

------------------------------------------------------------------------------
This SF.net email is sponsored by Sprint
What will you do first with EVO, the first 4G phone?
Visit sprint.com/first -- http://p.sf.net/sfu/sprint-com-first
_______________________________________________
Linuxwacom-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to