Rivalcfg : comment j'ai créé, un peu par hasard, cet outil de configuration pour les souris SteelSeries

Rivalcfg est un utilitaire en ligne de commande et une bibliothèque Python permettant de configurer les souris de la marque SteelSeries. Il fonctionne actuellement sous Linux, Windows et MacOS, et il est probable qu'il fonctionne également sur d'autres systèmes d'exploitation, mais je n'ai pas testé.

Rivalcfg v4.0 vient tout juste de sortir, je vais donc profiter de l'occasion pour vous parler un peu de ce projet sur lequel je bosse depuis un peu plus de 4 ans maintenant.

Le commencement

Tout a commencé en mars 2016 : ma souris de l'époque, une brave Logitech G5, a rencontré un terrain favorable à un décès prématuré... il m'a donc fallu lui trouver une remplaçante.

Mon choix s'est porté sur la SteelSeries Rival 100 : elle avait un design sobre, une sensibilité configurable et elle était en promo... Nickel ! Et puis, même si j'en avais pas spécialement grand-chose à faire, elle disposait de LEDs RGB. Bon OK, les LEDs ont pas mal joué dans le choix de la souris... en même temps, ça serait rigolo si on pouvait les programmer non ? 🤩️

Photo souris SteelSeries Rival 100

Souris SteelSeries Rival 100 version blanche

Je reçois donc ma souris, et comme on pouvait s'en douter, le constructeur ne fournit bien évidemment aucun outil de configuration pour Linux. Mais bon, j'ai l'habitude, on va bien trouver une solution pour configurer la souris quand même ! 😜️

La première solution, relativement simple : configurer la souris depuis Windows. Comme elle dispose d'une mémoire interne, les paramètres seront conservés une fois de retour sous Linux. C'est cool, mais moi, sur le principe, ça m'ennuie de devoir dépendre de Windows pour configurer mon mulot.

Une autre solution, c'est d'étudier comment l'outil de configuration de SteelSeries communique avec la souris sous Windows, et d'essayer de faire pareil sous Linux... Plus facile à dire qu'à faire, je n'avais absolument aucune expérience dans le domaine.... Mais c'est pourtant cette voie que j'ai choisie. 😅️

J'ai donc commencé à faire des recherches sur la manière de procéder, et j'ai fini par lire quelque part que Wireshark était capable de capturer des trames USB. Je connaissais cet outil, l'ayant déjà utilisé pour capturer des paquets sur un réseau, mais j'ignorais totalement qu'il pouvait aussi capturer sur un bus USB, cool !

J'ai donc commencé à tâtonner pour tenter de capturer des paquets, et une fois que j'ai réussi à en choper quelques-uns, je me suis efforcé de comprendre ce que j'avais sous les yeux (j'étais un noob complet en USB à ce moment-là). Au final j'ai réussi à m'en sortir avec un setup composé d'une machine virtuelle Windows (pour faire tourner l'outil de configuration officiel), de Wireshark et de pas mal de persévérance. Je ne vous raconte pas tous les détails, je l'ai déjà fait dans un article à l'époque si ça vous intéresse. 😋️

Capture d'écran du SteelSeries Engine 3 tournant dans une machine virtuelle Windows et de Wireshark capturant des paquets.

À gauche, une machine virtuelle Windows faisant tourner le SteelSeries Engine 3. À droite, Wireshark en train de capturer des paquets.

Naissance et évolution de Rivalcfg

Grâce à ce travail de reverse engineering, j'ai commencé à développer Rivalcfg, dont la première version (v1.0) est sortie début avril 2016 (eh oui, c'est allé vite !). Cette version supportait uniquement ma souris, la Rival 100, et comme je manipulais directement udev pour communiquer avec la souris, le programme fonctionnait uniquement sous Linux.

J'aurais pu m'arrêter là, mais comme ça m'amusait bien de tripatouiller des souris, j'ai poursuivi le développement du logiciel. J'ai fini par trouver sur internet un autre outil, nommé rivalctl, qui lui, ne supportait que la SteelSeries Rival (la première souris de la gamme), et je me suis dit que je pourrais essayer de supporter les deux modèles dans Rivalcfg.

C'est ainsi que j'ai refactorisé tout le code de Rivalcfg pour lui permettre de supporter plusieurs modèles. Au lieu d'implémenter une classe par souris, ce qui faisait beaucoup de code redondant, j'ai créé un système de « profile ». Chaque profile décrit les fonctionnalités d'une souris, et la classe permettant de la configurer, ainsi que la CLI, sont ensuite générés en runtime.

Tout ça s'est encore une fois passé très rapidement, puisque mi-avril sortait déjà Rivalcfg v2.0, qui supportait la Rival et la Rival 100. Plusieurs versions du logiciel se sont ensuite succédé pour supporter de nouveaux modèles, essentiellement des dérivés de la Rival 300 (nouveau nom commercial de la Rival originale).

