def delayed_speech_off(): """Disables "temporary speech" mode lazily, meaning that the next phrase that finishes will turn speech off.""" global delayed_enabled if delayed_enabled: delayed_enabled = False speech_system.register("post:phrase", do_disable)
def enable(self): if self.enabled == False: speech_system.register("pre:phrase", self.check_step) self.scope_job = cron.interval("1500ms", self.display_step_based_on_context) ctx.tags = ["user.talon_hud_walkthrough"] if self.development_mode: self.watch_walkthrough_file(True) self.enabled = True
from talon import speech_system import logging def debug(topic, j): logging.info(f"[speech_system] {topic} {j}") speech_system.register('', debug)
default=True, desc="play sounds when zoom clicks are buffered (or cancelled)", ) # TODO: Pull this out once talon exposes mouse mode scopes by default @module.scope def scope(*_): zoom_mouse = zoom_mouse_active() return { "zoom_mouse_active": zoom_mouse, "zoom_mouse_zooming": zoom_mouse and is_zooming(), } speech_system.register("pre:phrase", scope.update) # Noises won't trigger pre:phrase - bind them so we definitely catch the zoom. noise.register("post:pop", scope.update) noise.register("pre:hiss", scope.update) @module.action_class class Actions: def end_zoom() -> Point2d: """Terminate the zoom. Mouse will be moved to the user's gaze position. :returns: the final position """
from talon import actions, speech_system from talon import Context, Module, app ctx = Context() mod = Module() ABORT_WORDS = ["f**k", "shit", "abort", "cancel"] mod.list("abort_word", desc="Aborts the current command if heard") ctx.lists["self.abort_word"] = ABORT_WORDS def fn(d): words = d["parsed"]._unmapped if words[-1] in ABORT_WORDS and actions.speech.enabled(): d["parsed"]._sequence = [] app.notify("Command aborted") speech_system.register("pre:phrase", fn)
from talon.microphone import manager debugEngine = True debugNoise = True debugMic = True def listener(topic, m): if topic == "cmd" and m["cmd"]["cmd"] == "g.load" and m["success"] == True: print("speech_system event: [grammar reloaded]") else: print(f"speech_system event: {topic}", m) if debugEngine: speech_system.register("", listener) def on_mic_ev(topic, arg): print(f"mic event: {topic} {arg}") if debugMic: manager.register("", on_mic_ev) # def on_pop(active): # print(f"pop active:{active}") # # def on_hiss(active): # print(f"hiss active:{active}") #
from talon import ui, actions, cron, speech_system, app job = None def on_phrase(j): global job if j.get('phrase'): cron.cancel(job) job = cron.after('15m', actions.speech.disable) speech_system.register('post:phrase', on_phrase) def on_ready(): global job if actions.speech.enabled(): job = cron.after('15m', actions.speech.disable) app.register("ready", on_ready) # https://github.com/nriley/knausj_talon/blob/nriley/misc/screen.py ui.register('screen_sleep', lambda e: actions.speech.disable()) # ui.register('screen_wake')
current_phrase = None def pre_phrase(d): global current_phrase current_phrase = d def post_phrase(d): if ALWAYS_RECORD: phrase = ' '.join(getattr(d['parsed'], '_unmapped', d['phrase'])) actions.self.record_wav(phrase) speech_system.register('pre:phrase', pre_phrase) speech_system.register('post:phrase', post_phrase) mod = Module() @mod.action def record_wav(words: str): """Record the phrase audio to a file""" words = words.strip() if not current_phrase or not current_phrase.get('samples') or not words: return samples = current_phrase['samples'] scaled = (min(32767, max(-32767, int(s * 32767))) for s in samples) binary = struct.pack('<{}h'.format(len(samples)), *scaled) path = OUTPUT_DIR / f'{words}.wav'
def backdated_warn(message): LOGGER.warning( f"[backdated_position] {message}. Defaulting to position at `pre:phrase`." ) try: position = position_at_time(actual_word_start(word_meta)) if position: return position.pos else: backdated_warn(f"No backdated position returned. Was: `{position}`") except Exception as e: backdated_warn(f'Error getting backdated position: "{e}"') with PHRASE_START_POS_LOCK: return PHRASE_START_POSITION # Position of the mouse at phrase start PHRASE_START_POSITION = None PHRASE_START_POS_LOCK = threading.Lock() def _store_pre_position(*args): """Store the mouse position at phrase start.""" global PHRASE_START_POSITION, PHRASE_START_POS_LOCK with PHRASE_START_POS_LOCK: PHRASE_START_POSITION = ctrl.mouse_pos() speech_system.register("pre:phrase", _store_pre_position)
from talon.grammar import Phrase mod = Module() phrase_stack = [] def on_pre_phrase(d): phrase_stack.append(d) def on_post_phrase(d): phrase_stack.pop() speech_system.register("pre:phrase", on_pre_phrase) speech_system.register("post:phrase", on_post_phrase) @mod.action_class class Actions: def parse_phrase(phrase: Union[Phrase, str]): """Rerun phrase""" if phrase == "": return current_phrase = phrase_stack[-1] ts = current_phrase["_ts"] start = phrase.words[0].start - ts end = phrase.words[-1].end - ts samples = current_phrase["samples"] pstart = int(start * 16_000)
def enable(self): if not self.enabled: self.enabled = True speech_system.register("phrase", self.on_phrase)
from talon import actions, speech_system def fn(d): print(d) speech_system.register('pre:phrase', fn)
if gui.showing: gui.freeze() # todo: dynamic rect? @imgui.open(y=0, x=0, software=True) def gui(gui: imgui.GUI): gui.text("Command History") gui.line() text = history[:] # text = [str(x) for x in actions.core.recent_phrases()[:hist_len]] for line in text: gui.text(line) speech_system.register("post:phrase", on_phrase_post) @mod.action_class class Actions: def history_show(): """Shows the history""" gui.freeze() def history_hide(): """Hides the history""" gui.hide() def history_clear(): """Clear the history""" global history
def enable(self): if (self.enabled != True): self.enabled = True speech_system.register("phrase", self.on_phrase) if (self.job is None): self.job = cron.interval('100ms', self.state_check)
from talon import Module, actions, speech_system class Defer: def __init__(self): self.q = [] def add(self, text): self.q.append(text) def post_phrase(self, j): q, self.q = self.q, [] for s in reversed(q): actions.insert(s) defer = Defer() speech_system.register('post:phrase', defer.post_phrase) mod = Module() @mod.action_class class Actions: def defer(text: str): "Insert text after the current phrase is finished executing" defer.add(text)
history = history[-setting_command_history_size.get():] # todo: dynamic rect? @imgui.open(y=0) def gui(gui: imgui.GUI): global history gui.text("Command History") gui.line() text = (history[:] if hist_more else history[-setting_command_history_display.get():]) for line in text: gui.text(line) speech_system.register("phrase", on_phrase) @mod.action_class class Actions: def history_toggle(): """Toggles viewing the history""" if gui.showing: gui.hide() else: gui.show() def history_enable(): """Enables the history""" gui.show()
# to disable command cancellation, comment out this entire file. # you may also wish to adjust the commands in misc/cancel.talon. from talon import speech_system, actions # To change the phrase used to cancel commands, you must also adjust misc/cancel.talon cancel_phrase = "cancel cancel".split() def pre_phrase(d): n = len(cancel_phrase) before, after = d["text"][:-n], d['text'][-n:] if after != cancel_phrase: return # cancel the command d["parsed"]._sequence = [] actions.app.notify(f"Command canceled: {' '.join(before)!r}") speech_system.register("pre:phrase", pre_phrase)