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_clickthroughmozilla_embed_emit_mouse_signal;mozilla_embed_dom_mouse_down_cb—ge_dom_mouse_downthroughmozilla_embed_emit_mouse_signal;- and
mozilla_embed_dom_key_press_cb—ge-search-key-pressthroughg_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
Enteris 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
keyvalexplicitely 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-mozillatoextensions/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
embedfrom 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
Helpmenu. - 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
Shiftis pressed.Open in a new tab when
Ctrlis pressed. (It might be possible to open a new window, but which key would it be?Altmaybe?) 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 theControlkey from thekeyvalsent tomozilla_is_a_hotkey(), so this function might have to handle severalEntercases, with or withoutControland/orShiftpressed, for example. Hmm. After some tests, it looks likeControl+Enterdoesn't reach themozilla_is_a_hotkey()function. Not seen as aGdkEventby 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.hcontains theUSER_STYLESHEET_FILENAMEdefine. 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_FILENAMEdefine when one doesn't know in which directory it can be found? By the way,ephy-embed-prefs.his only about GConf keys, besides this define.Add an option to always have the same behaviour: pressing
Enteris needed even if there's only one link.