Puis en 2018, voyant les limites de l'architecture du logiciel, et souhaitant le rendre plus fiable, j'ai décidé de réécrire Rivalcfg, presque de zéro. Cette fois, plus question de manipuler directement udev : j'ai décidé de passer par la bibliothèque hidapi pour abstraire cette partie. Ce changement a notamment permis le support d'autres systèmes d'exploitation, comme Windows et Mac OS (mais il est probable que ça fonctionne également avec d'autres OS, je ne les ai simplement pas testés).

En septembre 2018 sortait donc Rivalcfg v3.0, fruit de ce travail de réécriture. Une douzaine de versions se sont succédé depuis, chacune supportant son lot de nouvelles souris. À l'origine, ce logiciel était censé ne supporter que des souris de la gamme Rival, mais assez rapidement des souris d'autres gammes se sont tapées l'incruste, comme la Kana V2, la Kinzu V2, ou les Sensei 310 et Sensei RAW.

Photos de souris SteelSeries en cours de test

Diverses souris SteelSeries sur le banc de test. De gauche à droite : Rival 110, Kinzu v2, Rival 100, Rival 300.

Rivalcfg v4.0

Tout ça nous mène à Rivalcfg v4.0, sorti tout récemment. Il s'agit cette fois encore d'une quasi-réécriture du projet, dans le but d'en améliorer l'architecture, d'en simplifier la maintenance, l'évolution et de réduire encore la duplication de code.

Pour ce dernier point, j'avais remarqué au fil des versions précédentes que SteelSeries avait tendance à sortir pas mal de souris identiques à des modèles existants, en ne changeant que le design. Le système de profile a donc été revu pour regrouper les souris en familles, ce qui permet de n'avoir qu'un seul et unique profil pour toutes les souris qui sont techniquement identiques.

D'ailleurs j'ai profité de cette amélioration pour supporter l'ensemble des souris des familles dont au moins un des membres était déjà supporté. Ceci a été rendu possible grâce à la constitution d'une base de données listant tous les modèles de souris SteelSeries existants, puisque pour supporter une souris, il faut à minima connaître son existence (bah oui, logique 😅️) et son product_id.

Base de données des souris SteelSeries

Base de données des souris SteelSeries

Avant cette version, la seule documentation disponible se trouvait dans le fichier README sur Github. C'était loin d'être suffisant, et ce point a été amélioré. Rivalcfg dispose à présent d'une documentation très complète : aussi bien les APIs Python que les spécificités de configuration de chaque souris y sont détaillés. Une page expliquant comment contribuer et une FAQ ont également été ajoutées.

Cette version a également été l'occasion de fortement améliorer la couverture du code par des tests unitaires. Les paquets d'octets envoyés aux souris sont maintenant strictement testés, pour permettre une évolution du logiciel en s'assurant de ne créer aucune régression.

Capture d'écran des tests unitaires

Tests unitaires de Rivalcfg

Enfin, Rivalcfg v4.0 prend en charge plusieurs nouveaux modèles de souris (comme la Rival 3) et de nouvelles fonctionnalités (notamment le mapping des boutons) sont maintenant supportées sur certains modèles...

Les changements apportés par cette version sont donc très nombreux, comme l'atteste l'interminable changelog, que je vous laisse lire si vous voulez plus de détails. 😁️

Remerciements

Je tiens à remercier la vingtaine de personnes qui ont contribué directement au code de Rivalcfg, je remercie ceux qui ont aidé au reverse engineering des différents modèles de souris que je ne possède pas, et ceux qui ont donné de leur temps pour tester si tout fonctionnait bien (ou pas).

Contributeurs de Rivalcfg

Quelques contributeurs de Rivalcfg.

Je remercie également les maintainers de la libratbag qui m'ont filé un coup de main pour certaines souris (par ce que oui, même s'il s'agit d'une lib « concurente », ça ne nous a pas empêchés de nous échanger des infos et de nous entre-aider 😉️).

Enfin je souhaite remercier tout particulièrement le généreux contributeur qui m'a envoyé une Rival 300, qui a permis de bien faire évoluer le logiciel, ainsi que mon collègue (qui se reconnaîtra), qui m'a laissé jouer avec sa Kinzu V2 et sa Sensei RAW pour ajouter et améliorer leur support. 😁️

Rivalcfg ne serait pas ce qu'il est aujourd'hui sans l'aide de tout ce petit monde !

Et maintenant ?

Pour commencer, j'ai encore pas mal de petites choses que j'avais à l'origine prévues pour la v4.0 et qui sortiront finalement au fil des futures versions. J'ai en effet fini par décider de sortir le logiciel avec un peu moins de choses que prévu, plutôt que de repousser sans cesse sa sortie et de perdre ma motivation au passage (effet tunnel, tout ça,...).

Ensuite, bah... tant qu'il y aura des contributeurs pour m'aider, je continuerai à faire évoluer le logiciel, à supporter de nouvelles souris et de nouvelles fonctionnalités.

