init commit
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
class Language:
|
||||
id: str
|
||||
spoken_forms: list[str]
|
||||
extensions: list[str]
|
||||
|
||||
def __init__(self, id: str, spoken_form: str | list[str], extensions: list[str]):
|
||||
self.id = id
|
||||
self.spoken_forms = (
|
||||
[spoken_form] if isinstance(spoken_form, str) else spoken_form
|
||||
)
|
||||
self.extensions = extensions
|
||||
|
||||
|
||||
# Maps code language identifiers, names and file extensions. Only put languages
|
||||
# here which have a supported language mode; that's why there are so many
|
||||
# commented out entries.
|
||||
code_languages = [
|
||||
# Language("assembly", "assembly", ["asm", "s"]),
|
||||
# Language("bash", "bash", ["sh", "bashbook"]),
|
||||
Language("batch", "batch", ["bat"]),
|
||||
Language("c", "see", ["c", "h"]),
|
||||
# Language("cmake", "see make", ["cmake"]),
|
||||
Language("csharp", "see sharp", ["cs"]),
|
||||
Language("css", "c s s", ["css"]),
|
||||
# Language("elisp", "elisp", ["el"]),
|
||||
Language("elixir", "elixir", ["ex"]),
|
||||
# Language("elm", "elm", ["elm"]),
|
||||
Language("gdb", "g d b", ["gdb"]),
|
||||
Language("go", ["go lang", "go language"], ["go"]),
|
||||
Language("java", "java", ["java"]),
|
||||
Language("javascript", "java script", ["js"]),
|
||||
Language("javascriptreact", "java script react", ["jsx"]),
|
||||
# Language("jsonl", "json lines", ["jsonl"]),
|
||||
Language("kotlin", "kotlin", ["kt"]),
|
||||
Language("lua", "lua", ["lua"]),
|
||||
Language("markdown", "mark down", ["md"]),
|
||||
# Language("perl", "perl", ["pl"]),
|
||||
Language("php", "p h p", ["php"]),
|
||||
# Language("powershell", "power shell", ["ps1"]),
|
||||
Language("protobuf", "proto buf", ["proto"]),
|
||||
Language("python", "python", ["py"]),
|
||||
Language("r", "are language", ["r"]),
|
||||
# Language("racket", "racket", ["rkt"]),
|
||||
Language("ruby", "ruby", ["rb"]),
|
||||
Language("rust", "rust", ["rs"]),
|
||||
Language("scala", "scala", ["scala"]),
|
||||
Language("scss", "scss", ["scss"]),
|
||||
# Language("snippets", "snippets", ["snippets"]),
|
||||
Language("sql", "sql", ["sql"]),
|
||||
Language("stata", "stata", ["do", "ado"]),
|
||||
Language("talon", "talon", ["talon"]),
|
||||
Language("talonlist", "talon list", ["talon-list"]),
|
||||
Language("terraform", "terraform", ["tf"]),
|
||||
Language("tex", ["tech", "lay tech", "latex"], ["tex"]),
|
||||
Language("typescript", "type script", ["ts"]),
|
||||
Language("typescriptreact", "type script react", ["tsx"]),
|
||||
# Language("vba", "vba", ["vba"]),
|
||||
Language("vimscript", "vim script", ["vim", "vimrc"]),
|
||||
# These languages doesn't actually have a language mode, but we do have snippets.
|
||||
Language("cpp", "see plus plus", ["cpp", "hpp"]),
|
||||
Language("csv", "csv", ["csv"]),
|
||||
Language("html", "html", ["html"]),
|
||||
Language("json", "json", ["json"]),
|
||||
Language("shellscript", "shell script", ["sh"]),
|
||||
Language("xml", "xml", ["xml"]),
|
||||
]
|
||||
|
||||
# Files without specific extensions but are associated with languages
|
||||
# Maps full filename to language identifiers
|
||||
code_special_file_map = {
|
||||
"CMakeLists.txt": "cmake",
|
||||
"Makefile": "make",
|
||||
"Dockerfile": "docker",
|
||||
"meson.build": "meson",
|
||||
".bashrc": "bash",
|
||||
".zshrc": "zsh",
|
||||
"PKGBUILD": "pkgbuild",
|
||||
".vimrc": "vimscript",
|
||||
"vimrc": "vimscript",
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
mode: command
|
||||
mode: dictation
|
||||
-
|
||||
^dictation mode$:
|
||||
mode.disable("sleep")
|
||||
mode.disable("command")
|
||||
mode.enable("dictation")
|
||||
user.code_clear_language_mode()
|
||||
user.gdb_disable()
|
||||
^command mode$:
|
||||
mode.disable("sleep")
|
||||
mode.disable("dictation")
|
||||
mode.enable("command")
|
||||
@@ -0,0 +1,41 @@
|
||||
from talon import Context, Module, actions
|
||||
|
||||
mod = Module()
|
||||
mod.tag(
|
||||
"deep_sleep",
|
||||
desc="Tag for enabling deep sleep, requiring a longer wakeup command (defined in `sleep_mode_deep.talon`)",
|
||||
)
|
||||
|
||||
ctx = Context()
|
||||
|
||||
|
||||
@mod.action_class
|
||||
class Actions:
|
||||
def deep_sleep_enable():
|
||||
"""Enable deep sleep.
|
||||
|
||||
Deep sleep requires a longer wakeup command to exit sleep
|
||||
mode, helping prevent unintended wakeups from conversations,
|
||||
meetings, listening to videos, etc.
|
||||
|
||||
Instead of invoking this action directly, consider enabling
|
||||
the `user.deep_sleep` tag in applications where unwanted
|
||||
wakeups are more likely or problematic, such as meeting
|
||||
apps. With this tag active, any sleep command triggers deep
|
||||
sleep.
|
||||
|
||||
You can also manually activate deep sleep by defining a custom
|
||||
voice command using this action.
|
||||
|
||||
Note: If the user.deep_sleep_disable action is not used to
|
||||
wake up from deep sleep, then the deep sleep tag will stay
|
||||
active.
|
||||
|
||||
"""
|
||||
ctx.tags = ["user.deep_sleep"]
|
||||
actions.speech.disable()
|
||||
|
||||
def deep_sleep_disable():
|
||||
"""Disable deep sleep"""
|
||||
ctx.tags = []
|
||||
actions.speech.enable()
|
||||
@@ -0,0 +1,76 @@
|
||||
mode: dictation
|
||||
-
|
||||
^press <user.modifiers>$: key(modifiers)
|
||||
^press <user.keys>$: key(keys)
|
||||
|
||||
# Everything here should call `user.dictation_insert()` instead of `insert()`, to correctly auto-capitalize/auto-space.
|
||||
<user.raw_prose>: user.dictation_insert(raw_prose)
|
||||
cap: user.dictation_format_cap()
|
||||
# Hyphenated variants are for Dragon.
|
||||
(no cap | no-caps): user.dictation_format_no_cap()
|
||||
(no space | no-space): user.dictation_format_no_space()
|
||||
^cap that$: user.dictation_reformat_cap()
|
||||
^(no cap | no-caps) that$: user.dictation_reformat_no_cap()
|
||||
^(no space | no-space) that$: user.dictation_reformat_no_space()
|
||||
|
||||
# Navigation
|
||||
go up <number_small> (line | lines):
|
||||
edit.up()
|
||||
repeat(number_small - 1)
|
||||
go down <number_small> (line | lines):
|
||||
edit.down()
|
||||
repeat(number_small - 1)
|
||||
go left <number_small> (word | words):
|
||||
edit.word_left()
|
||||
repeat(number_small - 1)
|
||||
go right <number_small> (word | words):
|
||||
edit.word_right()
|
||||
repeat(number_small - 1)
|
||||
go line start: edit.line_start()
|
||||
go line end: edit.line_end()
|
||||
|
||||
# Selection
|
||||
select left <number_small> (word | words):
|
||||
edit.extend_word_left()
|
||||
repeat(number_small - 1)
|
||||
select right <number_small> (word | words):
|
||||
edit.extend_word_right()
|
||||
repeat(number_small - 1)
|
||||
select left <number_small> (character | characters):
|
||||
edit.extend_left()
|
||||
repeat(number_small - 1)
|
||||
select right <number_small> (character | characters):
|
||||
edit.extend_right()
|
||||
repeat(number_small - 1)
|
||||
clear left <number_small> (word | words):
|
||||
edit.extend_word_left()
|
||||
repeat(number_small - 1)
|
||||
edit.delete()
|
||||
clear right <number_small> (word | words):
|
||||
edit.extend_word_right()
|
||||
repeat(number_small - 1)
|
||||
edit.delete()
|
||||
clear left <number_small> (character | characters):
|
||||
edit.extend_left()
|
||||
repeat(number_small - 1)
|
||||
edit.delete()
|
||||
clear right <number_small> (character | characters):
|
||||
edit.extend_right()
|
||||
repeat(number_small - 1)
|
||||
edit.delete()
|
||||
|
||||
# Formatting
|
||||
formatted <user.format_text>: user.dictation_insert_raw(format_text)
|
||||
^format selection <user.formatters>$: user.formatters_reformat_selection(formatters)
|
||||
|
||||
# Corrections
|
||||
nope that | scratch that: user.clear_last_phrase()
|
||||
(nope | scratch) selection: edit.delete()
|
||||
select that: user.select_last_phrase()
|
||||
spell that <user.letters>: user.dictation_insert(letters)
|
||||
spell that <user.formatters> <user.letters>:
|
||||
result = user.formatted_text(letters, formatters)
|
||||
user.dictation_insert_raw(result)
|
||||
|
||||
# Escape, type things that would otherwise be commands
|
||||
^escape <user.text>$: user.dictation_insert(user.text)
|
||||
@@ -0,0 +1,8 @@
|
||||
#defines modes specific to Dragon.
|
||||
speech.engine: dragon
|
||||
mode: all
|
||||
-
|
||||
# wakes Dragon on Mac, deactivates talon speech commands
|
||||
dragon mode: user.dragon_mode()
|
||||
#sleep dragon on Mac, activates talon speech commands
|
||||
talon mode: user.talon_mode()
|
||||
@@ -0,0 +1,73 @@
|
||||
from talon import Context, Module, actions, app
|
||||
|
||||
from .code_languages import code_languages, code_special_file_map
|
||||
|
||||
mod = Module()
|
||||
ctx = Context()
|
||||
|
||||
ctx_forced = Context()
|
||||
ctx_forced.matches = r"""
|
||||
tag: user.code_language_forced
|
||||
"""
|
||||
|
||||
|
||||
mod.tag("code_language_forced", "This tag is active when a language mode is forced")
|
||||
mod.list("language_mode", desc="Name of a programming language mode.")
|
||||
|
||||
# Maps spoken forms to language ids
|
||||
ctx.lists["user.language_mode"] = {
|
||||
spoken_form: language.id
|
||||
for language in code_languages
|
||||
for spoken_form in language.spoken_forms
|
||||
}
|
||||
|
||||
# Maps extension to language ids
|
||||
extension_lang_map = {
|
||||
f".{ext}": lang.id for lang in code_languages for ext in lang.extensions
|
||||
}
|
||||
|
||||
language_ids = {lang.id for lang in code_languages}
|
||||
forced_language = ""
|
||||
|
||||
|
||||
@ctx.action_class("code")
|
||||
class CodeActions:
|
||||
def language():
|
||||
file_name = actions.win.filename()
|
||||
if file_name in code_special_file_map:
|
||||
return code_special_file_map[file_name]
|
||||
|
||||
file_extension = actions.win.file_ext().lower()
|
||||
return extension_lang_map.get(file_extension, "")
|
||||
|
||||
|
||||
@ctx_forced.action_class("code")
|
||||
class ForcedCodeActions:
|
||||
def language():
|
||||
return forced_language
|
||||
|
||||
|
||||
@mod.action_class
|
||||
class Actions:
|
||||
def code_set_language_mode(language: str):
|
||||
"""Sets the active language mode, and disables extension matching"""
|
||||
global forced_language
|
||||
assert language in language_ids
|
||||
forced_language = language
|
||||
# Update tags to force a context refresh. Otherwise `code.language` will not update.
|
||||
# Necessary to first set an empty list otherwise you can't move from one forced language to another.
|
||||
ctx.tags = []
|
||||
ctx.tags = ["user.code_language_forced"]
|
||||
|
||||
def code_clear_language_mode():
|
||||
"""Clears the active language mode, and re-enables code.language: extension matching"""
|
||||
global forced_language
|
||||
forced_language = ""
|
||||
ctx.tags = []
|
||||
|
||||
def code_show_forced_language_mode():
|
||||
"""Show the active language for this context"""
|
||||
if forced_language:
|
||||
app.notify(f"Forced language: {forced_language}")
|
||||
else:
|
||||
app.notify("No language forced")
|
||||
@@ -0,0 +1,3 @@
|
||||
^force {user.language_mode}$: user.code_set_language_mode(language_mode)
|
||||
show [forced] language mode: user.code_show_forced_language_mode()
|
||||
^clear language mode$: user.code_clear_language_mode()
|
||||
@@ -0,0 +1,64 @@
|
||||
from talon import Context, Module, actions, app, speech_system
|
||||
|
||||
mod = Module()
|
||||
ctx_sleep = Context()
|
||||
ctx_awake = Context()
|
||||
|
||||
modes = {
|
||||
"presentation": "a more strict form of sleep where only a more strict wake up command works",
|
||||
}
|
||||
|
||||
for key, value in modes.items():
|
||||
mod.mode(key, value)
|
||||
|
||||
ctx_sleep.matches = r"""
|
||||
mode: sleep
|
||||
"""
|
||||
|
||||
ctx_awake.matches = r"""
|
||||
not mode: sleep
|
||||
"""
|
||||
|
||||
|
||||
@ctx_sleep.action_class("speech")
|
||||
class ActionsSleepMode:
|
||||
def disable():
|
||||
actions.app.notify("Talon is already asleep")
|
||||
|
||||
|
||||
@ctx_awake.action_class("speech")
|
||||
class ActionsAwakeMode:
|
||||
def enable():
|
||||
actions.app.notify("Talon is already awake")
|
||||
|
||||
|
||||
@mod.action_class
|
||||
class Actions:
|
||||
def talon_mode():
|
||||
"""For windows and Mac with Dragon, enables Talon commands and Dragon's command mode."""
|
||||
actions.speech.enable()
|
||||
|
||||
engine = speech_system.engine.name
|
||||
# app.notify(engine)
|
||||
if "dragon" in engine:
|
||||
if app.platform == "mac":
|
||||
actions.user.dragon_engine_sleep()
|
||||
elif app.platform == "windows":
|
||||
actions.user.dragon_engine_wake()
|
||||
# note: this may not do anything for all versions of Dragon. Requires Pro.
|
||||
actions.user.dragon_engine_command_mode()
|
||||
|
||||
def dragon_mode():
|
||||
"""For windows and Mac with Dragon, disables Talon commands and exits Dragon's command mode"""
|
||||
engine = speech_system.engine.name
|
||||
# app.notify(engine)
|
||||
|
||||
if "dragon" in engine:
|
||||
# app.notify("dragon mode")
|
||||
actions.speech.disable()
|
||||
if app.platform == "mac":
|
||||
actions.user.dragon_engine_wake()
|
||||
elif app.platform == "windows":
|
||||
actions.user.dragon_engine_wake()
|
||||
# note: this may not do anything for all versions of Dragon. Requires Pro.
|
||||
actions.user.dragon_engine_normal_mode()
|
||||
@@ -0,0 +1,34 @@
|
||||
mode: command
|
||||
mode: dictation
|
||||
mode: sleep
|
||||
not speech.engine: dragon
|
||||
-
|
||||
# The optional <phrase> afterwards allows these to match even if you say arbitrary text
|
||||
# after this command, without having to wait for the speech timeout.
|
||||
|
||||
# This is handy because you often need to put Talon asleep in order to immediately
|
||||
# talk to humans, and it's annoying to have to say "sleep all", wait for the timeout,
|
||||
# and then resume your conversation.
|
||||
|
||||
# With this, you can say "sleep all hey bob" and Talon will immediately go to
|
||||
# sleep and ignore "hey bob". Note that subtitles will show "sleep all hey bob",
|
||||
# because it's part of the rule definition, but "hey bob" will be ignored, because
|
||||
# we don't do anything with the <phrase> in the body of the command.
|
||||
|
||||
# We define this *only* if the speech engine isn't Dragon, because if you're using Dragon,
|
||||
# "go to sleep" is used to specifically control Dragon, and not affect Talon.
|
||||
#
|
||||
# It's a useful and well known command, though, so if you're using any other speech
|
||||
# engine, this controls Talon.
|
||||
^go to sleep [<phrase>]$: speech.disable()
|
||||
^talon sleep [<phrase>]$:
|
||||
speech.disable()
|
||||
user.deprecate_command("2025-06-25", "talon sleep (without dragon)", "go to sleep")
|
||||
|
||||
^sleep all [<phrase>]$:
|
||||
user.switcher_hide_running()
|
||||
user.history_disable()
|
||||
user.homophones_hide()
|
||||
user.help_hide()
|
||||
user.mouse_sleep()
|
||||
speech.disable()
|
||||
@@ -0,0 +1,9 @@
|
||||
mode: sleep
|
||||
-
|
||||
settings():
|
||||
# Stop continuous scroll/gaze scroll with a pop
|
||||
user.mouse_enable_pop_stops_scroll = false
|
||||
# Stop pop click with 'control mouse' mode
|
||||
user.mouse_enable_pop_click = 0
|
||||
# Stop mouse scroll down using hiss noise
|
||||
user.mouse_enable_hiss_scroll = false
|
||||
@@ -0,0 +1,5 @@
|
||||
mode: sleep
|
||||
tag: user.deep_sleep
|
||||
-
|
||||
|
||||
^wake up and listen$: user.deep_sleep_disable()
|
||||
@@ -0,0 +1,25 @@
|
||||
mode: all
|
||||
speech.engine: dragon
|
||||
-
|
||||
# The optional <phrase> afterwards allows these to match even if you say arbitrary text
|
||||
# after this command, without having to wait for the speech timeout.
|
||||
|
||||
# This is handy because you often need to put Talon asleep in order to immediately
|
||||
# talk to humans, and it's annoying to have to say "sleep all", wait for the timeout,
|
||||
# and then resume your conversation.
|
||||
|
||||
# With this, you can say "sleep all hey bob" and Talon will immediately go to
|
||||
# sleep and ignore "hey bob". Note that subtitles will show "sleep all hey bob",
|
||||
# because it's part of the rule definition, but "hey bob" will be ignored, because
|
||||
# we don't do anything with the <phrase> in the body of the command.
|
||||
^talon sleep [<phrase>]$: speech.disable()
|
||||
^talon wake [<phrase>]$: speech.enable()
|
||||
|
||||
^sleep all [<phrase>]$:
|
||||
user.switcher_hide_running()
|
||||
user.history_disable()
|
||||
user.homophones_hide()
|
||||
user.help_hide()
|
||||
user.mouse_sleep()
|
||||
speech.disable()
|
||||
user.dragon_engine_sleep()
|
||||
@@ -0,0 +1,18 @@
|
||||
mode: command
|
||||
mode: dictation
|
||||
mode: sleep
|
||||
not speech.engine: dragon
|
||||
not tag: user.deep_sleep
|
||||
-
|
||||
|
||||
# We define this *only* if the speech engine isn't Dragon, because if you're using Dragon,
|
||||
# "wake up" is used to specifically control Dragon, and not affect Talon.
|
||||
#
|
||||
# It's a useful and well known command, though, so if you're using any other speech
|
||||
# engine, this controls Talon.
|
||||
|
||||
^(wake up)+$: speech.enable()
|
||||
|
||||
^talon wake [<phrase>]$:
|
||||
speech.enable()
|
||||
user.deprecate_command("2025-06-25", "talon wake (without dragon)", "wake up")
|
||||
@@ -0,0 +1,44 @@
|
||||
import time
|
||||
|
||||
from talon import Context, Module, actions, settings
|
||||
|
||||
ctx = Context()
|
||||
mod = Module()
|
||||
|
||||
mod.tag("pop_twice_to_wake", desc="tag for enabling pop twice to wake in sleep mode")
|
||||
|
||||
mod.setting(
|
||||
"double_pop_speed_minimum",
|
||||
type=float,
|
||||
desc="""Shortest time in seconds to accept a second pop to trigger additional actions""",
|
||||
default=0.1,
|
||||
)
|
||||
|
||||
mod.setting(
|
||||
"double_pop_speed_maximum",
|
||||
type=float,
|
||||
desc="""Longest time in seconds to accept a second pop to trigger additional actions""",
|
||||
default=0.3,
|
||||
)
|
||||
|
||||
ctx.matches = r"""
|
||||
mode: sleep
|
||||
and tag: user.pop_twice_to_wake
|
||||
"""
|
||||
|
||||
time_last_pop = 0
|
||||
|
||||
|
||||
@ctx.action_class("user")
|
||||
class UserActions:
|
||||
def noise_trigger_pop():
|
||||
# Since zoom mouse is registering against noise.register("pop", on_pop), let that take priority
|
||||
if actions.tracking.control_zoom_enabled():
|
||||
return
|
||||
global time_last_pop
|
||||
double_pop_speed_minimum = settings.get("user.double_pop_speed_minimum")
|
||||
double_pop_speed_maximum = settings.get("user.double_pop_speed_maximum")
|
||||
delta = time.perf_counter() - time_last_pop
|
||||
if delta >= double_pop_speed_minimum and delta <= double_pop_speed_maximum:
|
||||
actions.speech.enable()
|
||||
time_last_pop = time.perf_counter()
|
||||
@@ -0,0 +1,30 @@
|
||||
mode: sleep
|
||||
not tag: user.deep_sleep
|
||||
-
|
||||
|
||||
#================================================================================
|
||||
# Commands to wake Talon
|
||||
#================================================================================
|
||||
|
||||
# Note: these have repeaters on them (+) to work around an issue where, in sleep mode,
|
||||
# you can get into a situation where these commands are difficult to trigger.
|
||||
|
||||
# These commands are fully anchored (^ and $), which means that there must be
|
||||
# silence before and after saying them in order for them to recognize (this reduces
|
||||
# false positives during normal sleep mode, normally a good thing).
|
||||
|
||||
# However, ignored background speech during sleep mode also counts as an utterance.
|
||||
|
||||
# Thus, if you say "blah blah blah talon wake", these won't trigger, because "blah
|
||||
# blah blah" was part of the same utterance. You have to say "blah blah blah" <pause,
|
||||
# wait for speech timeout>, "talon wake" <pause, wait for speech timeout>.
|
||||
|
||||
# Sometimes people would forget the second pause, notice things weren't working, and
|
||||
# say "talon wake" over and over again before the speech timeout ever gets hit, which
|
||||
# means that these won't recognize. The (+) handles this case, so if you say
|
||||
# <pause> "talon wake talon wake" <pause>, it'll still work.
|
||||
|
||||
^(welcome back)+$:
|
||||
user.mouse_wake()
|
||||
user.history_enable()
|
||||
user.talon_mode()
|
||||
@@ -0,0 +1,6 @@
|
||||
mode: sleep
|
||||
speech.engine: wav2letter
|
||||
-
|
||||
#this exists solely to prevent talon from waking up super easily in sleep mode at the moment with wav2letter
|
||||
#you probably shouldn't have any other commands here
|
||||
<phrase>: skip()
|
||||
Reference in New Issue
Block a user