9.4. How do I bind keyboard keys?

There are many default key bindings built in to the widgets of perl/Tk. Making proper use of them often involves setting up the right callback. (You may wish to consult the examples in BindTable.pod for help with this subject.)

The basic idea is:

    $widget -> bind('<keyname>' => action);
Where $widget is the tag or ID of the widget for which the bindings are to hold (note for global bindings you have to bind to <All>, for semi-global bindings you need to bind to all the relevant widgets in your application), '<keyname>' can be things like:
    <Key> or <KeyPress> or <Any-KeyPress>
    <KeyRelease>
    <Button> or <ButtonPress>
    <ButtonRelease>
    <Button-1> or <B1> 
    <Double-1>
    <Enter>
    <Leave>
    <Motion>
To figure out what names perl/Tk uses for such <bindings> use the "binder-finder" on a widget's .pm file. For example, you could find bindings hidden inside of Button.pm by typing this at your shell prompt:
    perl -ne 'print if s/.*(<[^>]*>).*/$1/g;' Button.pm
while in the directory where Button.pm is located (and if you are not there then simply specify the /path/to/Button.pm). Note that due to inheritance (e.g.the type of script bindings that are being discussed here) what the binder-finder turns up may not be the last word on a given widget's behaviour. This may be especially true for a widget inside of a compound/composite widget. Note also that the binder-finder will turn up things like <FILEHANDLES> as well as honest <Bindings>. Discrimination in its use is called for (and while your at it you could have just as easily used an editor and actually examined the code directly now couldn't you?).

To get an idea of what the code is for a key that you are interested in try running the xlib_demo that comes in your Tk-b# directory. Hold your mouse pointer over the window that appears and simply type the key that you are interested in. The code should appear in the window. If you do not have perl/Tk up and running yet try "xmodmap -pk" or look directly at the /usr/include/X11/keysymdef.h file where keysym names are given with an XK_ pre-pended. Do not try things like the Tcl/Tk %k symbols in perl scripts. %Ks will be mis-interpreted as non-existant perl hashes. Instead look at the Xevent function.

Ali Corbin <corbin@adsw.fteil.ca.boeing.com> recently posted a great little script for determining keyboard key bindings on a MainWindow:

    #!/usr/local/bin/perl -w
    use Tk;
    $top = MainWindow->new();
    $frame = $top->Frame( -height => '6c', -width => '6c',
                            -background => 'black', -cursor => 'gobbler' );
    $frame->pack;
    $top->bind( '<Any-KeyPress>' => sub
    {
        my($c) = @_;
        my $e = $c->XEvent;
        my( $x, $y, $W, $K, $A ) = ( $e->x, $e->y, $e->K, $e->W, $e->A );

        print "A key was pressed:\n";
        print "  x = $x\n";
        print "  y = $y\n";
        print "  W = $K\n";
        print "  K = $W\n";
        print "  A = $A\n";
    } );
    MainLoop();
To bind the action of one widget to that of another try taking a look at the .pm file for the widget of interest - is there a binding function already defined? If so you may use it. An example would be the use of "Up" & "Down" Buttons for a Listbox: one could bind the Buttons to call Tk::Listbox::UpDown, however, Guy Decoux describes a much more clever way to use the <Up> and <Down> already defined in Listbox.pm (this does not work with Tk-b9.01):
    #!/usr/local/bin/perl
    use Tk;
    $top = MainWindow->new;
    $lb = $top->Listbox(-height => 10);
    for($i=0; $i < 120; $i++) {
      $lb->insert('end', $i);
    }
    $f = $top->Frame;
    $up = $f->Button(
           -text => "Up",
           -command => [ $lb->bind(ref $lb, '<Up>'), $lb]
           );
    $down = $f->Button(
             -text => "Down",
             -command =>sub {&{$lb->bind(ref $lb, '<Down>')}($lb)}
             );
    $up->pack(-side => 'left');
    $down->pack;
    $f->pack;
    $lb->pack;
    MainLoop;

Previous | Return to table of contents | Next