Enfin, ce qu'il manque le plus à ce logiciel, c'est une interface graphique, pour simplifier au maximum la configuration des souris. C'est quelque chose qui prendra du temps à réaliser, et je ne vais pas forcément me pencher sur ce sujet tout de suite, mais j'y réfléchis en tout cas. 😊️

Si ce projet vous intéresse, vous le retrouverez sur Github :

N'hésitez pas à contribuer, que ça soit pour rapporter un truc qui manque ou qui ne marche pas, pour corriger une erreur dans la doc ou pour aider au reverse engineering d'une souris (c'est plus simple qu'on ne le pense) !


[29/08/2020] Quelques nouvelles suite à une discussion avec SteelSeries

En parallèle de cet article, j'avais posté lundi un petit message sur le subreddit de SteelSeries afin de leur demander un peu d'aide. Ayant déjà essayé de les contacter à plusieurs reprises sur Twitter, sans grand succès, je n'attendais pas forcément grand-chose de ce message, mais bon, qui ne tente rien... 😋️

Message posté sur le subreddit de SteelSeries

Au final, j'ai eu le plaisir de lire beaucoup de réponses très positives, notamment des messages de personnes utilisant Rivalcfg ! Et, plus tard dans la journée, j'ai la bonne surprise de recevoir une réponse de la part d'un employé de SteelSeries, m'invitant à venir discuter avec lui sur Discord ! 😁️

Réponse de SteelSeries sur Reddit

Quelques minutes plus tard on se retrouve donc sur Discord, et il commence par m'expliquer que les développeurs chez eux adoreraient pouvoir supporter Linux, mais qu'ils manquent de ressource pour cela. C'est tout à fait compréhensible : développer, maintenir et assurer le support des utilisateurs d'une plateforme supplémentaire à un coût non négligeable, pour trop peu de personnes au final (leur cible reste les gamers, qui sont essentiellement sous Windows).

Il m'indique également qu'il n'est malheureusement pas possible de libérer les spec des souris pour des raisons politiques internes, même si le sujet revient régulièrement sur le tapis (et souvent à cause de Rivalcfg 😋️). Par contre, même s'ils ne peuvent pas me fournir les spécifications du matériel, ils ne voient aucun inconvénient à répondre à quelques questions techniques, ni à ce que j'effectue de la rétro-ingéniérie sur leur matériel.

Je lui ai donc posé quelques questions, qui m'ont déjà permis de vérifier les informations dont je disposais sur certaines souris, et d'ajouter le support de la Rival 300S (qui sera donc disponible dans la prochaine version de Rivalcfg).

On a également parlé des souris qu'il pouvait m'envoyer. On est au final arrivé à une sélection de 5 modèles assez variés, choisis à la fois pour leur popularité et pour leurs spécificités :

  • La Rival 3 : il s'agit de l'une des souris les moins chères proposées par la marque, ce qui fait qu'elle compte de nombreux utilisateurs et il est donc très important pour moi de bien la supporter. En réalité, Rivalcfg la gère déjà partiellement grâce à des contributeurs, mais je vais à présent pouvoir compléter son support.
  • La Sensei 310 : avec la Rival 310 qui est quasiment identique, elle représente le cœur de la gamme. Je vais pouvoir grâce à cette souris travailler à corriger un bug que les utilisateurs rencontrent sous Windows, et terminer son support (notamment pour ce qui est du mapping des boutons).
  • La Rival 500 : le modèle aux 15 boutons. Cette souris est actuellement très partiellement gérée par Rivalcfg. Je vais enfin pouvoir lui ajouter le support du mapping des boutons (ce qui est une fonctionnalité essentielle pour une souris qui en dispose d'autant !), mais aussi améliorer le support des couleurs et travailler sur son vibreur (eh oui, cette souris dispose de retours haptiques !).
  • La Sensei TEN : il existe actuellement deux modèles de cette souris, et j'avais dû supprimer son support lors de la sortie de Rivalcfg v4.0 : il était trop expérimental. Je vais donc pouvoir la réintégrer, et bien sûr compléter la liste des fonctionnalités supportées sur ce modèle !
  • Et enfin, la Rival 650 : premier modèle sans fil qui sera intégré à Rivalcfg. Il va permettre de préparer le terrain pour les spécificités liées au sans-fil (récupération du niveau de batterie, etc).
Souris de test envoyées par SteelSeries

Comme vous pouvez le voir sur la photo ci-dessus, c'est allé très vite : j'ai déjà reçu les souris et je suis impatient de voir ce qu'elles ont dans le ventre ! 😃️

Pour le moment j'ai mal de boulot avec mes 5 nouvelles souris, mais je trouve très motivant que SteelSeries ne soit pas indifférent au projet, et j'espère pouvoir à nouveau obtenir leur aide sur de nouveaux modèles.

Quoi qu'il en soit, pas mal de nouveautés sortiront au fil des versions dans les prochaines semaines / les prochains mois ! 😋️