home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #16 / NN_1992_16.iso / spool / comp / lang / tcl / 1064 < prev    next >
Encoding:
Internet Message Format  |  1992-07-29  |  9.6 KB

  1. Path: sparky!uunet!snorkelwacker.mit.edu!bu.edu!wang!news
  2. From: nyh@gauss.technion.ac.il (Nadav Har'El)
  3. Newsgroups: comp.lang.tcl
  4. Subject: Re: Keyboard focus and keyboard driven traversal
  5. Message-ID: <1992Jul29.105705.428@discus.technion.ac.il>
  6. Date: 29 Jul 92 10:57:05 GMT
  7. References: <1992Jul28.214959.19452@twg.com>
  8. Sender: news@wang.com
  9. Organization: Technion, Israel Institute of Technology
  10. Lines: 269
  11.  
  12. In article <1992Jul28.214959.19452@twg.com>, "David Herron" <david@twg.com> writes:
  13. > Greetings!
  14. > One of the fundamental things in Motif is that every application must be
  15. > equally drivable from either keyboard or mouse.  There are at least two
  16. > reasons for this:
  17. > - Some people are either unwilling or unable to use a mouse (effectively).
  18. >   While one might not have much sympathy for those unwilling to use mice,
  19. >   the ones `unable' to do so deserve lots of sympathy.
  20. > - Some work environments are too busy and crowded to put a mouse on the
  21. >   persons desk.  Take a look at a stock traders work area sometime.  They
  22. >   have umpty-umpt screens in front of them, and a keyboard for each one
  23. >   lying around, a TV screen (or more), telephones, etc.  No Room for extravagences
  24. >   like mice.
  25.  
  26. dont forget people who's mouse broke down... Once our mouse broke down, and for a week
  27. I felt really crippled - there were many programs I couldn't use at all or barely use.
  28. I had real trouble choosing the current window on tvtwm, until I added keyboard macros
  29. to make the arrows move you in the icon manager.
  30.  
  31. > There is a complicated set of rules which a Motif application must follow
  32. > to allow this.  It is all detailed in the style guide, but I have not had
  33. > the time to learn it.  Fortunately the Motif toolkit implements either the
  34. > real thing, or something pretty close.
  35. > The basic idea is that TAB, BACK-TAB, and the arrow keys move keyboard focus
  36. > around the screen.  So if you have a data entry form to fill out the keyboard
  37. > use is: type value, TAB, type value, TAB, type value, ...  When done TAB
  38. > and ARROW to the right button, and hit RETURN.  Voila' no mouse activity
  39. > and much easier than: type, POSITION, type, POSITION, type, POSITION, ..., CLICK.
  40. > The other part is that each widget has a way to trigger actions using the
  41. > keyboard.  Above I mentioned RETURN to activate a button, SPACE works as well.
  42. > The arrow keys scroll listboxes or edit boxes.  The arrow keys also move
  43. > panes in paned windows.  Hitting F10 enable keyboard driving of the
  44. > menu bar, LEFT and RIGHT change which menu pane is pulled down, while UP
  45. > and DOWN change which menu button is enabled.  etc...
  46. > For the application I'm writing at home (SEARCH) it seems that a lot of time
  47. > is being spent moving back and forth between keyboard and mouse.  To cut
  48. > this down I wanted to drive as many things as possible from the keyboard.
  49. > This meant having a mechanism for moving keyboard focus around the screen.
  50. > Once keyboard focus is on a widget, to indicate this to the user.
  51. > So I wrote up a TK module to handle focus setting.  This has gone through
  52. > at least 3 design-coding iterations, and is pretty useful at the moment.
  53. > It does not match up with Motif's style guide in a couple of ways:
  54. > - I could not figure out how to tell TK to bind an action to Shift<Key>Tab.
  55. >   So instead of BACK-TAB, this module uses Control-b.
  56. > - It indicates focus differently from Motif.  Motif draws a border around
  57. >   the outside of the widget.  FOCUS changes the relief of a widget.
  58. > - It does not use LEFT, RIGHT, UP or DOWN for some traversals, Motif does this
  59. >   when there are a group of buttons in the same area.
  60. > - You cannot reach all widgets in the interface.  Only those described to FOCUS.
  61. > A weirdity in FOCUS is that you must initialize it by calling FOCUS:traverse
  62. > after setting up all the traversals.  (Or maybe it's FOCUS:enter?)  Otherwise
  63. > it doesn't work.
  64. > #
  65. > # $Id: focus.tcl,v 1.3 1992/07/21 15:36:33 david Exp $
  66. > # focus -- Functions for implementing keyboard-driven focus traversal
  67. > #
  68. > # This module deals with FocusObjects as its unit-of-discourse.
  69. > # A FocusObject is something which may have focus, and may
  70. > # be traversed through.  It has a couple of subfields as so:
  71. > #
  72. > #    widget to which keyboard focus is to be directed.
  73. > #
  74. > #    widget whose relief is to be modified.
  75. > #
  76. > # When a widget has focus, the relief-widget is made `raised'.  When
  77. > # it loses focus, it is made `flat'.  Normally one will want
  78. > # this relief-widget to be a frame widget.  This is largely because
  79. > # each widget has a `natural & preferred' relief which is part of
  80. > # what identifies that widget to the user.  In order for the relief
  81. > # to show up, the frame must have -borderwidth > 0.
  82. > #
  83. > # Three main entry points exist:
  84. > #
  85. > # FOCUS:OBJ:create -- Creates an FocusObject instance.
  86. > # FOCUS:OBJ:obj    -- Get widget name for the FocusObject's object.
  87. > # FOCUS:OBJ:frame  -- Get the widget name for its frame.
  88. > #
  89. > # FOCUS:circle     -- Sets up a circular chain of FocusObject traversals.
  90. > # FOCUS:bind       -- Sets up more specialized traversals.
  91. > # FOCUS:now        -- Return the FocusObject name where it is NOW.
  92. > #
  93. > # The FocusObjects are stored in a global array called FOCUS_OBJ_heap.
  94. > # The `name' of the FocusObject is used to reference into the heap.
  95. > # Each is stored as a TCL list, with members in the order specified above.
  96. > #
  97. > #
  98. > #
  99. > # $Log: focus.tcl,v $
  100. > # Revision 1.3  1992/07/21  15:36:33  david
  101. > # Create functions to return parts of FocusObject structure, and find
  102. > # the FocusObject which corresponds to a certain widget.  Add support
  103. > # for rebinding the bindings.  Remember where focus currently is.
  104. > #
  105. > # Revision 1.2  1992/07/19  19:41:02  david
  106. > # Change indicator of when a widget has focus.  Used to set background
  107. > # color, now change -raised option on a frame widget.
  108. > # Revamped API to focus module to allow for more terse descriptions
  109. > # of the traversals.  Did this through creation of the FocusObject
  110. > # concept.
  111. > #
  112. > # Revision 1.1  1992/05/27  06:51:32  david
  113. > # Initial revision.
  114. > #
  115. > #
  116. > #
  117. > proc FOCUS:OBJ:create {{name} {object} {frame}} {
  118. >     global FOCUS_OBJ_heap
  119. >     set FOCUS_OBJ_heap($name) [list $object $frame ]
  120. > }
  121. > proc FOCUS:OBJ:obj name {
  122. >     global FOCUS_OBJ_heap
  123. >     return [lindex $FOCUS_OBJ_heap($name) 0]
  124. > }
  125. > proc FOCUS:OBJ:frame name {
  126. >     global FOCUS_OBJ_heap
  127. >     return [lindex $FOCUS_OBJ_heap($name) 1]
  128. > }
  129. > proc FOCUS:OBJ:find object {
  130. >     global FOCUS_OBJ_heap
  131. >     foreach name [array names FOCUS_OBJ_heap] {
  132. >         set obj $FOCUS_OBJ_heap($name)
  133. >         if {"$object" == [lindex $obj 1] || \
  134. >             "$object" == [lindex $obj 0]} {
  135. >             return $name
  136. >         }
  137. >     }
  138. >     return ""
  139. > }
  140. > # FOCUS:circle -- Create a chain of FOCUS:traversals for the
  141. > #    Objects specified in the arg-list.  Use <Tab> to move forward
  142. > #    through the circle, and <Control-b> to move backwards.  We'd
  143. > #    **LIKE** to use BackTab for moving backwards, but cannot figure
  144. > #    out how to specify that to TK.
  145. > #
  146. > # We destroy any preexisting binding.
  147. > #
  148. > proc FOCUS:circle {args} {
  149. >     global FOCUS_OBJ_heap
  150. >     foreach arg $args {
  151. >         if {![info exists first]} {
  152. >             set first $arg
  153. >             set last $arg
  154. >             continue
  155. >         }
  156. >         set to $FOCUS_OBJ_heap($arg)
  157. >         set from $FOCUS_OBJ_heap($last)
  158. >         set to_w   [lindex $to   0]
  159. >         set from_w [lindex $from 0]
  160. >         catch {bind $from_w <Tab>}
  161. >         bind $from_w <Tab>       "FOCUS:traverse $last $arg"
  162. >         catch {bind $to_w   <Control-b>}
  163. >         bind $to_w   <Control-b> "FOCUS:traverse $arg  $last"
  164. >         set last $arg
  165. >     }
  166. >     if {[info exists last]} {
  167. >         if {"$first" != "$last"} {
  168. >             set to $FOCUS_OBJ_heap($first)
  169. >             set from $FOCUS_OBJ_heap($last)
  170. >             set to_w   [lindex $to   0]
  171. >             set from_w [lindex $from 0]
  172. >             catch {bind $from_w <Tab>}
  173. >             bind $from_w <Tab>       "FOCUS:traverse $last  $first"
  174. >             catch {bind $to_w   <Control-b>}
  175. >             bind $to_w   <Control-b> "FOCUS:traverse $first $last"
  176. >         }
  177. >     }
  178. > }
  179. > # FOCUS:bind -- Create special purpose bindings from a particular Object.
  180. > #    The Object is specified in $from_nm.
  181. > #    For each of the args, they are a TCL list of the following members
  182. > #        binding
  183. > #        destination FocusObject name
  184. > #
  185. > # We destroy any preexisting binding.
  186. > #
  187. > proc FOCUS:bind {{from_nm} args} {
  188. >     global FOCUS_OBJ_heap
  189. >     set from $FOCUS_OBJ_heap($from_nm)
  190. >     set from_w [lindex $from 0]
  191. >     foreach arg $args {
  192. >         set binding [lindex $arg 0]
  193. >         set to_nm   [lindex $arg 1]
  194. >         set to   $FOCUS_OBJ_heap($to_nm)
  195. >         set to_w [lindex $to   0]
  196. >         catch {bind $from_w $binding}
  197. >         bind $from_w $binding "FOCUS:traverse $from_nm $to_nm"
  198. >     }
  199. > }
  200. > # FOCUS:enter -- Utility to perform the `entering' part of the
  201. > #    focus traversal.
  202. > #
  203. > proc FOCUS:enter {{w} {f}} {
  204. >     focus $w
  205. >     $f configure -relief raised
  206. > }
  207. > # FOCUS:leave -- Handle the `leaving' part of traversal.
  208. > #
  209. > proc FOCUS:leave {{w} {f}} {
  210. >     $f configure -relief flat
  211. > }
  212. > # FOCUS:traverse -- Do the job of traversing from one widget to
  213. > #    the other.  Simply call FOCUS:enter and FOCUS:leave
  214. > #    to do the trick.
  215. > #
  216. > proc FOCUS:traverse {{from_nm} {to_nm}} {
  217. >     global FOCUS_OBJ_heap FOCUS_now
  218. >     set to   $FOCUS_OBJ_heap($to_nm)
  219. >     set from $FOCUS_OBJ_heap($from_nm)
  220. >     FOCUS:leave [lindex $from 0] [lindex $from 1]
  221. >     FOCUS:enter [lindex $to   0] [lindex $to   1]
  222. >     set FOCUS_now $to_nm
  223. > }
  224. > proc FOCUS:now {} {
  225. >     global FOCUS_now
  226. >     return $FOCUS_now
  227. > }
  228.  
  229. -- 
  230. Nadav Har'El                         | ######  ########     # | <-- Sorry if
  231. Email: nyh@gauss.technion.ac.il      |      #       #       # |    you can't
  232. Department of Mathematics, Technion  |      #       #       # |    read Hebrew.
  233. Israel Institute of Technology       | ########     #  ###### |    Nadav. ;)
  234.