Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ English (US) release notes, mirroring CHANGELOG.md (Brazilian Portuguese). Befor

## [Unreleased]
### What's new
- **Controller sounds** (#276): Menu → Configurações → **Sons do controle** (off, low, medium, high, max). Short, soft cues synthesized inside the app, distinct for moving focus, confirming/opening, going back and marking. They play only for controller actions (never the keyboard), don't machine-gun when you hold the D-pad, use the Windows audio output and don't change any button or navigation. Off by default; without a sound device nothing happens.
### What's new
- **Automation and `controlfs://` protocol**: support for `controlfs://start`, `controlfs://stop`, and `controlfs://show` links, as well as command-line arguments (`--start`, `--stop`, `--show`, `--close`), enabling seamless external integration with game launchers and frontends (such as Console Mode), Stream Deck buttons, and automation scripts. Invoking `controlfs://start` when the app is already open restores and brings the window to the foreground without launching duplicate instances; `controlfs://stop` cleanly exits the app; with copies or other operations running it doesn't cancel them by itself and shows the exit confirmation. The protocol is registered by the installer; the portable version writes nothing to the registry (the command-line flags work there). After an update, the app relaunched by the installer waits for the old instance to leave.

### Fixes
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Notas em português do Brasil; a versão em inglês (Estados Unidos) fica em `CH

## [Unreleased]
### Novidades
- **Sons do controle** (#276): Menu → Configurações → **Sons do controle** (desligados, baixo, médio, alto, máximo). Toques curtos e suaves, desenhados no próprio app, distintos para mover o foco, confirmar/abrir, voltar e marcar. Tocam só nas ações do controle (nunca do teclado), não repetem feito metralhadora ao segurar o direcional, usam a saída de áudio do Windows e não mudam nenhum botão nem a navegação. Vem desligado; sem placa de som, nada acontece.
### Novidades
- **Automação e protocolo `controlfs://`**: suporte aos links `controlfs://start`, `controlfs://stop` e `controlfs://show`, bem como argumentos de linha de comando (`--start`, `--stop`, `--show`, `--close`), facilitando a integração externa com launchers e frontends (como o Console Mode), botões de Stream Deck e scripts. Acionar `controlfs://start` quando o app já está aberto restaura e traz a janela para o primeiro plano sem abrir instâncias duplicadas; `controlfs://stop` encerra o app de forma limpa; havendo cópias ou outras operações em andamento, ele não as cancela sozinho e mostra a confirmação de saída. O protocolo é registrado pelo instalador; a versão portátil não escreve nada no registro (as opções de linha de comando funcionam nela). Depois de uma atualização, o app reaberto pelo instalador espera a instância antiga sair.

### Correções
Expand Down
6 changes: 5 additions & 1 deletion docs/GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Item actions (North) and the app Menu (Start) open with the most used actions as

In dialogs, the footer says what each button does. With the focus on the back option itself (**Cancelar**, **Fechar**), the footer shows the next option on Right instead of repeating the same thing on both buttons.

**Option pickers:** a setting with several values that the tile or row doesn't show (**Exibição**, **Densidade da lista**, **Tema**, **Cor de destaque**, **Ordenar por**, **Confirmar com**, **Legendas**, **Fluidez**) opens a picker listing every choice, each with a short explanation, the current one marked with a filled radio icon and the word "atual" and the focus on it. South/Enter or a click on a choice applies it and returns to Configurações on the same setting; Back (or Esc) closes the picker without changing anything. Simple on/off settings and settings that open their own screen stay one press. The same picker is used for the size and date filters of a search and the mode of batch rename. All settings live in Menu → **Configurações** (settings), grouped under **Exibição** (view, density, details panel, sort, hidden items), **Busca e privacidade** (search in subfolders, recents, keyboard suggestions), **Controles** (confirm button, button labels, Fluidez (controller read rate), Leve em segundo plano (light in the background), gyro aiming (experimental), active controller, controller test, controllers without a profile) and **ControlFS** (updates). In each group, short settings are **tiles** in a grid with the icon, a short name and the current value (e.g. **Ocultos** · escondidos, hidden items · hidden). Values are states, never verbs, and on/off settings say **ligado**/**desligado** (on/off); the same setting has the same name and value everywhere. The line under the focused tile explains what the setting does instead of repeating its value. Settings with long descriptions or that open another screen stay in a list below. In the grid, Left/Right move between tiles, Down from the last row continues to the group's list (and from there to the next group's grid) and Up goes back to the tile you came from. Every window of the app keeps its size while you use it: the panel never widens, narrows, grows or shrinks as focus moves, values change, a message appears or you switch options (for example ZIP, TAR.GZ and 7z in the Compress window are the same size); long texts wrap inside it, and the description area is as tall as the longest description. Changing a setting keeps Configurações open with the new value and focus on the same setting, so you can change several in a row; Back closes it.
**Option pickers:** a setting with several values that the tile or row doesn't show (**Exibição**, **Densidade da lista**, **Tema**, **Cor de destaque**, **Ordenar por**, **Confirmar com**, **Legendas**, **Fluidez**) opens a picker listing every choice, each with a short explanation, the current one marked with a filled radio icon and the word "atual" and the focus on it. South/Enter or a click on a choice applies it and returns to Configurações on the same setting; Back (or Esc) closes the picker without changing anything. Simple on/off settings and settings that open their own screen stay one press. The same picker is used for the size and date filters of a search and the mode of batch rename. All settings live in Menu → **Configurações** (settings), grouped under **Exibição** (view, density, details panel, sort, hidden items), **Busca e privacidade** (search in subfolders, recents, keyboard suggestions), **Controles** (confirm button, button labels, Fluidez (controller read rate), Sons do controle (controller sounds), Leve em segundo plano (light in the background), gyro aiming (experimental), active controller, controller test, controllers without a profile) and **ControlFS** (updates). In each group, short settings are **tiles** in a grid with the icon, a short name and the current value (e.g. **Ocultos** · escondidos, hidden items · hidden). Values are states, never verbs, and on/off settings say **ligado**/**desligado** (on/off); the same setting has the same name and value everywhere. The line under the focused tile explains what the setting does instead of repeating its value. Settings with long descriptions or that open another screen stay in a list below. In the grid, Left/Right move between tiles, Down from the last row continues to the group's list (and from there to the next group's grid) and Up goes back to the tile you came from. Every window of the app keeps its size while you use it: the panel never widens, narrows, grows or shrinks as focus moves, values change, a message appears or you switch options (for example ZIP, TAR.GZ and 7z in the Compress window are the same size); long texts wrap inside it, and the description area is as tall as the longest description. Changing a setting keeps Configurações open with the new value and focus on the same setting, so you can change several in a row; Back closes it.

### Controller test

Expand Down Expand Up @@ -307,6 +307,10 @@ ControlFS can be opened, brought to the front, or closed from external tools, sc

The `controlfs://` scheme is registered in Windows by the installer (and re-registered on startup if the install folder moved). The portable version writes nothing to the registry, so `controlfs://` links need the installed version; the command-line flags work everywhere. Only one instance of ControlFS runs per user session; launching a second instance signals the active window and exits immediately.

## Controller sounds

Menu → Configurações → **Sons do controle** plays short, soft cues for what you do with the controller: a tick when focus moves, a rising note for confirm/open, a falling one for back and a small blip when you mark an item. Choose **desligados** (off, the default), **baixo**, **médio**, **alto** or **máximo**. They play only for controller actions (never the keyboard), don't repeat faster than about 12 times a second when you hold the D-pad, use the default Windows audio output and never change a button or how navigation works. The sounds are generated inside the app (no audio files).

## Screen readers

With Narrator (or another UI Automation screen reader) on, the app announces where the focus is and the focused item as you move with the controller or keyboard: the home screen, folder, menu, dialog or on-screen keyboard when you enter it, then just the item as you move (name, type, size and position such as "3 of 20"). States are spoken in words: marked, cut, blocked (with the reason), password-protected, unavailable (with the reason). Notices (the pop-up in the bottom-right corner) and the line above the list are read without moving the focus. Nothing depends on sound, vibration or color alone.
Expand Down
6 changes: 5 additions & 1 deletion docs/GUIDE.pt-BR.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ As ações do item (Norte) e o Menu do app (Start) abrem com as ações mais usa

Nos diálogos, o rodapé diz o que cada botão faz. Com o foco na própria opção de voltar (**Cancelar**, **Fechar**), o rodapé mostra a próxima opção na seta para a direita em vez de repetir a mesma coisa nos dois botões.

**Seletor de opções:** um ajuste com vários valores que o bloco ou a linha não mostram (**Exibição**, **Densidade da lista**, **Tema**, **Cor de destaque**, **Ordenar por**, **Confirmar com**, **Legendas**, **Fluidez**) abre um seletor com todas as escolhas, cada uma com uma explicação curta, a atual marcada com um botão de opção cheio e a palavra "atual" e o foco nela. Sul/Enter ou um clique numa escolha a aplica e volta a Configurações no mesmo ajuste; Voltar (ou Esc) fecha o seletor sem mudar nada. Ligar/desligar simples e ajustes que abrem a própria tela continuam de um toque. O mesmo seletor vale para o tamanho e a data dos filtros da busca e para o modo de Renomear em lote. Todos os ajustes ficam em Menu → **Configurações**, em grupos: **Exibição** (lista/grade, densidade, painel de detalhes, ordenação, itens ocultos), **Busca e privacidade** (busca em subpastas, recentes, sugestões do teclado), **Controles** (botão de confirmar, legendas, Fluidez, Leve em segundo plano, mira por giroscópio (experimental), controle ativo, teste de controles, controles sem perfil) e **ControlFS** (atualizações). Em cada grupo, os ajustes curtos são **blocos** numa grade, com o ícone, o nome curto e o valor atual (ex.: **Ocultos** · escondidos). Os valores são estados, nunca verbos, e ajustes de ligar/desligar dizem **ligado**/**desligado**; o mesmo ajuste tem o mesmo nome e valor em qualquer tela. A linha sob o bloco focado explica o que o ajuste faz em vez de repetir o valor. Os que têm descrição longa ou abrem outra tela ficam numa lista abaixo. Na grade, esquerda/direita andam entre os blocos, baixo na última linha segue para a lista do grupo (e dela para a grade do grupo seguinte) e cima volta ao bloco de onde você veio. Toda janela do app mantém o tamanho enquanto você a usa: o painel não alarga, estreita, cresce nem encolhe quando o foco se move, um valor muda, aparece um aviso ou você troca de opção (por exemplo, ZIP, TAR.GZ e 7z na janela Compactar têm o mesmo tamanho); textos longos quebram linha dentro dele, e a área de descrição tem a altura da descrição mais longa. Mudar um ajuste mantém Configurações aberto com o valor novo e o foco no mesmo ajuste, para mudar vários seguidos; Voltar fecha.
**Seletor de opções:** um ajuste com vários valores que o bloco ou a linha não mostram (**Exibição**, **Densidade da lista**, **Tema**, **Cor de destaque**, **Ordenar por**, **Confirmar com**, **Legendas**, **Fluidez**) abre um seletor com todas as escolhas, cada uma com uma explicação curta, a atual marcada com um botão de opção cheio e a palavra "atual" e o foco nela. Sul/Enter ou um clique numa escolha a aplica e volta a Configurações no mesmo ajuste; Voltar (ou Esc) fecha o seletor sem mudar nada. Ligar/desligar simples e ajustes que abrem a própria tela continuam de um toque. O mesmo seletor vale para o tamanho e a data dos filtros da busca e para o modo de Renomear em lote. Todos os ajustes ficam em Menu → **Configurações**, em grupos: **Exibição** (lista/grade, densidade, painel de detalhes, ordenação, itens ocultos), **Busca e privacidade** (busca em subpastas, recentes, sugestões do teclado), **Controles** (botão de confirmar, legendas, Fluidez, Sons do controle, Leve em segundo plano, mira por giroscópio (experimental), controle ativo, teste de controles, controles sem perfil) e **ControlFS** (atualizações). Em cada grupo, os ajustes curtos são **blocos** numa grade, com o ícone, o nome curto e o valor atual (ex.: **Ocultos** · escondidos). Os valores são estados, nunca verbos, e ajustes de ligar/desligar dizem **ligado**/**desligado**; o mesmo ajuste tem o mesmo nome e valor em qualquer tela. A linha sob o bloco focado explica o que o ajuste faz em vez de repetir o valor. Os que têm descrição longa ou abrem outra tela ficam numa lista abaixo. Na grade, esquerda/direita andam entre os blocos, baixo na última linha segue para a lista do grupo (e dela para a grade do grupo seguinte) e cima volta ao bloco de onde você veio. Toda janela do app mantém o tamanho enquanto você a usa: o painel não alarga, estreita, cresce nem encolhe quando o foco se move, um valor muda, aparece um aviso ou você troca de opção (por exemplo, ZIP, TAR.GZ e 7z na janela Compactar têm o mesmo tamanho); textos longos quebram linha dentro dele, e a área de descrição tem a altura da descrição mais longa. Mudar um ajuste mantém Configurações aberto com o valor novo e o foco no mesmo ajuste, para mudar vários seguidos; Voltar fecha.

### Teste de controles

Expand Down Expand Up @@ -307,6 +307,10 @@ O ControlFS pode ser aberto, trazido para a frente ou encerrado por ferramentas

O esquema `controlfs://` é registrado no Windows pelo instalador (e de novo ao iniciar, se a pasta de instalação mudou). A versão portátil não escreve nada no registro, então os links `controlfs://` pedem a versão instalada; as opções de linha de comando funcionam em qualquer uma. Apenas uma instância do ControlFS roda por sessão de usuário; abrir uma segunda chamada sinaliza a janela ativa e encerra o novo processo imediatamente.

## Sons do controle

Menu → Configurações → **Sons do controle** toca sons curtos e suaves para o que você faz com o controle: um tique ao mover o foco, uma nota que sobe ao confirmar/abrir, uma que desce ao voltar e um toque pequeno ao marcar um item. Escolha **desligados** (o padrão), **baixo**, **médio**, **alto** ou **máximo**. Tocam só nas ações do controle (nunca do teclado), não repetem mais que umas 12 vezes por segundo ao segurar o direcional, usam a saída de áudio padrão do Windows e nunca mudam um botão nem a navegação. Os sons são gerados dentro do app (sem arquivos de áudio).

## Leitores de tela

Com o Narrador (ou outro leitor de tela com UI Automation) ligado, o app anuncia onde está o foco e o item focado enquanto você anda com o controle ou o teclado: a tela inicial, a pasta, o menu, o diálogo ou o teclado virtual ao entrar, depois só o item a cada movimento (nome, tipo, tamanho e posição, como "3 de 20"). Estados são ditos por extenso: marcado, recortado, bloqueado (com o motivo), com senha, indisponível (com o motivo). Os avisos (no canto inferior direito) e a linha acima da lista são lidos sem mover o foco. Nada depende só de som, vibração ou cor.
Expand Down
5 changes: 5 additions & 0 deletions docs/TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -856,3 +856,8 @@ Só a CI (WinRAR 7.23 pelo winget, arquivo criado pelo Rar.exe real e extraído
- [ ] Com o WinRAR instalado (outra versão que a da CI, ex.: 6.x e 7.x mais novo): marcar itens → Compactar → RAR → o `.rar` abre no WinRAR e no ControlFS com o mesmo conteúdo; nome existente vira "(2)".
- [ ] Criar um RAR grande e cancelar no meio pelo controle: o `.rar` parcial some, o Rar.exe não fica no Gerenciador de Tarefas.
- [ ] Arquivo em uso entre os itens: resultado "concluído com avisos" (o WinRAR devolve o código 1) e a mensagem pede para conferir.

## Sons do controle (#276) — não validado em hardware
- [ ] Menu → Configurações → Sons do controle → baixo/médio/alto: mover o foco, confirmar, voltar e marcar tocam sons diferentes e discretos; o volume muda entre as opções; "desligados" silencia tudo.
- [ ] Segurar o direcional numa lista longa: o tique não vira chiado nem atrasa o foco. O teclado (setas, Enter, Esc) não toca nada.
- [ ] Com fones/alto-falantes diferentes ou sem saída de áudio: segue a saída padrão do Windows; sem dispositivo, o app funciona igual.
9 changes: 7 additions & 2 deletions src/ControlFS.App/Navigation/InputHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,16 @@ public sealed class InputHost : IInputSink, IRawControllerSource, IControllerDia
private readonly Dictionary<string, AnalogScroller> _scrollers = [];
private readonly Dictionary<string, GyroPointer> _gyros = [];

public InputHost(AppController app, DispatcherQueue queue)
public InputHost(AppController app, DispatcherQueue queue, Core.Audio.ControllerSounds? sounds = null)
{
_app = app;
_queue = queue;
Router = new InputRouter(new ActionMap(app.Settings.Convention), InputSettings.Default, app.Handle);
// Só as ações do controle passam pelo som (o teclado chama app.Handle direto). O som é o primeiro passo e nunca bloqueia.
Router = new InputRouter(new ActionMap(app.Settings.Convention), InputSettings.Default, sounds is null ? app.Handle : action =>
{
sounds.OnAction(action);
app.Handle(action);
});
Router.RepeatPolicy = app.IsRepeatableInContext;
Router.ActiveDeviceChanged += _ =>
{
Expand Down
7 changes: 6 additions & 1 deletion src/ControlFS.App/Views/MainWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public sealed class MainWindow : Window
{
private readonly AppController _app;
private readonly InputHost _input;
private readonly WindowsSoundPlayer? _soundPlayer;
private readonly GitHubReleaseUpdateService? _updates;
/// <summary>Ouvinte de instância única e automação (sinais Show e Close). Null nas capturas.</summary>
private readonly SingleInstanceListener? _singleInstanceListener;
Expand Down Expand Up @@ -160,7 +161,10 @@ internal MainWindow(string? dataDirectory)
_app.AttachPhoneLink(_phone);
}
var inputStarted = startup.ElapsedMilliseconds;
_input = new InputHost(_app, DispatcherQueue);
if (dataDirectory is null) _soundPlayer = new WindowsSoundPlayer();
var clock = System.Diagnostics.Stopwatch.StartNew();
_input = new InputHost(_app, DispatcherQueue, _soundPlayer is null ? null
: new Core.Audio.ControllerSounds(_soundPlayer, () => _app.Settings.ControllerSoundVolume, () => clock.Elapsed));
if (dataDirectory is null)
{
_background = new BackgroundMode(_app, DispatcherQueue, _drives);
Expand Down Expand Up @@ -265,6 +269,7 @@ internal MainWindow(string? dataDirectory)
_app.ReleaseMediaForShutdown();
_app.PrepareShutdown(); // instala em silêncio uma atualização verificada, se o usuário deixou ligado
_input.Dispose();
_soundPlayer?.Dispose();
_phone?.Dispose(); // para de escutar e avisa o celular
_updates?.Dispose();
_iconProvider.Dispose();
Expand Down
Loading
Loading