On Tue, Jul 20, 2010 at 9:01 PM, Ping Cheng <[email protected]> wrote:
> 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.

It might be easier for you to amend the patch directly. Basically, we
can use "ctrl + mouse button 4/5" for zooming. So, it would be
something like the following:

       button = (dist > 0) ? SCROLL_UP : SCROLL_DOWN;
......

       wcmEmitKeycode (priv->local->dev, 37 /*XK_Control_L*/, 1);
       while (count--)
       {
             xf86WcmSendButtonClick(priv, button, 1);
             xf86WcmSendButtonClick(priv, button, 0);
       }
       wcmEmitKeycode (priv->local->dev, 37 /*XK_Control_L*/, 0);


This ugly gesture code will stay until the proper solution comes along....

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