Author: Joe Mistachkin <joe@mistachkin.com>
Author: Brian Griffin <brian_griffin@mentor.com>
Author: Don Porter <dgp@users.sf.net>
State: Final
Type: Project
Vote: Done
Created: 25-Feb-2015
Post-History:
Tcl-Version: 8.6.4
Abstract
This TIP proposes one new binding substitution, %M, to access the number of script-based binding patterns matched so far for the event.
Background
In a presentation at the 2012 Tcl Conference (http://www.tclcommunityassociation.org/wub/proceedings/Proceedings-2012/RonWold/Customizable-Keyboard-Shortcuts.pdf\), Ron Wold pointed out that coding global catch-all scripts bound to the same event in many widgets is complicated because Tk's bind machinery allows any bind script to use break to prevent later bind scripts from evaluating. Among a known set of bind scripts, this is a useful technique, but it interferes with the non-coordinated introduction of additional bind scripts on the same event.
An alternative strategy is to avoid any bind script using break, but to give the latter scripts the means to detect when an earlier script has run so it can defer its own operations. That motivates the introduction of a means by which a bind script can discover something about the history of other bind script evaluations on the same event.
Specification
Add to the set of substitutions made in scripts passed to bind the new one, %M. When the substring %M appears in a binding script, it will be replaced with a count of the number of binding script evaluations that have already been performed in the handling of the current event.
Simple Example
The script...
pack [entry .e]
bind all <Key> {set z %M}
bind Entry <Key> {set y %M}
bind .e <Key> {set x %M}
event generate .e <Key-a>
list $x $y $z
will produce the result:
0 1 2
Use Case Example
One of the default bind scripts in Tk is
event add <<NextWindow>> <Tab>
bind all <<NextWindow>> {tk::TabToWindow [tk_focusNext %W]}
which permits a
Some widgets have their own uses for
bind Text <Tab> {
if {[%W cget -state] eq "normal"} {
tk::TextInsert %W \t
focus %W
break
}
}
where a text widget in normal state accepts Tabs as entered text like any other keypresses. The break in this script serves to prevent the focus shift that would otherwise take place. Since the same Tk developers coded both bind scripts, the global knowledge can make the system work as a whole.
However, a third party facility trying to join the party has difficulty. Consider a simple key logging facility,
bind all <Key> {log_key %W %k %s %x %y %X %Y %A}
This will fail to log Tabs typed in a Text due to the break noted above.
With the %M binding proposed here, an alternative set of bind scripts is possible.
bind all <<NextWindow>> {if {%M==0} {tk::TabToWindow [tk_focusNext %W]}}
bind Text <Tab> {
if {[%W cget -state] eq "normal"} {
tk::TextInsert %W \t
focus %W
}
}
In fact with the revised script bound to all it may be that
the script bound to
bind Text <KeyPress> {tk::TextInsert %W %A}
is sufficient.
With this alternative in place the third-party keylogger would work.
Compatibility
Any %M in an existing bind script will now stop reproducing itself literally, and will result in the new substitution. This has the potential to cause trouble with any bind scripts that themselves make use of clock scan or clock format or any other command that invites the use of the literal string %M. Dealing with such a situation is not difficult, but it is still a potential incompatibility.
Prototype
This feature is already implemented and committed to both the core-8-5-branch and the trunk, and is poised to be released as part of Tk 8.5.18 and Tk 8.6.4. Any objections to that should be raised in TIP discussion and voting.
Copyright
This document has been placed in the public domain.