示例#1
0
def initialize():
    global SETTINGS, SYSTEM_INFORMATION
    global _BASE_PATH, _USER_DIR, _SETTINGS_PATH

    if SETTINGS is not None:
        return

    # calculate prerequisites
    SYSTEM_INFORMATION = _get_platform_information()
    _BASE_PATH = str(Path(__file__).resolve().parent.parent)
    if os.getenv("CASTER_USER_DIR") is not None:
        _USER_DIR = os.getenv("CASTER_USER_DIR")
    else:
        _USER_DIR = user_data_dir(appname="caster", appauthor=False)
    _SETTINGS_PATH = str(Path(_USER_DIR).joinpath("settings/settings.toml"))

    # Kick everything off.
    SETTINGS = _init(_SETTINGS_PATH)
    from castervoice.lib.migration import UserDirUpdater
    migrator = UserDirUpdater(_USER_DIR)
    migrator.create_user_dir_directories()
    migrator.update_user_dir_packages_to_v1_7_0()
    migrator.update_bringme_toml_to_v1_7_0()
    _debugger_path = SETTINGS["paths"]["REMOTE_DEBUGGER_PATH"]  # pylint: disable=invalid-sequence-index
    if _debugger_path not in sys.path and os.path.isdir(_debugger_path):
        sys.path.append(_debugger_path)

    # set up printer -- it doesn't matter where you do this; messages will start printing to the console after this
    dh = printer.get_delegating_handler()
    dh.register_handler(printer.SimplePrintMessageHandler())
    # begin using printer
    printer.out("Caster User Directory: {}".format(_USER_DIR))
示例#2
0
def _validate_engine_path():
    '''
    Validates path 'Engine Path' in settings.toml
    '''
    if not sys.platform.startswith('win'):
        return ''
    try:
        import natlink  # pylint: disable=import-error
    except ImportError:
        return ''
    if os.path.isfile(_SETTINGS_PATH):
        with io.open(_SETTINGS_PATH, "rt", encoding="utf-8") as toml_file:
            data = tomlkit.loads(toml_file.read()).value
            engine_path = data["paths"]["ENGINE_PATH"]
            if os.path.isfile(engine_path):
                return engine_path
            else:
                engine_path = _find_natspeak()
                data["paths"]["ENGINE_PATH"] = engine_path
                try:
                    formatted_data = str(tomlkit.dumps(data))
                    with io.open(_SETTINGS_PATH, "w",
                                 encoding="utf-8") as toml_file:
                        toml_file.write(formatted_data)
                    printer.out(
                        "Setting engine path to {}".format(engine_path))
                except Exception as e:
                    printer.out("Error saving settings file {} {} ".format(
                        e, _SETTINGS_PATH))
                return engine_path
    else:
        return _find_natspeak()
示例#3
0
def initialize():
    global SETTINGS, SYSTEM_INFORMATION
    global _BASE_PATH, _USER_DIR, _SETTINGS_PATH

    if SETTINGS is not None:
        return

    # calculate prerequisites
    SYSTEM_INFORMATION = _get_platform_information()
    _BASE_PATH = os.path.realpath(__file__).rsplit(os.path.sep + "lib",
                                                   1)[0].replace("\\", "/")
    _USER_DIR = _validate_user_dir().replace("\\", "/")
    _SETTINGS_PATH = os.path.normpath(
        os.path.join(_USER_DIR, "data/settings.toml"))

    for directory in ["data", "rules", "transformers", "hooks", "sikuli"]:
        d = _USER_DIR + "/" + directory
        if not os.path.exists(d):
            os.makedirs(d)

    # Kick everything off.
    SETTINGS = _init(_SETTINGS_PATH)
    _debugger_path = SETTINGS["paths"]["REMOTE_DEBUGGER_PATH"]
    if _debugger_path not in sys.path and os.path.isdir(_debugger_path):
        sys.path.append(_debugger_path)
    printer.out("Caster User Directory: " + _USER_DIR)
