diff options
author | fvogel <fvogelnew1@free.fr> | 2020-06-27 09:44:22 (GMT) |
---|---|---|
committer | fvogel <fvogelnew1@free.fr> | 2020-06-27 09:44:22 (GMT) |
commit | 5d193e26449b56e8301cd9808048b098bdcea79d (patch) | |
tree | 34e089605259b1588cac7da3ed9a10f2c5ba89b6 /generic | |
parent | d9d32ac66f73c6fffe70bdd8d545a2a9cfba0ed6 (diff) | |
parent | a1333159f86d40557e6e79e7424b6dc007358b07 (diff) | |
download | tk-5d193e26449b56e8301cd9808048b098bdcea79d.zip tk-5d193e26449b56e8301cd9808048b098bdcea79d.tar.gz tk-5d193e26449b56e8301cd9808048b098bdcea79d.tar.bz2 |
Fix [16ef161925]: <Escape><Control-c> binding sequence not working anymore.
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tkBind.c | 68 |
1 files changed, 56 insertions, 12 deletions
diff --git a/generic/tkBind.c b/generic/tkBind.c index e8827b3..8ffcc1d 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -59,7 +59,9 @@ /* * In old implementation (the one that used an event ring), <Double-1> and <1><1> were - * equivalent sequences. However it is logical to give <Double-1> higher precedence. + * equivalent sequences. However it is logical to give <Double-1> higher precedence + * since it is more specific. Indeed <Double-1> includes time and space requirements, + * which is not the case for <1><1>. * This is achieved by setting PREFER_MOST_SPECIALIZED_EVENT to 1. */ @@ -854,6 +856,20 @@ CountSpecialized( return sndCount - fstCount; } +int +IsKeyEventType( + unsigned eventType) +{ + return eventType == KeyPress || eventType == KeyRelease; +} + +int +IsButtonEventType( + unsigned eventType) +{ + return eventType == ButtonPress || eventType == ButtonRelease; +} + static int MatchEventNearby( const XEvent *lhs, /* previous button event */ @@ -861,7 +877,7 @@ MatchEventNearby( { assert(lhs); assert(rhs); - assert(lhs->type == ButtonPress || lhs->type == ButtonRelease); + assert(IsButtonEventType(lhs->type)); assert(lhs->type == rhs->type); /* assert: lhs->xbutton.time <= rhs->xbutton.time */ @@ -873,16 +889,16 @@ MatchEventNearby( static int MatchEventRepeat( - const XEvent *lhs, /* previous key event */ - const XEvent *rhs) /* current key event */ + const XKeyEvent *lhs, /* previous key event */ + const XKeyEvent *rhs) /* current key event */ { assert(lhs); assert(rhs); - assert(lhs->type == KeyPress || lhs->type == KeyRelease); + assert(IsKeyEventType(lhs->type)); assert(lhs->type == rhs->type); - /* assert: lhs->xkey.time <= rhs->xkey.time */ - return TestNearbyTime(rhs->xkey.time, lhs->xkey.time); + /* assert: lhs->time <= rhs->time */ + return lhs->keycode == rhs->keycode && TestNearbyTime(lhs->time, rhs->time); } static void @@ -2213,7 +2229,7 @@ Tk_BindEvent( * Ignore the event completely if it is an Enter, Leave, FocusIn, or * FocusOut event with detail NotifyInferior. The reason for ignoring * these events is that we don't want transitions between a window and its - * children to visible to bindings on the parent: this would cause + * children to be visible to bindings on the parent: this would cause * problems for mega-widgets, since the internal structure of a * mega-widget isn't supposed to be visible to people watching the parent. * @@ -2297,7 +2313,7 @@ Tk_BindEvent( switch (eventPtr->type) { case KeyPress: case KeyRelease: - if (MatchEventRepeat(&curEvent->xev, eventPtr)) { + if (MatchEventRepeat(&curEvent->xev.xkey, &eventPtr->xkey)) { if (curEvent->xev.xkey.keycode == eventPtr->xkey.keycode) { ++curEvent->countDetailed; } else { @@ -2521,13 +2537,13 @@ Tk_BindEvent( switch (patPtr->eventType) { case ButtonPress: case ButtonRelease: - if (curEvent->xev.type == KeyPress || curEvent->xev.type == KeyRelease) { + if (IsKeyEventType(curEvent->xev.type)) { RemoveListEntry(&bindPtr->lookupTables.entryPool, psEntry); } break; case KeyPress: case KeyRelease: - if (curEvent->xev.type == ButtonPress || curEvent->xev.type == ButtonRelease) { + if (IsButtonEventType(curEvent->xev.type)) { RemoveListEntry(&bindPtr->lookupTables.entryPool, psEntry); } break; @@ -2786,6 +2802,7 @@ MatchPatterns( PatSeq *bestPhysPtr; ModMask bestModMask; const PSModMaskArr *bestModMaskArr = NULL; + int i, isModKeyOnly = 0; assert(dispPtr); assert(bindPtr); @@ -2800,6 +2817,26 @@ MatchPatterns( bestPhysPtr = NULL; window = curEvent->xev.xany.window; + /* + * Modifier key events interlaced between patterns parts of a + * sequence shall not prevent a sequence from ultimately + * matching. Example: when trying to trigger <a><Control-c> + * from the keyboard, the sequence of events actually seen is + * <a> then <Control_L> (possibly repeating if the key is hold + * down), and finally <Control-c>. At the time <Control_L> is + * seen, we shall keep the <a><Control-c> pattern sequence in + * the promotion list, otherwise it is impossible to trigger + * it from the keyboard. See bug [16ef161925]. + */ + if (IsKeyEventType(curEvent->xev.type)) { + for (i = 0; i < dispPtr->numModKeyCodes; ++i) { + if (dispPtr->modKeyCodes[i] == curEvent->xev.xkey.keycode) { + isModKeyOnly = 1; + break; + } + } + } + for (psEntry = PSList_First(psList); psEntry; psEntry = PSList_Next(psEntry)) { if (patIndex == 0 || psEntry->window == window) { PatSeq* psPtr = psEntry->psPtr; @@ -2814,6 +2851,12 @@ MatchPatterns( : VirtPatIsBound(bindPtr, psPtr, object, physPtrPtr)) { TkPattern *patPtr = psPtr->pats + patIndex; + /* ignore modifier key events, and KeyRelease events if the current event + * is of a different type (e.g. a Button event) + */ + psEntry->keepIt = isModKeyOnly || \ + ((patPtr->eventType != (unsigned) curEvent->xev.type) && curEvent->xev.type == KeyRelease); + if (patPtr->eventType == (unsigned) curEvent->xev.type && (curEvent->xev.type != CreateNotify || curEvent->xev.xcreatewindow.parent == window) @@ -2828,8 +2871,9 @@ MatchPatterns( ModMask curModMask = ResolveModifiers(dispPtr, bindPtr->curModMask); psEntry->expired = 1; /* remove it from promotion list */ + psEntry->keepIt = 0; /* don't keep matching patterns */ - if ((modMask & ~curModMask) == 0) { + if (IsSubsetOf(modMask, curModMask)) { unsigned count = patPtr->info ? curEvent->countDetailed : curEvent->countAny; if (patIndex < PSModMaskArr_Size(psEntry->lastModMaskArr)) { |