Index: doc/text.n ================================================================== --- doc/text.n +++ doc/text.n @@ -3770,19 +3770,21 @@ all the sequences for which bindings have been defined for \fItagName\fR. .RS .PP The only events for which bindings may be specified are those related to the mouse and keyboard (such as \fBEnter\fR, \fBLeave\fR, \fBButton\fR, -\fBMotion\fR, and \fBKey\fR) or virtual events. Event bindings for a text -widget use the \fBcurrent\fR mark described under \fBMARKS\fR above. An +\fBMotion\fR, and \fBKey\fR) or virtual events. Mouse and keyboard event +bindings for a text widget respectively use the \fBcurrent\fR and \fBinsert\fR +marks described under \fBMARKS\fR above. An \fBEnter\fR event triggers for a tag when the tag first becomes present on the current character, and a \fBLeave\fR event triggers for a tag when it ceases to be present on the current character. \fBEnter\fR and \fBLeave\fR events can happen either because the \fBcurrent\fR mark moved or because the character at that position changed. Note that these events are different than \fBEnter\fR -and \fBLeave\fR events for windows. Mouse and keyboard events are directed to -the current character. If a virtual event is used in a binding, that binding +and \fBLeave\fR events for windows. Mouse events are directed to the current +character, while keyboard events are directed to the insert character. +If a virtual event is used in a binding, that binding can trigger only if the virtual event is defined by an underlying mouse-related or keyboard-related event. .PP It is possible for the current character to have multiple tags, and for each of them to have a binding for a particular event sequence. When this occurs, Index: generic/tkTextTag.c ================================================================== --- generic/tkTextTag.c +++ generic/tkTextTag.c @@ -2918,12 +2918,32 @@ TkTextPickCurrent(textPtr, eventPtr); } if (!(textPtr->flags & DESTROYED)) { const TkSharedText *sharedTextPtr = textPtr->sharedTextPtr; - if (sharedTextPtr->tagBindingTable && !TkTextTagSetIsEmpty(textPtr->curTagInfoPtr)) { - TagBindEvent(textPtr, eventPtr, textPtr->curTagInfoPtr, sharedTextPtr->tagEpoch); + if (sharedTextPtr->tagBindingTable) { + if (!TkTextTagSetIsEmpty(textPtr->curTagInfoPtr)) { + /* + * The mouse is inside the text widget, the 'current' mark was updated. + */ + + TagBindEvent(textPtr, eventPtr, textPtr->curTagInfoPtr, sharedTextPtr->tagEpoch); + } else if ((eventPtr->type == KeyPress) || (eventPtr->type == KeyRelease)) { + /* + * Key events fire independently of the 'current' mark and use the + * 'insert' mark. + */ + + TkTextIndex index; + TkTextTagSet *insertTags; + + TkTextMarkNameToIndex(textPtr, "insert", &index); + insertTags = TkTextIndexGetContentSegment(&index, NULL)->tagInfoPtr; + if (!TkTextTagSetIsEmpty(insertTags)) { + TagBindEvent(textPtr, eventPtr, insertTags, sharedTextPtr->tagEpoch); + } + } if (textPtr->flags & DESTROYED) { TkTextDecrRefCountAndTestIfDestroyed(textPtr); return; } } Index: tests/textTag.test ================================================================== --- tests/textTag.test +++ tests/textTag.test @@ -1351,10 +1351,28 @@ event gen .t -x $x3 -y $y3 -state 0x200 return $x } -cleanup { .t tag delete x y } -result {x-enter | x-down | | | x-up | x-leave y-enter} + +test textTag-15.4 {TkTextBindProc, key event with mouse outside the widget} -setup { + .t tag delete {*}[.t tag names] + wm geometry . +200+200 ; update +} -body { + set res {} + .t tag add tag1 1.0 end + .t tag bind tag1 {lappend res %K} + .t mark set insert 1.2 + update + event generate .t -warp 1 -x -50 -y -50 + controlPointerWarpTiming + focus -force .t + event generate .t -keysym a + set res +} -cleanup { + .t tag delete tag1 +} -result {a} test textTag-16.1 {TkTextPickCurrent procedure} -setup { .t tag delete {*}[.t tag names] wm geometry . +200+200 ; update