示例#4
0
    def register_rule(self, rule_class, details):
        """
        Takes a newly loaded copy of a rule (MappingRule or MergeRule),
        validates it, stores it for later instantiation, and adds it to the
        file tracking list.

        :param rule_class:
        :param details:
        :return:
        """
        class_name = rule_class.__name__

        # do not load or watch invalid rules
        invalidation = self._get_invalidation(rule_class, details)
        if invalidation is not None:
            print("invalidated by something or other")
            printer.out(invalidation)
            return

        _set_rdescripts(rule_class.mapping, class_name)
        '''
        rule should be safe for loading at this point: register it
        but do not load here -- this method only registers
        '''
        managed_rule = ManagedRule(rule_class, details)
        self._managed_rules[class_name] = managed_rule
        # set up de/activation command
        self._activator.register_rule(managed_rule)
        # watch this file for future changes
        if not details.watch_exclusion:
            self._reload_observable.register_watched_file(details.get_filepath())
示例#5
0
def clear_log():
    # Function to clear status window.
    # Natlink status window not used an out-of-process mode.
    # TODO: window_exists utilized when engine launched through Dragonfly CLI via bat in future
    try:
        if WIN32:
            clearcmd = "cls"  # Windows OS
        else:
            clearcmd = "clear"  # Linux
        if get_current_engine().name == 'natlink':
            import natlinkstatus  # pylint: disable=import-error
            status = natlinkstatus.NatlinkStatus()
            if status.NatlinkIsEnabled() == 1:
                import win32gui  # pylint: disable=import-error
                handle = get_window_by_title(
                    "Messages from Python Macros") or get_window_by_title(
                        "Messages from Natlink")
                rt_handle = win32gui.FindWindowEx(handle, None, "RICHEDIT",
                                                  None)
                win32gui.SetWindowText(rt_handle, "")
            else:
                if window_exists(windowname="Caster: Status Window"):
                    os.system(clearcmd)
        else:
            if window_exists(windowname="Caster: Status Window"):
                os.system(clearcmd)
            else:
                printer.out("clear_log: Not implemented with GUI")
    except Exception as e:
        printer.out(e)
示例#6
0
    def _bring_add(self, launch_type, key):
        # Add current program or highlighted text to bring me
        if launch_type == "program":
            path = utilities.get_active_window_path()
            if not path:
                # dragonfly.get_current_engine().speak("program not detected")
                printer.out("Program path for bring me not found ")
        elif launch_type == 'file':
            files = utilities.get_selected_files(folders=False)
            path = files[0] if files else None  # or allow adding multiple files
        elif launch_type == 'folder':
            files = utilities.get_selected_files(folders=True)
            path = files[
                0] if files else None  # or allow adding multiple folders
        else:
            Key("a-d/5").execute()
            fail, path = context.read_selected_without_altering_clipboard()
            if fail == 2:
                # FIXME: A better solution would be to specify a number of retries and the time interval.
                time.sleep(0.1)
                _, path = context.read_selected_without_altering_clipboard()
                if not path:
                    printer.out("Selection for bring me not found ")
            Key("escape").execute()
        if not path:
            # logger.warn('Cannot add %s as %s to bringme: cannot get path', launch, key)
            return

        config_copy = self._config.get_copy()
        config_copy[launch_type][str(key)] = path
        self._refresh(config_copy)
示例#7
0
def focus_mousegrid(gridtitle):
    '''
    Loops over active windows for MouseGrid window titles. Issue #171
    When MouseGrid window titles found focuses MouseGrid overly.
    '''
    if WIN32:
        # May not be needed for Linux/Mac OS - testing required
        try:
            for i in range(9):
                matches = Window.get_matching_windows(title=gridtitle,
                                                      executable="python")
                if not matches:
                    Pause("50").execute()
                else:
                    break
            if matches:
                for handle in matches:
                    handle.set_foreground()
                    break
            else:
                printer.out(
                    "`Title: `{}` no matching windows found".format(gridtitle))
        except Exception as e:
            printer.out("Error focusing MouseGrid: {}".format(e))
    else:
        pass
