DEV Community

elboKazQC
elboKazQC

Posted on

3 semaines de build-in-public plus tard : 4 abonnés, 0 vente, et le bug de hotkey qui m'a pris 2 soirs

Ça fait trois semaines que je publie ici en mode transparent sur Tania Dictée, mon outil de dictée vocale FR-Québec. Le premier article avait un titre franc : 0 inscrit, 3 jours pour valider l'idée. Il a eu une réaction. Les deux suivants, sur le code-switching et la vie privée, zéro.

Alors on continue avec les vrais chiffres, plus un bug qui m'a fait perdre deux soirées et qui vaut la peine d'être raconté.

Les chiffres, sans les habiller

Sur dev.to : 3 articles publiés, 4 abonnés au blog. Les 4 sont arrivés en silence, aucun commentaire, aucune réaction associée. Moins de 25 vues par article. Une seule réaction au total, sur le tout premier post.

Sur X (@TaniaDictee) : 1 abonné. Sur Hacker News, mon karma est à 1. Le repo GitHub a 0 star.

Zéro vente. Le produit est à 9$ CAD sur Gumroad depuis des semaines, personne n'a encore acheté.

Je pourrais dramatiser ou je pourrais dire que c'est normal pour un projet solo à budget zéro. La vérité est entre les deux : c'est petit, mais dev.to est le seul endroit où quelque chose bouge, même faiblement. Alors j'y mets plus d'énergie plutôt que de disperser sur cinq canaux qui ne répondent pas.

Le bug qui m'a pris deux soirs

Tania Dictée fonctionne en push-to-talk : tu tiens F6, tu parles, tu relâches, ça transcrit et ça colle le texte où t'as le curseur. Simple sur papier. Sauf que la détection du relâchement de touche sur Windows n'est pas aussi fiable qu'on pense.

Le module keyboard en Python expose deux événements : add_hotkey pour la pression, on_release_key pour le relâchement. Mon premier réflexe a été de démarrer l'enregistrement sur la pression et de l'arrêter sur le relâchement. Ça marchait... la plupart du temps.

Le problème : si tu relâches F6 pendant qu'une autre fenêtre a le focus, ou si Windows avale l'événement à cause d'un conflit avec un autre hook clavier actif (j'en avais un autre qui tournait pour une raison complètement différente), l'événement de relâchement ne se déclenche jamais. Résultat : Tania reste convaincue que tu parles encore. Elle enregistre en boucle jusqu'à ce que tu réappuies sur F6, ce qui bascule l'état dans le mauvais sens et fige l'app dans un état bizarre.

La vraie source du bug, ce n'était pas mon code d'enregistrement, c'était une hypothèse fausse : je pensais qu'un événement clavier Windows me serait toujours livré. Dans mon cas il ne l'était pas, surtout avec plusieurs hooks actifs en parallèle.

La solution qui a fini par tenir : au lieu de dépendre uniquement de l'événement on_release_key, j'ai ajouté un threading.Timer qui revérifie activement l'état des touches à intervalle court avec keyboard.is_pressed(). Si aucune des touches du hotkey n'est physiquement pressée, on arrête l'enregistrement, peu importe si l'événement de relâchement est arrivé ou pas.

def _schedule_stop_if_hotkey_released(self):
    # debounce configurable, pas un chiffre magique code en dur
    delay = max(0.0, float(self.cfg.release_debounce_ms) / 1000.0)
    timer = threading.Timer(delay, self._stop_if_hotkey_inactive)
    timer.daemon = True
    timer.start()

def _stop_if_hotkey_inactive(self):
    # on ne fait pas confiance a l'evenement de relachement :
    # on verifie l'etat physique reel des touches
    if any(keyboard.is_pressed(key) for key in self.hotkey_keys):
        return
    self.stop_recording()
Enter fullscreen mode Exit fullscreen mode

En gros : ne fais pas confiance à l'événement, vérifie l'état réel. Ça semble évident écrit comme ça, mais sur le coup j'ai passé deux soirées à ajouter des logs, suspecter le driver du micro, suspecter faster-whisper, avant de réaliser que le vrai coupable était une hypothèse sur le comportement du clavier que je n'avais jamais vérifiée.

Il y a un deuxième détail qui a mordu en même temps : add_hotkey avec suppress=True empêche la touche d'atteindre les autres apps (utile pour que F6 ne tape pas un caractère parasite dans ton éditeur), mais ça change aussi comment Windows route certains événements de relâchement selon le contexte de focus. Ce n'est documenté nulle part de façon limpide, il a fallu tester à la main pour comprendre.

Ce que ça change concrètement

Depuis ce fix, Tania tourne chez moi tous les jours sans ce comportement fantôme. C'est le genre de bug qu'un utilisateur externe aurait rencontré dans sa première semaine et qui aurait tué la confiance direct. Bonne nouvelle : c'est réglé avant que qui que ce soit d'autre que moi ne l'ait vécu, parce que pour l'instant je suis mon seul utilisateur.

C'est aussi une leçon plus large sur le solo dev : quand t'es le seul testeur, les bugs les plus vicieux sont ceux qui dépendent du contexte système (autres apps ouvertes, autres hooks actifs, focus de fenêtre) et que tu ne reproduis pas facilement en isolation. Le fix a fini par être plus robuste que l'approche initiale précisément parce qu'il ne fait plus confiance à un seul signal.

Au fond, c'est pour ça que je bâtis ce truc : si tu dictes en français québécois une bonne partie de ta journée et que l'idée d'envoyer ta voix dans le cloud te dérange, c'est exactement l'outil que j'aurais voulu trouver au lieu de le coder.

Où on en est

Le code reste ouvert sous licence MIT sur github.com/elboKazQC/tania-dictee si le bug ou le hotkey handling vous intéresse en détail. Toujours 0 star, ça ne me dérange pas de le dire.

La suite : je continue de nourrir dev.to en priorité puisque c'est le seul canal où il se passe quelque chose, même petit. Prochain post, probablement le premier vrai benchmark de précision (WER) que j'ai promis dans les articles précédents et que je n'ai toujours pas publié. Il est temps.

Si vous avez déjà chassé un bug qui se cachait derrière une hypothèse fausse sur un événement système (clavier, réseau, fichier), ça m'intéresse de l'entendre en commentaire.

Top comments (0)