Deblan blog

Remote i3-wm WS : ma télécommande pour bureau Debian GNU/Linux

Il m'arrive d'avoir besoin de prendre le contrôle de ma machine via mon Android (bouger la souris, scroller et taper du texte).

J'ai quasiment toujours utilisé l'application Pointer Host. elle s'appuie sur un serveur Java lancé sur ma machine. Pour bouger la souris et générer des cliques, elle est très efficace. Cependant, l'écriture de caractères a toujours posé problème (chiffres et lettres accentuées erronés).

Depuis quelques semaines, j'ai envie de jouer avec les websockets et réécrire une appli du genre m'a semblé être un bon exercice.

Ce que je vais vous présenter est une POC. Cette application n'est pas sécurisée et est orientée pour mes besoins. Il est cependant très simple de la faire évoluer.

Voici mon cahier des charges :

  1. aucune application ne doit être installée sur mon téléphone
  2. utilisation du navigateur web pour le pilotage
  3. pouvoir bouger la souris
  4. pouvoir générer des cliques
  5. pouvoir scroller
  6. pouvoir taper des mots
  7. pouvoir lancer des raccouris claviers
  8. pouvoir gérer le volume du son
  9. pour Spotify : lancer et mettre en pause la musique, avancer et reculer dans la playlist en cours de lecture
  10. pouvoir changer de workspace dans mon gestionnaire de fenêtres i3-wm

Les outils pour scripter tout ça sont connus :

  • xdotool pour simuler un clavier et une souris (3, 4, 5, 6, 7) :
    • xdotool type "ceci va être tapé"
    • xdotool key Enter (touche Entrée)
    • xdotool click 1 (clique gauche)
  • amixer pour gérer le volume (8) :
    • amixer set Master 50% (volume à 50%)
  • playerctl pour piloter Spotify (9) :
    • playerctl -p spotify next (titre suivant)
  • i3-msg pour piloter i3-wm (10) :
    • i3-msg 'workspace "Foo"' (affichage du workspace Foo)

Websocket est un protocole réseau issu du web qui permet de créer un canal full-duplex entre un client et un serveur. Ils peuvent donc communiquer en temps réel dans une connexion TCP.

Comme à mon habitude et par esprit de contradiction (pas de NodeJS), j'ai décidé d'écrire la partie serveur en PHP 7. La partie cliente est en HTML 5 avec un peu de javascript.

Entre le serveur et le client, ce sont des messages textes qui sont échangés. J'ai décidé de les formater en JSON et seul le client va en envoyer. Ils sont toujours sous cette forme : {"type":"un type de message", [données complémentaires]}. Voici quelques exemples :

  • {"type":"workspace","value":"1. IRC"}
  • {"type":"pointer","click":"left"}
  • {"type":"media","value":"next"}
  • {"type":"volume","value":"down"}
  • {"type":"scroll","value":"up"}
  • {"type":"pointer","x":"-2","y":"3"}
  • {"type":"text","value":"Un texte"}

On peut aussi envoyer plusieurs messages dans un seul. Voici un exemple qui va permettre d'ouvrir urxvt via dmenu que je lance avec win+d :

{"type":"messages","value":[{"type":"keys","value":"win,d"},{"type":"text","value":"urxvt"},{"type":"key","value":"enter"}]}

Ces messages sont générés par le client et sont interprétés par des messageHandler une fois transmis au serveur. En voici un exemple :

Le code source de l'application est disponible sur deblan/remote-i3wm-ws et la procédure d'installation est simple :

Pour lancer le serveur websocket, il faut exécuter server/server start (@see restart et stop). Le serveur va écouter sur le port 14598. Concernant la partie cliente, vous pouvez créer un vhost Apache/Nginx qui pointera sur client/ ou lancer le serveur web built-in de PHP via php -S 0.0.0.0:15000 -t client/. Il faudra à présent vous connecter au serveur web depuis un navigateur.

Quelques captures de la partie cliente :

Remote i3-wm WS: keyboardRemote i3-wm WS: i3Remote i3-wm WS: mouseRemote i3-wm WS: media

Je vais essayer de faire une vidéo de démonstration. Depuis mon Samsung S8, ça fonctionne du feu de dieu et sur un petit Iphone 4S, c'est tout aussi fonctionnel (à part l'interface web un peu étriquée).

Edit 1

  • dbus-send a été remplacé par playerctl (merci Thomas L)
  • le type messages a été ajouté et permet d'envoyer plusieurs messages (cf l'exemple avec urxvt) et les mises à jour du code

Edit 2

  • Le code PHP du serveur a été déplacé dans server/src/resource/server.php
  • server/server est à présent un script shell et permet de lancer, relancer et stopper le serveur websocket (server/server start|restart|stop)

  • jerry wham
    • ,
    • Génial.
      Je vais étudier ça.

      Pour arrêter le serveur, un ctrl+c suffit ?

      Pour changer le port utilisé, il faut le faire dans les fichiers server/server et client/assets/js/main.js.

      Y a-t-il un autre endroit ou est-ce que ce sont les seuls fichiers ?

      Est-ce que le fait de changer le port utilisé par php dans la commande qui lance le client (15000) aura une conséquence quant au fonctionnement de l'appli ?

      Merci pour le partage.
  • Thomas L
    • ,
    • Tu devrais essayer playerctl pour la musique, c'est un player assez universel qui est bien pratique.
  • Simon
    • ,
    • Merci pour le tips ! Je l'utilise déjà pour afficher le titre en cours de lecture mais je n'avais pas du tout penser à lui pour gérer la lecture.
  • jerry wham
    • ,
    • Pour arrêter le serveur, un ctrl+c ne suffit pas. Si on actualise la page, le serveur se relance.
      Pour vraiment l'arrêter, il faut tuer le processus (kill) en ajoutant les deux index donnés lors du lancement des commandes pour le client et le serveur.
  • Simon
    • ,
    • J'ai également détecté ce problème…je vais essayer de trouver un fix !
  • jerry wham
    • ,
    • Ça fonctionne pour le serveur mais pas pour le client qui continue de fonctionner si on rafraichit la page.
      On devrait pouvoir rafraichir uniquement si le client n'a pas été tué via le terminal.
      Par contre, je ne parviens pas à afficher la page sur mon tel ou sur ma tablette, uniquement sur l'ordi qui lance les processus...
  • Simon
    • ,
    • Effectivement, le correctif mis en ligne ne permet que de piloter le serveur websocket et pas le serveur web. En effet, il pourrait être tout à fait possible de passer par apache ou nginx pour délivrer cette partie du service.

      Quand tu lances le serveur web, quelles commandes utilises-tu ?

Ajouter un commentaire

Vous pouvez utiliser du markdown. Afficher l'aide.

Prévisualiser