示例#8
0
    def _handle_companion_rules(self, enabled_diff):
        newly_enabled = list()
        newly_disabled = set()
        diff = [(rcn, True) for rcn in enabled_diff.newly_enabled] + \
               [(rcn, False) for rcn in enabled_diff.newly_disabled]
        for difference in diff:
            rcn = difference[0]
            enabled = difference[1]
            for companion_rcn in self._companion_config.get_companions(rcn):
                if companion_rcn in self._managed_rules:
                    mr = self._managed_rules[companion_rcn]
                    is_ccr = mr.get_details().declared_ccrtype is not None
                    if is_ccr:
                        raise InvalidCompanionConfigurationError(companion_rcn)

                    self._change_rule_enabled(companion_rcn, enabled, False)
                    if enabled:
                        newly_enabled.append(companion_rcn)
                    else:
                        newly_disabled.add(companion_rcn)
                else:
                    invalid_msg = "Invalid companion rule (not loaded): {}"
                    printer.out(invalid_msg.format(companion_rcn))

        return RulesEnabledDiff(enabled_diff.newly_enabled + newly_enabled,
                                enabled_diff.newly_disabled | newly_disabled)
示例#9
0
def reboot():
    # TODO: Save engine arguments elsewhere and retrieves for reboot. Allows for user-defined arguments.
    popen_parameters = []
    engine = get_current_engine()
    if engine.name == 'kaldi':
        engine.disconnect()
        subprocess.Popen([sys.executable, '-m', 'dragonfly', 'load', '_*.py', '--engine', 'kaldi',  '--no-recobs-messages'])
    if engine.name == 'sapi5inproc':
        engine.disconnect()
        subprocess.Popen([sys.executable, '-m', 'dragonfly', 'load', '--engine', 'sapi5inproc', '_*.py', '--no-recobs-messages'])
    if engine.name in ["sapi5shared", "sapi5"]:
        popen_parameters.append(settings.SETTINGS["paths"]["REBOOT_PATH_WSR"])
        popen_parameters.append(settings.SETTINGS["paths"]["WSR_PATH"])
        printer.out(popen_parameters)
        subprocess.Popen(popen_parameters)
    if engine.name == 'natlink':
        import natlinkstatus # pylint: disable=import-error
        status = natlinkstatus.NatlinkStatus()
        if status.NatlinkIsEnabled() == 1:
            # Natlink in-process
            popen_parameters.append(settings.SETTINGS["paths"]["REBOOT_PATH"])
            popen_parameters.append(settings.SETTINGS["paths"]["ENGINE_PATH"])
            username = status.getUserName()
            popen_parameters.append(username)
            printer.out(popen_parameters)
            subprocess.Popen(popen_parameters)
        else:
           # Natlink out-of-process
            engine.disconnect()
            subprocess.Popen([sys.executable, '-m', 'dragonfly', 'load', '--engine', 'natlink', '_*.py', '--no-recobs-messages'])
示例#10
0
    def test_broken_handler(self):
        """
        Tests that messages passed to a broken handler will still be printed to the console.
        """
        # set up arg capture on default handler
        args_capturer = _PrinterArgsCapturer()
        self._delegating_handler._error_handler._print = args_capturer._print

        # create and register a broken handler
        class BrokenHandler(BaseMessageHandler):
            def __init__(self):
                super(BrokenHandler, self).__init__()

            def handle_message(self, items):
                raise Exception("something unexpected happened")

        self._delegating_handler.register_handler(BrokenHandler())

        # queue up messages
        printer.out("asdf")

        # wait for the timer on the other thread
        time.sleep(1.5)

        # assert that the default handler still printed the message despite the error
        self.assertEqual("asdf", args_capturer.captured_args[0])
示例#11
0
    def idem_import_module(self, module_name, fn_name):
        """
        Returns the content requested from the specified module.
        """
        module = None
        if module_name in _MODULES:
            module = _MODULES[module_name]
            module = self._reimport_module(module)
        else:
            module = self._import_module(module_name)

        if module is None:
            return None

        # get them and add them to nexus
        fn = None
        try:
            fn = getattr(module, fn_name)
        except AttributeError:
            msg = "No method named '{}' was found on '{}'. Did you forget to implement it?".format(fn_name, module_name)
            if ContentLoader._detect_pythonpath_module_name_in_use(module):
                msg = "{} module name is already in use: {}".format(module_name, module.__file__)
            printer.out(msg)
            return None
        except:
            msg = "Error loading module '{}'."
            printer.out(msg.format(module_name))
            return None

        return fn()
