October 2003, Frank de Lange Last modified: 20031110, Frank de Lange Keyboard Navigation =================== You can use the keyboard to navigate links and controls in Dillo. In the default configuration, the following keys are used: Alt-Up: link UP Alt-Down: link DOWN Alt-Left: link LEFT Alt-Right: link RIGHT Enter: follow link or activate GTK+ widget Escape: unhighlight link The Tab and Shift-Tab key combinations are NOT used for link movement. Their function is to move focus between form elements, the location bar, the search entry (when using status bar search, an optional feature in the tab/frame patch) and other interface elements. These keys are also used to move focus between frames in the frame-capable version of Dillo. Keyboard navigation tries to minimize the number of scrolling movements for the document by highlighting links within the currently visible part of the document whenever possible. It selects the next link to highlight according to these criteria: - if this is the first time keyboard navigation is used on this document, select the first (when moving DOWN or RIGHT) or last (when moving UP or LEFT) link in the currently visible part of the document. If there are no links in the currently visible part of the document, select the first link searching downwards from the currently visible part of the document, or upwards from the end of the document. - if keyboard navigation has been used before on this document, try to highlight the next or previous link (UP, DOWN, LEFT, RIGHT) in the visible part of the document. If the user has scrolled the document after the last keyboard navigation action, start the search in the currently visible part of the document. Search and keyboard navigation ------------------------------ Keyboard navigation also works with the Search feature. If search hits a link, it will be focused. Press in the viewport to follow the link. When using the status bar for search (an optional feature in the tabbed version of Dillo), press to close the search entry followed by to follow the link. A second will unhighlight the focused link. History ------- The focus location is saved when navigating to another document in the same window or tab. This makes it possible to go back in history and continue to the next link on the page. Form fields ----------- The same keys used for link navigation work for form field navigation. Do note however that form fields, being embedded GTK+ widgets, can have their own bindings for some functions. As an example, the space bar is bound to the activate function in radio buttons. To move between form elements you can use both the normal navigation keys as well as the traditional Tab/Shift-Tab combination. Tab and Shift-Tab can also be used to move focus to the next or previous document in a frameset by skipping through all form elements (if any). Keyboard bindings ================= It is possible to change the keyboard bindings used for keyboard navigation, either through editing the dillorc or by adding a section to any of the current GTK+ rc-files. The syntax is the same, the only difference is the addition of the preference keyword "key_bindings" in the dillorc and the fact that the bindings have to be enclosed in double quotes. As an example, this configuration (in gtkrc) uses the numerical keypad for link navigation: binding "keypad-keys" { bind "KP_Add" { "focus_move" (0) } bind "KP_Subtract" { "focus_move" (1) } bind "KP_8" { "focus_move" (2) } bind "KP_2" { "focus_move" (3) } bind "KP_4" { "focus_move" (4) } bind "KP_6" { "focus_move" (5) } bind "KP_Enter" { "focus_activate" () } } class "GtkDwScrolledFrame" binding "keypad-keys" You can also use 'widget "*dillo-content" instead of 'class "GtkDwScrolledFrame" if you prefer to use widget names: widget "*dillo-content" binding "keypad-keys" This one (in dillorc, note the enclosing double quotes, the use of single quotes and the preference name 'key_bindings') makes Dillo behave like the vi editor when it comes to link navigation: key_bindings = "binding 'vi-keys' { bind 'k' { 'focus_move' (2) } bind 'j' { 'focus_move' (3) } bind 'h' { 'focus_move' (4) } bind 'l' { 'focus_move' (5) } } class 'GtkDwScrolledFrame' binding 'vi-keys'" The numerical values after "focus_move" are actually GTK enumeration values, but the current implementation does not support this. It would of course look much better to be able to write "focus_move" (GTK_DIR_DOWN) instead of "focus_move" (3)... It is also possible to bind a sequence of actions to a single keypress by adding more actions after the first. Internals ========= Focus state is kept in the focus_state structure which is tied to the viewport. Focus movement is controlled through the gtk_container_focus signal, which is handled by the viewport, scrolled_frame and scrolled_window. The actual movement of focus within a document is initiated by the viewport calling A_Focus_state_focus_next, which returns TRUE when it succeeded in focusing a link. Focus is trapped within a document for links, but not for form elements (moving focus past the first or last form element will pass focus to the next container child). focus_state contains two GList pointers (links and links_y) which contain the focusable content for the current document. The links_y list is sorted in y.x order. These lists get filled by calls to a_Focus_state_focusable_add from the DwPage. The location for focusable content is set through a_Focus_state_focusable_allocate, which gets called by the _allocate methods for DwPage and other widgets. The list points to FocusLink structures, which contain all information pertaining focusable content. There are currently two types of FocusLink: DW_FOCUSABLE_LINK and DW_FOCUSABLE_WIDGET. The former is used for anything which points to a link, the latter is used for form elements (which are embedded GTK+ widgets). Focusable content in a document is tagged as such by using the content type DW_CONTENT_FOCUSABLE. This content type can be used as a modifier for other content types, eg. a textual link has content type DW_CONTENT_TEXT|DW_CONTENT_FOCUSABLE. To get all focusable content in a document, use a dw_ext_iterator with a mask of DW_CONTENT_FOCUSABLE. See the source for more details on how to handle focusable content. When in doubt, ask around on the mailing list or contact the author (frank@unternet.org). TODO ==== Add more GTK+ bindings, replacing current key_press event handling. ...