TIP #433: ADD %M BINDING SUBSTITUTION ======================================= Version: $Revision: 1.7 $ Author: Joe Mistachkin Brian Griffin Don Porter State: Final Type: Project Tcl-Version: 8.6.4 Vote: Done Created: Wednesday, 25 February 2015 URL: https://tip.tcl-lang.org433.html Post-History: ------------------------------------------------------------------------- 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 (), 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 {set z %M} bind Entry {set y %M} bind .e {set x %M} event generate .e 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 <> bind all <> {tk::TabToWindow [tk_focusNext %W]} which permits a ** anywhere in Tk to shift the focus. Some widgets have their own uses for **, though, notably bind Text { if {[%W cget -state] eq "normal"} { tk::TextInsert %W \t focus %W break } } where a text widget in normal state accepts *Tab*s 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 {log_key %W %k %s %x %y %X %Y %A} This will fail to log *Tab*s 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 <> {if {%M==0} {tk::TabToWindow [tk_focusNext %W]}} bind Text { 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 ** is no longer needed at all and the general default binding bind Text {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. ------------------------------------------------------------------------- TIP AutoGenerator - written by Donal K. Fellows