示例#12
0
def get_clipboard_files(folders=False):
    '''
    Enumerate clipboard content and return files either directly copied or
    highlighted path copied
    '''
    if sys.platform.startswith('win'):
        import win32clipboard  # pylint: disable=import-error
        files = None
        win32clipboard.OpenClipboard()
        f = get_clipboard_formats()
        if win32clipboard.CF_HDROP in f:
            files = win32clipboard.GetClipboardData(win32clipboard.CF_HDROP)
        elif win32clipboard.CF_UNICODETEXT in f:
            files = [
                win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)
            ]
        elif win32clipboard.CF_TEXT in f:
            files = [win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)]
        elif win32clipboard.CF_OEMTEXT in f:
            files = [
                win32clipboard.GetClipboardData(win32clipboard.CF_OEMTEXT)
            ]
        if folders:
            files = [f for f in files if os.path.isdir(f)] if files else None
        else:
            files = [f for f in files if os.path.isfile(f)] if files else None
        win32clipboard.CloseClipboard()
        return files
    else:
        printer.out("get_clipboard_files: Not implemented for OS")
示例#13
0
    def receive(self, file_path_changed):
        """
        This being called indicates that the file at file_path_changed has been updated
        and that it should be reloaded and potentially replace the old copy.

        DO NOT CALL THIS MANUALLY. Should only be called by the reload observable.

        :param file_path_changed: str
        :return:
        """
        try:
            module_name = GrammarManager._get_module_name_from_file_path(
                file_path_changed)
            rule_class, details = self._content_loader.idem_import_module(
                module_name, ContentType.GET_RULE)
            # re-register:
            self.register_rule(rule_class, details)

            class_name = rule_class.__name__
            if class_name in self._config.get_enabled_rcns_ordered():
                self._delegate_enable_rule(class_name, True)
        except Exception as error:
            printer.out(
                'Grammar Manager: {} - See error message above'.format(error))
            self._hooks_runner.execute(OnErrorEvent())
示例#14
0
def initialize():
    global SETTINGS, SYSTEM_INFORMATION
    global _BASE_PATH, _USER_DIR, _SETTINGS_PATH

    if SETTINGS is not None:
        return

    # calculate prerequisites
    SYSTEM_INFORMATION = _get_platform_information()
    _BASE_PATH = str(Path(__file__).resolve().parent.parent)
    if os.getenv("CASTER_USER_DIR") is not None:
        _USER_DIR = os.getenv("CASTER_USER_DIR")
    else:
        _USER_DIR = user_data_dir(appname="caster", appauthor=False)
    _SETTINGS_PATH = str(Path(_USER_DIR).joinpath("settings/settings.toml"))

    for directory in [
            "data", "rules", "transformers", "hooks", "sikuli", "settings"
    ]:
        d = Path(_USER_DIR).joinpath(directory)
        d.mkdir(parents=True, exist_ok=True)
    # Kick everything off.
    SETTINGS = _init(_SETTINGS_PATH)
    _debugger_path = SETTINGS["paths"]["REMOTE_DEBUGGER_PATH"]  # pylint: disable=invalid-sequence-index
    if _debugger_path not in sys.path and os.path.isdir(_debugger_path):
        sys.path.append(_debugger_path)
    printer.out("Caster User Directory: {}".format(_USER_DIR))
示例#15
0
 def __init__(self, parser=TRParser):
     try:
         parser_instance = parser()
         self._definitions = parser_instance.create_definitions()
         if len(self._definitions) > 0:
             printer.out("Text replacing transformer from file 'words.txt' activated ...")
     except Exception:
         printer.out("Unable to parse words.txt")
