dragonfly-grammars/_firefox.py

349 lines
14 KiB
Python
Raw Normal View History

2019-08-23 13:27:37 -05:00
#
# This file is a command-module for Dragonfly.
# (c) Copyright 2008 by Christo Butcher
# Licensed under the LGPL, see <http://www.gnu.org/licenses/>
#
"""
Command-module for **Firefox**
============================================================================
2021-02-12 12:26:10 -06:00
This module offers direct control of the `Firefox
<http://www.mozilla.com/en-US/firefox/>`_ web browser. It
requires the `mouseless-browsing
<https://addons.mozilla.org/en-US/firefox/addon/879>`_
2019-08-23 13:27:37 -05:00
(mlb) add-on for reliable access to hyperlinks.
2021-02-12 12:26:10 -06:00
This module includes direct searching using Firefox's
search bar and Firefox's keyword searching. It also
allows single-utterance submitting of text into form text
2019-08-23 13:27:37 -05:00
fields.
Installation
----------------------------------------------------------------------------
2021-02-12 12:26:10 -06:00
If you are using DNS and Natlink, simply place this file in you Natlink
macros directory. It will then be automatically loaded by Natlink when
2019-08-23 13:27:37 -05:00
you next toggle your microphone or restart Natlink.
Customization
----------------------------------------------------------------------------
2021-02-12 12:26:10 -06:00
Users should customize this module by editing its
configuration file. In this file they should edit the
``search.searchbar`` and ``search.keywords`` settings to
match their own personal search preferences. These
variables map *what you say* to which *search engines* to
2019-08-23 13:27:37 -05:00
use.
"""
from dragonfly import *
#---------------------------------------------------------------------------
# Set up this module's configuration.
config = Config("Firefox control")
config.search = Section("Search-related section")
config.search.keywords = Item(
default={
"wikipedia": "wikipedia",
},
doc="Mapping of spoken-forms to Firefox search-keywords.",
)
config.search.searchbar = Item(
default=[
"google",
"yahoo",
"amazon",
"answers",
"creative commons",
"eBay",
"wikipedia",
],
doc="Spoken-forms of search engines in the Firefox search-bar; they must be given in the same order here as they are available in Firefox.",
)
config.lang = Section("Language section")
config.lang.new_win = Item("new (window | win)")
config.lang.new_tab = Item("new (tab | sub)")
config.lang.close_tab = Item("close (tab | sub)")
config.lang.close_tab_n = Item("close (tab | sub) <n>")
config.lang.close_n_tabs = Item("close <n> (tabs | subs)")
config.lang.address_bar = Item("address [bar]")
config.lang.copy_address = Item("copy address")
config.lang.paste_address = Item("paste address")
config.lang.search_bar = Item("search bar")
config.lang.go_home = Item("go home")
config.lang.stop_loading = Item("stop loading")
config.lang.toggle_tags = Item("toggle tags")
config.lang.fresh_tags = Item("fresh tags")
config.lang.caret_browsing = Item("(caret | carrot) browsing")
config.lang.bookmark_page = Item("bookmark [this] page")
config.lang.save_page_as = Item("save [page | file] as")
config.lang.print_page = Item("print [page | file]")
config.lang.show_tab_n = Item("show tab <n>")
config.lang.back = Item("back [<n>]")
config.lang.forward = Item("forward [<n>]")
config.lang.next_tab = Item("next tab [<n>]")
config.lang.prev_tab = Item("(previous | preev) tab [<n>]")
config.lang.normal_size = Item("normal text size")
config.lang.smaller_size = Item("smaller text size [<n>]")
config.lang.bigger_size = Item("bigger text size [<n>]")
config.lang.find = Item("find")
config.lang.find_text = Item("find <text>")
config.lang.find_next = Item("find next [<n>]")
config.lang.submit = Item("submit")
config.lang.submit_text = Item("submit <text>")
config.lang.submit_clipboard = Item("submit (clipboard | clip board)")
config.lang.link_open = Item("[link] <link> [open]")
config.lang.link_save = Item("save [link] <link> [as]")
config.lang.link_save_now = Item("save [link] <link> now now")
config.lang.link_select = Item("[link] <link> select")
config.lang.link_menu = Item("[link] <link> (menu | pop up)")
config.lang.link_force = Item("[link] <link> force")
config.lang.link_window = Item("[link] <link> [in [new]] window")
config.lang.link_tab = Item("[link] <link> [in [new]] tab")
config.lang.link_copy = Item("[link] <link> copy")
config.lang.link_copy_into_tab = Item("[link] <link> copy into tab")
config.lang.link_list = Item("[link] <link> list")
config.lang.link_submit = Item("[link] <link> submit")
config.lang.link_submit_text = Item("[link] <link> submit <text>")
config.lang.link_submit_clipboard = Item("[link] <link> submit (clipboard | clip board)")
config.lang.link_dictation_box = Item("edit [link] <link>")
config.lang.link_assign_keyword = Item("assign [a] keyword to [link] <link>")
config.lang.tabify_links = Item("tab if I <links>")
config.lang.tabify_links_sep = Item("comma")
config.lang.search_text = Item("[power] search [for] <text>")
config.lang.search_keyword_text = Item("[power] search <keyword> [for] <text>")
config.lang.search_searchbar_text = Item("[power] search <searchbar> [for] <text>")
config.lang.search_clipboard = Item("[power] search [for] (clipboard | clip board)")
config.lang.search_keyword_clipboard = Item("[power] search <keyword> [for] clipboard")
config.lang.search_searchbar_clipboard = Item("[power] search <searchbar> [for] clipboard")
#config.generate_config_file()
config.load()
#---------------------------------------------------------------------------
# Check and prepare search-related config values.
keywords = config.search.keywords
searchbar = dict([(n,i) for i,n in enumerate(config.search.searchbar)])
#---------------------------------------------------------------------------
# Create the rule to match mouseless-browsing link numbers.
class LinkRule(Rule):
def __init__(self):
element = Number(zero=True)
Rule.__init__(self, "link_rule", element, exported=False)
def value(self, node):
# Format and return keystrokes to select the link.
digits = str(node.children[0].value())
link_keys = "f6,s-f6," + ",".join(["numpad"+i for i in digits])
self._log.debug("Link keys: %r" % link_keys)
return link_keys
link = RuleRef(name="link", rule=LinkRule())
#---------------------------------------------------------------------------
# Create the main command rule.
class CommandRule(MappingRule):
mapping = {
config.lang.new_win: Key("c-n"),
config.lang.new_tab: Key("c-t"),
config.lang.close_tab: Key("c-w"),
config.lang.close_tab_n: Key("0, %(n)d, enter/20, c-w"),
config.lang.close_n_tabs: Key("c-w/20:%(n)d"),
config.lang.address_bar: Key("a-d"),
config.lang.copy_address: Key("a-d, c-c"),
config.lang.paste_address: Key("a-d, c-v, enter"),
config.lang.search_bar: Key("c-k"),
config.lang.go_home: Key("a-home"),
config.lang.stop_loading: Key("escape"),
config.lang.toggle_tags: Key("f12"),
config.lang.fresh_tags: Key("f12, f12"),
config.lang.caret_browsing: Key("f7"),
config.lang.bookmark_page: Key("c-d"),
config.lang.save_page_as: Key("c-s"),
config.lang.print_page: Key("c-p"),
config.lang.show_tab_n: Key("0, %(n)d, enter"),
config.lang.back: Key("a-left/15:%(n)d"),
config.lang.forward: Key("a-right/15:%(n)d"),
config.lang.next_tab: Key("c-tab:%(n)d"),
config.lang.prev_tab: Key("cs-tab:%(n)d"),
config.lang.normal_size: Key("a-v/20, z/20, r"),
config.lang.smaller_size: Key("c-minus:%(n)d"),
config.lang.bigger_size: Key("cs-equals:%(n)d"),
config.lang.submit: Key("enter"),
config.lang.submit_text: Text("%(text)s") + Key("enter"),
config.lang.submit_clipboard: Key("c-v, enter"),
config.lang.find: Key("c-f"),
config.lang.find_text: Key("c-f") + Text("%(text)s"),
config.lang.find_next: Key("f3/10:%(n)d"),
config.lang.link_open: Key("%(link)s, enter"),
config.lang.link_save: Key("%(link)s, shift/10, apps/20, k"),
config.lang.link_save_now: Key("%(link)s, shift/10, apps/20, k")
+ WaitWindow(title="Enter name of file")
+ Pause("20") + Key("enter"),
config.lang.link_select: Key("%(link)s, shift"),
config.lang.link_menu: Key("%(link)s, shift/10, apps"),
config.lang.link_force: Key("%(link)s, shift/10, enter"),
config.lang.link_window: Key("%(link)s, shift/10, apps/20, w"),
config.lang.link_tab: Key("%(link)s, shift/10, apps/20, t"),
config.lang.link_copy: Key("%(link)s, shift/10, apps/20, a"),
config.lang.link_copy_into_tab: Key("%(link)s, shift/10, apps/20, a/10, c-t/20, c-v, enter"),
config.lang.link_list: Key("%(link)s, enter, a-down"),
config.lang.link_submit: Key("%(link)s, enter/30, enter"),
config.lang.link_submit_text: Key("%(link)s, enter/30")
+ Text("%(text)s") + Key("enter"),
config.lang.link_submit_clipboard: Key("%(link)s, enter/30, c-v, enter"),
config.lang.link_dictation_box: Key("%(link)s, enter/30, cs-d"),
config.lang.link_assign_keyword: Key("%(link)s, enter/10, apps/20, k"),
config.lang.search_text: Key("c-k")
+ Text("%(text)s") + Key("enter"),
config.lang.search_searchbar_text: Key("c-k, c-up:20, c-down:%(searchbar)d")
+ Text("%(text)s") + Key("enter"),
config.lang.search_keyword_text: Key("a-d")
+ Text("%(keyword)s %(text)s")
+ Key("enter"),
config.lang.search_clipboard: Key("c-k, c-v, enter"),
config.lang.search_searchbar_clipboard: Key("c-k, c-up:20, c-down:%(searchbar)d, c-v, enter"),
config.lang.search_keyword_clipboard: Key("a-d") + Text("%(keyword)s")
+ Key("c-v, enter"),
}
extras = [
link,
IntegerRef("n", 1, 20),
Dictation("text"),
Choice("keyword", keywords),
Choice("searchbar", searchbar),
]
defaults = {
"n": 1,
}
#---------------------------------------------------------------------------
# Create the command rule for sliding.
slide_directions = {
"up": (0,-1),
"down": (0,+1),
}
slide_speeds = {
"1": 10,
"2": 20,
"3": 30,
"4": 40,
}
slide_default_speed = 15
slide_start_spec = "(-15,0.6)"
slide_grammar = None
def start_sliding(direction, speed):
offset_x = direction[0] * speed
offset_y = direction[1] * speed
offset_spec = "<%d,%d>" % (offset_x, offset_y)
action = Key("escape")
action.execute()
action = Mouse("%s/25, middle/25, %s" % (slide_start_spec, offset_spec))
action.execute()
global slide_grammar
if not slide_grammar:
slide_grammar = Grammar("Firefox slide grammar")
slide_grammar.add_rule(SlideControlRule())
slide_grammar.load()
slide_grammar.set_exclusive(True)
def stop_sliding():
action = Key("escape")
action.execute()
global slide_grammar
if slide_grammar:
slide_grammar.set_exclusive(False)
slide_grammar.unload()
slide_grammar = None
class SlideStartRule(MappingRule):
mapping = {
"slide <direction> [<speed>]": Function(start_sliding),
}
extras = [
Choice("direction", slide_directions),
Choice("speed", slide_speeds),
]
defaults = {
"speed": slide_default_speed,
}
class SlideControlRule(MappingRule):
mapping = {
"[slide] <direction> [<speed>]": Function(start_sliding),
"[slide] stop": Function(stop_sliding),
}
extras = [
Choice("direction", slide_directions),
Choice("speed", slide_speeds),
]
defaults = {
"speed": slide_default_speed,
}
#---------------------------------------------------------------------------
# Create the main command rule.
class TabifyRule(CompoundRule):
spec = config.lang.tabify_links
sep_element = Compound(config.lang.tabify_links_sep)
repeat_element = Sequence([sep_element, link])
repetitions = Repetition(child=repeat_element, min=0, max=8)
extras = [Sequence(name="links", children=(link, repetitions))]
def _process_recognition(self, node, extras):
link_nodes = node.get_children_by_name("link")
for n in link_nodes:
action = Key(n.value()) + Key("shift/10, apps/20, t/20")
action.execute()
#---------------------------------------------------------------------------
# Create and load this module's grammar.
context = AppContext(executable="firefox")
grammar = Grammar("firefox_general", context=context)
grammar.add_rule(CommandRule())
grammar.add_rule(SlideStartRule())
grammar.add_rule(TabifyRule())
grammar.load()
# Unload function which will be called by natlink at unload time.
def unload():
global grammar
if grammar: grammar.unload()
grammar = None