diff options
author | Mihail Konev <k.mvc@ya.ru> | 2017-01-04 07:08:51 +0500 |
---|---|---|
committer | Peter Hutterer <peter.hutterer@who-t.net> | 2017-01-04 13:23:31 +1000 |
commit | 9d32b71c93cf6187e9320c99ae857e34a51b7102 (patch) | |
tree | 004ab764b8afe1b9b3849d0ef1892518e02f5f01 | |
parent | 29a4f3db60fdeaef7bca3aa2746bb43a1850fddd (diff) |
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 <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@gmail.com>
Signed-off-by: Mihail Konev <k.mvc@ya.ru>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r-- | include/xkbsrv.h | 2 | ||||
-rw-r--r-- | xkb/xkbInit.c | 9 | ||||
-rw-r--r-- | 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; |