Access keys (i.e., keyboard shortcuts) can be defined for common features. Something like the following: * 1 - Homepage * 2 - Search box * E - Edit * R - RecentChanges * H - History * P - Preferences * D - Discussion * S - Save the current page (when editing) * C - Cancel the current edit * V - Preview the current page Then, for example, in Firefox one could press Alt+Shift+E to edit the page. For links, this is implemented as: RecentChanges and for forms buttons: --[[JasonBlevins]], March 21, 2008 18:05 EDT - - - There were also a few thoughts about access keys on the [[main_discussion_page|index/discussion]]. Now moved to here: > Would anyone else find this a valuable addition. In oddmuse and instiki (the only other > wiki engines I am currently using, the edit, home, and submit link tags have an > accesskey attribute. I find it nice not to have to resort to the mouse for those > actions. However, it may not be something everyone appreciates. Any thoughts? > --[Mazirian](http://mazirian.com) > > > Maybe, although it would need to take the critisism at > > into account. > > >> Thank you for that link. Given that the edit link is the first thing you tab to > >> in the current layout, I guess it isn't all that necessary. I have had a > >> a user complaint recently that Alt-e in oddmuse was overriding his access > >> to the browser menu. ---- The main criticism there it seems is that some browsers implement access keys in a way (via the Alt key) that allows them to override built-in keyboard shortcuts. I believe this is not a problem any longer in Firefox (which uses the Shift+Alt prefix) but I suppose it could still be a problem in other browsers. Another criticism is that most browsers do not display the access keys that are defined. The [article][] cited on the main discussion page suggests underlining the relevant mnemonic. I think it would be sufficient to just list them in the basewiki documentation somewhere. [article]: http://www.cs.tut.fi/~jkorpela/forms/accesskey.html It's an unfortunate situation—I'd like an alternative to the rodent but there are quite a few downsides to using access keys. Tabbing isn't quite the same as a nice shortcut key. There's always Conkeror... --[[JasonBlevins]], March 22, 2008 10:35 EDT ---- I've written a plugin to implement access keys, configured using a wiki page similar to [[shortcuts]]. It works for links and most form submit buttons. As I am new to ikiwiki plugin writing, feedback is greatly appreciated. [[!toggle id="accesskeys" text="Toggle: accesskeys.pm"]] [[!toggleable id="accesskeys" text=""" #!/usr/bin/perl package IkiWiki::Plugin::accesskeys; use warnings; use strict; use IkiWiki 3.00; use CGI::FormBuilder; =head1 NAME accesskeys.pm - IkiWiki module to implement access keys (keyboard shortcuts) =head1 VERSION v.5.0 - initial version =head1 DESCRIPTION Access keys are defined on a page called B, using the C directive. Example: [[!accesskey command="Save Page" key="s"]] B may contain only alphanumeric characters (and spaces), and must be a complete match to the target link or submit button's display name. B may only be a single alphanumeric character. The access key is applied to the first matching link on a page (including header), or the first matching submit button in the @buttons array. The wiki must be completely rebuilt every time the B page changes. =head2 Sample accesskeys page [[!if test="enabled(accesskeys)" then="This wiki has accesskeys **enabled**." else="This wiki has accesskeys **disabled**."]] This page controls what access keys the wiki uses. * [[!accesskey command="Save Page" key="s"]] * [[!accesskey command="Cancel" key="c"]] * [[!accesskey command="Preview" key="v"]] * [[!accesskey command="Edit" key="e"]] * [[!accesskey command="RecentChanges" key="c"]] * [[!accesskey command="Preferences" key="p"]] * [[!accesskey command="Discussion" key="d"]] =head1 IMPLEMENTATION This plugin uses the following flow: =over 1 =item 1. Override default CGI::FormBuilder::submit function FormBuilder does not support any arbitrary modification of it's submit buttons, so in order to add the necessary attributes you have to intercept the internal function call which generates the formatted html for the submit buttons. Not pretty, but it works. =item 2. Get list of keys During the B stage the B source file is read (default F) to generate a list of defined keys. =item 3. Insert keys (links) Keys are inserted into links during the format stage. All defined commands are checked against the page's links and if there is a match the key is inserted. Only the first match for each command is processed. =item 4. Insert keys (FormBuilder buttons) FormBuilder pages are intercepted during formatting. Keys are inserted as above. =back =head1 TODO =over 1 =item * non-existant page links ex: ?Discussion =item * Support non-submit array buttons (like those added after the main group for attachments) =item * Support form fields (search box) =back =cut #=head1 HISTORY =head1 AUTHOR Written by Damian Small. =cut my %accesskeys = (); # Initialize original function pointer to FormBuilder::submit my $original_submit_function = \&{'CGI::FormBuilder::submit'}; # Override default submit function in FormBuilder { no strict 'refs'; no warnings; *{'CGI::FormBuilder::submit'} = \&submit_override; } sub submit_override { # Call the original function, and get the results my $contents = $original_submit_function->(@_); # Hack the results to add accesskeys foreach my $buttonName (keys %accesskeys) { $contents =~ s/()/$1 title="$buttonName [$accesskeys{$buttonName}]" accesskey="$accesskeys{$buttonName}"$2/; } return $contents; } sub import { hook(type => "getsetup", id => "accesskeys", call => \&getsetup); hook(type => "checkconfig", id => "accesskeys", call => \&checkconfig); hook(type => "preprocess", id => "accesskey", call => \&preprocess_accesskey); hook(type => "format", id => "accesskeys", call => \&format); } sub getsetup () { return plugin => { safe => 1, rebuild => 1, section => "widget", }, } sub checkconfig () { if (defined $config{srcdir} && length $config{srcdir}) { # Preprocess the accesskeys page to get all the access keys # defined before other pages are rendered. my $srcfile=srcfile("accesskeys.".$config{default_pageext}, 1); if (! defined $srcfile) { $srcfile=srcfile("accesskeys.mdwn", 1); } if (! defined $srcfile) { print STDERR sprintf(gettext("accesskeys plugin will not work without %s"), "accesskeys.".$config{default_pageext})."\n"; } else { IkiWiki::preprocess("accesskeys", "accesskeys", readfile($srcfile)); } } } sub preprocess_accesskey (@) { my %params=@_; if (! defined $params{command} || ! defined $params{key}) { error gettext("missing command or key parameter"); } # check the key if ($params{key} !~ /^[a-zA-Z0-9]$/) { error gettext("key parameter is not a single character"); } # check the command if ($params{command} !~ /^[a-zA-Z0-9 _]+$/) { error gettext("command parameter is not an alphanumeric string"); } # Add the access key: $accesskeys{$params{command}} = $params{key}; return sprintf(gettext("[%s] is the access key for command '%s'"), $params{key}, $params{command}); } sub format (@) { my %params = @_; my $contents = $params{content}; # If the accesskey page changes, all pages will need to be updated #debug("Adding dependency: for " . $params{page} . " to AccessKeys"); add_depends($params{page}, "AccessKeys"); # insert access keys foreach my $command (keys %accesskeys) { $contents =~ s/(]+)(>$command<\/a>)/$1 accesskey="$accesskeys{$command}"$2/; } # may need special handling for non-existant discussion links (and possibly other similar cases?) #$contents =~ s/(]+)(>\?<\/a>Discussion)/$1 accesskey="d"$2/; return $contents; } 1 [[!toggle id="accesskeys" text="hide accesskeys.pm"]] """]] --[[DamianSmall]] [[!tag wishlist]]