def get_current_cmdproc(self): current_cmdproc = None if self._is_sending or self._is_talking: current_cmdproc = self._receiving_cmdproc else: current_program = window.get_current_program() if current_program in self._cmdproc_config: # current window takes priority. current_cmdproc = current_program # the user is switched to the program and commanding it directly (when they lose focus, # they probably expect to continue speaking to that application). # self._last_focussed = current_program elif self._last_focussed is not None: # otherwise use the program that last had activity current_cmdproc = self._last_focussed return current_cmdproc
def cmd(self, words, callback, err): """ Interpret a command for the server or the current in focus application. Call callback when we're ready to handle the next command. When receiving a bad command, an exception will be called as an argument to err. """ last_focussed = self._cmdserver.get_last_focussed_cmdproc() logger.info("LAST FOCUSSED: %s", last_focussed) if self._asking_for_input: logger.info( "We're asking the user for input, hold off on commands for now..." ) return cmd = [] def consume(i, cmd_str): if i >= len(words): err(IncompleteCmdServerCommand(cmd)) return elif words[i] == cmd_str: cmd.append(['cmd', cmd_str]) else: # TODO: wrong, shouldn't call err here (unless last command tried) err(BadCmdServerCommand(cmd, words[i])) return def is_cmd(*cmd_strs): if len(words) < len(cmd_strs): return False new_cmd = [] for i in range(len(cmd_strs)): if type(cmd_strs[i]) == str: if words[i] != cmd_strs[i]: return False new_cmd.append(['cmd', words[i]]) elif cmd_strs[i] == ['cmdproc']: if words[i] not in self._cmdproc_delims: return False new_cmd.append(['cmdproc', words[i]]) cmd.extend(new_cmd) return True if not self._cmdserver.listening: if is_cmd('WAKEUP', 'CALM'): self._cmdserver.wakeup() callback() return elif is_cmd('HELP'): self._cmdserver.notify_server( 'Calm is sleeping', 'Say WAKEUP CALM to get started') callback() return else: # We're ignoring input since we're sleeping callback() return elif is_cmd('SLEEP'): self._cmdserver.sleep() callback() return elif is_cmd('HELP'): self._cmdserver.cmd_help() callback() return # TODO: add try / except and then handle current application in focus # logger.info("is sending?? %s", self._is_sending) if self._is_sending: cmdproc_cmd = None if is_cmd('FINISH', 'SENDING'): self.done_sending() callback() return elif is_cmd('SEND', ['cmdproc']) or is_cmd('SEND', 'TO', ['cmdproc']): # index of cmdproc i = len(cmd) - 1 cmdproc = cmd[i][1].lower() if cmdproc != self._cmdserver._receiving_cmdproc: # Sometimes the user will not notice they've switched to sending to a # cmdproc, so let them switch. # # Otherwise, the user might not have not have noticed their switch to # sending to the application, so they're trying the whole "SEND # <PROGRAM> cmd" phrase. Extract it and send it off. self.switch_to_sending(cmdproc) cmdproc_cmd = words[i + 1:] else: cmdproc_cmd = words def send_cmd_cb(cmd): self._cmdserver.send_cmd(self._cmdserver._receiving_cmdproc, cmd) self.done_sending() callback() self.cmdproc_cmd(self._cmdserver._receiving_cmdproc, cmdproc_cmd, send_cmd_cb, err) return if len(words) < 1: err(IncompleteCmdServerCommand(cmd)) return def ask_for_program(cb, description): # TODO: use voice for this def get_ready_to_send_cb(cmdproc): # logger.info("send to... %s", cmdproc) if cmdproc not in self._cmdserver._cmdproc_config: # self.error("No such program named {cmdproc}".format(**locals())) # raise BadCmdServerCommand(cmd, cmdproc) err(BadCmdServerCommand(cmd, cmdproc)) return cb(cmdproc) self.ask_for_string( 'program to {description} to'.format(**locals()), get_ready_to_send_cb, self._cmdserver._cmdproc_config.keys()) def talk_to_cb(cmdproc): if self._talking_to_cmdproc: # We're already talking to a cmdproc; switch to talking to this cmdproc self.done_talking(self._cmdserver._receiving_cmdproc) self.get_ready_to_talk(cmdproc) callback() def send_cb(cmdproc): self.get_ready_to_send(cmdproc) callback() if is_cmd('TALK', 'TO', ['cmdproc']): talk_to_cb(cmd[2][1].lower()) return elif is_cmd('TALK'): ask_for_program(talk_to_cb, description='talk') return elif is_cmd('FINISH', 'TALKING'): if self._talking_to_cmdproc: self.done_talking(self._cmdserver._receiving_cmdproc) callback() return elif is_cmd('SEND', ['cmdproc']) or is_cmd('SEND', 'TO', ['cmdproc']): # index of cmdproc i = len(cmd) - 1 cmdproc = cmd[i][1].lower() if len(words) == i + 1: # the user only specified the command send_cb(cmdproc) else: # the user may be trying to send a command all in one sentence; try to send everything # after SEND TO <cmdproc> to the cmdproc, but if it rejects, fall back to the SEND TO # <cmdproc> def fallback(cmdproc_error): send_cb(cmdproc) def send_cmd_cb(cmdproc_cmd): # no need to notify of the receiving process, or use done_sending self._cmdserver.send_cmd(cmdproc, cmdproc_cmd) callback() self.cmdproc_cmd(cmdproc, words[i + 1:], send_cmd_cb, err=fallback) return elif is_cmd('SEND'): ask_for_program(send_cb, description='send') return elif is_cmd('RECORD'): def start_recording_cb(macroname): if macroname is not None: self._cmdserver.record_macro(macroname) callback() self.ask_for_string('the name of your recording', start_recording_cb, self._cmdserver.macros) return elif is_cmd('FINISH', 'MACRO'): self._cmdserver.end_macro() callback() return elif is_cmd('REPLAY'): def replay_macro_cb(macroname): self._cmdserver.replay_macro(macroname) callback() self.ask_for_string('the recording to replay', replay_macro_cb, self._cmdserver.macros) return elif is_cmd('UNDO'): if self._cmdserver.is_recording: self._cmdserver.undo_last_cmd() callback() return def cmdproc_and_cmdserver_err(e): if type(e) == BadCmdProcCommandInput: err(e) else: err( NeitherCmdProcOrServerCommand( e, BadCmdServerCommand(cmd, words[0]))) def send_cmd_to_cmdproc(cmdproc, err): """ Sending a command to a command processor: - try the current application with priority if it is a command processor - otherwise, send to the last focussed application (either the current application, or an application we're talking to). """ def send_cmd_cb(cmd): self._cmdserver.send_cmd(cmdproc, cmd) callback() self.cmdproc_cmd(cmdproc, words, send_cmd_cb, err) # See if we're talking to a specific command processor if self._talking_to_cmdproc: send_cmd_to_cmdproc(self._cmdserver._receiving_cmdproc, cmdproc_and_cmdserver_err) return # Sending a command to a command processor: # - try the current application with priority if it is a command processor # - otherwise, send to the last focussed application def send_to_last_focussed(*args): if self._cmdserver._last_focussed is not None: send_cmd_to_cmdproc(self._cmdserver._last_focussed, cmdproc_and_cmdserver_err) else: # No command processor available; interpret as a bad server command. err(BadCmdServerCommand(cmd, words[0])) current_window = window.get_current_program() if current_window in self._cmdserver._cmdproc_config: send_cmd_to_cmdproc(current_window, send_to_last_focussed) return else: send_to_last_focussed() return
def cmd(self, words, callback, err): """ Interpret a command for the server or the current in focus application. Call callback when we're ready to handle the next command. When receiving a bad command, an exception will be called as an argument to err. """ last_focussed = self._cmdserver.get_last_focussed_cmdproc() logger.info("LAST FOCUSSED: %s", last_focussed) if self._asking_for_input: logger.info("We're asking the user for input, hold off on commands for now...") return cmd = [] def consume(i, cmd_str): if i >= len(words): err(IncompleteCmdServerCommand(cmd)) return elif words[i] == cmd_str: cmd.append(['cmd', cmd_str]) else: # TODO: wrong, shouldn't call err here (unless last command tried) err(BadCmdServerCommand(cmd, words[i])) return def is_cmd(*cmd_strs): if len(words) < len(cmd_strs): return False new_cmd = [] for i in range(len(cmd_strs)): if type(cmd_strs[i]) == str: if words[i] != cmd_strs[i]: return False new_cmd.append(['cmd', words[i]]) elif cmd_strs[i] == ['cmdproc']: if words[i] not in self._cmdproc_delims: return False new_cmd.append(['cmdproc', words[i]]) cmd.extend(new_cmd) return True if not self._cmdserver.listening: if is_cmd('WAKEUP', 'CALM'): self._cmdserver.wakeup() callback() return elif is_cmd('HELP'): self._cmdserver.notify_server('Calm is sleeping', 'Say WAKEUP CALM to get started') callback() return else: # We're ignoring input since we're sleeping callback() return elif is_cmd('SLEEP'): self._cmdserver.sleep() callback() return elif is_cmd('HELP'): self._cmdserver.cmd_help() callback() return # TODO: add try / except and then handle current application in focus # logger.info("is sending?? %s", self._is_sending) if self._is_sending: cmdproc_cmd = None if is_cmd('FINISH', 'SENDING'): self.done_sending() callback() return elif is_cmd('SEND', ['cmdproc']) or is_cmd('SEND', 'TO', ['cmdproc']): # index of cmdproc i = len(cmd) - 1 cmdproc = cmd[i][1].lower() if cmdproc != self._cmdserver._receiving_cmdproc: # Sometimes the user will not notice they've switched to sending to a # cmdproc, so let them switch. # # Otherwise, the user might not have not have noticed their switch to # sending to the application, so they're trying the whole "SEND # <PROGRAM> cmd" phrase. Extract it and send it off. self.switch_to_sending(cmdproc) cmdproc_cmd = words[i + 1:] else: cmdproc_cmd = words def send_cmd_cb(cmd): self._cmdserver.send_cmd(self._cmdserver._receiving_cmdproc, cmd) self.done_sending() callback() self.cmdproc_cmd(self._cmdserver._receiving_cmdproc, cmdproc_cmd, send_cmd_cb, err) return if len(words) < 1: err(IncompleteCmdServerCommand(cmd)) return def ask_for_program(cb, description): # TODO: use voice for this def get_ready_to_send_cb(cmdproc): # logger.info("send to... %s", cmdproc) if cmdproc not in self._cmdserver._cmdproc_config: # self.error("No such program named {cmdproc}".format(**locals())) # raise BadCmdServerCommand(cmd, cmdproc) err(BadCmdServerCommand(cmd, cmdproc)) return cb(cmdproc) self.ask_for_string('program to {description} to'.format(**locals()), get_ready_to_send_cb, self._cmdserver._cmdproc_config.keys()) def talk_to_cb(cmdproc): if self._talking_to_cmdproc: # We're already talking to a cmdproc; switch to talking to this cmdproc self.done_talking(self._cmdserver._receiving_cmdproc) self.get_ready_to_talk(cmdproc) callback() def send_cb(cmdproc): self.get_ready_to_send(cmdproc) callback() if is_cmd('TALK', 'TO', ['cmdproc']): talk_to_cb(cmd[2][1].lower()) return elif is_cmd('TALK'): ask_for_program(talk_to_cb, description='talk') return elif is_cmd('FINISH', 'TALKING'): if self._talking_to_cmdproc: self.done_talking(self._cmdserver._receiving_cmdproc) callback() return elif is_cmd('SEND', ['cmdproc']) or is_cmd('SEND', 'TO', ['cmdproc']): # index of cmdproc i = len(cmd) - 1 cmdproc = cmd[i][1].lower() if len(words) == i + 1: # the user only specified the command send_cb(cmdproc) else: # the user may be trying to send a command all in one sentence; try to send everything # after SEND TO <cmdproc> to the cmdproc, but if it rejects, fall back to the SEND TO # <cmdproc> def fallback(cmdproc_error): send_cb(cmdproc) def send_cmd_cb(cmdproc_cmd): # no need to notify of the receiving process, or use done_sending self._cmdserver.send_cmd(cmdproc, cmdproc_cmd) callback() self.cmdproc_cmd(cmdproc, words[i + 1:], send_cmd_cb, err=fallback) return elif is_cmd('SEND'): ask_for_program(send_cb, description='send') return elif is_cmd('RECORD'): def start_recording_cb(macroname): if macroname is not None: self._cmdserver.record_macro(macroname) callback() self.ask_for_string('the name of your recording', start_recording_cb, self._cmdserver.macros) return elif is_cmd('FINISH', 'MACRO'): self._cmdserver.end_macro() callback() return elif is_cmd('REPLAY'): def replay_macro_cb(macroname): self._cmdserver.replay_macro(macroname) callback() self.ask_for_string('the recording to replay', replay_macro_cb, self._cmdserver.macros) return elif is_cmd('UNDO'): if self._cmdserver.is_recording: self._cmdserver.undo_last_cmd() callback() return def cmdproc_and_cmdserver_err(e): if type(e) == BadCmdProcCommandInput: err(e) else: err(NeitherCmdProcOrServerCommand(e, BadCmdServerCommand(cmd, words[0]))) def send_cmd_to_cmdproc(cmdproc, err): """ Sending a command to a command processor: - try the current application with priority if it is a command processor - otherwise, send to the last focussed application (either the current application, or an application we're talking to). """ def send_cmd_cb(cmd): self._cmdserver.send_cmd(cmdproc, cmd) callback() self.cmdproc_cmd(cmdproc, words, send_cmd_cb, err) # See if we're talking to a specific command processor if self._talking_to_cmdproc: send_cmd_to_cmdproc(self._cmdserver._receiving_cmdproc, cmdproc_and_cmdserver_err) return # Sending a command to a command processor: # - try the current application with priority if it is a command processor # - otherwise, send to the last focussed application def send_to_last_focussed(*args): if self._cmdserver._last_focussed is not None: send_cmd_to_cmdproc(self._cmdserver._last_focussed, cmdproc_and_cmdserver_err) else: # No command processor available; interpret as a bad server command. err(BadCmdServerCommand(cmd, words[0])) current_window = window.get_current_program() if current_window in self._cmdserver._cmdproc_config: send_cmd_to_cmdproc(current_window, send_to_last_focussed) return else: send_to_last_focussed() return