示例#16
0
 def _print_not_found_message(self, file_path):
     """
     Print the 'not found' error only once.
     """
     if file_path not in self._deleted:
         msg = "{} appears to have been deleted or renamed. Please reboot Caster to re-track."
         printer.out(msg.format(file_path))
         self._deleted.add(file_path)
示例#17
0
def simple_log(to_file=False):
    msg = list_to_string(sys.exc_info())
    printer.out(msg)
    for tb in traceback.format_tb(sys.exc_info()[2]):
        printer.out(tb)
    if to_file:
        with io.open(settings.SETTINGS["paths"]["LOG_PATH"], 'at', encoding="utf-8") as f:
            f.write(msg + "\n")
示例#18
0
 def test_instantiation(self):
     utilities_mocking.mock_toml_files()
     for module in self._rule_modules():
         printer.out("Test instantiating {}".format(str(module)))
         content = module.get_rule()
         rule_class = content[0]
         self._run_rule_modifications_for_testing(rule_class)
         rule_class()
示例#19
0
 def reset(self):
     class_name = self.__class__.__name__
     if self._reload_shim is None:
         printer.out(
             "Reload shim is not set for {}. Rule cannot hot-reset, will only reset with engine."
             .format(class_name))
         return
     self._reload_shim.signal_reload(class_name)
示例#20
0
def remote_debug(who_called_it=None):
    if who_called_it is None:
        who_called_it = "An unidentified process"
    try:
        import pydevd  # @UnresolvedImport pylint: disable=import-error
        pydevd.settrace()
    except Exception:
        printer.out("ERROR: " + who_called_it +
              " called utilities.remote_debug() but the debug server wasn't running.")
示例#21
0
def restore_window():
    '''
    Restores last minimized window triggered minimize_window.
    '''
    global lasthandle
    if lasthandle is None:
        printer.out("No previous window minimized by voice")
    else:
        Window.restore(lasthandle)
示例#22
0
    def mouse_alternates(cls, mode, monitor=1, rough=True):
        # Launches the Mouse Grid
        args = []

        if cls.GRID_PROCESS is not None:
            cls.GRID_PROCESS.poll()
            # If close by Task Manager
            # TODO Test MacOS/Linux. Handle error codes when Grid close by Task Manager.
            if cls.GRID_PROCESS.returncode == 15:
                cls.GRID_PROCESS = None
                cls.MODE = None
            else:
                # This message should only occur if grid is visible.
                printer.out(
                    "Mouse Grid navigation already in progress \n Return Code: {}"
                    .format(cls.GRID_PROCESS.returncode))
                return

        if mode == "legion":
            from castervoice.asynch.mouse.legion import LegionScanner
            r = monitors[int(monitor) - 1].rectangle
            bbox = [
                int(r.x),
                int(r.y),
                int(r.x) + int(r.dx) - 1,
                int(r.y) + int(r.dy) - 1
            ]
            ls = LegionScanner()
            ls.scan(bbox, rough)
            tscan = ls.get_update()
            args = [
                settings.settings(["paths", "PYTHONW"]),
                settings.settings(["paths", "LEGION_PATH"]), "-t", tscan[0],
                "-m",
                str(monitor)
            ]
        elif mode == "rainbow":
            args = [
                settings.settings(["paths", "PYTHONW"]),
                settings.settings(["paths", "RAINBOW_PATH"]), "-g", "r", "-m",
                str(monitor)
            ]
        elif mode == "douglas":
            args = [
                settings.settings(["paths", "PYTHONW"]),
                settings.settings(["paths", "DOUGLAS_PATH"]), "-g", "d", "-m",
                str(monitor)
            ]
        elif mode == "sudoku":
            args = [
                settings.settings(["paths", "PYTHONW"]),
                settings.settings(["paths", "SUDOKU_PATH"]), "-g", "s", "-m",
                str(monitor)
            ]
        cls.MODE = mode
        cls.GRID_PROCESS = subprocess.Popen(args) if args else None
示例#23
0
 def execute(self, event):
     for hook in self._hooks:
         if not self._hooks_config.is_hook_active(hook.get_class_name()):
             continue
         if hook.match(event.get_type()):
             try:
                 hook.run(event)
             except:
                 err = "Error while running hook {} with {} event."
                 printer.out(err.format(hook, event.get_type()))
