emilbarton has asked for the wisdom of the Perl Monks concerning the following question:

Hello, I'm facing a small but annoying problem in my Tk code: some control keys - like ctl-s - keep inserting sequences of characters - like \x{13} - in a Text field of my Notebook tab provided that the insertion point is located in this field when the key is pressed. The bindings for this Text field can be reordered, it doesn't change this, for example I have a main window binding for <Control-s> that is inhibited by the following Text widget binding, the unwanted \x{13} appears nevertheless:

$mw->bind($mw, "<Control-s>" => sub { print "not printed\n" } ); my $Notes_tw = $Tabs{'Notes'}->Scrolled( 'TextUndo' , -background=>$COLOR{input_bgcolor} , -foreground =>$COLOR{input_fgcolor} , -scrollbars => 'se' , -wrap => 'word' ); $Notes_tw->bind("<Control-s>", \&handlectl); sub handlectl { my @tags = $Notes_tw->bindtags; print ' typefield=', $Tk::event->T,"\n", ' winfield=', $Tk::event->i,"\n", ' widgetfield=', $Tk::event->W,"\n", ' xrootfield=', $Tk::event->X,"\n", ' yrootfield=', $Tk::event->Y,"\n", ' sendfield=', $Tk::event->E,"\n", ' state=', $Tk::event->s,"\n", ' unicode=', $Tk::event->A,"\n", ' KeySym=', $Tk::event->K,"\n", ' numeric=', $Tk::event->N,"\n", ' keycode=', $Tk::event->k,"\n", "tags=@tags\n"; Tk->break; }

program output:

typefield=KeyPress
winfield=
widgetfield=Tk::TextUndo=HASH(0x2909c78)
xrootfield=1115
yrootfield=558
sendfield=0
state=Control-Mod2-
unicode=
KeySym=s
numeric=115
keycode=39
tags=Tk::Frame .notebook.notes.frame1 . all Freeze

The main window binding is well inhibited by the Tk->break, but no matter if I change the tags order with:

$Notes_tw->bindtags([$Notes_tw,$Notes_tw->toplevel,'all',ref($Notes_tw)]); # for example...

the Notes_tw field will keep displaying a \x{13} each time I press <Control-s>.

What can I do to get rid of this?

P.S.
This problem is specially embarrassing to me because if I save my config with ctl-s when located in my Notes field, then the content of this field is copied in my config file which in turn will get loaded at next launch and parsed by XML.pm. However XML.pm aborts when meeting \x{13}. I can easily forget that I'm within a Text field when saving my job.

