[PATCH v7 xserver] xkb: Match key releases with an overlaid press

Peter Hutterer peter.hutterer at who-t.net
Wed Jan 4 03:25:26 UTC 2017


On Wed, Jan 04, 2017 at 07:08:51AM +0500, Mihail Konev wrote:
> Testcase:
> 
> In ~/.xbindkeysrc:
>   "xterm &"
>        XF86LaunchA
> 
> In ~/ov.xkb:
>   xkb_keymap {
>       xkb_keycodes { include "evdev" };
>       xkb_types    { include "complete" };
>       xkb_compat   { include "complete"
>           interpret Overlay1_Enable+AnyOfOrNone(all) {
>               action= SetControls(controls=Overlay1);
>           };
>       };
>       xkb_symbols  { include "pc+inet(evdev)+us"
>           key <INS> { [ Overlay1_Enable ] };
>           key <AE01> { overlay1 = <AE02> }; // Insert+1 => 2
>           key <TLDE> { overlay1 = <I128> }; // Insert+~ => XF86LaunchA
>       };
>       xkb_geometry { include "pc(pc104)" };
>   };
> 
> Apply this layout: 'xkbcomp ~/ov.xkb $DISPLAY'.
> Run "xbindkeys -n -v"
> In the exact order:
> - press Insert
> - press Tilde
> - release Insert
> - wait
> - release Tilde
> Keyboard input in the new terminal window(s) would be locked
> until another Insert+Tilde .
> 
> Reported-by: Mariusz Mazur <mariusz.g.mazur at gmail.com>
> Signed-off-by: Mihail Konev <k.mvc at ya.ru>

Thanks!

   29a4f3d..9d32b71  master -> master

Cheers,
   Peter

> ---
>  include/xkbsrv.h |  2 ++
>  xkb/xkbInit.c    |  9 +++++++++
>  xkb/xkbPrKeyEv.c | 29 +++++++++++++++++++++--------
>  3 files changed, 32 insertions(+), 8 deletions(-)
> 
> diff --git a/include/xkbsrv.h b/include/xkbsrv.h
> index 6e4ad44d49f9..2870f3987f66 100644
> --- a/include/xkbsrv.h
> +++ b/include/xkbsrv.h
> @@ -195,6 +195,8 @@ typedef struct _XkbSrvInfo {
>      XkbFilterPtr filters;
>  
>      XkbSrvCheckRepeatPtr checkRepeat;
> +
> +    char overlay_perkey_state[256/8]; /* bitfield */
>  } XkbSrvInfoRec, *XkbSrvInfoPtr;
>  
>  #define	XkbSLI_IsDefault	(1L<<0)
> diff --git a/xkb/xkbInit.c b/xkb/xkbInit.c
> index 9c772f549be0..46016aba5553 100644
> --- a/xkb/xkbInit.c
> +++ b/xkb/xkbInit.c
> @@ -505,6 +505,13 @@ XkbInitControls(DeviceIntPtr pXDev, XkbSrvInfoPtr xkbi)
>      return Success;
>  }
>  
> +static Status
> +XkbInitOverlayState(XkbSrvInfoPtr xkbi)
> +{
> +    memset(xkbi->overlay_perkey_state, 0, sizeof(xkbi->overlay_perkey_state));
> +    return Success;
> +}
> +
>  static Bool
>  InitKeyboardDeviceStructInternal(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
>                                   const char *keymap, int keymap_length,
> @@ -608,6 +615,8 @@ InitKeyboardDeviceStructInternal(DeviceIntPtr dev, XkbRMLVOSet * rmlvo,
>  
>      XkbInitIndicatorMap(xkbi);
>  
> +    XkbInitOverlayState(xkbi);
> +
>      XkbUpdateActions(dev, xkb->min_key_code, XkbNumKeys(xkb), &changes,
>                       &check, &cause);
>  
> diff --git a/xkb/xkbPrKeyEv.c b/xkb/xkbPrKeyEv.c
> index f7a6b4b14306..d2c7e33f4213 100644
> --- a/xkb/xkbPrKeyEv.c
> +++ b/xkb/xkbPrKeyEv.c
> @@ -121,20 +121,33 @@ XkbProcessKeyboardEvent(DeviceEvent *event, DeviceIntPtr keybd)
>          case XkbKB_Overlay2:
>          {
>              unsigned which;
> +            unsigned overlay_active_now;
> +            unsigned is_keyrelease = (event->type == ET_KeyRelease) ? 1 : 0;
> +            /* Remembers whether the key was pressed while overlay was down,
> +             * for when overlay is already released, but the key is not. */
> +            unsigned key_was_overlaid = 0;
>  
>              if (behavior.type == XkbKB_Overlay1)
>                  which = XkbOverlay1Mask;
>              else
>                  which = XkbOverlay2Mask;
> -            if ((xkbi->desc->ctrls->enabled_ctrls & which) == 0)
> -                break;
> -            if ((behavior.data >= xkbi->desc->min_key_code) &&
> -                (behavior.data <= xkbi->desc->max_key_code)) {
> +            overlay_active_now = (xkbi->desc->ctrls->enabled_ctrls & which) ? 1 : 0;
> +
> +            if ((unsigned char)key == key) {
> +                key_was_overlaid = BitIsOn(xkbi->overlay_perkey_state, key);
> +                if (!is_keyrelease) {
> +                    if (overlay_active_now)
> +                        SetBit(xkbi->overlay_perkey_state, key);
> +                } else {
> +                    if (key_was_overlaid)
> +                        ClearBit(xkbi->overlay_perkey_state, key);
> +                }
> +            }
> +
> +            if ((overlay_active_now || key_was_overlaid) &&
> +                    (behavior.data >= xkbi->desc->min_key_code) &&
> +                    (behavior.data <= xkbi->desc->max_key_code)) {
>                  event->detail.key = behavior.data;
> -                /* 9/11/94 (ef) -- XXX! need to match release with */
> -                /*                 press even if the state of the  */
> -                /*                 corresponding overlay control   */
> -                /*                 changes while the key is down   */
>              }
>          }
>              break;
> -- 
> 2.9.2
> 


More information about the xorg-devel mailing list