Aller au contenu

Whoa Type

Utilitaire macOS de la barre de menus qui joue un son à chaque touche et chaque clic : 38 packs sonores, préécoute, et un moteur audio qui préalloue ses voix.

  • Swift
  • SwiftUI
  • Core Graphics
  • AVAudioEngine
Whoa Type : du caractère dans chaque frappe.

Du caractère dans chaque frappe.

Un utilitaire macOS qui donne une voix au clavier, à la souris et au trackpad. Tout se règle depuis la barre de menus, avec 38 packs sonores embarqués.

Fonctionnalités · Architecture


À propos

Le plaisir d'un clavier mécanique tient aussi à son bruit : une touche plus grave, une barre d'espace plus marquée, un petit relief à chaque frappe.

Whoa Type reprend cette idée dans une app native. On choisit un pack, on règle le volume, puis l'app accompagne les appuis et les relâchements.

Le traitement reste local : pas de compte, pas de service réseau, pas d'enregistrement de ce qui est saisi. L'écoute globale demande l'autorisation de surveillance des entrées de macOS. Le son est désactivé au premier lancement.


✨ Fonctionnalités

⌨️ Une frappe qui varie selon les touches

Un son à l'appui, un autre au relâchement. Les répétitions automatiques d'une touche maintenue sont ignorées, pour qu'un appui produise exactement un son à l'appui et un au relâchement.

Espace, Retour et Supprimer ont davantage de poids ; les touches de modification restent plus légères. De gauche à droite, le son passe d'un timbre plus chaud et grave à un rendu plus clair et aigu, avec un placement stéréo adapté à la position de la touche.

Les géométries physiques ANSI, ISO et JIS se choisissent dans les réglages.


🎛️ 38 packs et une préécoute

La bibliothèque embarquée permet d'écouter chaque pack avant de le sélectionner. La préécoute passe par le même moteur que la frappe, fonctionne sans autorisation de surveillance des entrées et même lorsque le son est désactivé. Elle respecte le volume choisi.

Les noms (Amber, Birch, Ember…) désignent les enregistrements, sans prétendre identifier des modèles de switches. Dans cette première bibliothèque, chaque pack réutilise le même enregistrement pour l'appui et le relâchement ; les différences entre touches sont produites par le traitement audio.

  • Bibliothèque · sélection et préécoute


🖱️ Des clics pour la souris et le trackpad

Les boutons gauche, droit et auxiliaires déclenchent leurs propres sons d'appui et de relâchement.

Six enregistrements d'appui alternent au hasard, sans répétition immédiate. Souris et trackpad partagent cette bibliothèque et suivent le même volume que le clavier. Les déplacements, le défilement et les gestes ne produisent aucun son, et aucune coordonnée n'est lue.


⚙️ Dans la barre de menus

Activation du son et accès aux réglages depuis le menu. Pas d'icône dans le Dock. Une fenêtre de réglages regroupe la lecture (volume, géométrie), la bibliothèque, les autorisations et le démarrage à la connexion.

Le volume, le pack choisi, la géométrie du clavier et l'état du son sont conservés entre les lancements. Fermer les réglages laisse l'utilitaire actif.


🧱 Architecture

Une seule application, avec des responsabilités séparées pour l'interface, la capture des entrées, le chargement des sons et le rendu audio.

whoa_typeApp.swift — Point d'entrée et scènes SwiftUI
App/ — Coordination et état de l'application
AppShell/ — Menu, réglages et parcours d'autorisation
Input/ — Capture passive, touches et boutons
Permissions/ — Accès à la surveillance des entrées
SoundPacks/ — Manifestes, validation et chargement PCM
Audio/ — Files bornées, mixage et sortie audio
Settings/ — Préférences et lancement à la connexion
Resources/SoundPacks/ — 38 packs embarqués
Package.swift — Cœur testable avec Swift Package Manager
Tests/WhoaTypeCoreTests/ — Tests Swift Testing
Tools/ — Préparation audio, sondes, benchmark et distribution

🧠 Le core : séparer la frappe du rendu audio

Le travail principal se trouve dans le chemin entre une touche physique et le son joué.

  • Une écoute passive. Le tap Core Graphics (listenOnly) observe les événements sans les modifier. Le clavier est traité par codes physiques, sans conversion en texte.
  • Une file bornée. La capture transmet de petites commandes audio à une file à producteur et consommateur uniques, synchronisée par opérations atomiques. Si elle est pleine, le son entrant est abandonné sans jamais bloquer la saisie.
  • Des sons prêts avant la frappe. Les manifestes sont validés, puis les fichiers décodés et convertis en PCM sur une file dédiée, hors du chemin de rendu.
  • Un mixeur à 64 voix. Le rendu superpose les sons, ajuste leur hauteur, leur timbre et leur placement stéréo, avec des fondus pour les transitions.
  • Un changement de pack coordonné. L'ancienne banque reste disponible jusqu'à l'acquittement du moteur. La préécoute suspend la capture réelle, puis restaure le pack sélectionné.

L'app distingue une autorisation manquante d'un échec de capture. Les contextes de saisie sécurisée de macOS peuvent suspendre les sons ; cette protection est respectée, pas contournée.


🛠️ Stack technique

  1. Application

    • Swift 6
    • SwiftUI (MenuBarExtra)
    • Observation
    • macOS 26.5 minimum
  2. Entrées

    • Core Graphics
    • CGEventTap (listenOnly)
    • CFRunLoop
  3. Audio

    • AVFoundation
    • AVAudioEngine
    • AVAudioSourceNode
    • AVAudioConverter
  4. Synchronisation

    • Synchronization (atomiques)
    • DispatchQueue
    • Files SPSC bornées
  5. Préférences

    • UserDefaults
    • ServiceManagement (SMAppService)
  6. Outillage

    • Swift Package Manager
    • Swift Testing
    • Script afconvert
    • Benchmark synthétique

Aucune dépendance tierce à l'exécution.


💡 Ce que j'en retiens

  • Préparer avant de jouer. Décoder les sons et réserver les voix en amont garde le chemin de rendu court et borné.
  • Donner une responsabilité à chaque file. Interface, capture, chargement et contrôle audio ont des rythmes différents. Des échanges explicites rendent les changements de pack et les annulations plus faciles à maîtriser.
  • Créer du relief avec peu de matière. Un même enregistrement change de caractère avec la hauteur, le gain, le timbre et la position stéréo.
  • Séparer le benchmark de l'expérience réelle. Les tests synthétiques vérifient le mixeur ; ils ne mesurent pas le délai entre une touche physique et le haut-parleur. Cette mesure reste à faire sur le matériel.

📸 Captures d'écran

  • Menu · activation et accès aux réglages

  • Lecture · volume et géométrie du clavier

  • Autorisations · surveillance des entrées


🛣️ Roadmap

  • Interface SwiftUI dans la barre de menus
  • Capture passive des touches et des boutons
  • Bibliothèque de 38 packs avec préécoute
  • Variations de hauteur, de timbre et de placement stéréo
  • Clics de souris et de trackpad, avec six appuis alternés
  • Réglages persistants et lancement à la connexion
  • Tests du cœur et benchmark synthétique
  • Terminer la validation des autorisations dans l'app signée
  • Valider sur matériel les géométries, les périphériques audio et la veille
  • Mesurer la latence physique et compléter le profilage sous Instruments
  • Ajouter des enregistrements distincts de relâchement clavier
  • Compléter la provenance et les licences des enregistrements
  • Notariser l'application et publier une version sur GitHub