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;