Touch ups and additional capabilities added to fifo functionality. Sample Fenrir scripts in extra

This commit is contained in:
Storm Dragon
2026-09-06 17:55:21 -04:00
parent 4ef8553c7d
commit 6817ecd90b
7 changed files with 75 additions and 37 deletions
+6 -1
View File
@@ -62,14 +62,19 @@ Each command must end with a \n (0x0a) character.
Commands may be added at any time. Commands may be added at any time.
Per the robustness principle, be liberal in what you receive. Per the robustness principle, be liberal in what you receive.
Current Commands: Current Commands:
* error: An error has occured to prevent transmitting audio, or taking another action.
* micup: Start transmitting, just as when you hold down the talk key. Does nothing if you are already transmiting. * micup: Start transmitting, just as when you hold down the talk key. Does nothing if you are already transmiting.
* micdown: Stop transmitting, just like when you release your talk key. Does nothing if you are not already transmitting. * micdown: Stop transmitting, just like when you release your talk key. Does nothing if you are not already transmitting.
* toggle: Toggle your transmission state. * toggle: Toggle your transmission state.
* talk: Synonym for toggle. * talk: Synonym for toggle.
* mute: Toggle self-mute, just like Alt+M by default.
* deafen: Toggle self-deafen, just like Alt+D by default. Self-deafening also mutes your microphone.
* noise: Toggle noise suppression on/off for microphone input. * noise: Toggle noise suppression on/off for microphone input.
* agc: Toggle automatic gain control on/off for microphone input. * agc: Toggle automatic gain control on/off for microphone input.
* record: Toggle recording. You may also use `record start` or `record stop`. * record: Toggle recording. You may also use `record start` or `record stop`.
* file: Play an audio file or URL. The path or URL follows the command.
* stop: Stop file playback.
* status: Announce whether you are transmitting.
* admin: Run an admin command. See the admin command section below.
* exit: Exit Barnard, just like when you press your quit key. * exit: Exit Barnard, just like when you press your quit key.
## Recording ## Recording
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Script for fenrir
# Replace USER with your user name
fifoPath=/home/USER/.config/barnard/cmd
[[ -p $fifoPath ]] || exit 0
printf '%s\n' talk | timeout 1s sudo -u USER tee "$fifoPath" &> /dev/null
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Script for fenrir
# Replace USER with your user name
fifoPath=/home/USER/.config/barnard/cmd
[[ -p $fifoPath ]] || exit 0
printf '%s\n' deafen | timeout 1s sudo -u USER tee "$fifoPath" &> /dev/null
+9
View File
@@ -0,0 +1,9 @@
#!/usr/bin/env bash
# Script for fenrir
# Replace USER with your user name
fifoPath=/home/USER/.config/barnard/cmd
[[ -p $fifoPath ]] || exit 0
printf '%s\n' status | timeout 1s sudo -u USER tee "$fifoPath" &> /dev/null
+14 -33
View File
@@ -327,6 +327,14 @@ func (b *Barnard) CommandTalk(ui *uiterm.Ui, cmd string) {
b.setTransmit(ui, 2) b.setTransmit(ui, 2)
} }
func (b *Barnard) CommandSelfMute(ui *uiterm.Ui, cmd string) {
b.toggleSelfMute()
}
func (b *Barnard) CommandSelfDeafen(ui *uiterm.Ui, cmd string) {
b.toggleSelfDeafen()
}
func (b *Barnard) CommandMicUp(ui *uiterm.Ui, cmd string) { func (b *Barnard) CommandMicUp(ui *uiterm.Ui, cmd string) {
b.setTransmit(ui, 1) b.setTransmit(ui, 1)
} }
@@ -649,40 +657,11 @@ func (b *Barnard) OnTextInput(ui *uiterm.Ui, textbox *uiterm.Textbox, text strin
// Check if this is a command (starts with /) // Check if this is a command (starts with /)
if strings.HasPrefix(text, "/") { if strings.HasPrefix(text, "/") {
// Remove the leading slash and process as command // Remove the leading slash and process it through the same command
// registry used by FIFO control.
cmdText := strings.TrimPrefix(text, "/") cmdText := strings.TrimPrefix(text, "/")
parts := strings.SplitN(cmdText, " ", 2) if !ui.DispatchCommand(cmdText) {
cmdName := parts[0] cmdName, _, _ := strings.Cut(cmdText, " ")
cmdArgs := ""
if len(parts) > 1 {
cmdArgs = parts[1]
}
// Handle built-in commands
switch cmdName {
case "file":
b.CommandPlayFile(ui, cmdArgs)
case "stop":
b.CommandStopFile(ui, cmdArgs)
case "exit":
b.CommandExit(ui, cmdArgs)
case "status":
b.CommandStatus(ui, cmdArgs)
case "noise":
b.CommandNoiseSuppressionToggle(ui, cmdArgs)
case "agc":
b.CommandAGCToggle(ui, cmdArgs)
case "record":
b.CommandRecord(ui, cmdArgs)
case "admin":
b.CommandAdmin(ui, cmdArgs)
case "micup":
b.CommandMicUp(ui, cmdArgs)
case "micdown":
b.CommandMicDown(ui, cmdArgs)
case "toggle", "talk":
b.CommandTalk(ui, cmdArgs)
default:
b.AddOutputLine(fmt.Sprintf("Unknown command: /%s", cmdName)) b.AddOutputLine(fmt.Sprintf("Unknown command: /%s", cmdName))
} }
return return
@@ -766,6 +745,8 @@ func (b *Barnard) OnUiInitialize(ui *uiterm.Ui) {
b.Ui.AddCommandListener(b.CommandMicDown, "micdown") b.Ui.AddCommandListener(b.CommandMicDown, "micdown")
b.Ui.AddCommandListener(b.CommandTalk, "toggle") b.Ui.AddCommandListener(b.CommandTalk, "toggle")
b.Ui.AddCommandListener(b.CommandTalk, "talk") b.Ui.AddCommandListener(b.CommandTalk, "talk")
b.Ui.AddCommandListener(b.CommandSelfMute, "mute")
b.Ui.AddCommandListener(b.CommandSelfDeafen, "deafen")
b.Ui.AddCommandListener(b.CommandExit, "exit") b.Ui.AddCommandListener(b.CommandExit, "exit")
b.Ui.AddCommandListener(b.CommandStatus, "status") b.Ui.AddCommandListener(b.CommandStatus, "status")
b.Ui.AddCommandListener(b.CommandNoiseSuppressionToggle, "noise") b.Ui.AddCommandListener(b.CommandNoiseSuppressionToggle, "noise")
+10 -3
View File
@@ -210,25 +210,32 @@ func (ui *Ui) onKeyEvent(key Key) {
} }
func (ui *Ui) onCommandEvent(cmd string) { func (ui *Ui) onCommandEvent(cmd string) {
ui.DispatchCommand(cmd)
}
// DispatchCommand sends a command to its registered listeners and reports
// whether any listener accepted it.
func (ui *Ui) DispatchCommand(cmd string) bool {
ta := strings.SplitN(cmd, " ", 2) ta := strings.SplitN(cmd, " ", 2)
t := ta[0] t := ta[0]
rest := "" rest := ""
if len(ta) == 2 { if len(ta) == 2 {
rest = ta[1] rest = ta[1]
} }
handled := false
if ui.commandListeners[t] != nil { if ui.commandListeners[t] != nil {
handled = true
for _, listener := range ui.commandListeners[t] { for _, listener := range ui.commandListeners[t] {
listener(ui, rest) listener(ui, rest)
} }
} }
if ui.commandListeners["*"] != nil { if ui.commandListeners["*"] != nil {
handled = true
for _, listener := range ui.commandListeners["*"] { for _, listener := range ui.commandListeners["*"] {
listener(ui, cmd) listener(ui, cmd)
} }
} }
// if ui.activeElement != nil { return handled
// ui.activeElement.View.uiKeyEvent(key)
// }
} }
func (ui *Ui) Add(name string, view View) error { func (ui *Ui) Add(name string, view View) error {
+18
View File
@@ -43,3 +43,21 @@ func TestSafeRuneRemovesTerminalControlCharacters(t *testing.T) {
t.Fatalf("safeRune altered printable text: %U", got) t.Fatalf("safeRune altered printable text: %U", got)
} }
} }
func TestDispatchCommandReportsMatchesAndPreservesArguments(t *testing.T) {
ui := New(nil)
got := ""
ui.AddCommandListener(func(_ *Ui, command string) {
got = command
}, "record")
if !ui.DispatchCommand("record start") {
t.Fatal("registered command was not handled")
}
if got != "start" {
t.Fatalf("command argument = %q, want start", got)
}
if ui.DispatchCommand("unknown") {
t.Fatal("unknown command was reported as handled")
}
}