home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!snorkelwacker.mit.edu!bu.edu!wang!news
- From: nyh@gauss.technion.ac.il (Nadav Har'El)
- Newsgroups: comp.lang.tcl
- Subject: Re: Keyboard focus and keyboard driven traversal
- Message-ID: <1992Jul29.105705.428@discus.technion.ac.il>
- Date: 29 Jul 92 10:57:05 GMT
- References: <1992Jul28.214959.19452@twg.com>
- Sender: news@wang.com
- Organization: Technion, Israel Institute of Technology
- Lines: 269
-
- In article <1992Jul28.214959.19452@twg.com>, "David Herron" <david@twg.com> writes:
- > Greetings!
- >
- > One of the fundamental things in Motif is that every application must be
- > equally drivable from either keyboard or mouse. There are at least two
- > reasons for this:
- >
- > - Some people are either unwilling or unable to use a mouse (effectively).
- > While one might not have much sympathy for those unwilling to use mice,
- > the ones `unable' to do so deserve lots of sympathy.
- >
- > - Some work environments are too busy and crowded to put a mouse on the
- > persons desk. Take a look at a stock traders work area sometime. They
- > have umpty-umpt screens in front of them, and a keyboard for each one
- > lying around, a TV screen (or more), telephones, etc. No Room for extravagences
- > like mice.
- >
-
- dont forget people who's mouse broke down... Once our mouse broke down, and for a week
- I felt really crippled - there were many programs I couldn't use at all or barely use.
- I had real trouble choosing the current window on tvtwm, until I added keyboard macros
- to make the arrows move you in the icon manager.
-
- > There is a complicated set of rules which a Motif application must follow
- > to allow this. It is all detailed in the style guide, but I have not had
- > the time to learn it. Fortunately the Motif toolkit implements either the
- > real thing, or something pretty close.
- >
- > The basic idea is that TAB, BACK-TAB, and the arrow keys move keyboard focus
- > around the screen. So if you have a data entry form to fill out the keyboard
- > use is: type value, TAB, type value, TAB, type value, ... When done TAB
- > and ARROW to the right button, and hit RETURN. Voila' no mouse activity
- > and much easier than: type, POSITION, type, POSITION, type, POSITION, ..., CLICK.
- >
- > The other part is that each widget has a way to trigger actions using the
- > keyboard. Above I mentioned RETURN to activate a button, SPACE works as well.
- > The arrow keys scroll listboxes or edit boxes. The arrow keys also move
- > panes in paned windows. Hitting F10 enable keyboard driving of the
- > menu bar, LEFT and RIGHT change which menu pane is pulled down, while UP
- > and DOWN change which menu button is enabled. etc...
- >
- >
- > For the application I'm writing at home (SEARCH) it seems that a lot of time
- > is being spent moving back and forth between keyboard and mouse. To cut
- > this down I wanted to drive as many things as possible from the keyboard.
- > This meant having a mechanism for moving keyboard focus around the screen.
- > Once keyboard focus is on a widget, to indicate this to the user.
- >
- > So I wrote up a TK module to handle focus setting. This has gone through
- > at least 3 design-coding iterations, and is pretty useful at the moment.
- >
- > It does not match up with Motif's style guide in a couple of ways:
- >
- > - I could not figure out how to tell TK to bind an action to Shift<Key>Tab.
- > So instead of BACK-TAB, this module uses Control-b.
- >
- > - It indicates focus differently from Motif. Motif draws a border around
- > the outside of the widget. FOCUS changes the relief of a widget.
- >
- > - It does not use LEFT, RIGHT, UP or DOWN for some traversals, Motif does this
- > when there are a group of buttons in the same area.
- >
- > - You cannot reach all widgets in the interface. Only those described to FOCUS.
- >
- >
- > A weirdity in FOCUS is that you must initialize it by calling FOCUS:traverse
- > after setting up all the traversals. (Or maybe it's FOCUS:enter?) Otherwise
- > it doesn't work.
- >
- >
- >
- >
- > #
- > # $Id: focus.tcl,v 1.3 1992/07/21 15:36:33 david Exp $
- > # focus -- Functions for implementing keyboard-driven focus traversal
- > #
- > # This module deals with FocusObjects as its unit-of-discourse.
- > # A FocusObject is something which may have focus, and may
- > # be traversed through. It has a couple of subfields as so:
- > #
- > # widget to which keyboard focus is to be directed.
- > #
- > # widget whose relief is to be modified.
- > #
- > # When a widget has focus, the relief-widget is made `raised'. When
- > # it loses focus, it is made `flat'. Normally one will want
- > # this relief-widget to be a frame widget. This is largely because
- > # each widget has a `natural & preferred' relief which is part of
- > # what identifies that widget to the user. In order for the relief
- > # to show up, the frame must have -borderwidth > 0.
- > #
- > # Three main entry points exist:
- > #
- > # FOCUS:OBJ:create -- Creates an FocusObject instance.
- > # FOCUS:OBJ:obj -- Get widget name for the FocusObject's object.
- > # FOCUS:OBJ:frame -- Get the widget name for its frame.
- > #
- > # FOCUS:circle -- Sets up a circular chain of FocusObject traversals.
- > # FOCUS:bind -- Sets up more specialized traversals.
- > # FOCUS:now -- Return the FocusObject name where it is NOW.
- > #
- > # The FocusObjects are stored in a global array called FOCUS_OBJ_heap.
- > # The `name' of the FocusObject is used to reference into the heap.
- > # Each is stored as a TCL list, with members in the order specified above.
- > #
- > #
- > #
- > # $Log: focus.tcl,v $
- > # Revision 1.3 1992/07/21 15:36:33 david
- > # Create functions to return parts of FocusObject structure, and find
- > # the FocusObject which corresponds to a certain widget. Add support
- > # for rebinding the bindings. Remember where focus currently is.
- > #
- > # Revision 1.2 1992/07/19 19:41:02 david
- > # Change indicator of when a widget has focus. Used to set background
- > # color, now change -raised option on a frame widget.
- > # Revamped API to focus module to allow for more terse descriptions
- > # of the traversals. Did this through creation of the FocusObject
- > # concept.
- > #
- > # Revision 1.1 1992/05/27 06:51:32 david
- > # Initial revision.
- > #
- > #
- > #
- >
- > proc FOCUS:OBJ:create {{name} {object} {frame}} {
- > global FOCUS_OBJ_heap
- > set FOCUS_OBJ_heap($name) [list $object $frame ]
- > }
- >
- > proc FOCUS:OBJ:obj name {
- > global FOCUS_OBJ_heap
- > return [lindex $FOCUS_OBJ_heap($name) 0]
- > }
- >
- >
- > proc FOCUS:OBJ:frame name {
- > global FOCUS_OBJ_heap
- > return [lindex $FOCUS_OBJ_heap($name) 1]
- > }
- >
- > proc FOCUS:OBJ:find object {
- > global FOCUS_OBJ_heap
- >
- > foreach name [array names FOCUS_OBJ_heap] {
- > set obj $FOCUS_OBJ_heap($name)
- > if {"$object" == [lindex $obj 1] || \
- > "$object" == [lindex $obj 0]} {
- > return $name
- > }
- > }
- > return ""
- > }
- >
- > # FOCUS:circle -- Create a chain of FOCUS:traversals for the
- > # Objects specified in the arg-list. Use <Tab> to move forward
- > # through the circle, and <Control-b> to move backwards. We'd
- > # **LIKE** to use BackTab for moving backwards, but cannot figure
- > # out how to specify that to TK.
- > #
- > # We destroy any preexisting binding.
- > #
- > proc FOCUS:circle {args} {
- > global FOCUS_OBJ_heap
- >
- > foreach arg $args {
- > if {![info exists first]} {
- > set first $arg
- > set last $arg
- > continue
- > }
- >
- > set to $FOCUS_OBJ_heap($arg)
- > set from $FOCUS_OBJ_heap($last)
- >
- > set to_w [lindex $to 0]
- > set from_w [lindex $from 0]
- >
- > catch {bind $from_w <Tab>}
- > bind $from_w <Tab> "FOCUS:traverse $last $arg"
- > catch {bind $to_w <Control-b>}
- > bind $to_w <Control-b> "FOCUS:traverse $arg $last"
- >
- > set last $arg
- > }
- >
- > if {[info exists last]} {
- > if {"$first" != "$last"} {
- > set to $FOCUS_OBJ_heap($first)
- > set from $FOCUS_OBJ_heap($last)
- >
- > set to_w [lindex $to 0]
- > set from_w [lindex $from 0]
- >
- > catch {bind $from_w <Tab>}
- > bind $from_w <Tab> "FOCUS:traverse $last $first"
- > catch {bind $to_w <Control-b>}
- > bind $to_w <Control-b> "FOCUS:traverse $first $last"
- > }
- > }
- > }
- >
- > # FOCUS:bind -- Create special purpose bindings from a particular Object.
- > # The Object is specified in $from_nm.
- > # For each of the args, they are a TCL list of the following members
- > # binding
- > # destination FocusObject name
- > #
- > # We destroy any preexisting binding.
- > #
- > proc FOCUS:bind {{from_nm} args} {
- > global FOCUS_OBJ_heap
- >
- > set from $FOCUS_OBJ_heap($from_nm)
- > set from_w [lindex $from 0]
- >
- > foreach arg $args {
- > set binding [lindex $arg 0]
- > set to_nm [lindex $arg 1]
- >
- > set to $FOCUS_OBJ_heap($to_nm)
- > set to_w [lindex $to 0]
- >
- > catch {bind $from_w $binding}
- > bind $from_w $binding "FOCUS:traverse $from_nm $to_nm"
- > }
- > }
- >
- > # FOCUS:enter -- Utility to perform the `entering' part of the
- > # focus traversal.
- > #
- > proc FOCUS:enter {{w} {f}} {
- > focus $w
- > $f configure -relief raised
- > }
- >
- > # FOCUS:leave -- Handle the `leaving' part of traversal.
- > #
- > proc FOCUS:leave {{w} {f}} {
- > $f configure -relief flat
- > }
- >
- > # FOCUS:traverse -- Do the job of traversing from one widget to
- > # the other. Simply call FOCUS:enter and FOCUS:leave
- > # to do the trick.
- > #
- > proc FOCUS:traverse {{from_nm} {to_nm}} {
- > global FOCUS_OBJ_heap FOCUS_now
- >
- > set to $FOCUS_OBJ_heap($to_nm)
- > set from $FOCUS_OBJ_heap($from_nm)
- >
- > FOCUS:leave [lindex $from 0] [lindex $from 1]
- > FOCUS:enter [lindex $to 0] [lindex $to 1]
- >
- > set FOCUS_now $to_nm
- > }
- >
- > proc FOCUS:now {} {
- > global FOCUS_now
- > return $FOCUS_now
- > }
-
- --
- Nadav Har'El | ###### ######## # | <-- Sorry if
- Email: nyh@gauss.technion.ac.il | # # # | you can't
- Department of Mathematics, Technion | # # # | read Hebrew.
- Israel Institute of Technology | ######## # ###### | Nadav. ;)
-