示例#24
0
 def _run_on_disable(self):
     # Manages run_on_disable hook state
     try:
         if self.hook_state:
             self.hook_state = False
             self.run_on_disable()
         else:
             printer.out("{} is already disabled.".format(self.get_class_name()))
     except Exception as err:
         message = "{}: Error with `disable` hook function.\n {}"
         printer.out(message.format(self.get_class_name(), err))
 def _retry_server_proxy(self):
     printer.out("Attempting Caster-Sikuli connection [...]")
     try:
         self._start_server_proxy()
         if self._timer:
             self._timer.stop()
             self._timer = None
     except socket.error:
         pass
     except Exception:
         traceback.print_exc()
 def _start_server_proxy(self):
     """
     This method will fail if the server isn't started yet.
     """
     # this will never fail:
     self._server_proxy = control.nexus().comm.get_com("sikuli")
     # this will fail if the server isn't started yet:
     self._server_proxy.list_functions()
     # success at this point:
     printer.out("Caster-Sikuli server started successfully.")
     SikuliController._ENABLE_GEN_RULE.execute()
示例#27
0
def get_clipboard_files(folders=False):
    '''
    Enumerate clipboard content and return files/folders either directly copied or
    highlighted path copied
    '''
    files = None
    if WIN32:
        import win32clipboard  # pylint: disable=import-error
        win32clipboard.OpenClipboard()
        f = get_clipboard_formats()
        try:
            if win32clipboard.CF_HDROP in f:
                files = win32clipboard.GetClipboardData(
                    win32clipboard.CF_HDROP)
            elif win32clipboard.CF_UNICODETEXT in f:
                files = [
                    win32clipboard.GetClipboardData(
                        win32clipboard.CF_UNICODETEXT)
                ]
            elif win32clipboard.CF_TEXT in f:
                files = [
                    win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)
                ]
            elif win32clipboard.CF_OEMTEXT in f:
                files = [
                    win32clipboard.GetClipboardData(win32clipboard.CF_OEMTEXT)
                ]
            if folders:
                files = [f for f in files
                         if os.path.isdir(f)] if files else None
            else:
                files = [f for f in files
                         if os.path.isfile(f)] if files else None
            win32clipboard.CloseClipboard()
            return files
        except Exception as e:
            win32clipboard.CloseClipboard()
            printer.out(e)

    if LINUX:
        f = get_clipboard_formats()
        if "UTF8_STRING" in f:
            files = enum_files_from_clipboard("UTF8_STRING")
        elif "TEXT" in f:
            files = enum_files_from_clipboard("TEXT")
        elif "text/plain" in f:
            files = enum_files_from_clipboard("text/plain")
        if folders:
            files = [f for f in files
                     if os.path.isdir(str(f))] if files else None
        else:
            files = [f for f in files
                     if os.path.isfile(str(f))] if files else None
        return files
示例#28
0
    def _import_module(self, module_name):
        """
        Attempts to import a module by name.
        :param module_name: string
        :return: (module) module
        """

        try:
            return self._module_load_fn(module_name)
        except Exception as e:
            printer.out("Could not import '{}'. Module has errors: {}".format(module_name, traceback.format_exc()))
            return None
示例#29
0
 def transform_rule(self, rule_instance):
     r = rule_instance
     orig_class = TransformersRunner._get_rule_class(r)
     for transformer in self._transformers:
         try:
             r = transformer.get_transformed_rule(r)
             TransformersRunner._post_transform_validate(orig_class, r)
         except:
             err = "Error while running transformer {} with {} rule."
             printer.out(err.format(transformer, r))
             traceback.print_exc()
     return r
示例#30
0
    def _reimport_module(self, module):
        """
        Reimports an already imported module. Python 2/3 compatible method.
        """

        try:
            reload_fn = self._get_reload_fn()
            return reload_fn(module)
        except:
            msg = "An error occurred while importing '{}': {}"
            printer.out(msg.format(str(module), traceback.format_exc()))
            return None