# # This file is a command-module for Dragonfly. # (c) Copyright 2008 by Christo Butcher # Licensed under the LGPL, see # """ Command-module for **Firefox** ============================================================================ This module offers direct control of the `Firefox `_ web browser. It requires the `mouseless-browsing `_ (mlb) add-on for reliable access to hyperlinks. 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 fields. Installation ---------------------------------------------------------------------------- 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 you next toggle your microphone or restart Natlink. Customization ---------------------------------------------------------------------------- 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 use. """ try: import pkg_resources pkg_resources.require("dragonfly >= 0.6.5beta1.dev-r76") except ImportError: pass 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) ") config.lang.close_n_tabs = Item("close (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 ") config.lang.back = Item("back []") config.lang.forward = Item("forward []") config.lang.next_tab = Item("next tab []") config.lang.prev_tab = Item("(previous | preev) tab []") config.lang.normal_size = Item("normal text size") config.lang.smaller_size = Item("smaller text size []") config.lang.bigger_size = Item("bigger text size []") config.lang.find = Item("find") config.lang.find_text = Item("find ") config.lang.find_next = Item("find next []") config.lang.submit = Item("submit") config.lang.submit_text = Item("submit ") config.lang.submit_clipboard = Item("submit (clipboard | clip board)") config.lang.link_open = Item("[link] [open]") config.lang.link_save = Item("save [link] [as]") config.lang.link_save_now = Item("save [link] now now") config.lang.link_select = Item("[link] select") config.lang.link_menu = Item("[link] (menu | pop up)") config.lang.link_force = Item("[link] force") config.lang.link_window = Item("[link] [in [new]] window") config.lang.link_tab = Item("[link] [in [new]] tab") config.lang.link_copy = Item("[link] copy") config.lang.link_copy_into_tab = Item("[link] copy into tab") config.lang.link_list = Item("[link] list") config.lang.link_submit = Item("[link] submit") config.lang.link_submit_text = Item("[link] submit ") config.lang.link_submit_clipboard = Item("[link] submit (clipboard | clip board)") config.lang.link_dictation_box = Item("edit [link] ") config.lang.link_assign_keyword = Item("assign [a] keyword to [link] ") config.lang.tabify_links = Item("tab if I ") config.lang.tabify_links_sep = Item("comma") config.lang.search_text = Item("[power] search [for] ") config.lang.search_keyword_text = Item("[power] search [for] ") config.lang.search_searchbar_text = Item("[power] search [for] ") config.lang.search_clipboard = Item("[power] search [for] (clipboard | clip board)") config.lang.search_keyword_clipboard = Item("[power] search [for] clipboard") config.lang.search_searchbar_clipboard = Item("[power] search [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 []": Function(start_sliding), } extras = [ Choice("direction", slide_directions), Choice("speed", slide_speeds), ] defaults = { "speed": slide_default_speed, } class SlideControlRule(MappingRule): mapping = { "[slide] []": 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