summaryrefslogtreecommitdiffstats
path: root/generic/tkBind.c
diff options
context:
space:
mode:
authorfvogel <fvogelnew1@free.fr>2020-06-27 09:44:22 (GMT)
committerfvogel <fvogelnew1@free.fr>2020-06-27 09:44:22 (GMT)
commit5d193e26449b56e8301cd9808048b098bdcea79d (patch)
tree34e089605259b1588cac7da3ed9a10f2c5ba89b6 /generic/tkBind.c
parentd9d32ac66f73c6fffe70bdd8d545a2a9cfba0ed6 (diff)
parenta1333159f86d40557e6e79e7424b6dc007358b07 (diff)
downloadtk-5d193e26449b56e8301cd9808048b098bdcea79d.zip
tk-5d193e26449b56e8301cd9808048b098bdcea79d.tar.gz
tk-5d193e26449b56e8301cd9808048b098bdcea79d.tar.bz2
Fix [16ef161925]: <Escape><Control-c> binding sequence not working anymore.
Diffstat (limited to 'generic/tkBind.c')
-rw-r--r--generic/tkBind.c68
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)) {