def gui(gui: imgui.GUI): gui.text("Scope") gui.line() gui.spacer() gui.text("Modes") gui.line() for mode in sorted(scope.get("mode")): gui.text(mode) gui.spacer() gui.text("Tags") gui.line() for tag in sorted(scope.get("tag")): gui.text(tag) gui.spacer() gui.text("Misc") gui.line() ignore = {"main", "mode", "tag"} keys = {*scope.data.keys(), *scope.data["main"].keys()} for key in sorted(keys): if key not in ignore: value = scope.get(key) print_value(gui, key, value, ignore) gui.spacer() if gui.button("Hide"): actions.user.help_scope_toggle()
def talon_hud_ready(): # Check if Talon HUD is available to the user TALON_HUD_RELEASE_WALKTHROUGH = 3 if "user.talon_hud_available" in scope.get("tag") and \ scope.get("user.talon_hud_version") != None and scope.get("user.talon_hud_version") >= TALON_HUD_RELEASE_WALKTHROUGH: # Get the absolute path to the documentation directory for your package documentation_dir = str(os.path.dirname(os.path.abspath(__file__))) # Add an item to the Toolkit documentation page actions.user.hud_add_documentation( "Widget settings", "shows the general Talon HUD commands related to widgets", documentation_dir + "/hud_widget_documentation.txt") # Add a walkthrough to the Toolkit walkthrough options actions.user.hud_add_walkthrough( "Head up display", documentation_dir + "/hud_walkthrough.json") # Dictation actions.user.hud_add_walkthrough( "Basic sentence dictation", documentation_dir + "/dictation_walkthrough.json") # Text formatters actions.user.hud_add_documentation( "Letters and keys", "gives a list of all the individual keystrokes you can make.", documentation_dir + "/individual_keys.txt") # Text formatters actions.user.hud_add_documentation( "Text formatting", "gives a list with examples of commands that can change text with a different format.", documentation_dir + "/text_formatters.txt") # Talon draft usage actions.user.hud_add_documentation( "Talon draft window", "shows all the available commands used for the draft window, which can be used to dictate and edit text outside of the current program.", documentation_dir + "/talon_draft_usage.txt") # Browser documentation actions.user.hud_add_documentation( "Browser usage", "shows the commands and explanations related to web browser usage", documentation_dir + "/browser_usage_documentation.txt") # Basic browser usage actions.user.hud_add_walkthrough( "Basic browser usage", documentation_dir + "/basic_browser_usage_walkthrough.json") # Media usage actions.user.hud_add_walkthrough( "Music and video controls", documentation_dir + "/music_and_video_walkthrough.json")
def _maybe_record(): """In the right context, start recording on every mic, otherwise stop.""" global _last_transition if "user._noise_recorder_context" in scope.get("tag", []): # Assume it's a fullscreen video if the window is on the PRIMARY screen, # and matches the fullscreen dimensions. This may require the primary # screen to have a toolbar to work properly. app = ui.active_app() window = app.active_window should_record = 0 == window.rect.compare_to_rect(ui.main_screen().rect) else: should_record = False # The window dimensions can bounce around during the transitions to & from # fullscreen, so deadzones are used for debouncing. if should_record: if (not recording() and time.monotonic() > _last_transition + TRANSITION_DEADZONE): _last_transition = time.monotonic() noise, existing = noise_with_least_data() LOGGER.info(f'Recording noise with the least data: "{noise}", ' f"{existing / 60:0.1f} mins exist already.") record(noise) # TODO: Probably enable a tag here so people can hook behaviour elif recording( ) and time.monotonic() > _last_transition + TRANSITION_DEADZONE: _last_transition = time.monotonic() stop() # Lambda is used becayse Python thinks `print_total_noise_recorded` # isn't callable. cron.after("2s", actions.self.print_total_noise_recorded)
def hud_get_programming_language() -> str: """Get the programming language to be displayed in the status bar - By default tries to mimic knausj""" lang = actions.code.language() if not lang: active_modes = scope.get("mode") if (active_modes is not None): for index, active_mode in enumerate(active_modes): if (active_mode.replace("user.", "") in languages.keys()): return active_mode.replace("user.", "") active_tags = scope.get("tag") if (active_tags is not None): for index, active_tag in enumerate(active_tags): if (active_tag.replace("user.", "") in languages.keys()): return active_tag.replace("user.", "") return "" else: return lang if lang else ""
def detect_language(self): language = scope.get("language", "en_US") if isinstance(language, str): return language for lang in language: if "_" in lang: return lang
def jb_close_search(direction: str, phrase: str): """Search in the given direction for phrase""" bundle = scope.get("user.jetbrains") if not bundle: return cmd = f"find {direction} {phrase}" _send_jetbrains(bundle, cmd) global extendCommands extendCommands = [cmd]
def get_state_in_text(self): tags = scope.get("tag") new_tags = [] if tags is not None: for tag in tags: new_tags.append(tag) modes = [] scopemodes = scope.get("mode") if scopemodes is not None: for mode in scopemodes: modes.append(mode) text = "<*app: " + scope.get("app")["name"] + "/> " + scope.get( "win")["title"] + "/>\n<*Tags:/>\n" + "\n".join( sorted(new_tags)) + "\n<*Modes:/> " + " - ".join(sorted(modes)) return text
def _log(args): global text, can if "command" not in scope.get("mode"): return text = f"\"{' '.join(args['text'])}\"" can.show() can.freeze() actions.sleep(action_wait) cron.after(canvas_hide_wait, hide_canvas)
def is_in_right_context(self): """Check if we are in the right context for the step""" in_right_context = True if self.current_walkthrough is not None: if self.current_stepnumber < len(self.current_walkthrough.steps): step = self.current_walkthrough.steps[self.current_stepnumber] tags = scope.get("tag") modes = scope.get("mode") app_name = scope.get("app")["name"] in_correct_tags = set(step.tags) <= tags in_correct_modes = set(step.modes) <= modes in_correct_app = step.app == "" correct_app_names = step.app.split(",") for correct_app_name in correct_app_names: if correct_app_name == app_name: in_correct_app = True in_right_context = in_correct_tags and in_correct_modes and in_correct_app return in_right_context
def jb_extend(number: str): """Perform the current extension action""" global extendCommands bundle = scope.get("user.jetbrains") if not bundle: return # noinspection PyProtectedMember count = max(int(number), 1) for _ in range(count): for cmd in extendCommands: if cmd: _send_jetbrains(bundle, cmd)
def jb_bounded_search(direction: str, start: str, end: str): """Search in the given direction for a word starting and ending with letters.""" bundle = scope.get("user.jetbrains") if not bundle: return search_string = "%5Cb" + r"%5B^-_ .()%5D*?".join( start, end ) # URL escaped Java regex! '\b' 'A[%-_.()]*?Z" cmd = f"find {direction} {search_string}" _send_jetbrains(bundle, cmd) global extendCommands extendCommands = [cmd]
def determine_mode(self): active_modes = scope.get('mode') # If no mode is given, just show command mode = 'command' if (active_modes is not None): if ('sleep' in active_modes): mode = 'sleep' if ('dictation' in active_modes): mode = 'dictation' return mode
def jb_cmd(commands: str): """Send a list of commands, split on commas""" global extendCommands # print(f"commands: {commands}") bundle = scope.get("user.jetbrains") if not bundle: return commands = commands.split(",") extendCommands = commands for cmd in commands: if cmd: _send_jetbrains(bundle, cmd)
def hud_determine_mode() -> str: """Determine the current mode used for the status bar icons and the widget states""" active_modes = scope.get("mode") available_modes = actions.user.hud_get_status_modes() current_mode = "command" for available_mode in available_modes: if available_mode in active_modes: current_mode = available_mode break return current_mode
def determine_programming_language(self): lang = actions.code.language() if (not lang): active_modes = scope.get('mode') if (active_modes is not None): for index, active_mode in enumerate(active_modes): if (active_mode.replace("user.", "") in self.language_to_ext): self.current_lang_forced = True return active_mode.replace("user.", "") return "" else: self.current_lang_forced = False return lang if lang else ""
def _maybe_record(): """In the right context, start recording on every mic, otherwise stop.""" global _last_transition, _original_mic, _gui_text # The window dimensions can bounce around during the transitions to & from # fullscreen, so deadzones are used for debouncing. if ( "user._noise_recorder_context" in scope.get("tag", []) and # Assume it's a fullscreen video if the window is on the PRIMARY screen, # and matches the fullscreen dimensions. This basically assumes the # primary screen has a toolbar. ui.active_app().active_window.rect == ui.main_screen().rect ): if ( not recording() and time.monotonic() > _last_transition + TRANSITION_DEADZONE ): _last_transition = time.monotonic() active_mic = microphone.manager.active_mic() _original_mic = active_mic.name if active_mic else None print("Disabling mic while recording noises.") actions.speech.set_microphone("None") with _gui_lock: # This can take a while (e.g. on a cold disk drive) so pop a # message _gui_text = "Scanning noise recordings on disk, this may be slow..." gui.show() noise, existing = noise_with_least_data() LOGGER.info( f'Recording noise with the least data: "{noise}", ' f"{existing / 60:0.1f} mins exist already." ) record(noise) context.tags.add("user.recording_noises") elif recording() and time.monotonic() > _last_transition + TRANSITION_DEADZONE: _last_transition = time.monotonic() context.tags.remove("user.recording_noises") stop() gui.hide() with _gui_lock: _gui_text = None print("Re-enabling microphone.") if _original_mic: actions.speech.set_microphone(_original_mic) _original_mic = None else: # Shouldn't ever get here but just use this as a fallback print('No previous mic found. Switching to "System Default"') actions.speech.set_microphone("System Default")
def jb_psi(psi_path: dict, cmd: str, index: str): """Do a PSI based movement or selection""" global extendCommands bundle = scope.get("user.jetbrains") if not bundle: return if not index: index = psi_path["_"] extension = scope.get("user.language") resolved_path = psi_path.get(extension, psi_path.get("default", None)) if resolved_path is None: return cmd_string = f"psi {cmd} {resolved_path}" if "##" in cmd_string: cmd_string = cmd_string.replace("##", f"%23{index}") else: cmd_string = f"{cmd_string}%23{index}" _send_jetbrains(bundle, cmd_string) extendCommands = []
def on_phrase_post(j): global flag if flag: flag = False checked_modes = list( scope.get('mode').intersection({'sleep', 'dictation'})) # make sure we're in sleep or dictation mode: if len(checked_modes) == 1: mode = checked_modes[0] actions.mode.enable('command') actions.mode.disable(mode) try: # NOTE: the following API is completely private and subject to change with no notice speech_system._on_audio_frame(j['samples']) finally: actions.mode.disable('command') actions.mode.enable(mode)
def determine_language(self): return scope.get('language')
def current_language() -> str: """Get current language.""" print(f"current language is {language}") return scope.get("user.language")
def talon_debug_scope(name: str): """Dumps the active scope information to the console""" print("**** Dumping {} scope ****".format(name)) print(scope.get(name)) print("***********************")
def current_jetbrains() -> str: """Get current jetbrains bundle.""" return scope.get("user.jetbrains")
def emacs_focussed(): """Is Emacs focussed?""" return "user.emacs" in scope.get("tag", [])
def jb_location() -> list: """ Get current line and column """ bundle = scope.get("user.jetbrains") if not bundle: return [] return _send_jetbrains(bundle, "location").split()
def draw(self, canvas) -> bool: self.icon_positions = [] stroke_width = 1.5 circle_margin = 4 element_height = self.height - (stroke_width * 2) icon_diameter = self.height - (circle_margin * 2) element_width = self.width paint = canvas.paint # Draw the background with bigger stroke than 1px stroke_colours = (self.theme.get_colour('top_stroke_colour'), self.theme.get_colour('down_stroke_colour')) paint.shader = skia.Shader.linear_gradient(self.x, self.y, self.x, self.y + element_height * 2, stroke_colours, None) self.draw_background(canvas, self.x, self.y, element_width, element_height + (stroke_width * 2), paint) # Calculate the blinking colour continue_drawing = False if (self.blink_state > 0): self.blink_state = max(0, self.blink_state - 4) continue_drawing = self.blink_state > 0 red = self.blink_colour[0] - int(self.blink_difference[0] * (self.blink_state - 100) / 100) green = self.blink_colour[1] - int(self.blink_difference[1] * (self.blink_state - 100) / 100) blue = self.blink_colour[2] - int(self.blink_difference[2] * (self.blink_state - 100) / 100) else: red, green, blue = self.background_colour red_hex = '0' + format(red, 'x') if red <= 15 else format(red, 'x') green_hex = '0' + format(green, 'x') if green <= 15 else format( green, 'x') blue_hex = '0' + format(blue, 'x') if blue <= 15 else format(blue, 'x') # Draw the background based on the state accent_colour = red_hex + green_hex + blue_hex mode_colour = self.theme.get_colour(self.content["mode"] + '_mode_colour') background_shader = skia.Shader.linear_gradient( self.x, self.y, self.x, self.y + element_height * 2, (mode_colour, accent_colour), None) paint.shader = background_shader self.draw_background(canvas, self.x + stroke_width, self.y + stroke_width, element_width - stroke_width * 2, element_height, paint) # Draw icons for index, icon in enumerate(self.icons): button_colour = self.theme.get_colour( 'button_hover_colour' ) if self.icon_hover_index == index else self.theme.get_colour( 'button_colour') paint.shader = skia.Shader.linear_gradient( self.x, self.y, self.x, self.y + element_height, (self.theme.get_colour('button_colour'), button_colour), None) if (index == 0 and self.content["mode"] == 'sleep'): paint.shader = background_shader image_name = None if (index == 0): image_name = self.content["mode"] + '_icon' self.draw_icon( canvas, self.x + stroke_width + circle_margin + (index * icon_diameter) + (index * circle_margin), self.y + circle_margin, icon_diameter, paint, 'mode', image_name) height_center = self.y + element_height + (circle_margin / 2) - (element_height / 2) # Draw selected language # TODO - FAKE BOLD until I find out how to properly use font style if ((self.content["mode"] == "command" and self.content["language"]["ext"] is not None) or self.content["mode"] == "dictation"): text_colour = self.theme.get_colour( 'text_forced_colour' ) if self.content["language"]["forced"] else self.theme.get_colour( 'text_colour') paint.shader = skia.Shader.linear_gradient( self.x, self.y, self.x, self.y + element_height, (text_colour, text_colour), None) paint.style = paint.Style.STROKE paint.textsize = 24 text_x = self.x + circle_margin * 2 + ( len(self.icons) * (icon_diameter + circle_margin)) canvas.draw_text( self.content["language"]["ext"] if self.content["mode"] == "command" else "Dictate", text_x, height_center - circle_margin + paint.textsize / 2) paint.style = paint.Style.FILL canvas.draw_text( self.content["language"]["ext"] if self.content["mode"] == "command" else "Dictate", text_x, height_center - circle_margin + paint.textsize / 2) # Draw closing icon #paint.style = paint.Style.FILL #close_colour = self.theme.get_colour('close_icon_hover_colour') if self.icon_hover_index == len(self.icons) else self.theme.get_colour('close_icon_accent_colour') #paint.shader = skia.Shader.linear_gradient(self.x, self.y, self.x, self.y + element_height, (self.theme.get_colour('close_icon_colour'), close_colour), None) #close_icon_diameter = icon_diameter / 2 #self.draw_icon(canvas, self.x + element_width - close_icon_diameter - close_icon_diameter / 2 - stroke_width, height_center - close_icon_diameter / 2, close_icon_diameter, paint, 'close' ) image_name = 'english' active_modes = scope.get('mode') for index, active_mode in enumerate(active_modes): if (active_mode == "user.german"): image_name = 'german' self.draw_icon(canvas, self.x + element_width - 30, self.y + circle_margin, icon_diameter, paint, 'tongue', image_name) return continue_drawing
def talon_debug_modes(): """Dumps active modes to the console""" print("**** Active modes ****") print(scope.get("mode")) print("***********************")