Replies are listed 'Best First'.
Re: Tk hidden binding
by zentara (Cardinal) on Jul 23, 2011 at 21:10 UTC
    Yeah, you are right. I saw that \x{13} and just thought it was unicode not being properly handled, like maybe your shell settings were en_US instead of en_US.UTF-8, (or some such confusion :-)) But now that I woke up, :-) I think it might have to do with the bindtag order with the way you have control s bindings for both the $mw and the Text widget.

    This is about all I can figure out. My guess is the \x{13} is the text widget trying to print the line ( which is normal behavior), but the $mw binding is somehow messing it up. If the below setting of the bindtags dosn't help, I would guess you have a defective Tk installation? Can you reinstall Tk? What version of Tk and Perl are you running? Does the following script give good behavior? I left the "test 4" uncommented. Play with it and see what happens. Otherwise, post a self contained complete mini example that demonstrates the problem.

    I just diid notice a different behavior for the Text::Undo vs the plain Text widget, and if the widget is Scrolled or not. So you may want to try binding to the REAL text widget, not the Scrolled widget. I noticed with a Scrolled widget, the line gets printed, whearas in the plain widget it does not. Also, can you test your real script with a Scrolled Text instead of a Scrolled TextUndo?

    my $t1 = $mw->Scrolled('TextUndo')->pack; my $t1_real = $t1->Subwidget("scrolled");
    #!/usr/bin/perl use warnings; use strict; use Tk; require Tk::TextUndo; my $mw = tkinit; # create a top bar for testing pure $mw focus my $button = $mw->Button(-text=>'test')->pack(); $mw->bind('<Control-s>', sub { print "main control s \n" }); my $t1 = $mw->Scrolled('TextUndo')->pack; # uncomment the following sections to get different behavior of the # bindings, the test 4 is left uncommented to start, to show proper be +havior ##################################################### # test 1 # without any Text control s binding, the text widget prints a # line across the text widget AND a "main control s" to the console ################################################### # test 2 #if we just add a control s binding to the text widget # we get main control s, and text control s printed to console, # and a line printed in the text widget #$t1->bind('<Control-s>', sub { print "\ttext control s\n"; }); #################################################### #test 3 # we get only text control s to the console and the line, # but NO main control s #$t1->bind('<Control-s>', sub { print "\t\tfoo\n"; $_[0]->break }); ##################################################### #test 4 # no line is shown, no line printed, no main control s , # just a foo. # # the order of bindtags is: # class name (Tk::Text), window name, ancestral toplevel, "all" # this modifies the tag list so that the instance binding, # which includes a call to break(), has higher priority # than the class binding $t1->bind('<Control-s>', sub { print "\t\tfoo\n"; $_[0]->break }); $t1->bindtags([($t1->bindtags)[1,0,2,3]]); MainLoop;

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh

      Many thanks for your concerned handling of this case and for the time spent. My version of Perl is v5.10.1 (*) built for x86_64-linux-gnu-thread-multi (with 53 registered patches) and Tk installed (by Cpan I think) under /usr/local/lib/perl/5.10.1/Tk.pm seems to be Tk804.029 (as displayed by 'man Tk').

      I've run your tests and the results reported below are quite puzzling to me. I won't create another mini example because I think yours is perfectly demonstrative of my problem. Apart from the fact that I still don't know how to solve it I find some ease in not having disturbed you for mere carelessness.

      My results for the keypress of <control-s>:

      test 4 (the original behaviour of your program):
      "main control s\n" is printed to the console when the focus is $mw.
      "\t\tfoo\n" is printed in the in the console and "\x{13}" in the text widget when the insertion point is in.

      test 3 uncommented (other tests commented out):
      "main control s\n" is printed to the console when the focus is $mw.
      "\t\tfoo\n" is printed in the in the console and "\x{13}" in the text widget when the insertion point is in.
      Behaves as test 4.

      test 2 uncommented (other tests commented out):
      "main control s\n" is printed to the console when the focus is $mw.
      "\ttext control s\nmain control s\n" is printed in the in the console and "\x{13}" in the text widget when the insertion point is in.

      test 1 (each test commented out):
      "main control s\n" is printed to the console when the focus is $mw.
      "main control s\n" is printed in the in the console and "\x{13}" in the text widget when the insertion point is in.

      Comment:
      If it wouldn't be for test4 which differs deeply, I would think that your newline is replaced by \x{13} in my Tk version. But why should a newline be printed anyway?

        I would think that your newline is replaced by \x{13} in my Tk version. But why should a newline be printed anyway?

        This brings up a good point, what do YOU expect to happen when you press a <control s> in the TextUndo widget? The normal behavior, on my Tk ( version Tk-804.029_500 ) , with no extra bindings associated with it, is to print what appears to be an underscore line segment, not a newline. It is not a dash or hyphen. Repeated presses of <control s> create a continuous line looking like an underscore (at the bottom of the font area).

        Do you want this behaviour?

        If you want to stop all text insertion, with a <control s>, try this and see what happens. I get NO insertion of any kind into the TextUndo widget. Notice I'm getting the REAL widget, not the Scrolled one.

        #!/usr/bin/perl use warnings; use strict; use Tk; require Tk::TextUndo; # a <control s> in the TextUndo widget produces # nothing in the Text area, and a foo to the console my $mw = tkinit; # create a top bar for testing pure $mw focus my $button = $mw->Button(-text=>'test')->pack(); $mw->bind('<Control-s>', sub { print "main control s \n" }); my $t = $mw->Scrolled ('TextUndo')->pack; my $t1 = $t->Subwidget("scrolled"); # get real widget $t1->bind('<Control-s>', sub { print "\t\tfoo\n"; $_[0]->break }); $t1->bindtags([($t1->bindtags)[1,0,2,3]]); MainLoop;

        To address the point that you saw no difference in binding to a Scrolled or standard TextUndo widget, notice the difference in behavior in this script, where I bind to the Scrolled widget. I get the foo to the console, plus the underscore line gets printed to the TextUndo.

        #!/usr/bin/perl use warnings; use strict; use Tk; require Tk::TextUndo; # when binding to the Scrolled widget, instead # of the real widget, a line gets printed to the text area # as well as the foo to the console my $mw = tkinit; # create a top bar for testing pure $mw focus my $button = $mw->Button(-text=>'test')->pack(); $mw->bind('<Control-s>', sub { print "main control s \n" }); my $t1 = $mw->Scrolled ('TextUndo')->pack; $t1->bind('<Control-s>', sub { print "\t\tfoo\n"; $_[0]->break }); $t1->bindtags([($t1->bindtags)[1,0,2,3]]); MainLoop;

        I'm not really a human, but I play one on earth.
        Old Perl Programmer Haiku ................... flash japh

      As for the TextUndo vs Text or Scrolled vs normal, it doesnt seem to bear on the issue in my configuration.

