From bfb219f532f3c78ba905424365ee7c5f7b5f21a2 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Fri, 21 Aug 2009 16:03:36 +1000 Subject: [PATCH] input: allow for detectable autorepeat. For core and XI1 events, store the key_repeat flag in the sequence number until TryClientEvents. The sequenceNumber is unset until TryClientEvents. [Also thrown in, some random indentation changes. Thanks] Signed-off-by: Peter Hutterer --- Xi/exevents.c | 3 +- dix/eventconvert.c | 7 ++ dix/events.c | 53 +++++++++++-- include/eventstr.h | 1 + include/xkbsrv.h | 4 +- xkb/xkbAccessX.c | 11 +-- xkb/xkbEvents.c | 190 +++++++++++++++++---------------------------- xkb/xkbPrKeyEv.c | 67 ++++++---------- 8 files changed, 155 insertions(+), 181 deletions(-) diff --git a/Xi/exevents.c b/Xi/exevents.c index 7f77aa872..0211e72b7 100644 --- a/Xi/exevents.c +++ b/Xi/exevents.c @@ -814,7 +814,8 @@ UpdateDeviceState(DeviceIntPtr device, DeviceEvent* event) return DONT_PROCESS; kptr = &k->down[key >> 3]; - if (*kptr & bit) /* don't allow ddx to generate multiple downs */ + /* don't allow ddx to generate multiple downs, but repeats are okay */ + if ((*kptr & bit) && !event->key_repeat) return DONT_PROCESS; if (device->valuator) device->valuator->motionHintWindow = NullWindow; diff --git a/dix/eventconvert.c b/dix/eventconvert.c index 07a8e5fb9..69d2f1fec 100644 --- a/dix/eventconvert.c +++ b/dix/eventconvert.c @@ -90,6 +90,8 @@ EventToCore(InternalEvent *event, xEvent *core) core->u.keyButtonPointer.rootX = e->root_x; core->u.keyButtonPointer.rootY = e->root_y; core->u.keyButtonPointer.state = e->corestate; + if (e->type == ET_KeyPress && e->key_repeat) + core->u.u.sequenceNumber = 1; } break; case ET_ProximityIn: @@ -237,6 +239,8 @@ eventToKeyButtonPointer(DeviceEvent *ev, xEvent **xi, int *count) kbp->root_y = ev->root_y; kbp->deviceid = ev->deviceid; kbp->state = ev->corestate; + if (ev->type == ET_KeyPress && ev->key_repeat) + kbp->sequenceNumber = 1; if (num_events > 1) kbp->deviceid |= MORE_EVENTS; @@ -528,6 +532,9 @@ eventToDeviceEvent(DeviceEvent *ev, xEvent **xi) xde->root_x = FP1616(ev->root_x, ev->root_x_frac); xde->root_y = FP1616(ev->root_y, ev->root_y_frac); + if (ev->key_repeat) + xde->flags |= XIKeyRepeat; + xde->mods.base_mods = ev->mods.base; xde->mods.latched_mods = ev->mods.latched; xde->mods.locked_mods = ev->mods.locked; diff --git a/dix/events.c b/dix/events.c index acc1803ef..62eb6c225 100644 --- a/dix/events.c +++ b/dix/events.c @@ -1941,12 +1941,53 @@ TryClientEvents (ClientPtr client, DeviceIntPtr dev, xEvent *pEvents, pEvents->u.u.detail = NotifyNormal; } } - else + else if (type == DeviceMotionNotify) { - if ((type == DeviceMotionNotify) && - MaybeSendDeviceMotionNotifyHint - ((deviceKeyButtonPointer*)pEvents, mask) != 0) + if (MaybeSendDeviceMotionNotifyHint((deviceKeyButtonPointer*)pEvents, + mask) != 0) return 1; + } else if (type == KeyPress) + { + /* sequenceNumber == 1 if autorepeat is set */ + if (pEvents->u.u.sequenceNumber) + { + if (!_XkbWantsDetectableAutoRepeat(client)) + { + xEvent release = *pEvents; + release.u.u.type = KeyRelease; + release.u.u.sequenceNumber = client->sequence; + WriteEventsToClient(client, 1, &release); +#ifdef DEBUG_EVENTS + ErrorF(" (plus fake core release for repeat)"); +#endif + } else + { +#ifdef DEBUG_EVENTS + ErrorF(" (detectable autorepeat for core)"); +#endif + } + } + + } else if (type == DeviceKeyPress) + { + if (((deviceKeyButtonPointer *)pEvents)->sequenceNumber) + { + if (!_XkbWantsDetectableAutoRepeat(client)) + { + deviceKeyButtonPointer release = *(deviceKeyButtonPointer *)pEvents; + release.type = DeviceKeyRelease; + release.sequenceNumber = client->sequence; +#ifdef DEBUG_EVENTS + ErrorF(" (plus fake xi1 release for repeat)"); +#endif + WriteEventsToClient(client, 1, (xEvent *) &release); + } + else { +#ifdef DEBUG_EVENTS + ErrorF(" (detectable autorepeat for core)"); +#endif + } + } } type &= 0177; @@ -5622,8 +5663,8 @@ WriteEventsToClient(ClientPtr pClient, int count, xEvent *events) int i, eventlength = sizeof(xEvent); - if (!XkbFilterEvents(pClient, count, events)) - return; + /* Let XKB rewrite the state, as it depends on client preferences. */ + XkbFilterEvents(pClient, count, events); #ifdef PANORAMIX if(!noPanoramiXExtension && diff --git a/include/eventstr.h b/include/eventstr.h index 8dd98be5f..f082db34a 100644 --- a/include/eventstr.h +++ b/include/eventstr.h @@ -117,6 +117,7 @@ struct _DeviceEvent } group; Window root; /**< Root window of the event */ int corestate; /**< Core key/button state BEFORE the event */ + int key_repeat; /**< Internally-generated key repeat event */ }; diff --git a/include/xkbsrv.h b/include/xkbsrv.h index cdca8f157..2c7d86aaa 100644 --- a/include/xkbsrv.h +++ b/include/xkbsrv.h @@ -297,8 +297,6 @@ extern _X_EXPORT int XkbKeyboardErrorCode; extern _X_EXPORT char * XkbBaseDirectory; extern _X_EXPORT char * XkbBinDirectory; -extern _X_EXPORT pointer XkbLastRepeatEvent; - extern _X_EXPORT CARD32 xkbDebugFlags; #define _XkbTypedAlloc(t) ((t *)xalloc(sizeof(t))) @@ -942,7 +940,7 @@ extern Bool XkbCopyDeviceKeymap( DeviceIntPtr /* dst */, DeviceIntPtr /* src */); -extern Bool XkbFilterEvents( +extern void XkbFilterEvents( ClientPtr /* pClient */, int /* nEvents */, xEvent* /* xE */); diff --git a/xkb/xkbAccessX.c b/xkb/xkbAccessX.c index 7df8e06cf..47023c048 100644 --- a/xkb/xkbAccessX.c +++ b/xkb/xkbAccessX.c @@ -44,7 +44,6 @@ THE USE OR PERFORMANCE OF THIS SOFTWARE. int XkbDfltRepeatDelay= 660; int XkbDfltRepeatInterval= 40; -pointer XkbLastRepeatEvent= NULL; #define DFLT_TIMEOUT_CTRLS (XkbAX_KRGMask|XkbStickyKeysMask|XkbMouseKeysMask) #define DFLT_TIMEOUT_OPTS (XkbAX_IndicatorFBMask) @@ -131,18 +130,15 @@ AccessXKeyboardEvent(DeviceIntPtr keybd, event.detail.key = keyCode; event.time = GetTimeInMillis(); event.length = sizeof(DeviceEvent); + event.key_repeat = isRepeat; if (xkbDebugFlags&0x8) { DebugF("[xkb] AXKE: Key %d %s\n", keyCode, (event.type == ET_KeyPress ? "down" : "up")); } - if (!_XkbIsPressEvent(type) && isRepeat) - XkbLastRepeatEvent= (pointer)&event; XkbProcessKeyboardEvent(&event, keybd); - XkbLastRepeatEvent= NULL; return; - } /* AccessXKeyboardEvent */ /************************************************************************/ @@ -309,14 +305,11 @@ AccessXRepeatKeyExpire(OsTimerPtr timer,CARD32 now,pointer arg) { DeviceIntPtr dev = (DeviceIntPtr) arg; XkbSrvInfoPtr xkbi = dev->key->xkbInfo; -KeyCode key; if (xkbi->repeatKey == 0) return 0; - key = xkbi->repeatKey; - AccessXKeyboardEvent(dev, ET_KeyRelease, key, True); - AccessXKeyboardEvent(dev, ET_KeyPress, key, True); + AccessXKeyboardEvent(dev, ET_KeyPress, xkbi->repeatKey, True); return xkbi->desc->ctrls->repeat_interval; } diff --git a/xkb/xkbEvents.c b/xkb/xkbEvents.c index e56694dbf..8fb49c1d8 100644 --- a/xkb/xkbEvents.c +++ b/xkb/xkbEvents.c @@ -914,145 +914,99 @@ XkbSrvLedInfoPtr sli; /***====================================================================***/ -Bool -XkbFilterEvents(ClientPtr pClient,int nEvents,xEvent *xE) +void +XkbFilterEvents(ClientPtr client,int nEvents,xEvent *xE) { -int i, button_mask; -DeviceIntPtr pXDev = NULL; -XkbSrvInfoPtr xkbi; + DeviceIntPtr dev = NULL; + XkbSrvInfoPtr xkbi; + CARD8 type = xE[0].u.u.type; if (xE->u.u.type & EXTENSION_EVENT_BASE) - pXDev = XIGetDevice(xE); + dev = XIGetDevice(xE); - if (!pXDev) - pXDev = PickKeyboard(pClient); + if (!dev) + dev = PickKeyboard(client); - xkbi= (pXDev->key) ? pXDev->key->xkbInfo : NULL; + if (!dev->key) + return; - if ( pClient->xkbClientFlags & _XkbClientInitialized ) { + xkbi = dev->key->xkbInfo; + + if (client->xkbClientFlags & _XkbClientInitialized) { if ((xkbDebugFlags&0x10)&& - ((xE[0].u.u.type==KeyPress)||(xE[0].u.u.type==KeyRelease)|| - (xE[0].u.u.type==DeviceKeyPress)|| - (xE[0].u.u.type == DeviceKeyRelease))) { - DebugF("[xkb] XKbFilterWriteEvents:\n"); - DebugF("[xkb] Event state= 0x%04x\n",xE[0].u.keyButtonPointer.state); - DebugF("[xkb] XkbLastRepeatEvent!=xE (0x%p!=0x%p) %s\n", - XkbLastRepeatEvent,xE, - ((XkbLastRepeatEvent!=(pointer)xE)?"True":"False")); - DebugF("[xkb] (xkbClientEventsFlags&XWDA)==0 (0x%x) %s\n", - pClient->xkbClientFlags, - (_XkbWantsDetectableAutoRepeat(pClient)?"True":"False")); - DebugF("[xkb] !IsRelease(%d) %s\n",xE[0].u.u.type, - (!_XkbIsReleaseEvent(xE[0].u.u.type))?"True":"False"); - } - if ( (XkbLastRepeatEvent==(pointer)xE) && - (_XkbWantsDetectableAutoRepeat(pClient)) && - (_XkbIsReleaseEvent(xE[0].u.u.type)) ) { - return False; - } + (type == KeyPress || type == KeyRelease || + type == DeviceKeyPress || type == DeviceKeyRelease)) + DebugF("[xkb] XkbFilterWriteEvents (XKB client): state 0x%04x\n", + xE[0].u.keyButtonPointer.state); - if (!xkbi) - return True; + if (dev->deviceGrab.grab != NullGrab && dev->deviceGrab.fromPassiveGrab && + (type == KeyPress || type == KeyRelease || + type == DeviceKeyPress || type == DeviceKeyRelease)) { + unsigned int state, flags; - if ((pXDev->deviceGrab.grab != NullGrab) - && pXDev->deviceGrab.fromPassiveGrab && - ((xE[0].u.u.type==KeyPress)||(xE[0].u.u.type==KeyRelease)|| - (xE[0].u.u.type==DeviceKeyPress)|| - (xE[0].u.u.type == DeviceKeyRelease))) { - register unsigned state,flags; - - flags= pClient->xkbClientFlags; - state= xkbi->state.compat_grab_mods; + flags = client->xkbClientFlags; + state = xkbi->state.compat_grab_mods; if (flags & XkbPCF_GrabsUseXKBStateMask) { int group; - if (flags&XkbPCF_LookupStateWhenGrabbed) { - group= xkbi->state.group; - state= xkbi->state.lookup_mods; + if (flags & XkbPCF_LookupStateWhenGrabbed) { + group = xkbi->state.group; + state = xkbi->state.lookup_mods; } else { - state= xkbi->state.grab_mods; - group= xkbi->state.base_group+xkbi->state.latched_group; - if ((group<0)||(group>=xkbi->desc->ctrls->num_groups)) { - group= XkbAdjustGroup(group,xkbi->desc->ctrls); - } + state = xkbi->state.grab_mods; + group = xkbi->state.base_group + xkbi->state.latched_group; + if (group < 0 || group >= xkbi->desc->ctrls->num_groups) + group = XkbAdjustGroup(group, xkbi->desc->ctrls); } state = XkbBuildCoreState(state, group); } - else if (flags&XkbPCF_LookupStateWhenGrabbed) - state= xkbi->state.compat_lookup_mods; - xE[0].u.keyButtonPointer.state= state; + else if (flags & XkbPCF_LookupStateWhenGrabbed) { + state = xkbi->state.compat_lookup_mods; + } + xE[0].u.keyButtonPointer.state = state; } - button_mask = 1 << xE[0].u.u.detail; - if (xE[0].u.u.type == ButtonPress && - ((xE[0].u.keyButtonPointer.state >> 7) & button_mask) == button_mask && - (xkbi->lockedPtrButtons & button_mask) == button_mask) { - /* If the MouseKeys is pressed, and the "real" mouse is also pressed - * when the mouse is released, the server does not behave properly. - * Faking a release of the button here solves the problem. - */ - DebugF("[xkb] Faking release of button %d\n", xE[0].u.u.detail); - XkbDDXFakeDeviceButton(xkbi->device, 0, xE[0].u.u.detail); - } } else { - register CARD8 type; - - if (!xkbi) - return True; - - for (i=0;istate.lookup_mods, - xkbi->state.grab_mods); - DebugF("[xkb] compat lookup= 0x%02x, grab= 0x%02x\n", - xkbi->state.compat_lookup_mods, - xkbi->state.compat_grab_mods); - } - if ( (type>=KeyPress)&&(type<=MotionNotify) ) { - CARD16 old,new; - - old= xE[i].u.keyButtonPointer.state&(~0x1f00); - new= xE[i].u.keyButtonPointer.state&0x1F00; - - if (old==XkbStateFieldFromRec(&xkbi->state)) - new|= xkbi->state.compat_lookup_mods; - else new|= xkbi->state.compat_grab_mods; - xE[i].u.keyButtonPointer.state= new; - } - else if ((type==EnterNotify)||(type==LeaveNotify)) { - xE[i].u.enterLeave.state&= 0x1F00; - xE[i].u.enterLeave.state|= xkbi->state.compat_grab_mods; - } else if ((type>=DeviceKeyPress)&&(type<=DeviceMotionNotify)) { - CARD16 old, new; - deviceKeyButtonPointer *kbp = (deviceKeyButtonPointer*)&xE[i]; - old= kbp->state&(~0x1F00); - new= kbp->state&0x1F00; - if (old==XkbStateFieldFromRec(&xkbi->state)) - new|= xkbi->state.compat_lookup_mods; - else new|= xkbi->state.compat_grab_mods; - kbp->state= new; - } - button_mask = 1 << xE[i].u.u.detail; - if (type == ButtonPress && - ((xE[i].u.keyButtonPointer.state >> 7) & button_mask) == button_mask && - (xkbi->lockedPtrButtons & button_mask) == button_mask) { - DebugF("[xkb] Faking release of button %d\n", xE[i].u.u.detail); - XkbDDXFakeDeviceButton(xkbi->device, 0, xE[i].u.u.detail); - } else if (type == DeviceButtonPress && - ((((deviceKeyButtonPointer*)&xE[i])->state >> 7) & button_mask) == button_mask && - (xkbi->lockedPtrButtons & button_mask) == button_mask) { - DebugF("[xkb] Faking release of button %d\n", ((deviceKeyButtonPointer*)&xE[i])->state); - XkbDDXFakeDeviceButton(xkbi->device, 0, ((deviceKeyButtonPointer*)&xE[i])->state); - } + if ((xkbDebugFlags & 0x4) && + (xE[0].u.u.type == KeyPress || xE[0].u.u.type==KeyRelease || + xE[0].u.u.type == DeviceKeyPress || + xE[0].u.u.type == DeviceKeyRelease)) { + DebugF("[xkb] XKbFilterWriteEvents (non-XKB):\n"); + DebugF("[xkb] event= 0x%04x\n",xE[0].u.keyButtonPointer.state); + DebugF("[xkb] lookup= 0x%02x, grab= 0x%02x\n", + xkbi->state.lookup_mods, xkbi->state.grab_mods); + DebugF("[xkb] compat lookup= 0x%02x, grab= 0x%02x\n", + xkbi->state.compat_lookup_mods, xkbi->state.compat_grab_mods); } + if (type >= KeyPress && type <= MotionNotify) { + CARD16 old, new; + + old = xE[0].u.keyButtonPointer.state & ~0x1f00; + new = xE[0].u.keyButtonPointer.state & 0x1F00; + + if (old == XkbStateFieldFromRec(&xkbi->state)) + new |= xkbi->state.compat_lookup_mods; + else + new |= xkbi->state.compat_grab_mods; + xE[0].u.keyButtonPointer.state = new; + } + else if (type == EnterNotify || type == LeaveNotify) { + xE[0].u.enterLeave.state &= 0x1F00; + xE[0].u.enterLeave.state |= xkbi->state.compat_grab_mods; + } + else if (type >= DeviceKeyPress && type <= DeviceMotionNotify) { + CARD16 old, new; + deviceKeyButtonPointer *kbp = (deviceKeyButtonPointer*) &xE[0]; + + old = kbp->state & ~0x1F00; + new = kbp->state & 0x1F00; + if (old == XkbStateFieldFromRec(&xkbi->state)) + new |= xkbi->state.compat_lookup_mods; + else + new |= xkbi->state.compat_grab_mods; + kbp->state = new; + } } - return True; } /***====================================================================***/ diff --git a/xkb/xkbPrKeyEv.c b/xkb/xkbPrKeyEv.c index e01282d9b..8f6705f9f 100644 --- a/xkb/xkbPrKeyEv.c +++ b/xkb/xkbPrKeyEv.c @@ -52,59 +52,38 @@ int key; XkbBehavior behavior; unsigned ndx; - xkbi= keyc->xkbInfo; - key= event->detail.key; - if (xkbDebugFlags&0x8) { + xkbi = keyc->xkbInfo; + key = event->detail.key; + if (xkbDebugFlags & 0x8) DebugF("[xkb] XkbPKE: Key %d %s\n",key,(event->type == ET_KeyPress?"down":"up")); - } - if ( (xkbi->repeatKey==key) && (event->type== ET_KeyRelease) && - ((xkbi->desc->ctrls->enabled_ctrls&XkbRepeatKeysMask)==0) ) { - AccessXCancelRepeatKey(xkbi,key); - } + if (xkbi->repeatKey == key && event->type== ET_KeyRelease && + !(xkbi->desc->ctrls->enabled_ctrls & XkbRepeatKeysMask)) + AccessXCancelRepeatKey(xkbi, key); - behavior= xkbi->desc->server->behaviors[key]; + behavior = xkbi->desc->server->behaviors[key]; /* The "permanent" flag indicates a hard-wired behavior that occurs */ /* below XKB, such as a key that physically locks. XKB does not */ /* do anything to implement the behavior, but it *does* report that */ /* key is hardwired */ - if ((behavior.type&XkbKB_Permanent)==0) { + if (!(behavior.type & XkbKB_Permanent)) { switch (behavior.type) { case XkbKB_Default: - if (event->type == ET_KeyPress && - (keyc->down[key>>3] & (1<<(key&7)))) { - XkbLastRepeatEvent= (pointer)event; - - event->type = ET_KeyRelease; - XkbHandleActions(keybd, keybd, event); - - event->type = ET_KeyPress; - XkbHandleActions(keybd, keybd, event); - XkbLastRepeatEvent= NULL; - return; - } + /* Neither of these should happen in practice, but ignore them + anyway. */ + if (event->type == ET_KeyPress && !event->key_repeat && + key_is_down(keybd, key, KEY_PROCESSED)) + return; else if (event->type == ET_KeyRelease && - (!(keyc->down[key>>3]&(1<<(key&7))))) { - XkbLastRepeatEvent= (pointer)event; - event->type = ET_KeyPress; - XkbHandleActions(keybd, keybd, event); - event->type = ET_KeyRelease; - XkbHandleActions(keybd, keybd, event); - XkbLastRepeatEvent= NULL; - return; - } + !key_is_down(keybd, key, KEY_PROCESSED)) + return; break; case XkbKB_Lock: - if (event->type == ET_KeyRelease) { + if (event->type == ET_KeyRelease) return; - } - else { - int bit= 1<<(key&7); - if ( keyc->down[key>>3]&bit ) { - event->type = ET_KeyRelease; - } - } + else if (key_is_down(keybd, key, KEY_PROCESSED)) + event->type = ET_KeyRelease; break; case XkbKB_RadioGroup: ndx= (behavior.data&(~XkbKB_RGAllowNone)); @@ -173,9 +152,6 @@ ProcessKeyboardEvent(InternalEvent *ev, DeviceIntPtr keybd) int is_press = (event->type == ET_KeyPress); int is_release = (event->type == ET_KeyRelease); - if (keyc) - xkbi = keyc->xkbInfo; - /* We're only interested in key events. */ if (!is_press && !is_release) { UNWRAP_PROCESS_INPUT_PROC(keybd, xkb_priv, backup_proc); @@ -185,6 +161,8 @@ ProcessKeyboardEvent(InternalEvent *ev, DeviceIntPtr keybd) return; } + xkbi = keyc->xkbInfo; + /* If AccessX filters are active, then pass it through to * AccessXFilter{Press,Release}Event; else, punt to * XkbProcessKeyboardEvent. @@ -196,8 +174,9 @@ ProcessKeyboardEvent(InternalEvent *ev, DeviceIntPtr keybd) AccessXFilterPressEvent(event, keybd); else if (is_release) AccessXFilterReleaseEvent(event, keybd); - - } else { + return; + } + else { XkbProcessKeyboardEvent(event, keybd); }