Foreword
Since epiphany is moving away from Gecko, this page will likely be unmaintained for quite some time. Hopefully, that extension will then get ported to WebKit.
Goal
Make epiphany able to
emphasize some shortcuts to ease the navigation through the links of a
given page, so that it becomes possible to access them with a single
key, instead of a bunch of TAB
hits. The goal is to clone
konqueror's Control
key behaviour.
Definition
The term hotkey will be preferred to accesskey, which is defined by the W3 Consortium, but looks like mostly unsupported. This term might be changed as soon as a better one is found.
Documentation
Many links are available.
Plans
As an
epiphany extension
as much as possible, but it looks like needed to add some code in
epiphany too. It seems that there's no way to catch key presses in the
embed mozilla widget, so that would have to be added (probably in
embed/
).
According to the
GtkMozEmbed signal reference
there are no mouse click callbacks, but there are in
EphyEmbed signal reference:
ge-dom-mouse-click
and ge-dom-mouse-down
. So it should be possible
to add something like ge-dom-key-down
, so as to determine the
pressed key.
Once it is done, the proposed way is the following: On Ctrl
press,
the accessibility mode is toggled. Off by default, when it turns to
on, the DOM is modified so as to emphasize some given characters in
the links, possibly using the first letter of each, but also avoiding
hotkey collision. To ease customization, using a span
tag could be
use at least at the beginning, so that changing a bit of CSS is
sufficient to have a nice display. When it is switch back to off, a
simple way to remove the added information would be to reload the
page, which would flush this.
At the moment, a javascript DOM modification is quite easy, based on the one published by Christian Schmidt, but it would be better to do it on epiphany side, so that the hotkey—URL mapping is kept where it is computed. This javascript basic implementation could still be used until the key handling is implemented, so as to get an overview.
Progress
Key presses
In embed/mozilla/mozilla-embed.cpp
, the following mapping happens:
mozilla_embed_dom_mouse_click_cb
—ge_dom_mouse_click
throughmozilla_embed_emit_mouse_signal
;mozilla_embed_dom_mouse_down_cb
—ge_dom_mouse_down
throughmozilla_embed_emit_mouse_signal
;- and
mozilla_embed_dom_key_press_cb
—ge-search-key-press
throughg_signal_emit_by_name
.
So it looks that no modification to the mozilla code in epiphany is needed. There's still a need of exposing an additional signal in epiphany.
Key presses (bis)
Just grep in epiphany-extensions
for key-press | key_press
, and
here it is:
/* Prototype taken from ephy-gesture.c */
static gboolean
dom_key_press_cb (GtkWidget *widget,
GdkEventKey *event,
EphySample2Extension *extension)
Unfortunately, it looks like it is not possible to receive the events when the focus is in an input text field, but that sounds like a good start.
Now let's work on epiphany-extensions
only, using sample-mozilla
as a basis:
git repository.
Proposed behaviour
h
enables the hotkeys, Esc
then disables them. Once enabled, if a
key is pressed, an eventual mapping is checked. If it's mapped, load
the link in the embed, if not, ignore it.
To store the mapping, the proposed structure is proposed: a linked
list of structures, containing: an guint
(the key value), the
old nsIDOMHTMLLinkElement
(backuped so that it can be restored once
the hotkeys are disabled), and the new nsIDOMHTMLLinkElement
(which
could be replaced by a const char*
, being the URL to load.
At the beginning, restoring the old nsIDOMHTMLLinkElement
could be
ignored.
At the beginning, when a hotkey matches several times, the first
occurrence is considered. Then, one could consider having a cycling
through all occurrences until Enter
is pressed, and a direct loading
when there's only one occurrence. Another way is to use additional
keys, as konqueror
does, but that means additional code to pick the
right one.
Browse the DOM to find the Anchors
It is done by getting the DOM toplevel, then querying each node, checking the Anchor (and not Link) ones, and modifying them, while keeping a copy of them, so that they can be restored once the hotkeys are disabled.
Here is an example of hotkeys enabled on http://www.google.fr/ with an hardcoded (quick & dirty) CSS style:
0.1 release
As of this release
(git tag),
it is possible to enable/disable the hotkeys using h
/Esc
, and to
browse the links on a first matching occurrence basis.
Next step: make it possible to browse the links when there are multiple key value occurrences, use only uppercase characters.
Proposed implementations:
When there's only a match, load the link directly. When there are several matches, cycle through them, and only link when
Enter
is pressed.When there are multiple matches, try and use another character of the link for the next occurrences. The implementation using
GSList *
could be a bit inefficient, beware. Also, what kind of character to use when all characters are already taken? A bit harder, left for later.
Later goals:
- Make the CSS style customizable.
Unicode handling, uppercase
The following functions are used to determine the key value to store/look for.
gchar g_ascii_toupper (gchar c);
gboolean g_unichar_isalnum (gunichar c);
Later...
Maybe update the statusbar when there are several links, explaining
one has to use Enter
to validate the current link.
Note to self
Don't forget to copy the objects passed to g_hash_table_insert
,
especially if they are integers.
As of 0.2
[Fixed] Troubles with some pages, e.g. on http://news.google.fr/, but might be unrelated to the number of links, though.
[Fixed] When going back and forth, the extension toggling appears to be buggy. Hooking another even might be sufficient to fix this.
An additional feature could be back-cycling, which could be achieved
when Shift
, which can be detected thanks to:
guint state; a bit-mask representing the state of the modifier
keys (e.g. Control, Shift and Alt) and the pointer buttons. See
GdkModifierType.
Another alternative/configuration option
To have a visible emphasis, it is possible to call Focus()
on the
selected item, but the way it is focussed might be unpleasant. That's
why it has been implemented the following way: Focus()
is called so
that the page scrolls to the appropriate location if needed, then
Blur()
is called so that there's no visible trace of the previsou
Focus()
call.
0.3 release
Just two things:
- [Improvement]
Focus()/Blur()
calls. - [Major fix] Fixes crash when an empty link is encountered, by initializing
keyval
explicitely to0
. Hopefully epiphany shouldn't crash anymore.
Next targets:
- Handle nested tags (e.g. contained
<b>
,<strong>
, etc. tags). - Handle links beginning with spaces (either
[space]
,
and so on).
Known bug
- Gmail sounds like not functional, and might not be trivial to debug, there's a lot of javascript and not that much HTML.
Installation on debian sid (and maybe lenny)
Just do the following the first time:
git-clone git://git.debian.org/git/users/kibi-guest/epiphany-extensions.git
cd epiphany-extensions
DEB_BUILD_OPTIONS=nostrip debuild -us -uc -b -nc # Some Build-Depends may
# need to be installed.
sudo debi # Installs the generated binary package
pkill epiphany && epiphany # Then Tools>Extensions, and activate Hotkeys
To update:
cd extensions/hotkeys # Or in the inverse order, not important
git-pull # Merge remote changes into local working copy
make # Optional, make install will call it if needed
sudo make install # Update the .so in /usr/lib/epiphany/2.18
pkill epiphany && epiphany
0.4 release
- Moved from
extensions/sample-mozilla
toextensions/hotkeys
, with proper copyright entries. Restored the ancient tree. - Added an icon indicating the current hotkeys status.
- Fixed bad tab handling. Now the extension should just behave fine with several tabs (that was just an horror, really). There are still problems when several windows are involved, but at least it sounds less critical than non-functional tabs.
Next features/TODOs
- [Done] Add a textbox displaying the number of links.
- [Done] Factor some parts of the code (hotkeys enabling/disabling), remove
the
embed
from the structure if one is certain (or can make certain) that the tab sync is called when finalizing. Putting a call in theephy_hotkeys_extension_finalize()
function should be sufficient, so that the structures are freed before closing. - Implement the above-mentioned next targets.
- Add configuration items (accessible through an UI?)
- Try using additional CSS style to let the user customize the hotkeys display.
How to implement these features
[Done] 1st target: first character isn't alphanum()
Move to the next element. If it is '<', call
continue
(at least until the 2nd target is implemented).Otherwise, see whether that other character is alphanum(), then move to a if needed.
2nd target: nested element: If there are nested elements, dig further if there's only a hierarchy of modifier elements (b, i, strong, font), until... what?
Maybe until InnerHTML doesn't contain any '<' anymore?
Maybe until there's no more HTMLElement child(ren)?
Problems/remarks
[Done] What if a link contains entity-encoded characters? No problem since the InnerHTML string is encoded using HTML entities, so an opening ‘&’ should always match a closing ‘;’.
0.5 release
- [New] Statusbar gets an icon and a label displaying the number of links when the hotkeys are enabled.
- [New] CSS can be customised through the user stylesheet in Epiphany's preferences. No hardcoded default properties are used anymore. See the README file in the sources for an example (and full instructions).
- [New] Handle the cases where the first character of a link isn't alphanumerical. Previously, the link was dropped, now the next characters are considered. Nested tags aren't supported yet, though.
- Code cleanup (with no user-visible change).
Idea to handle nested tags
To be able to handle the nested tags, it is of course possible to
analyze the tree, but an alternative way could be used: when an <
character is encountered, search for a matching >
. The problem is
that it might break on things like that:
<a href="/location"><img src="someimage>.png" >Foo</a>
which would result in having the p
of png
being defined as the
hotkey, and the additional <span>
being embedded in the src
attribute. Hopefully such things get escaped (and extra spaces get
munged):
<img src="someimage%3E.png">Foo</a>
Further tasks
- [Done] Add help accessible through the
Help
menu. - I18N/L10N.
- Use the clickable item to popup the instructions to set the CSS and an example?
- Investigate the disparition of the RSS icon when the hotkeys get activated.
0.6 release
- [New] Handle nested tags
(e.g.
<a href="..."><b>Bold links</b></a>
). - [Fix] Re-ordered instructions for the status of hotkeys display, so that it is not possible to either disable the hotkeys while they are still being computed, or disable the hotkeys twice in a row. That prevents two kinds of (SEGV) crashes.
Fetching the sources
It looks like it is not possible to mix git-svn
and git-fetch
…
Well, see the first post tagged epiphany.
0.7 release
- [New] A manual entry has been added with introduction, usage, configuration (with an example), and limitations.
Further ideas
[Done] Add backcycling when
Shift
is pressed.Open in a new tab when
Ctrl
is pressed. (It might be possible to open a new window, but which key would it be?Alt
maybe?) Interesting thinks are inephy-link.h
(public API):ephy_link_open()
, with some nice flags. A problem, though: it might be difficult (if not impossible) to substract theControl
key from thekeyval
sent tomozilla_is_a_hotkey()
, so this function might have to handle severalEnter
cases, with or withoutControl
and/orShift
pressed, for example. Hmm. After some tests, it looks likeControl+Enter
doesn't reach themozilla_is_a_hotkey()
function. Not seen as aGdkEvent
by the DOM, maybe?When either the hotkeys get activated or the browser/extension gets started (whatever is OK with both performance and usability), see whether the user (custom) stylesheet contains a given identifier. If it does, just use the
<span>
tags as they are used now. If the CSS doesn't contain such identifier, use an hardcoded default style in thestyle=
attribute, so that the extension is usable without any configuration, and remains fully customizable to ones needs. Hopefullyephy-embed-prefs.h
contains theUSER_STYLESHEET_FILENAME
define. Unfortunately, it would be needed to have access to the (private)ephy_dot_dir()
for it to be useful, so that we can concat'em (it is located inlibs/ephy-file-helpers.c
). Given the code ofephy_file_helpers_init()
(same file), it is unlikely to be duplicated. Deadend until one assumes a particular location? :/ (e.g.~/.gnome2/epiphany
).The question is: how would one benefit from the
USER_STYLESHEET_FILENAME
define when one doesn't know in which directory it can be found? By the way,ephy-embed-prefs.h
is only about GConf keys, besides this define.Add an option to always have the same behaviour: pressing
Enter
is needed even if there's only one link.