Re: Tk hidden binding
by zentara (Cardinal) on Jul 23, 2011 at 13:57 UTC
    Unicode is still a dark area for me too, but before one of the unicode experts can answer you, try putting one, the other, or both, in your script.
    use utf8; $Tk::encodeFallback=1;

    I'm not really a human, but I play one on earth.
    Old Perl Programmer Haiku ................... flash japh
      Thank you but unfortunately these lines don't impede the insertion.
      Besides I don't understand why I should care about Unicode in my program which doesn't deal with special characters.
Re: Tk hidden binding
by Anonymous Monk on Jul 24, 2011 at 10:28 UTC
    As far as I can tell, this is a bug in Tk :) Run one of these and type Ctrl+[
    perl -MTk -le " tkinit->Text->pack->focus; MainLoop; " perl -MTk -le ' tkinit->Text->pack->focus; MainLoop; '
    or type Ctrl+] and you'll get esc(\033) and gs(\035) respectively

    This is a bug

    $ perl -MTk -le " print for Tk->VERSION, $^V " 804.0295 v5.12.2 $ perl -MTk -le " print for Tk->VERSION, $] " 804.028 5.008009
    Ctrl+g results in bel(\a)

    This isn't supposed to happen :)

    Checking the Tk bug cue i find Bug #47173 for Tk: "Modifier" key releases don't track key presses correctly

    perl/Tk is built upon Tcl/Tk 8.5.7

    Tcl/Tk 8.6 doesn't have this problem

    #!/usr/bin/perl -- use strict; use warnings; use Tcl::pTk; my $int = new Tcl::pTk; $int->Eval(<<'EOS'); # pure-tcl code to create widgets (e.g. generated by some GUI builder) text .e ## http://wiki.tcl.tk/1626#tk_version .e insert end "tcl_version $tcl_version\n" .e insert end "tcl_patchLevel $tcl_patchLevel\n" .e insert end "tk_version $tk_version\n" .e insert end "tk_patchLevel $tk_patchLevel\n" .e insert end "tk_library $tk_library\n" pack .e EOS my $e = $int->widget('.e'); # get .e entry into play $e->insert( "end", " Tcl::pTk $Tcl::pTk::VERSION Tcl $Tcl::VERSION \$^V $^V \$] $] "); $int->MainLoop; __END__ tcl_version 8.6 tcl_patchLevel 8.6b1.2 tk_version 8.6 tk_patchLevel 8.6b1.2 tk_library C:/Tcl8.6/lib/tk8.6 Tcl::pTk 0.85 Tcl 1.02 $^V v5.12.2 $] 5.012002
      On my Tk (Tk-804.029_500) a <control ]> prints a # character to the Text area. I don't know for sure if this is what is normal or not, I'm running Slackware 1337 for AMD64 , if that makes any difference in keyboard setups.

      I'm not really a human, but I play one on earth.
      Old Perl Programmer Haiku ................... flash japh

        I don't know for sure if this is what is normal or not, I'm running Slackware 1337 for AMD64 , if that makes any difference in keyboard setups.

        I think it is not normal , I've yet to see a toolkit where a text widget does that by default going back some 20 years :)

        Nice catch with the subwidget in Re^3: Tk hidden binding, I also get the same thing you describe

      It's amazing how things can get complicated quickly. I get \x{1b} and \x{1d}. Thank you for the various informations in your answer.
        Hey, thats almost the same thing ;)
        $ perl -le " print qq[\033\035] " |od -tacx1 0000000 esc gs cr nl 033 035 \r \n 1b 1d 0d 0a 0000004