From 9d32b71c93cf6187e9320c99ae857e34a51b7102 Mon Sep 17 00:00:00 2001 From: Mihail Konev Date: Wed, 4 Jan 2017 07:08:51 +0500 Subject: [PATCH] xkb: Match key releases with an overlaid press 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 { [ Overlay1_Enable ] }; key { overlay1 = }; // Insert+1 => 2 key { overlay1 = }; // 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 Signed-off-by: Mihail Konev Reviewed-by: Peter Hutterer Signed-off-by: Peter Hutterer --- 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 6e4ad44d4..2870f3987 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 9c772f549..46016aba5 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 f7a6b4b14..d2c7e33f4 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;